2 ; Low leve IA32 specific debug support functions.
4 ; Copyright (c) 2006 - 2022, 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
31 global ASM_PFX(OrigVector)
32 global ASM_PFX(InterruptEntryStub)
33 global ASM_PFX(StubSize)
34 global ASM_PFX(CommonIdtEntry)
35 global ASM_PFX(FxStorSupport)
36 extern ASM_PFX(InterruptDistrubutionHub)
38 ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
39 AppEsp: dd 0x11111111 ; ?
40 DebugEsp: dd 0x22222222 ; ?
41 ExtraPush: dd 0x33333333 ; ?
42 ExceptData: dd 0x44444444 ; ?
43 Eflags: dd 0x55555555 ; ?
44 ASM_PFX(OrigVector): dd 0x66666666 ; ?
46 ;; The declarations below define the memory region that will be used for the debug stack.
47 ;; The context record will be built by pushing register values onto this stack.
48 ;; It is imparitive that alignment be carefully managed, since the FXSTOR and
49 ;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
51 ;; The stub will switch stacks from the application stack to the debuger stack
52 ;; and pushes the exception number.
54 ;; Then we building the context record on the stack. Since the stack grows down,
55 ;; we push the fields of the context record from the back to the front. There
56 ;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
57 ;; used as the memory buffer for the fxstor instruction. Therefore address of
58 ;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
59 ;; must be 16 byte aligned.
61 ;; We carefully locate the stack to make this happen.
63 ;; For reference, the context structure looks like this:
65 ;; UINT32 ExceptionData;
66 ;; FX_SAVE_STATE_IA32 FxSaveState; // 512 bytes, must be 16 byte aligned
67 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
68 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
71 ;; UINT32 Gdtr[2], Idtr[2];
73 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
74 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
75 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
78 DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
79 times 0x1ffc dd 0x0 ;; 32K should be enough stack
80 ;; This allocation is coocked to insure
81 ;; that the the buffer for the FXSTORE instruction
82 ;; will be 16 byte aligned also.
84 ExceptionNumber: dd 0 ;; first entry will be the vector number pushed by the stub
86 DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
90 ;------------------------------------------------------------------------------
96 ; Abstract: Returns TRUE if FxStor instructions are supported
98 global ASM_PFX(FxStorSupport)
99 ASM_PFX(FxStorSupport):
102 ; cpuid corrupts ebx which must be preserved per the C calling convention
113 ;------------------------------------------------------------------------------
116 ; DESCRIPTOR * DestDesc,
117 ; void (*Vector) (void)
120 ; Abstract: Encodes an IDT descriptor with the given physical address
122 global ASM_PFX(Vect2Desc)
128 mov word [ecx], ax ; write bits 15..0 of offset
130 mov word [ecx+2], dx ; SYS_CODE_SEL from GDT
131 mov word [ecx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
133 mov word [ecx+6], ax ; write bits 31..16 of offset
137 ;------------------------------------------------------------------------------
140 ; Abstract: This code is not a function, but is a small piece of code that is
141 ; copied and fixed up once for each IDT entry that is hooked.
143 ASM_PFX(InterruptEntryStub):
144 mov [AppEsp], esp ; save stack top
145 mov esp, DebugStackBegin ; switch to debugger stack
146 push 0 ; push vector number - will be modified before installed
148 dd 0 ; fixed up to relative address of CommonIdtEntry
149 InterruptEntryStubEnd:
151 ;------------------------------------------------------------------------------
154 ; Abstract: This code is not a function, but is the common part for all IDT
157 ASM_PFX(CommonIdtEntry):
159 ;; At this point, the stub has saved the current application stack esp into AppEsp
160 ;; and switched stacks to the debug stack, where it pushed the vector number
162 ;; The application stack looks like this:
165 ;; (last application stack entry)
166 ;; eflags from interrupted task
167 ;; CS from interrupted task
168 ;; EIP from interrupted task
169 ;; Error code <-------------------- Only present for some exeption types
173 ;; The stub switched us to the debug stack and pushed the interrupt number.
175 ;; Next, construct the context record. It will be build on the debug stack by
176 ;; pushing the registers in the correct order so as to create the context structure
177 ;; on the debug stack. The context record must be built from the end back to the
178 ;; beginning because the stack grows down...
180 ;; For reference, the context record looks like this:
184 ;; UINT32 ExceptionData;
185 ;; FX_SAVE_STATE_IA32 FxSaveState;
186 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
187 ;; UINT32 Cr0, Cr2, Cr3, Cr4;
190 ;; UINT32 Gdtr[2], Idtr[2];
192 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
193 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
194 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
196 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
199 ;; Save interrupt state eflags register...
204 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
205 ;; To do this, we check the exception number pushed by the stub, and cache the
206 ;; result in a variable since we'll need this again.
207 cmp dword [ExceptionNumber], EXCPT32_DOUBLE_FAULT
209 cmp dword [ExceptionNumber], EXCPT32_INVALID_TSS
211 cmp dword [ExceptionNumber], EXCPT32_SEG_NOT_PRESENT
213 cmp dword [ExceptionNumber], EXCPT32_STACK_FAULT
215 cmp dword [ExceptionNumber], EXCPT32_GP_FAULT
217 cmp dword [ExceptionNumber], EXCPT32_PAGE_FAULT
219 cmp dword [ExceptionNumber], EXCPT32_ALIGNMENT_CHECK
221 mov dword [ExtraPush], 0
222 mov dword [ExceptData], 0
226 mov dword [ExtraPush], 1
228 ;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
229 ;; pop this value off the application's stack.
232 mov [ExceptData], ebx
238 ;; The "pushad" above pushed the debug stack esp. Since what we're actually doing
239 ;; is building the context record on the debug stack, we need to save the pushed
240 ;; debug ESP, and replace it with the application's last stack entry...
245 ; application stack has eflags, cs, & eip, so
246 ; last actual application stack entry is
247 ; 12 bytes into the application stack.
250 ;; continue building context record
251 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
255 ; CS from application is one entry back in application stack
257 movzx eax, word [eax + 4]
270 ; Eip from application is on top of application stack
274 ;; UINT32 Gdtr[2], Idtr[2];
290 ;; Eflags from application is two entries back in application stack
294 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
295 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
296 ;; ... while we're at it, make sure DE is also enabled...
309 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
312 ;; clear Dr7 while executing debugger itself
318 ;; insure all status bits in dr6 are clear...
331 ;; FX_SAVE_STATE_IA32 FxSaveState;
334 ; IMPORTANT!! The debug stack has been carefully constructed to
335 ; insure that esp and edi are 16 byte aligned when we get here.
336 ; They MUST be. If they are not, a GP fault will occur.
339 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
342 ;; UINT32 ExceptionData;
343 mov eax, [ExceptData]
346 ; call to C code which will in turn call registered handler
347 ; pass in the vector number
350 mov eax, [ExceptionNumber]
352 call ASM_PFX(InterruptDistrubutionHub)
356 ;; UINT32 ExceptionData;
359 ;; FX_SAVE_STATE_IA32 FxSaveState;
364 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
373 ;; skip restore of dr6. We cleared dr6 during the context save.
378 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
394 ;; UINT32 Gdtr[2], Idtr[2];
395 ;; Best not let anyone mess with these particular registers...
401 ;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
402 ;; NOTE - modified segment registers could hang the debugger... We
403 ;; could attempt to insulate ourselves against this possibility,
404 ;; but that poses risks as well.
414 ;; The next stuff to restore is the general purpose registers that were pushed
415 ;; using the "pushad" instruction.
417 ;; The value of ESP as stored in the context record is the application ESP
418 ;; including the 3 entries on the application stack caused by the exception
419 ;; itself. It may have been modified by the debug agent, so we need to
420 ;; determine if we need to relocate the application stack.
422 mov ebx, [esp + 12] ; move the potentially modified AppEsp into ebx
432 mov ecx, [eax + 4] ; CS
435 mov ecx, [eax + 8] ; EFLAGS
438 mov eax, ebx ; modify the saved AppEsp to the new AppEsp
441 mov eax, [DebugEsp] ; restore the DebugEsp on the debug stack
442 ; so our "popad" will not cause a stack switch
445 cmp dword [ExceptionNumber], 0x68
450 ;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
451 ;; We gin up the stack to do an iretd so we can get ALL the flags.
454 and ebx, ~ 0x300 ; special handling for IF and TF
461 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
464 ;; Switch back to application stack
467 ;; Jump to original handler
468 jmp [ASM_PFX(OrigVector)]
471 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
474 ;; Switch back to application stack
477 ;; We're outa here...