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