]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.asm
f486bd32b55457d7d37f23ae49e61bc63c875e88
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / X64 / AsmFuncs.asm
1 ;/** @file
2 ; Low level x64 routines used by the debug support driver.
3 ;
4 ; Copyright (c) 2007 - 2008, Intel Corporation. <BR>
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 EXCPT64_DIVIDE_ERROR EQU 0
16 EXCPT64_DEBUG EQU 1
17 EXCPT64_NMI EQU 2
18 EXCPT64_BREAKPOINT EQU 3
19 EXCPT64_OVERFLOW EQU 4
20 EXCPT64_BOUND EQU 5
21 EXCPT64_INVALID_OPCODE EQU 6
22 EXCPT64_DOUBLE_FAULT EQU 8
23 EXCPT64_INVALID_TSS EQU 10
24 EXCPT64_SEG_NOT_PRESENT EQU 11
25 EXCPT64_STACK_FAULT EQU 12
26 EXCPT64_GP_FAULT EQU 13
27 EXCPT64_PAGE_FAULT EQU 14
28 EXCPT64_FP_ERROR EQU 16
29 EXCPT64_ALIGNMENT_CHECK EQU 17
30 EXCPT64_MACHINE_CHECK EQU 18
31 EXCPT64_SIMD EQU 19
32
33 FXSTOR_FLAG EQU 01000000h ; bit cpuid 24 of feature flags
34
35 ;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
36 ;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver
37 ;; MUST check the CPUID feature flags to see that these instructions are available
38 ;; and fail to init if they are not.
39
40 ;; fxstor [rdi]
41 FXSTOR_RDI MACRO
42 db 0fh, 0aeh, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [rdi]
43 ENDM
44
45 ;; fxrstor [rsi]
46 FXRSTOR_RSI MACRO
47 db 0fh, 0aeh, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [rsi]
48 ENDM
49
50 data SEGMENT
51
52 public OrigVector, InterruptEntryStub, StubSize, CommonIdtEntry, FxStorSupport
53
54 StubSize dd InterruptEntryStubEnd - InterruptEntryStub
55 AppRsp dq 1111111111111111h ; ?
56 DebugRsp dq 2222222222222222h ; ?
57 ExtraPush dq 3333333333333333h ; ?
58 ExceptData dq 4444444444444444h ; ?
59 Rflags dq 5555555555555555h ; ?
60 OrigVector dq 6666666666666666h ; ?
61
62 ;; The declarations below define the memory region that will be used for the debug stack.
63 ;; The context record will be built by pushing register values onto this stack.
64 ;; It is imparitive that alignment be carefully managed, since the FXSTOR and
65 ;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
66 ;;
67 ;; The stub will switch stacks from the application stack to the debuger stack
68 ;; and pushes the exception number.
69 ;;
70 ;; Then we building the context record on the stack. Since the stack grows down,
71 ;; we push the fields of the context record from the back to the front. There
72 ;; are 336 bytes of stack used prior allocating the 512 bytes of stack to be
73 ;; used as the memory buffer for the fxstor instruction. Therefore address of
74 ;; the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which
75 ;; must be 16 byte aligned.
76 ;;
77 ;; We carefully locate the stack to make this happen.
78 ;;
79 ;; For reference, the context structure looks like this:
80 ;; struct {
81 ;; UINT64 ExceptionData;
82 ;; FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
83 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
84 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
85 ;; UINT64 RFlags;
86 ;; UINT64 Ldtr, Tr;
87 ;; UINT64 Gdtr[2], Idtr[2];
88 ;; UINT64 Rip;
89 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
90 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
91 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
92 ;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
93
94 align 16
95 DebugStackEnd db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
96 dd 1ffch dup (000000000h) ;; 32K should be enough stack
97 ;; This allocation is coocked to insure
98 ;; that the the buffer for the FXSTORE instruction
99 ;; will be 16 byte aligned also.
100 ;;
101 ExceptionNumber dq ? ;; first entry will be the vector number pushed by the stub
102
103 DebugStackBegin db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
104
105 data ENDS
106
107 text SEGMENT
108
109 externdef InterruptDistrubutionHub:near
110
111 ;------------------------------------------------------------------------------
112 ; BOOLEAN
113 ; FxStorSupport (
114 ; void
115 ; )
116 ;
117 ; Abstract: Returns TRUE if FxStor instructions are supported
118 ;
119 FxStorSupport PROC PUBLIC
120
121 ;
122 ; cpuid corrupts rbx which must be preserved per the C calling convention
123 ;
124 push rbx
125 mov rax, 1
126 cpuid
127 mov eax, edx
128 and rax, FXSTOR_FLAG
129 shr rax, 24
130 pop rbx
131 ret
132 FxStorSupport ENDP
133
134
135
136
137 ;------------------------------------------------------------------------------
138 ; BOOLEAN
139 ; WriteInterruptFlag (
140 ; BOOLEAN NewState // rcx
141 ; )
142 ;
143 ; Abstract: Programs interrupt flag to the requested state and returns previous
144 ; state.
145 ;
146 WriteInterruptFlag PROC PUBLIC
147
148 pushfq
149 pop rax
150 and rax, 200h
151 shr rax, 9
152 cmp rcx, 0
153 jnz EnableIF
154 cli
155 ret
156 EnableIF:
157 sti
158 ret
159
160 WriteInterruptFlag ENDP
161
162
163
164 ;------------------------------------------------------------------------------
165 ; void
166 ; Vect2Desc (
167 ; IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
168 ; void (*Vector) (void) // rdx
169 ; )
170 ;
171 ; Abstract: Encodes an IDT descriptor with the given physical address
172 ;
173 Vect2Desc PROC PUBLIC
174
175 mov rax, rdx
176 mov word ptr [rcx], ax ; write bits 15..0 of offset
177 mov dx, cs
178 mov word ptr [rcx+2], dx ; SYS_CODE_SEL from GDT
179 mov word ptr [rcx+4], 0e00h OR 8000h ; type = 386 interrupt gate, present
180 shr rax, 16
181 mov word ptr [rcx+6], ax ; write bits 31..16 of offset
182 shr rax, 16
183 mov dword ptr [rcx+8], eax ; write bits 63..32 of offset
184
185 ret
186
187 Vect2Desc ENDP
188
189
190
191 ;------------------------------------------------------------------------------
192 ; InterruptEntryStub
193 ;
194 ; Abstract: This code is not a function, but is a small piece of code that is
195 ; copied and fixed up once for each IDT entry that is hooked.
196 ;
197 InterruptEntryStub::
198 push 0 ; push vector number - will be modified before installed
199 db 0e9h ; jump rel32
200 dd 0 ; fixed up to relative address of CommonIdtEntry
201 InterruptEntryStubEnd:
202
203
204
205 ;------------------------------------------------------------------------------
206 ; CommonIdtEntry
207 ;
208 ; Abstract: This code is not a function, but is the common part for all IDT
209 ; vectors.
210 ;
211 CommonIdtEntry::
212 ;;
213 ;; At this point, the stub has saved the current application stack esp into AppRsp
214 ;; and switched stacks to the debug stack, where it pushed the vector number
215 ;;
216 ;; The application stack looks like this:
217 ;;
218 ;; ...
219 ;; (last application stack entry)
220 ;; [16 bytes alignment, do not care it]
221 ;; SS from interrupted task
222 ;; RSP from interrupted task
223 ;; rflags from interrupted task
224 ;; CS from interrupted task
225 ;; RIP from interrupted task
226 ;; Error code <-------------------- Only present for some exeption types
227 ;;
228 ;; Vector Number <----------------- pushed in our IDT Entry
229 ;;
230
231
232 ;; The stub switched us to the debug stack and pushed the interrupt number.
233 ;;
234 ;; Next, construct the context record. It will be build on the debug stack by
235 ;; pushing the registers in the correct order so as to create the context structure
236 ;; on the debug stack. The context record must be built from the end back to the
237 ;; beginning because the stack grows down...
238 ;
239 ;; For reference, the context record looks like this:
240 ;;
241 ;; typedef
242 ;; struct {
243 ;; UINT64 ExceptionData;
244 ;; FX_SAVE_STATE_X64 FxSaveState;
245 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
246 ;; UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
247 ;; UINT64 RFlags;
248 ;; UINT64 Ldtr, Tr;
249 ;; UINT64 Gdtr[2], Idtr[2];
250 ;; UINT64 Rip;
251 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
252 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
253 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
254 ;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
255
256 ;; NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
257 push rax
258 mov rax, qword ptr [rsp][8] ; save vector number
259 mov ExceptionNumber, rax ; save vector number
260 pop rax
261 add rsp, 8 ; pop vector number
262 mov AppRsp, rsp ; save stack top
263 mov rsp, offset DebugStackBegin ; switch to debugger stack
264 sub rsp, 8 ; leave space for vector number
265
266 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
267 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
268 push r15
269 push r14
270 push r13
271 push r12
272 push r11
273 push r10
274 push r9
275 push r8
276 push rax
277 push rcx
278 push rdx
279 push rbx
280 push rsp
281 push rbp
282 push rsi
283 push rdi
284
285 ;; Save interrupt state rflags register...
286 pushfq
287 pop rax
288 mov qword ptr Rflags, rax
289
290 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
291 ;; To do this, we check the exception number pushed by the stub, and cache the
292 ;; result in a variable since we'll need this again.
293 cmp ExceptionNumber, EXCPT64_DOUBLE_FAULT
294 jz ExtraPushOne
295 cmp ExceptionNumber, EXCPT64_INVALID_TSS
296 jz ExtraPushOne
297 cmp ExceptionNumber, EXCPT64_SEG_NOT_PRESENT
298 jz ExtraPushOne
299 cmp ExceptionNumber, EXCPT64_STACK_FAULT
300 jz ExtraPushOne
301 cmp ExceptionNumber, EXCPT64_GP_FAULT
302 jz ExtraPushOne
303 cmp ExceptionNumber, EXCPT64_PAGE_FAULT
304 jz ExtraPushOne
305 cmp ExceptionNumber, EXCPT64_ALIGNMENT_CHECK
306 jz ExtraPushOne
307 mov ExtraPush, 0
308 mov ExceptData, 0
309 jmp ExtraPushDone
310 ExtraPushOne:
311 mov ExtraPush, 1
312
313 ;; If there's some extra data, save it also, and modify the saved AppRsp to effectively
314 ;; pop this value off the application's stack.
315 mov rax, AppRsp
316 mov rbx, [rax]
317 mov ExceptData, rbx
318 add rax, 8
319 mov AppRsp, rax
320
321 ExtraPushDone:
322
323 ;; The "push" above pushed the debug stack rsp. Since what we're actually doing
324 ;; is building the context record on the debug stack, we need to save the pushed
325 ;; debug RSP, and replace it with the application's last stack entry...
326 mov rax, [rsp + 24]
327 mov DebugRsp, rax
328 mov rax, AppRsp
329 add rax, 40
330 ; application stack has ss, rsp, rflags, cs, & rip, so
331 ; last actual application stack entry is
332 ; 40 bytes into the application stack.
333 mov [rsp + 24], rax
334
335 ;; continue building context record
336 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
337 mov rax, ss
338 push rax
339
340 ; CS from application is one entry back in application stack
341 mov rax, AppRsp
342 movzx rax, word ptr [rax + 8]
343 push rax
344
345 mov rax, ds
346 push rax
347 mov rax, es
348 push rax
349 mov rax, fs
350 push rax
351 mov rax, gs
352 push rax
353
354 ;; UINT64 Rip;
355 ; Rip from application is on top of application stack
356 mov rax, AppRsp
357 push qword ptr [rax]
358
359 ;; UINT64 Gdtr[2], Idtr[2];
360 push 0
361 push 0
362 sidt fword ptr [rsp]
363 push 0
364 push 0
365 sgdt fword ptr [rsp]
366
367 ;; UINT64 Ldtr, Tr;
368 xor rax, rax
369 str ax
370 push rax
371 sldt ax
372 push rax
373
374 ;; UINT64 RFlags;
375 ;; Rflags from application is two entries back in application stack
376 mov rax, AppRsp
377 push qword ptr [rax + 16]
378
379 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
380 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
381 ;; ... while we're at it, make sure DE is also enabled...
382 mov rax, cr8
383 push rax
384 mov rax, cr4
385 or rax, 208h
386 mov cr4, rax
387 push rax
388 mov rax, cr3
389 push rax
390 mov rax, cr2
391 push rax
392 push 0
393 mov rax, cr0
394 push rax
395
396 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
397 mov rax, dr7
398 push rax
399 ;; clear Dr7 while executing debugger itself
400 xor rax, rax
401 mov dr7, rax
402
403 mov rax, dr6
404 push rax
405 ;; insure all status bits in dr6 are clear...
406 xor rax, rax
407 mov dr6, rax
408
409 mov rax, dr3
410 push rax
411 mov rax, dr2
412 push rax
413 mov rax, dr1
414 push rax
415 mov rax, dr0
416 push rax
417
418 ;; FX_SAVE_STATE_X64 FxSaveState;
419 sub rsp, 512
420 mov rdi, rsp
421 ; IMPORTANT!! The debug stack has been carefully constructed to
422 ; insure that rsp and rdi are 16 byte aligned when we get here.
423 ; They MUST be. If they are not, a GP fault will occur.
424 FXSTOR_RDI
425
426 ;; UINT64 ExceptionData;
427 mov rax, ExceptData
428 push rax
429
430 ; call to C code which will in turn call registered handler
431 ; pass in the vector number
432 mov rdx, rsp
433 mov rcx, ExceptionNumber
434 sub rsp, 40
435 call InterruptDistrubutionHub
436 add rsp, 40
437
438 ; restore context...
439 ;; UINT64 ExceptionData;
440 add rsp, 8
441
442 ;; FX_SAVE_STATE_X64 FxSaveState;
443 mov rsi, rsp
444 FXRSTOR_RSI
445 add rsp, 512
446
447 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
448 pop rax
449 mov dr0, rax
450 pop rax
451 mov dr1, rax
452 pop rax
453 mov dr2, rax
454 pop rax
455 mov dr3, rax
456 ;; skip restore of dr6. We cleared dr6 during the context save.
457 add rsp, 8
458 pop rax
459 mov dr7, rax
460
461 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
462 pop rax
463 mov cr0, rax
464 add rsp, 8
465 pop rax
466 mov cr2, rax
467 pop rax
468 mov cr3, rax
469 pop rax
470 mov cr4, rax
471 pop rax
472 mov cr8, rax
473
474 ;; UINT64 RFlags;
475 mov rax, AppRsp
476 pop qword ptr [rax + 16]
477
478 ;; UINT64 Ldtr, Tr;
479 ;; UINT64 Gdtr[2], Idtr[2];
480 ;; Best not let anyone mess with these particular registers...
481 add rsp, 48
482
483 ;; UINT64 Rip;
484 pop qword ptr [rax]
485
486 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
487 ;; NOTE - modified segment registers could hang the debugger... We
488 ;; could attempt to insulate ourselves against this possibility,
489 ;; but that poses risks as well.
490 ;;
491
492 pop rax
493 ; mov gs, rax
494 pop rax
495 ; mov fs, rax
496 pop rax
497 mov es, rax
498 pop rax
499 mov ds, rax
500 mov rax, AppRsp
501 pop qword ptr [rax + 8]
502 pop rax
503 mov ss, rax
504
505 ;; The next stuff to restore is the general purpose registers that were pushed
506 ;; using the "push" instruction.
507 ;;
508 ;; The value of RSP as stored in the context record is the application RSP
509 ;; including the 5 entries on the application stack caused by the exception
510 ;; itself. It may have been modified by the debug agent, so we need to
511 ;; determine if we need to relocate the application stack.
512
513 mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx
514 mov rax, AppRsp
515 add rax, 40
516 cmp rbx, rax
517 je NoAppStackMove
518
519 mov rax, AppRsp
520 mov rcx, [rax] ; RIP
521 mov [rbx], rcx
522
523 mov rcx, [rax + 8] ; CS
524 mov [rbx + 8], rcx
525
526 mov rcx, [rax + 16] ; RFLAGS
527 mov [rbx + 16], rcx
528
529 mov rcx, [rax + 24] ; RSP
530 mov [rbx + 24], rcx
531
532 mov rcx, [rax + 32] ; SS
533 mov [rbx + 32], rcx
534
535 mov rax, rbx ; modify the saved AppRsp to the new AppRsp
536 mov AppRsp, rax
537 NoAppStackMove:
538 mov rax, DebugRsp ; restore the DebugRsp on the debug stack
539 ; so our "pop" will not cause a stack switch
540 mov [rsp + 24], rax
541
542 cmp ExceptionNumber, 068h
543 jne NoChain
544
545 Chain:
546
547 ;; Restore rflags so when we chain, the flags will be exactly as if we were never here.
548 ;; We gin up the stack to do an iretq so we can get ALL the flags.
549 mov rax, AppRsp
550 mov rbx, [rax + 40]
551 push rbx
552 mov rax, ss
553 push rax
554 mov rax, rsp
555 add rax, 16
556 push rax
557 mov rax, AppRsp
558 mov rbx, [rax + 16]
559 and rbx, NOT 300h ; special handling for IF and TF
560 push rbx
561 mov rax, cs
562 push rax
563 mov rax, offset PhonyIretq
564 push rax
565 iretq
566 PhonyIretq:
567
568 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
569 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
570 pop rdi
571 pop rsi
572 pop rbp
573 pop rsp
574 pop rbx
575 pop rdx
576 pop rcx
577 pop rax
578 pop r8
579 pop r9
580 pop r10
581 pop r11
582 pop r12
583 pop r13
584 pop r14
585 pop r15
586
587 ;; Switch back to application stack
588 mov rsp, AppRsp
589
590 ;; Jump to original handler
591 jmp OrigVector
592
593 NoChain:
594 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
595 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
596 pop rdi
597 pop rsi
598 pop rbp
599 pop rsp
600 pop rbx
601 pop rdx
602 pop rcx
603 pop rax
604 pop r8
605 pop r9
606 pop r10
607 pop r11
608 pop r12
609 pop r13
610 pop r14
611 pop r15
612
613 ;; Switch back to application stack
614 mov rsp, AppRsp
615
616 ;; We're outa here...
617 iretq
618 text ENDS
619
620 END
621
622
623