2 ; Low level x64 routines used by the debug support driver.
4 ; Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
5 ; SPDX-License-Identifier: BSD-2-Clause-Patent
9 %define EXCPT64_DIVIDE_ERROR 0
10 %define EXCPT64_DEBUG 1
12 %define EXCPT64_BREAKPOINT 3
13 %define EXCPT64_OVERFLOW 4
14 %define EXCPT64_BOUND 5
15 %define EXCPT64_INVALID_OPCODE 6
16 %define EXCPT64_DOUBLE_FAULT 8
17 %define EXCPT64_INVALID_TSS 10
18 %define EXCPT64_SEG_NOT_PRESENT 11
19 %define EXCPT64_STACK_FAULT 12
20 %define EXCPT64_GP_FAULT 13
21 %define EXCPT64_PAGE_FAULT 14
22 %define EXCPT64_FP_ERROR 16
23 %define EXCPT64_ALIGNMENT_CHECK 17
24 %define EXCPT64_MACHINE_CHECK 18
25 %define EXCPT64_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 AppRsp: dq 0x1111111111111111 ; ?
40 DebugRsp: dq 0x2222222222222222 ; ?
41 ExtraPush: dq 0x3333333333333333 ; ?
42 ExceptData: dq 0x4444444444444444 ; ?
43 Rflags: dq 0x5555555555555555 ; ?
44 ASM_PFX(OrigVector): dq 0x6666666666666666 ; ?
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 336 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 - 336 - 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 ;; UINT64 ExceptionData;
66 ;; FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
67 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
68 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
71 ;; UINT64 Gdtr[2], Idtr[2];
73 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
74 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
75 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
76 ;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
79 DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
80 times 0x1ffc dd 0x0 ;; 32K should be enough stack
81 ;; This allocation is coocked to insure
82 ;; that the the buffer for the FXSTORE instruction
83 ;; will be 16 byte aligned also.
85 ExceptionNumber: dq 0 ;; first entry will be the vector number pushed by the stub
87 DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
92 ;------------------------------------------------------------------------------
98 ; Abstract: Returns TRUE if FxStor instructions are supported
100 global ASM_PFX(FxStorSupport)
101 ASM_PFX(FxStorSupport):
104 ; cpuid corrupts rbx which must be preserved per the C calling convention
115 ;------------------------------------------------------------------------------
118 ; IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
119 ; void (*Vector) (void) // rdx
122 ; Abstract: Encodes an IDT descriptor with the given physical address
124 global ASM_PFX(Vect2Desc)
128 mov word [rcx], ax ; write bits 15..0 of offset
130 mov word [rcx+2], dx ; SYS_CODE_SEL from GDT
131 mov word [rcx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
133 mov word [rcx+6], ax ; write bits 31..16 of offset
135 mov dword [rcx+8], eax ; write bits 63..32 of offset
139 ;------------------------------------------------------------------------------
142 ; Abstract: This code is not a function, but is a small piece of code that is
143 ; copied and fixed up once for each IDT entry that is hooked.
145 ASM_PFX(InterruptEntryStub):
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 AppRsp
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 ;; [16 bytes alignment, do not care it]
167 ;; SS from interrupted task
168 ;; RSP from interrupted task
169 ;; rflags from interrupted task
170 ;; CS from interrupted task
171 ;; RIP from interrupted task
172 ;; Error code <-------------------- Only present for some exeption types
174 ;; Vector Number <----------------- pushed in our IDT Entry
177 ;; The stub switched us to the debug stack and pushed the interrupt number.
179 ;; Next, construct the context record. It will be build on the debug stack by
180 ;; pushing the registers in the correct order so as to create the context structure
181 ;; on the debug stack. The context record must be built from the end back to the
182 ;; beginning because the stack grows down...
184 ;; For reference, the context record looks like this:
188 ;; UINT64 ExceptionData;
189 ;; FX_SAVE_STATE_X64 FxSaveState;
190 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
191 ;; UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
194 ;; UINT64 Gdtr[2], Idtr[2];
196 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
197 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
198 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
199 ;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
201 ;; NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
203 mov rax, qword [rsp+8] ; save vector number
204 mov [ExceptionNumber], rax ; save vector number
206 add rsp, 8 ; pop vector number
207 mov [AppRsp], rsp ; save stack top
208 lea rsp, [DebugStackBegin] ; switch to debugger stack
209 sub rsp, 8 ; leave space for vector number
211 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
212 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
230 ;; Save interrupt state rflags register...
235 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
236 ;; To do this, we check the exception number pushed by the stub, and cache the
237 ;; result in a variable since we'll need this again.
238 cmp qword [ExceptionNumber], EXCPT64_DOUBLE_FAULT
240 cmp qword [ExceptionNumber], EXCPT64_INVALID_TSS
242 cmp qword [ExceptionNumber], EXCPT64_SEG_NOT_PRESENT
244 cmp qword [ExceptionNumber], EXCPT64_STACK_FAULT
246 cmp qword [ExceptionNumber], EXCPT64_GP_FAULT
248 cmp qword [ExceptionNumber], EXCPT64_PAGE_FAULT
250 cmp qword [ExceptionNumber], EXCPT64_ALIGNMENT_CHECK
252 mov qword [ExtraPush], 0
253 mov qword [ExceptData], 0
256 mov qword [ExtraPush], 1
258 ;; If there's some extra data, save it also, and modify the saved AppRsp to effectively
259 ;; pop this value off the application's stack.
262 mov qword [ExceptData], rbx
268 ;; The "push" above pushed the debug stack rsp. Since what we're actually doing
269 ;; is building the context record on the debug stack, we need to save the pushed
270 ;; debug RSP, and replace it with the application's last stack entry...
274 mov rax, QWORD [rax + 24]
275 ; application stack has ss, rsp, rflags, cs, & rip, so
276 ; last actual application stack entry is saved at offset
277 ; 24 bytes from stack top.
280 ;; continue building context record
281 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
285 ; CS from application is one entry back in application stack
287 movzx rax, word [rax + 8]
300 ; Rip from application is on top of application stack
304 ;; UINT64 Gdtr[2], Idtr[2];
320 ;; Rflags from application is two entries back in application stack
322 push qword [rax + 16]
324 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
325 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
326 ;; ... while we're at it, make sure DE is also enabled...
341 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
344 ;; clear Dr7 while executing debugger itself
350 ;; insure all status bits in dr6 are clear...
363 ;; FX_SAVE_STATE_X64 FxSaveState;
366 ; IMPORTANT!! The debug stack has been carefully constructed to
367 ; insure that rsp and rdi are 16 byte aligned when we get here.
368 ; They MUST be. If they are not, a GP fault will occur.
371 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
374 ;; UINT64 ExceptionData;
375 mov rax, [ExceptData]
378 ; call to C code which will in turn call registered handler
379 ; pass in the vector number
381 mov rcx, [ExceptionNumber]
383 call ASM_PFX(InterruptDistrubutionHub)
387 ;; UINT64 ExceptionData;
390 ;; FX_SAVE_STATE_X64 FxSaveState;
395 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
404 ;; skip restore of dr6. We cleared dr6 during the context save.
409 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
427 ;; UINT64 Gdtr[2], Idtr[2];
428 ;; Best not let anyone mess with these particular registers...
434 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
435 ;; NOTE - modified segment registers could hang the debugger... We
436 ;; could attempt to insulate ourselves against this possibility,
437 ;; but that poses risks as well.
453 ;; The next stuff to restore is the general purpose registers that were pushed
454 ;; using the "push" instruction.
456 ;; The value of RSP as stored in the context record is the application RSP
457 ;; including the 5 entries on the application stack caused by the exception
458 ;; itself. It may have been modified by the debug agent, so we need to
459 ;; determine if we need to relocate the application stack.
461 mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx
463 mov rax, QWORD [rax + 24]
471 mov rcx, [rax + 8] ; CS
474 mov rcx, [rax + 16] ; RFLAGS
477 mov rcx, [rax + 24] ; RSP
480 mov rcx, [rax + 32] ; SS
483 mov rax, rbx ; modify the saved AppRsp to the new AppRsp
486 mov rax, [DebugRsp] ; restore the DebugRsp on the debug stack
487 ; so our "pop" will not cause a stack switch
490 cmp qword [ExceptionNumber], 0x68
495 ;; Restore rflags so when we chain, the flags will be exactly as if we were never here.
496 ;; We gin up the stack to do an iretq so we can get ALL the flags.
507 and rbx, ~ 0x300 ; special handling for IF and TF
511 lea rax, [PhonyIretq]
516 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
517 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
535 ;; Switch back to application stack
538 ;; Jump to original handler
539 jmp [ASM_PFX(OrigVector)]
542 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
543 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
561 ;; Switch back to application stack
564 ;; We're outa here...