]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.S
Port AsmFuncs.s to pass CYGWINGCC build for x64.
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / X64 / AsmFuncs.S
1 #/**@file
2 # Low leve x64 specific debug support functions.
3 #
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
9 #
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.
12 #
13 #**/
14
15 .intel_syntax noprefix
16
17
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)
23
24 .data
25
26 ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
27 ASM_PFX(AppRsp): .long 0x11111111 # ?
28 .long 0x11111111 # ?
29 ASM_PFX(DebugRsp): .long 0x22222222 # ?
30 .long 0x22222222 # ?
31 ASM_PFX(ExtraPush): .long 0x33333333 # ?
32 .long 0x33333333 # ?
33 ASM_PFX(ExceptData): .long 0x44444444 # ?
34 .long 0x44444444 # ?
35 ASM_PFX(Rflags): .long 0x55555555 # ?
36 .long 0x55555555 # ?
37 ASM_PFX(OrigVector): .long 0x66666666 # ?
38 .long 0x66666666 # ?
39
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.
44 ##
45 ## The stub will switch stacks from the application stack to the debuger stack
46 ## and pushes the exception number.
47 ##
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.
54 ##
55 ## We carefully locate the stack to make this happen.
56 ##
57 ## For reference, the context structure looks like this:
58 ## struct {
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;
63 ## UINT64 RFlags;
64 ## UINT64 Ldtr, Tr;
65 ## UINT64 Gdtr[2], Idtr[2];
66 ## UINT64 Rip;
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
71
72 .align 16
73 DebugStackEnd : .ascii "DbgStkEnd >>>>>>" # 16 byte long string - must be 16 bytes to preserve alignment
74 .rept 0x1ffc
75 .long 0x00000000
76 .endr
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.
81 #
82 ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub
83 .long 0x77777777 # ?
84
85 DebugStackBegin : .ascii "<<<< DbgStkBegin" # initial debug ESP == DebugStackBegin, set in stub
86
87
88 .text
89
90 #------------------------------------------------------------------------------
91 # BOOLEAN
92 # FxStorSupport (
93 # void
94 # )
95 #
96 # Abstract: Returns TRUE if FxStor instructions are supported
97 #
98 .globl ASM_PFX(FxStorSupport)
99 ASM_PFX(FxStorSupport):
100 #
101 # cpuid corrupts rbx which must be preserved per the C calling convention
102 #
103 push rbx
104 mov rax, 1
105 cpuid
106 mov eax, edx
107 and rax, 0x01000000
108 shr rax, 24
109 pop rbx
110 ret
111 #------------------------------------------------------------------------------
112 # void
113 # Vect2Desc (
114 # IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
115 # void (*Vector) (void) // rdx
116 # )
117 #
118 # Abstract: Encodes an IDT descriptor with the given physical address
119 #
120 .globl ASM_PFX(Vect2Desc)
121 ASM_PFX(Vect2Desc):
122 mov rax, rdx
123 mov word ptr [rcx], ax # write bits 15..0 of offset
124 mov dx, cs
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
127 shr rax, 16
128 mov word ptr [rcx+6], ax # write bits 31..16 of offset
129 shr rax, 16
130 mov dword ptr [rcx+8], eax # write bits 63..32 of offset
131
132 ret
133
134 #------------------------------------------------------------------------------
135 # InterruptEntryStub
136 #
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.
139 #
140 .globl ASM_PFX(InterruptEntryStub)
141 ASM_PFX(InterruptEntryStub):
142
143 push 0 # push vector number - will be modified before installed
144 jmp ASM_PFX(CommonIdtEntry)
145
146 .globl ASM_PFX(InterruptEntryStubEnd)
147 ASM_PFX(InterruptEntryStubEnd):
148
149 ret
150
151 #------------------------------------------------------------------------------
152 # CommonIdtEntry
153 #
154 # Abstract: This code is not a function, but is the common part for all IDT
155 # vectors.
156 #
157 .globl ASM_PFX(CommonIdtEntry)
158 ##
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
161 ##
162 ## The application stack looks like this:
163 ##
164 ## ...
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
173 ##
174 ## Vector Number <----------------- pushed in our IDT Entry
175 ##
176
177
178 ## The stub switched us to the debug stack and pushed the interrupt number.
179 ##
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...
184 #
185 ## For reference, the context record looks like this:
186 ##
187 ## typedef
188 ## struct {
189 ## UINT64 ExceptionData;
190 ## FX_SAVE_STATE_X64 FxSaveState;
191 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
192 ## UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
193 ## UINT64 RFlags;
194 ## UINT64 Ldtr, Tr;
195 ## UINT64 Gdtr[2], Idtr[2];
196 ## UINT64 Rip;
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):
202
203 ret
204
205 ## NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
206 push rax
207 mov rax, qword ptr [rsp][8] # save vector number
208 mov ASM_PFX(ExceptionNumber), rax # save vector number
209 pop rax
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;
216 push r15
217 push r14
218 push r13
219 push r12
220 push r11
221 push r10
222 push r9
223 push r8
224 push rax
225 push rcx
226 push rdx
227 push rbx
228 push rsp
229 push rbp
230 push rsi
231 push rdi
232 ## Save interrupt state rflags register...
233 pushfq
234 pop rax
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
240 jz ExtraPushOne
241 cmp dword ptr ASM_PFX(ExceptionNumber), 10
242 jz ExtraPushOne
243 cmp dword ptr ASM_PFX(ExceptionNumber), 11
244 jz ExtraPushOne
245 cmp dword ptr ASM_PFX(ExceptionNumber), 12
246 jz ExtraPushOne
247 cmp dword ptr ASM_PFX(ExceptionNumber), 13
248 jz ExtraPushOne
249 cmp dword ptr ASM_PFX(ExceptionNumber), 14
250 jz ExtraPushOne
251 cmp dword ptr ASM_PFX(ExceptionNumber), 17
252 jz ExtraPushOne
253 mov dword ptr ASM_PFX(ExtraPush), 0
254 mov dword ptr ASM_PFX(ExceptData), 0
255 jmp ExtraPushDone
256 ExtraPushOne:
257 mov dword ptr ASM_PFX(ExtraPush), 1
258
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)
262 mov rbx, [rax]
263 mov ASM_PFX(ExceptData), rbx
264 add rax, 8
265 mov ASM_PFX(AppRsp), rax
266
267 ExtraPushDone:
268
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...
272 mov rax, [rsp + 24]
273 mov ASM_PFX(DebugRsp), rax
274 mov rax, ASM_PFX(AppRsp)
275 add rax, 40
276 # application stack has ss, rsp, rflags, cs, & rip, so
277 # last actual application stack entry is
278 # 40 bytes into the application stack.
279 mov [rsp + 24], rax
280 ## continue building context record
281 ## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
282 mov rax, ss
283 push rax
284 # CS from application is one entry back in application stack
285 mov rax, ASM_PFX(AppRsp)
286 movzx rax, word ptr [rax + 8]
287 push rax
288
289 mov rax, ds
290 push rax
291 mov rax, es
292 push rax
293 mov rax, fs
294 push rax
295 mov rax, gs
296 push rax
297 ## UINT64 Rip;
298 # Rip from application is on top of application stack
299 mov rax, ASM_PFX(AppRsp)
300 push qword ptr [rax]
301 ## UINT64 Gdtr[2], Idtr[2];
302 push 0
303 push 0
304 sidt qword ptr [rsp]
305 push 0
306 push 0
307 sgdt qword ptr [rsp]
308
309 ## UINT64 Ldtr, Tr;
310 xor rax, rax
311 str ax
312 push rax
313 sldt ax
314 push rax
315
316 ## UINT64 RFlags;
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...
323 mov rax, cr8
324 push rax
325 mov rax, cr4
326 or rax, 0x208
327 mov cr4, rax
328 push rax
329 mov rax, cr3
330 push rax
331 mov rax, cr2
332 push rax
333 push 0
334 mov rax, cr0
335 push rax
336 ## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
337 mov rax, dr7
338 push rax
339 ## clear Dr7 while executing debugger itself
340 xor rax, rax
341 mov dr7, rax
342
343 mov rax, dr6
344 push rax
345 ## insure all status bits in dr6 are clear...
346 xor rax, rax
347 mov dr6, rax
348
349 mov rax, dr3
350 push rax
351 mov rax, dr2
352 push rax
353 mov rax, dr1
354 push rax
355 mov rax, dr0
356 push rax
357
358 ## FX_SAVE_STATE_X64 FxSaveState;
359 sub rsp, 512
360 mov rdi, rsp
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.
364 # FXSTOR_RDI
365 .byte 0x0f
366 .byte 0xae
367 .byte 0x07
368
369 ## UINT64 ExceptionData;
370 mov rax, ASM_PFX(ExceptData)
371 push rax
372 # call to C code which will in turn call registered handler
373 # pass in the vector number
374 mov rdx, rsp
375 mov rcx, ASM_PFX(ExceptionNumber)
376 sub rsp, 40
377 call ASM_PFX(InterruptDistrubutionHub)
378 add rsp, 40
379 # restore context...
380 ## UINT64 ExceptionData;
381 add rsp, 8
382 ## FX_SAVE_STATE_X64 FxSaveState;
383 mov rsi, rsp
384 # FXRSTOR_RSI
385 .byte 0x0f
386 .byte 0xae
387 .byte 0x0e
388 add rsp, 512
389 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
390 pop rax
391 mov dr0, rax
392 pop rax
393 mov dr1, rax
394 pop rax
395 mov dr2, rax
396 pop rax
397 mov dr3, rax
398 ## skip restore of dr6. We cleared dr6 during the context save.
399 add rsp, 8
400 pop rax
401 mov dr7, rax
402 ## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
403 pop rax
404 mov cr0, rax
405 add rsp, 8
406 pop rax
407 mov cr2, rax
408 pop rax
409 mov cr3, rax
410 pop rax
411 mov cr4, rax
412 pop rax
413 mov cr8, rax
414 ## UINT64 RFlags;
415 mov rax, ASM_PFX(AppRsp)
416 pop qword ptr [rax + 16]
417 ## UINT64 Ldtr, Tr;
418 ## UINT64 Gdtr[2], Idtr[2];
419 ## Best not let anyone mess with these particular registers...
420 add rsp, 48
421 ## UINT64 Rip;
422 pop qword ptr [rax]
423
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.
428 ##
429
430 pop rax
431 # mov gs, rax
432 pop rax
433 # mov fs, rax
434 pop rax
435 mov es, rax
436 pop rax
437 mov ds, rax
438 mov rax, ASM_PFX(AppRsp)
439 pop qword ptr [rax + 8]
440 pop rax
441 mov ss, rax
442 ## The next stuff to restore is the general purpose registers that were pushed
443 ## using the "push" instruction.
444 ##
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.
449
450 mov rbx, [rsp + 24] # move the potentially modified AppRsp into rbx
451 mov rax, ASM_PFX(AppRsp)
452 add rax, 40
453 cmp rbx, rax
454 je NoAppStackMove
455
456 mov rax, ASM_PFX(AppRsp)
457 mov rcx, [rax] # RIP
458 mov [rbx], rcx
459
460 mov rcx, [rax + 8] # CS
461 mov [rbx + 8], rcx
462
463 mov rcx, [rax + 16] # RFLAGS
464 mov [rbx + 16], rcx
465
466 mov rcx, [rax + 24] # RSP
467 mov [rbx + 24], rcx
468
469 mov rcx, [rax + 32] # SS
470 mov [rbx + 32], rcx
471
472 mov rax, rbx # modify the saved AppRsp to the new AppRsp
473 mov ASM_PFX(AppRsp), rax
474 NoAppStackMove:
475 mov rax, ASM_PFX(DebugRsp) # restore the DebugRsp on the debug stack
476 # so our "pop" will not cause a stack switch
477 mov [rsp + 24], rax
478
479 cmp dword ptr ASM_PFX(ExceptionNumber), 0x068
480 jne NoChain
481
482 Chain:
483
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)
487 mov rbx, [rax + 40]
488 push rbx
489 mov rax, ss
490 push rax
491 mov rax, rsp
492 add rax, 16
493 push rax
494 mov rax, ASM_PFX(AppRsp)
495 mov rbx, [rax + 16]
496 and rbx, NOT 0x300 # special handling for IF and TF
497 push rbx
498 mov rax, cs
499 push rax
500 mov rax, offset PhonyIretq
501 push rax
502 iretq
503 PhonyIretq:
504
505 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
506 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
507 pop rdi
508 pop rsi
509 pop rbp
510 pop rsp
511 pop rbx
512 pop rdx
513 pop rcx
514 pop rax
515 pop r8
516 pop r9
517 pop r10
518 pop r11
519 pop r12
520 pop r13
521 pop r14
522 pop r15
523
524 ## Switch back to application stack
525 mov rsp, ASM_PFX(AppRsp)
526 ## Jump to original handler
527 jmp ASM_PFX(OrigVector)
528 NoChain:
529 ## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
530 ## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
531 pop rdi
532 pop rsi
533 pop rbp
534 pop rsp
535 pop rbx
536 pop rdx
537 pop rcx
538 pop rax
539 pop r8
540 pop r9
541 pop r10
542 pop r11
543 pop r12
544 pop r13
545 pop r14
546 pop r15
547
548 ## Switch back to application stack
549 mov rsp, ASM_PFX(AppRsp)
550
551 ## We're outa here...
552 iret