2 ; Low leve IA32 specific debug support functions.
4 ; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 ; This program and the accompanying materials
6 ; are licensed and made available under the terms and conditions of the BSD License
7 ; which accompanies this distribution. The full text of the license may be found at
8 ; http://opensource.org/licenses/bsd-license.php
10 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 %define EXCPT32_DIVIDE_ERROR 0
16 %define EXCPT32_DEBUG 1
18 %define EXCPT32_BREAKPOINT 3
19 %define EXCPT32_OVERFLOW 4
20 %define EXCPT32_BOUND 5
21 %define EXCPT32_INVALID_OPCODE 6
22 %define EXCPT32_DOUBLE_FAULT 8
23 %define EXCPT32_INVALID_TSS 10
24 %define EXCPT32_SEG_NOT_PRESENT 11
25 %define EXCPT32_STACK_FAULT 12
26 %define EXCPT32_GP_FAULT 13
27 %define EXCPT32_PAGE_FAULT 14
28 %define EXCPT32_FP_ERROR 16
29 %define EXCPT32_ALIGNMENT_CHECK 17
30 %define EXCPT32_MACHINE_CHECK 18
31 %define EXCPT32_SIMD 19
33 %define FXSTOR_FLAG 0x1000000 ; bit cpuid 24 of feature flags
35 ;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
36 ;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver
37 ;; MUST check the CPUID feature flags to see that these instructions are available
38 ;; and fail to init if they are not.
42 db 0xf, 0xae, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi]
47 db 0xf, 0xae, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi]
51 global ASM_PFX(OrigVector)
52 global ASM_PFX(InterruptEntryStub)
53 global ASM_PFX(StubSize)
54 global ASM_PFX(CommonIdtEntry)
55 global ASM_PFX(FxStorSupport)
56 extern ASM_PFX(InterruptDistrubutionHub)
58 ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
59 AppEsp: dd 0x11111111 ; ?
60 DebugEsp: dd 0x22222222 ; ?
61 ExtraPush: dd 0x33333333 ; ?
62 ExceptData: dd 0x44444444 ; ?
63 Eflags: dd 0x55555555 ; ?
64 ASM_PFX(OrigVector): dd 0x66666666 ; ?
66 ;; The declarations below define the memory region that will be used for the debug stack.
67 ;; The context record will be built by pushing register values onto this stack.
68 ;; It is imparitive that alignment be carefully managed, since the FXSTOR and
69 ;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
71 ;; The stub will switch stacks from the application stack to the debuger stack
72 ;; and pushes the exception number.
74 ;; Then we building the context record on the stack. Since the stack grows down,
75 ;; we push the fields of the context record from the back to the front. There
76 ;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
77 ;; used as the memory buffer for the fxstor instruction. Therefore address of
78 ;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
79 ;; must be 16 byte aligned.
81 ;; We carefully locate the stack to make this happen.
83 ;; For reference, the context structure looks like this:
85 ;; UINT32 ExceptionData;
86 ;; FX_SAVE_STATE_IA32 FxSaveState; // 512 bytes, must be 16 byte aligned
87 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
88 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
91 ;; UINT32 Gdtr[2], Idtr[2];
93 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
94 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
95 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
98 DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
99 times 0x1ffc dd 0x0 ;; 32K should be enough stack
100 ;; This allocation is coocked to insure
101 ;; that the the buffer for the FXSTORE instruction
102 ;; will be 16 byte aligned also.
104 ExceptionNumber: dd 0 ;; first entry will be the vector number pushed by the stub
106 DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
110 ;------------------------------------------------------------------------------
116 ; Abstract: Returns TRUE if FxStor instructions are supported
118 global ASM_PFX(FxStorSupport)
119 ASM_PFX(FxStorSupport):
122 ; cpuid corrupts ebx which must be preserved per the C calling convention
133 ;------------------------------------------------------------------------------
136 ; DESCRIPTOR * DestDesc,
137 ; void (*Vector) (void)
140 ; Abstract: Encodes an IDT descriptor with the given physical address
142 global ASM_PFX(Vect2Desc)
148 mov word [ecx], ax ; write bits 15..0 of offset
150 mov word [ecx+2], dx ; SYS_CODE_SEL from GDT
151 mov word [ecx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
153 mov word [ecx+6], ax ; write bits 31..16 of offset
157 ;------------------------------------------------------------------------------
160 ; Abstract: This code is not a function, but is a small piece of code that is
161 ; copied and fixed up once for each IDT entry that is hooked.
163 ASM_PFX(InterruptEntryStub):
164 mov [AppEsp], esp ; save stack top
165 mov esp, DebugStackBegin ; switch to debugger stack
166 push 0 ; push vector number - will be modified before installed
168 dd 0 ; fixed up to relative address of CommonIdtEntry
169 InterruptEntryStubEnd:
171 ;------------------------------------------------------------------------------
174 ; Abstract: This code is not a function, but is the common part for all IDT
177 ASM_PFX(CommonIdtEntry):
179 ;; At this point, the stub has saved the current application stack esp into AppEsp
180 ;; and switched stacks to the debug stack, where it pushed the vector number
182 ;; The application stack looks like this:
185 ;; (last application stack entry)
186 ;; eflags from interrupted task
187 ;; CS from interrupted task
188 ;; EIP from interrupted task
189 ;; Error code <-------------------- Only present for some exeption types
193 ;; The stub switched us to the debug stack and pushed the interrupt number.
195 ;; Next, construct the context record. It will be build on the debug stack by
196 ;; pushing the registers in the correct order so as to create the context structure
197 ;; on the debug stack. The context record must be built from the end back to the
198 ;; beginning because the stack grows down...
200 ;; For reference, the context record looks like this:
204 ;; UINT32 ExceptionData;
205 ;; FX_SAVE_STATE_IA32 FxSaveState;
206 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
207 ;; UINT32 Cr0, Cr2, Cr3, Cr4;
210 ;; UINT32 Gdtr[2], Idtr[2];
212 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
213 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
214 ;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
216 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
219 ;; Save interrupt state eflags register...
224 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
225 ;; To do this, we check the exception number pushed by the stub, and cache the
226 ;; result in a variable since we'll need this again.
227 cmp dword [ExceptionNumber], EXCPT32_DOUBLE_FAULT
229 cmp dword [ExceptionNumber], EXCPT32_INVALID_TSS
231 cmp dword [ExceptionNumber], EXCPT32_SEG_NOT_PRESENT
233 cmp dword [ExceptionNumber], EXCPT32_STACK_FAULT
235 cmp dword [ExceptionNumber], EXCPT32_GP_FAULT
237 cmp dword [ExceptionNumber], EXCPT32_PAGE_FAULT
239 cmp dword [ExceptionNumber], EXCPT32_ALIGNMENT_CHECK
241 mov dword [ExtraPush], 0
242 mov dword [ExceptData], 0
246 mov dword [ExtraPush], 1
248 ;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
249 ;; pop this value off the application's stack.
252 mov [ExceptData], ebx
258 ;; The "pushad" above pushed the debug stack esp. Since what we're actually doing
259 ;; is building the context record on the debug stack, we need to save the pushed
260 ;; debug ESP, and replace it with the application's last stack entry...
265 ; application stack has eflags, cs, & eip, so
266 ; last actual application stack entry is
267 ; 12 bytes into the application stack.
270 ;; continue building context record
271 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
275 ; CS from application is one entry back in application stack
277 movzx eax, word [eax + 4]
290 ; Eip from application is on top of application stack
294 ;; UINT32 Gdtr[2], Idtr[2];
310 ;; Eflags from application is two entries back in application stack
314 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
315 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
316 ;; ... while we're at it, make sure DE is also enabled...
329 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
332 ;; clear Dr7 while executing debugger itself
338 ;; insure all status bits in dr6 are clear...
351 ;; FX_SAVE_STATE_IA32 FxSaveState;
354 ; IMPORTANT!! The debug stack has been carefully constructed to
355 ; insure that esp and edi are 16 byte aligned when we get here.
356 ; They MUST be. If they are not, a GP fault will occur.
359 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
362 ;; UINT32 ExceptionData;
363 mov eax, [ExceptData]
366 ; call to C code which will in turn call registered handler
367 ; pass in the vector number
370 mov eax, [ExceptionNumber]
372 call ASM_PFX(InterruptDistrubutionHub)
376 ;; UINT32 ExceptionData;
379 ;; FX_SAVE_STATE_IA32 FxSaveState;
384 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
393 ;; skip restore of dr6. We cleared dr6 during the context save.
398 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
414 ;; UINT32 Gdtr[2], Idtr[2];
415 ;; Best not let anyone mess with these particular registers...
421 ;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
422 ;; NOTE - modified segment registers could hang the debugger... We
423 ;; could attempt to insulate ourselves against this possibility,
424 ;; but that poses risks as well.
434 ;; The next stuff to restore is the general purpose registers that were pushed
435 ;; using the "pushad" instruction.
437 ;; The value of ESP as stored in the context record is the application ESP
438 ;; including the 3 entries on the application stack caused by the exception
439 ;; itself. It may have been modified by the debug agent, so we need to
440 ;; determine if we need to relocate the application stack.
442 mov ebx, [esp + 12] ; move the potentially modified AppEsp into ebx
452 mov ecx, [eax + 4] ; CS
455 mov ecx, [eax + 8] ; EFLAGS
458 mov eax, ebx ; modify the saved AppEsp to the new AppEsp
461 mov eax, [DebugEsp] ; restore the DebugEsp on the debug stack
462 ; so our "popad" will not cause a stack switch
465 cmp dword [ExceptionNumber], 0x68
470 ;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
471 ;; We gin up the stack to do an iretd so we can get ALL the flags.
474 and ebx, ~ 0x300 ; special handling for IF and TF
481 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
484 ;; Switch back to application stack
487 ;; Jump to original handler
488 jmp [ASM_PFX(OrigVector)]
491 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
494 ;; Switch back to application stack
497 ;; We're outa here...