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