| /* machdep.S - machine dependent assembly routines for the GDB stub */ |
| /* |
| * Copyright (C) 2006 Lubomir Kundrak |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| #include <grub/cpu/gdb.h> |
| #include <grub/symbol.h> |
| |
| #define EC_PRESENT 1 |
| #define EC_ABSENT 0 |
| |
| #define GRUB_GDB_STACKSIZE 40000 |
| |
| #define SEP , |
| |
| #ifdef __APPLE__ |
| .zerofill __DATA, __bss, LOCAL(grub_gdb_stack_end), GRUB_GDB_STACKSIZE, 4 |
| LOCAL(grub_gdb_stack) = LOCAL(grub_gdb_stack_end) |
| #else |
| /* |
| * The .data index for the address vector. |
| */ |
| |
| #define VECTOR 1 |
| |
| .bss |
| .space GRUB_GDB_STACKSIZE |
| VARIABLE(grub_gdb_stack) |
| #endif |
| |
| /* |
| * Supplemental macros for register saving/restoration |
| * on exception handler entry/leave. |
| */ |
| |
| #ifdef __APPLE__ |
| .macro save32 |
| #define REG $0 |
| #define NDX $1 |
| #else |
| .macro save32 reg ndx |
| #define REG \reg |
| #define NDX \ndx |
| #endif |
| movl REG, EXT_C(grub_gdb_regs)+(NDX * 4) |
| .endm |
| |
| #undef REG |
| #undef NDX |
| |
| #ifdef __APPLE__ |
| .macro save16 |
| #define REG $0 |
| #define NDX $1 |
| #else |
| .macro save16 reg ndx |
| #define REG \reg |
| #define NDX \ndx |
| #endif |
| #ifdef __APPLE__ |
| xorl %eax, %eax |
| #else |
| movl $0, %eax |
| #endif |
| movw REG, EXT_C(grub_gdb_regs)+(NDX * 4) |
| movw %ax, EXT_C(grub_gdb_regs)+(NDX * 4 + 2) |
| movl EXT_C(grub_gdb_regs)+(EAX * 4), %eax |
| .endm |
| |
| #undef REG |
| #undef NDX |
| |
| #ifdef __APPLE__ |
| .macro load32 |
| #define NDX $0 |
| #define REG $1 |
| #else |
| .macro load32 ndx reg |
| #define REG \reg |
| #define NDX \ndx |
| #endif |
| movl EXT_C(grub_gdb_regs)+(NDX * 4), REG |
| .endm |
| |
| #undef REG |
| #undef NDX |
| |
| #ifdef __APPLE__ |
| .macro load16 |
| #define NDX $0 |
| #define REG $1 |
| #else |
| .macro load16 ndx reg |
| #define NDX \ndx |
| #define REG \reg |
| #endif |
| movw EXT_C(grub_gdb_regs)+(NDX * 4), REG |
| .endm |
| |
| #undef REG |
| #undef NDX |
| |
| .macro save_context |
| save32 %eax, EAX |
| |
| save32 %ecx, ECX |
| save32 %edx, EDX |
| save32 %ebx, EBX |
| save32 %ebp, EBP |
| save32 %esi, ESI |
| save32 %edi, EDI |
| |
| popl %ebx |
| save32 %ebx, EIP |
| popl %ebx |
| save32 %ebx, CS |
| popl %ebx |
| save32 %ebx, EFLAGS |
| |
| save32 %esp, ESP |
| |
| save16 %ds, DS |
| save16 %es, ES |
| save16 %fs, FS |
| save16 %gs, GS |
| save16 %ss, SS |
| .endm |
| |
| .macro load_context |
| load16 SS, %ss |
| load32 ESP, %esp |
| |
| load32 EBP, %ebp |
| load32 ESI, %esi |
| load32 EDI, %edi |
| |
| load16 DS, %ds |
| load16 ES, %es |
| load16 FS, %fs |
| load16 GS, %gs |
| |
| load32 EFLAGS, %eax |
| pushl %eax |
| load32 CS, %eax |
| pushl %eax |
| load32 EIP, %eax |
| pushl %eax |
| |
| load32 EBX, %ebx |
| load32 EDX, %edx |
| load32 ECX, %ecx |
| load32 EAX, %eax |
| .endm |
| |
| /* |
| * This macro creates handlers for a given range of exception numbers |
| * and adds their addresses to the grub_gdb_trapvec array. |
| */ |
| |
| #ifdef __APPLE__ |
| .macro ent |
| #define EC $0 |
| #define BEG $1 |
| #define END $2 |
| #else |
| .macro ent ec beg end=0 |
| #define EC \ec |
| #define BEG \beg |
| #define END \end |
| #endif |
| |
| /* |
| * Wrapper body itself. |
| */ |
| |
| .text |
| 1: |
| .if EC |
| #ifdef __APPLE__ |
| add $$4, %esp |
| #else |
| add $4, %esp |
| #endif |
| .endif |
| |
| save_context |
| #ifdef __APPLE__ |
| mov $LOCAL(grub_gdb_stack), %esp |
| #else |
| mov $EXT_C(grub_gdb_stack), %esp |
| #endif |
| mov $(BEG), %eax /* trap number */ |
| call EXT_C(grub_gdb_trap) |
| load_context |
| iret |
| |
| /* |
| * Address entry in trapvec array. |
| */ |
| |
| #ifdef __APPLE__ |
| .section __DATA, VECTOR |
| #else |
| .data VECTOR |
| #endif |
| .long 1b |
| |
| /* |
| * Next... (recursion). |
| */ |
| |
| .if END-BEG > 0 |
| #ifdef __APPLE__ |
| ent EC, (BEG+1), END |
| #else |
| ent \ec "(\beg+1)" \end |
| #endif |
| .endif |
| .endm |
| |
| /* |
| * Here does the actual construction of the address array and handlers |
| * take place. |
| */ |
| #ifdef __APPLE__ |
| .section __DATA, VECTOR |
| #else |
| .data VECTOR |
| #endif |
| VARIABLE(grub_gdb_trapvec) |
| ent EC_ABSENT, 0, 7 |
| ent EC_PRESENT, 8 |
| ent EC_ABSENT, 9 |
| ent EC_PRESENT, 10, 14 |
| /* |
| * You may have to split this further or as(1) |
| * will complain about nesting being too deep. |
| */ |
| ent EC_ABSENT, 15, GRUB_GDB_LAST_TRAP |