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
18 .globl ASM_PFX(OrigVector)
19 .globl ASM_PFX(InterruptEntryStub)
20 .globl ASM_PFX(StubSize)
21 .globl ASM_PFX(CommonIdtEntry)
22 .globl ASM_PFX(FxStorSupport)
26 ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
27 ASM_PFX(AppRsp): .long 0x11111111 # ?
29 ASM_PFX(DebugRsp): .long 0x22222222 # ?
31 ASM_PFX(ExtraPush): .long 0x33333333 # ?
33 ASM_PFX(ExceptData): .long 0x44444444 # ?
35 ASM_PFX(Rflags): .long 0x55555555 # ?
37 ASM_PFX(OrigVector): .long 0x66666666 # ?
40 ## The declarations below define the memory region that will be used for the debug stack.
41 ## The context record will be built by pushing register values onto this stack.
42 ## It is imparitive that alignment be carefully managed, since the FXSTOR and
43 ## FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
45 ## The stub will switch stacks from the application stack to the debuger stack
46 ## and pushes the exception number.
48 ## Then we building the context record on the stack. Since the stack grows down,
49 ## we push the fields of the context record from the back to the front. There
50 ## are 336 bytes of stack used prior allocating the 512 bytes of stack to be
51 ## used as the memory buffer for the fxstor instruction. Therefore address of
52 ## the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which
53 ## must be 16 byte aligned.
55 ## We carefully locate the stack to make this happen.
57 ## For reference, the context structure looks like this:
59 ## UINT64 ExceptionData;
60 ## FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
61 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
62 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
65 ## UINT64 Gdtr[2], Idtr[2];
67 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
68 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
69 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
70 ## } SYSTEM_CONTEXT_X64; // 64 bit system context record
73 DebugStackEnd : .ascii "DbgStkEnd >>>>>>" # 16 byte long string - must be 16 bytes to preserve alignment
77 # 32K should be enough stack
78 # This allocation is coocked to insure
79 # that the the buffer for the FXSTORE instruction
80 # will be 16 byte aligned also.
82 ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub
85 DebugStackBegin : .ascii "<<<< DbgStkBegin" # initial debug ESP == DebugStackBegin, set in stub
90 #------------------------------------------------------------------------------
96 # Abstract: Returns TRUE if FxStor instructions are supported
98 .globl ASM_PFX(FxStorSupport)
99 ASM_PFX(FxStorSupport):
101 # cpuid corrupts rbx which must be preserved per the C calling convention
111 #------------------------------------------------------------------------------
114 # IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
115 # void (*Vector) (void) // rdx
118 # Abstract: Encodes an IDT descriptor with the given physical address
120 .globl ASM_PFX(Vect2Desc)
123 mov word ptr [rcx], ax # write bits 15..0 of offset
125 mov word ptr [rcx+2], dx # SYS_CODE_SEL from GDT
126 mov word ptr [rcx+4], 0x0e00 OR 0x8000 # type = 386 interrupt gate, present
128 mov word ptr [rcx+6], ax # write bits 31..16 of offset
130 mov dword ptr [rcx+8], eax # write bits 63..32 of offset
134 #------------------------------------------------------------------------------
137 # Abstract: This code is not a function, but is a small piece of code that is
138 # copied and fixed up once for each IDT entry that is hooked.
140 .globl ASM_PFX(InterruptEntryStub)
141 ASM_PFX(InterruptEntryStub):
143 push 0 # push vector number - will be modified before installed
144 jmp ASM_PFX(CommonIdtEntry)
146 .globl ASM_PFX(InterruptEntryStubEnd)
147 ASM_PFX(InterruptEntryStubEnd):
151 #------------------------------------------------------------------------------
154 # Abstract: This code is not a function, but is the common part for all IDT
157 .globl 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
178 ## The stub switched us to the debug stack and pushed the interrupt number.
180 ## Next, construct the context record. It will be build on the debug stack by
181 ## pushing the registers in the correct order so as to create the context structure
182 ## on the debug stack. The context record must be built from the end back to the
183 ## beginning because the stack grows down...
185 ## For reference, the context record looks like this:
189 ## UINT64 ExceptionData;
190 ## FX_SAVE_STATE_X64 FxSaveState;
191 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
192 ## UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
195 ## UINT64 Gdtr[2], Idtr[2];
197 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
198 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
199 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
200 ## } SYSTEM_CONTEXT_X64; // 64
201 ASM_PFX(CommonIdtEntry):
205 ## NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
207 mov rax, qword ptr [rsp][8] # save vector number
208 mov ASM_PFX(ExceptionNumber), rax # save vector number
210 add rsp, 8 # pop vector number
211 mov ASM_PFX(AppRsp), rsp # save stack top
212 mov rsp, offset DebugStackBegin # switch to debugger stack
213 sub rsp, 8 # leave space for vector number
214 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
215 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
232 ## Save interrupt state rflags register...
235 mov qword ptr ASM_PFX(Rflags), rax
236 ## We need to determine if any extra data was pushed by the exception, and if so, save it
237 ## To do this, we check the exception number pushed by the stub, and cache the
238 ## result in a variable since we'll need this again.
239 cmp dword ptr ASM_PFX(ExceptionNumber), 0
241 cmp dword ptr ASM_PFX(ExceptionNumber), 10
243 cmp dword ptr ASM_PFX(ExceptionNumber), 11
245 cmp dword ptr ASM_PFX(ExceptionNumber), 12
247 cmp dword ptr ASM_PFX(ExceptionNumber), 13
249 cmp dword ptr ASM_PFX(ExceptionNumber), 14
251 cmp dword ptr ASM_PFX(ExceptionNumber), 17
253 mov dword ptr ASM_PFX(ExtraPush), 0
254 mov dword ptr ASM_PFX(ExceptData), 0
257 mov dword ptr ASM_PFX(ExtraPush), 1
259 ## If there's some extra data, save it also, and modify the saved AppRsp to effectively
260 ## pop this value off the application's stack.
261 mov rax, ASM_PFX(AppRsp)
263 mov ASM_PFX(ExceptData), rbx
265 mov ASM_PFX(AppRsp), rax
269 ## The "push" above pushed the debug stack rsp. Since what we're actually doing
270 ## is building the context record on the debug stack, we need to save the pushed
271 ## debug RSP, and replace it with the application's last stack entry...
273 mov ASM_PFX(DebugRsp), rax
274 mov rax, ASM_PFX(AppRsp)
276 # application stack has ss, rsp, rflags, cs, & rip, so
277 # last actual application stack entry is
278 # 40 bytes into the application stack.
280 ## continue building context record
281 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
284 # CS from application is one entry back in application stack
285 mov rax, ASM_PFX(AppRsp)
286 movzx rax, word ptr [rax + 8]
298 # Rip from application is on top of application stack
299 mov rax, ASM_PFX(AppRsp)
301 ## UINT64 Gdtr[2], Idtr[2];
317 ## Rflags from application is two entries back in application stack
318 mov rax, ASM_PFX(AppRsp)
319 push qword ptr [rax + 16]
320 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
321 ## insure FXSAVE/FXRSTOR is enabled in CR4...
322 ## ... while we're at it, make sure DE is also enabled...
336 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
339 ## clear Dr7 while executing debugger itself
345 ## insure all status bits in dr6 are clear...
358 ## FX_SAVE_STATE_X64 FxSaveState;
361 # IMPORTANT!! The debug stack has been carefully constructed to
362 # insure that rsp and rdi are 16 byte aligned when we get here.
363 # They MUST be. If they are not, a GP fault will occur.
369 ## UINT64 ExceptionData;
370 mov rax, ASM_PFX(ExceptData)
372 # call to C code which will in turn call registered handler
373 # pass in the vector number
375 mov rcx, ASM_PFX(ExceptionNumber)
377 call ASM_PFX(InterruptDistrubutionHub)
380 ## UINT64 ExceptionData;
382 ## FX_SAVE_STATE_X64 FxSaveState;
389 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
398 ## skip restore of dr6. We cleared dr6 during the context save.
402 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
415 mov rax, ASM_PFX(AppRsp)
416 pop qword ptr [rax + 16]
418 ## UINT64 Gdtr[2], Idtr[2];
419 ## Best not let anyone mess with these particular registers...
424 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
425 ## NOTE - modified segment registers could hang the debugger... We
426 ## could attempt to insulate ourselves against this possibility,
427 ## but that poses risks as well.
438 mov rax, ASM_PFX(AppRsp)
439 pop qword ptr [rax + 8]
442 ## The next stuff to restore is the general purpose registers that were pushed
443 ## using the "push" instruction.
445 ## The value of RSP as stored in the context record is the application RSP
446 ## including the 5 entries on the application stack caused by the exception
447 ## itself. It may have been modified by the debug agent, so we need to
448 ## determine if we need to relocate the application stack.
450 mov rbx, [rsp + 24] # move the potentially modified AppRsp into rbx
451 mov rax, ASM_PFX(AppRsp)
456 mov rax, ASM_PFX(AppRsp)
460 mov rcx, [rax + 8] # CS
463 mov rcx, [rax + 16] # RFLAGS
466 mov rcx, [rax + 24] # RSP
469 mov rcx, [rax + 32] # SS
472 mov rax, rbx # modify the saved AppRsp to the new AppRsp
473 mov ASM_PFX(AppRsp), rax
475 mov rax, ASM_PFX(DebugRsp) # restore the DebugRsp on the debug stack
476 # so our "pop" will not cause a stack switch
479 cmp dword ptr ASM_PFX(ExceptionNumber), 0x068
484 ## Restore rflags so when we chain, the flags will be exactly as if we were never here.
485 ## We gin up the stack to do an iretq so we can get ALL the flags.
486 mov rax, ASM_PFX(AppRsp)
494 mov rax, ASM_PFX(AppRsp)
496 and rbx, NOT 0x300 # special handling for IF and TF
500 mov rax, offset PhonyIretq
505 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
506 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
524 ## Switch back to application stack
525 mov rsp, ASM_PFX(AppRsp)
526 ## Jump to original handler
527 jmp ASM_PFX(OrigVector)
529 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
530 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
548 ## Switch back to application stack
549 mov rsp, ASM_PFX(AppRsp)
551 ## We're outa here...