2 ; Low leve IA32 specific debug support functions.
4 ; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 ; SPDX-License-Identifier: BSD-2-Clause-Patent
9 %define EXCPT32_DIVIDE_ERROR 0
10 %define EXCPT32_DEBUG 1
12 %define EXCPT32_BREAKPOINT 3
13 %define EXCPT32_OVERFLOW 4
14 %define EXCPT32_BOUND 5
15 %define EXCPT32_INVALID_OPCODE 6
16 %define EXCPT32_DOUBLE_FAULT 8
17 %define EXCPT32_INVALID_TSS 10
18 %define EXCPT32_SEG_NOT_PRESENT 11
19 %define EXCPT32_STACK_FAULT 12
20 %define EXCPT32_GP_FAULT 13
21 %define EXCPT32_PAGE_FAULT 14
22 %define EXCPT32_FP_ERROR 16
23 %define EXCPT32_ALIGNMENT_CHECK 17
24 %define EXCPT32_MACHINE_CHECK 18
25 %define EXCPT32_SIMD 19
27 %define FXSTOR_FLAG 0x1000000 ; bit cpuid 24 of feature flags
29 ;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
30 ;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver
31 ;; MUST check the CPUID feature flags to see that these instructions are available
32 ;; and fail to init if they are not.
36 db 0xf, 0xae, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi]
41 db 0xf, 0xae, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi]
45 global ASM_PFX(OrigVector)
46 global ASM_PFX(InterruptEntryStub)
47 global ASM_PFX(StubSize)
48 global ASM_PFX(CommonIdtEntry)
49 global ASM_PFX(FxStorSupport)
50 extern ASM_PFX(InterruptDistrubutionHub)
52 ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
53 AppEsp: dd 0x11111111 ; ?
54 DebugEsp: dd 0x22222222 ; ?
55 ExtraPush: dd 0x33333333 ; ?
56 ExceptData: dd 0x44444444 ; ?
57 Eflags: dd 0x55555555 ; ?
58 ASM_PFX(OrigVector): dd 0x66666666 ; ?
60 ;; The declarations below define the memory region that will be used for the debug stack.
61 ;; The context record will be built by pushing register values onto this stack.
62 ;; It is imparitive that alignment be carefully managed, since the FXSTOR and
63 ;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
65 ;; The stub will switch stacks from the application stack to the debuger stack
66 ;; and pushes the exception number.
68 ;; Then we building the context record on the stack. Since the stack grows down,
69 ;; we push the fields of the context record from the back to the front. There
70 ;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
71 ;; used as the memory buffer for the fxstor instruction. Therefore address of
72 ;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
73 ;; must be 16 byte aligned.
75 ;; We carefully locate the stack to make this happen.
77 ;; For reference, the context structure looks like this:
79 ;; UINT32 ExceptionData;
80 ;; FX_SAVE_STATE_IA32 FxSaveState; // 512 bytes, must be 16 byte aligned
81 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
82 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
85 ;; UINT32 Gdtr[2], Idtr[2];
87 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
88 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
89 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
92 DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
93 times 0x1ffc dd 0x0 ;; 32K should be enough stack
94 ;; This allocation is coocked to insure
95 ;; that the the buffer for the FXSTORE instruction
96 ;; will be 16 byte aligned also.
98 ExceptionNumber: dd 0 ;; first entry will be the vector number pushed by the stub
100 DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
104 ;------------------------------------------------------------------------------
110 ; Abstract: Returns TRUE if FxStor instructions are supported
112 global ASM_PFX(FxStorSupport)
113 ASM_PFX(FxStorSupport):
116 ; cpuid corrupts ebx which must be preserved per the C calling convention
127 ;------------------------------------------------------------------------------
130 ; DESCRIPTOR * DestDesc,
131 ; void (*Vector) (void)
134 ; Abstract: Encodes an IDT descriptor with the given physical address
136 global ASM_PFX(Vect2Desc)
142 mov word [ecx], ax ; write bits 15..0 of offset
144 mov word [ecx+2], dx ; SYS_CODE_SEL from GDT
145 mov word [ecx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
147 mov word [ecx+6], ax ; write bits 31..16 of offset
151 ;------------------------------------------------------------------------------
154 ; Abstract: This code is not a function, but is a small piece of code that is
155 ; copied and fixed up once for each IDT entry that is hooked.
157 ASM_PFX(InterruptEntryStub):
158 mov [AppEsp], esp ; save stack top
159 mov esp, DebugStackBegin ; switch to debugger stack
160 push 0 ; push vector number - will be modified before installed
162 dd 0 ; fixed up to relative address of CommonIdtEntry
163 InterruptEntryStubEnd:
165 ;------------------------------------------------------------------------------
168 ; Abstract: This code is not a function, but is the common part for all IDT
171 ASM_PFX(CommonIdtEntry):
173 ;; At this point, the stub has saved the current application stack esp into AppEsp
174 ;; and switched stacks to the debug stack, where it pushed the vector number
176 ;; The application stack looks like this:
179 ;; (last application stack entry)
180 ;; eflags from interrupted task
181 ;; CS from interrupted task
182 ;; EIP from interrupted task
183 ;; Error code <-------------------- Only present for some exeption types
187 ;; The stub switched us to the debug stack and pushed the interrupt number.
189 ;; Next, construct the context record. It will be build on the debug stack by
190 ;; pushing the registers in the correct order so as to create the context structure
191 ;; on the debug stack. The context record must be built from the end back to the
192 ;; beginning because the stack grows down...
194 ;; For reference, the context record looks like this:
198 ;; UINT32 ExceptionData;
199 ;; FX_SAVE_STATE_IA32 FxSaveState;
200 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
201 ;; UINT32 Cr0, Cr2, Cr3, Cr4;
204 ;; UINT32 Gdtr[2], Idtr[2];
206 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
207 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
208 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
210 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
213 ;; Save interrupt state eflags register...
218 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
219 ;; To do this, we check the exception number pushed by the stub, and cache the
220 ;; result in a variable since we'll need this again.
221 cmp dword [ExceptionNumber], EXCPT32_DOUBLE_FAULT
223 cmp dword [ExceptionNumber], EXCPT32_INVALID_TSS
225 cmp dword [ExceptionNumber], EXCPT32_SEG_NOT_PRESENT
227 cmp dword [ExceptionNumber], EXCPT32_STACK_FAULT
229 cmp dword [ExceptionNumber], EXCPT32_GP_FAULT
231 cmp dword [ExceptionNumber], EXCPT32_PAGE_FAULT
233 cmp dword [ExceptionNumber], EXCPT32_ALIGNMENT_CHECK
235 mov dword [ExtraPush], 0
236 mov dword [ExceptData], 0
240 mov dword [ExtraPush], 1
242 ;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
243 ;; pop this value off the application's stack.
246 mov [ExceptData], ebx
252 ;; The "pushad" above pushed the debug stack esp. Since what we're actually doing
253 ;; is building the context record on the debug stack, we need to save the pushed
254 ;; debug ESP, and replace it with the application's last stack entry...
259 ; application stack has eflags, cs, & eip, so
260 ; last actual application stack entry is
261 ; 12 bytes into the application stack.
264 ;; continue building context record
265 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
269 ; CS from application is one entry back in application stack
271 movzx eax, word [eax + 4]
284 ; Eip from application is on top of application stack
288 ;; UINT32 Gdtr[2], Idtr[2];
304 ;; Eflags from application is two entries back in application stack
308 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
309 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
310 ;; ... while we're at it, make sure DE is also enabled...
323 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
326 ;; clear Dr7 while executing debugger itself
332 ;; insure all status bits in dr6 are clear...
345 ;; FX_SAVE_STATE_IA32 FxSaveState;
348 ; IMPORTANT!! The debug stack has been carefully constructed to
349 ; insure that esp and edi are 16 byte aligned when we get here.
350 ; They MUST be. If they are not, a GP fault will occur.
353 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
356 ;; UINT32 ExceptionData;
357 mov eax, [ExceptData]
360 ; call to C code which will in turn call registered handler
361 ; pass in the vector number
364 mov eax, [ExceptionNumber]
366 call ASM_PFX(InterruptDistrubutionHub)
370 ;; UINT32 ExceptionData;
373 ;; FX_SAVE_STATE_IA32 FxSaveState;
378 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
387 ;; skip restore of dr6. We cleared dr6 during the context save.
392 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
408 ;; UINT32 Gdtr[2], Idtr[2];
409 ;; Best not let anyone mess with these particular registers...
415 ;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
416 ;; NOTE - modified segment registers could hang the debugger... We
417 ;; could attempt to insulate ourselves against this possibility,
418 ;; but that poses risks as well.
428 ;; The next stuff to restore is the general purpose registers that were pushed
429 ;; using the "pushad" instruction.
431 ;; The value of ESP as stored in the context record is the application ESP
432 ;; including the 3 entries on the application stack caused by the exception
433 ;; itself. It may have been modified by the debug agent, so we need to
434 ;; determine if we need to relocate the application stack.
436 mov ebx, [esp + 12] ; move the potentially modified AppEsp into ebx
446 mov ecx, [eax + 4] ; CS
449 mov ecx, [eax + 8] ; EFLAGS
452 mov eax, ebx ; modify the saved AppEsp to the new AppEsp
455 mov eax, [DebugEsp] ; restore the DebugEsp on the debug stack
456 ; so our "popad" will not cause a stack switch
459 cmp dword [ExceptionNumber], 0x68
464 ;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
465 ;; We gin up the stack to do an iretd so we can get ALL the flags.
468 and ebx, ~ 0x300 ; special handling for IF and TF
475 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
478 ;; Switch back to application stack
481 ;; Jump to original handler
482 jmp [ASM_PFX(OrigVector)]
485 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
488 ;; Switch back to application stack
491 ;; We're outa here...