2 # Low leve x64 specific debug support functions.
4 # Copyright (c) 2006 - 2008, Intel Corporation
5 # All rights reserved. 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 .intel_syntax noprefix
17 ASM_GLOBAL ASM_PFX(OrigVector)
18 ASM_GLOBAL ASM_PFX(InterruptEntryStub)
19 ASM_GLOBAL ASM_PFX(StubSize)
20 ASM_GLOBAL ASM_PFX(CommonIdtEntry)
21 ASM_GLOBAL ASM_PFX(FxStorSupport)
25 ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
26 ASM_PFX(AppRsp): .long 0x11111111 # ?
28 ASM_PFX(DebugRsp): .long 0x22222222 # ?
30 ASM_PFX(ExtraPush): .long 0x33333333 # ?
32 ASM_PFX(ExceptData): .long 0x44444444 # ?
34 ASM_PFX(Rflags): .long 0x55555555 # ?
36 ASM_PFX(OrigVector): .long 0x66666666 # ?
39 ## The declarations below define the memory region that will be used for the debug stack.
40 ## The context record will be built by pushing register values onto this stack.
41 ## It is imparitive that alignment be carefully managed, since the FXSTOR and
42 ## FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
44 ## The stub will switch stacks from the application stack to the debuger stack
45 ## and pushes the exception number.
47 ## Then we building the context record on the stack. Since the stack grows down,
48 ## we push the fields of the context record from the back to the front. There
49 ## are 336 bytes of stack used prior allocating the 512 bytes of stack to be
50 ## used as the memory buffer for the fxstor instruction. Therefore address of
51 ## the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which
52 ## must be 16 byte aligned.
54 ## We carefully locate the stack to make this happen.
56 ## For reference, the context structure looks like this:
58 ## UINT64 ExceptionData;
59 ## FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
60 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
61 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
64 ## UINT64 Gdtr[2], Idtr[2];
66 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
67 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
68 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
69 ## } SYSTEM_CONTEXT_X64; // 64 bit system context record
72 DebugStackEnd : .ascii "DbgStkEnd >>>>>>" # 16 byte long string - must be 16 bytes to preserve alignment
76 # 32K should be enough stack
77 # This allocation is coocked to insure
78 # that the the buffer for the FXSTORE instruction
79 # will be 16 byte aligned also.
81 ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub
84 DebugStackBegin : .ascii "<<<< DbgStkBegin" # initial debug ESP == DebugStackBegin, set in stub
89 #------------------------------------------------------------------------------
95 # Abstract: Returns TRUE if FxStor instructions are supported
97 ASM_GLOBAL ASM_PFX(FxStorSupport)
98 ASM_PFX(FxStorSupport):
100 # cpuid corrupts rbx which must be preserved per the C calling convention
110 #------------------------------------------------------------------------------
113 # IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
114 # void (*Vector) (void) // rdx
117 # Abstract: Encodes an IDT descriptor with the given physical address
119 ASM_GLOBAL ASM_PFX(Vect2Desc)
122 mov word ptr [rcx], ax # write bits 15..0 of offset
124 mov word ptr [rcx+2], dx # SYS_CODE_SEL from GDT
125 mov word ptr [rcx+4], 0x0e00 OR 0x8000 # type = 386 interrupt gate, present
127 mov word ptr [rcx+6], ax # write bits 31..16 of offset
129 mov dword ptr [rcx+8], eax # write bits 63..32 of offset
133 #------------------------------------------------------------------------------
136 # Abstract: This code is not a function, but is a small piece of code that is
137 # copied and fixed up once for each IDT entry that is hooked.
139 ASM_GLOBAL ASM_PFX(InterruptEntryStub)
140 ASM_PFX(InterruptEntryStub):
142 push 0 # push vector number - will be modified before installed
143 jmp ASM_PFX(CommonIdtEntry)
145 ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd)
146 ASM_PFX(InterruptEntryStubEnd):
148 #------------------------------------------------------------------------------
151 # Abstract: This code is not a function, but is the common part for all IDT
154 ASM_GLOBAL ASM_PFX(CommonIdtEntry)
156 ## At this point, the stub has saved the current application stack esp into AppRsp
157 ## and switched stacks to the debug stack, where it pushed the vector number
159 ## The application stack looks like this:
162 ## (last application stack entry)
163 ## [16 bytes alignment, do not care it]
164 ## SS from interrupted task
165 ## RSP from interrupted task
166 ## rflags from interrupted task
167 ## CS from interrupted task
168 ## RIP from interrupted task
169 ## Error code <-------------------- Only present for some exeption types
171 ## Vector Number <----------------- pushed in our IDT Entry
175 ## The stub switched us to the debug stack and pushed the interrupt number.
177 ## Next, construct the context record. It will be build on the debug stack by
178 ## pushing the registers in the correct order so as to create the context structure
179 ## on the debug stack. The context record must be built from the end back to the
180 ## beginning because the stack grows down...
182 ## For reference, the context record looks like this:
186 ## UINT64 ExceptionData;
187 ## FX_SAVE_STATE_X64 FxSaveState;
188 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
189 ## UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
192 ## UINT64 Gdtr[2], Idtr[2];
194 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
195 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
196 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
197 ## } SYSTEM_CONTEXT_X64; // 64
198 ASM_PFX(CommonIdtEntry):
199 ## NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
201 mov rax, qword ptr [rsp][8] # save vector number
202 mov ASM_PFX(ExceptionNumber), rax # save vector number
204 add rsp, 8 # pop vector number
205 mov ASM_PFX(AppRsp), rsp # save stack top
206 mov rsp, offset DebugStackBegin # switch to debugger stack
207 sub rsp, 8 # leave space for vector number
208 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
209 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
226 ## Save interrupt state rflags register...
229 mov qword ptr ASM_PFX(Rflags), rax
230 ## We need to determine if any extra data was pushed by the exception, and if so, save it
231 ## To do this, we check the exception number pushed by the stub, and cache the
232 ## result in a variable since we'll need this again.
233 cmp dword ptr ASM_PFX(ExceptionNumber), 0
235 cmp dword ptr ASM_PFX(ExceptionNumber), 10
237 cmp dword ptr ASM_PFX(ExceptionNumber), 11
239 cmp dword ptr ASM_PFX(ExceptionNumber), 12
241 cmp dword ptr ASM_PFX(ExceptionNumber), 13
243 cmp dword ptr ASM_PFX(ExceptionNumber), 14
245 cmp dword ptr ASM_PFX(ExceptionNumber), 17
247 mov dword ptr ASM_PFX(ExtraPush), 0
248 mov dword ptr ASM_PFX(ExceptData), 0
251 mov dword ptr ASM_PFX(ExtraPush), 1
253 ## If there's some extra data, save it also, and modify the saved AppRsp to effectively
254 ## pop this value off the application's stack.
255 mov rax, ASM_PFX(AppRsp)
257 mov ASM_PFX(ExceptData), rbx
259 mov ASM_PFX(AppRsp), rax
263 ## The "push" above pushed the debug stack rsp. Since what we're actually doing
264 ## is building the context record on the debug stack, we need to save the pushed
265 ## debug RSP, and replace it with the application's last stack entry...
267 mov ASM_PFX(DebugRsp), rax
268 mov rax, ASM_PFX(AppRsp)
270 # application stack has ss, rsp, rflags, cs, & rip, so
271 # last actual application stack entry is 40 bytes
272 # into the application stack.
275 ## continue building context record
276 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
279 # CS from application is one entry back in application stack
280 mov rax, ASM_PFX(AppRsp)
281 movzx rax, word ptr [rax + 8]
293 # Rip from application is on top of application stack
294 mov rax, ASM_PFX(AppRsp)
296 ## UINT64 Gdtr[2], Idtr[2];
312 ## Rflags from application is two entries back in application stack
313 mov rax, ASM_PFX(AppRsp)
314 push qword ptr [rax + 16]
315 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
316 ## insure FXSAVE/FXRSTOR is enabled in CR4...
317 ## ... while we're at it, make sure DE is also enabled...
331 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
334 ## clear Dr7 while executing debugger itself
340 ## insure all status bits in dr6 are clear...
353 ## FX_SAVE_STATE_X64 FxSaveState;
356 # IMPORTANT!! The debug stack has been carefully constructed to
357 # insure that rsp and rdi are 16 byte aligned when we get here.
358 # They MUST be. If they are not, a GP fault will occur.
363 ## UINT64 ExceptionData;
364 mov rax, ASM_PFX(ExceptData)
367 # call to C code which will in turn call registered handler
368 # pass in the vector number
370 mov rcx, ASM_PFX(ExceptionNumber)
372 call ASM_PFX(InterruptDistrubutionHub)
375 ## UINT64 ExceptionData;
378 ## FX_SAVE_STATE_X64 FxSaveState;
386 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
396 ## skip restore of dr6. We cleared dr6 during the context save.
401 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
414 mov rax, ASM_PFX(AppRsp)
415 pop qword ptr [rax + 16]
417 ## UINT64 Gdtr[2], Idtr[2];
418 ## Best not let anyone mess with these particular registers...
423 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
424 ## NOTE - modified segment registers could hang the debugger... We
425 ## could attempt to insulate ourselves against this possibility,
426 ## but that poses risks as well.
437 mov rax, ASM_PFX(AppRsp)
438 pop qword ptr [rax + 8]
441 ## The next stuff to restore is the general purpose registers that were pushed
442 ## using the "push" instruction.
444 ## The value of RSP as stored in the context record is the application RSP
445 ## including the 5 entries on the application stack caused by the exception
446 ## itself. It may have been modified by the debug agent, so we need to
447 ## determine if we need to relocate the application stack.
449 mov rbx, [rsp + 24] # move the potentially modified AppRsp into rbx
450 mov rax, ASM_PFX(AppRsp)
455 mov rax, ASM_PFX(AppRsp)
459 mov rcx, [rax + 8] # CS
462 mov rcx, [rax + 16] # RFLAGS
465 mov rcx, [rax + 24] # RSP
468 mov rcx, [rax + 32] # SS
471 mov rax, rbx # modify the saved AppRsp to the new AppRsp
472 mov ASM_PFX(AppRsp), rax
474 mov rax, ASM_PFX(DebugRsp) # restore the DebugRsp on the debug stack
475 # so our "pop" will not cause a stack switch
478 cmp dword ptr ASM_PFX(ExceptionNumber), 0x068
483 ## Restore rflags so when we chain, the flags will be exactly as if we were never here.
484 ## We gin up the stack to do an iretq so we can get ALL the flags.
485 mov rax, ASM_PFX(AppRsp)
493 mov rax, ASM_PFX(AppRsp)
495 and rbx, NOT 0x300 # special handling for IF and TF
499 mov rax, offset PhonyIretq
504 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
505 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
523 ## Switch back to application stack
524 mov rsp, ASM_PFX(AppRsp)
525 ## Jump to original handler
526 jmp ASM_PFX(OrigVector)
528 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
529 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
547 ## Switch back to application stack
548 mov rsp, ASM_PFX(AppRsp)
550 ## We're outa here...