]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugSupportDxe/x64/AsmFuncs.asm
Add DebugPort & DebugSupport drivers
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / 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 sidt QWORD PTR [rbp - 0ah]
160 mov rax, QWORD PTR [rbp - 8h]
161
162 mov rsp, rbp
163 pop rbp
164 ret
165 GetIdtr ENDP
166
167
168 ;------------------------------------------------------------------------------
169 ; BOOLEAN
170 ; WriteInterruptFlag (
171 ; BOOLEAN NewState // rcx
172 ; )
173 ;
174 ; Abstract: Programs interrupt flag to the requested state and returns previous
175 ; state.
176 ;
177 WriteInterruptFlag PROC PUBLIC
178
179 pushfq
180 pop rax
181 and rax, 200h
182 shr rax, 9
183 cmp rcx, 0
184 jnz EnableIF
185 cli
186 ret
187 EnableIF:
188 sti
189 ret
190
191 WriteInterruptFlag ENDP
192
193
194
195 ;------------------------------------------------------------------------------
196 ; void
197 ; Vect2Desc (
198 ; DESCRIPTOR * DestDesc, // rcx
199 ; void (*Vector) (void) // rdx
200 ; )
201 ;
202 ; Abstract: Encodes an IDT descriptor with the given physical address
203 ;
204 Vect2Desc PROC PUBLIC
205
206 mov rax, rdx
207 mov word ptr [rcx], ax ; write bits 15..0 of offset
208 mov dx, cs
209 mov word ptr [rcx+2], dx ; SYS_CODE_SEL from GDT
210 mov word ptr [rcx+4], 0e00h OR 8000h ; type = 386 interrupt gate, present
211 shr rax, 16
212 mov word ptr [rcx+6], ax ; write bits 31..16 of offset
213 shr rax, 16
214 mov dword ptr [rcx+8], eax ; write bits 63..32 of offset
215
216 ret
217
218 Vect2Desc ENDP
219
220
221
222 ;------------------------------------------------------------------------------
223 ; InterruptEntryStub
224 ;
225 ; Abstract: This code is not a function, but is a small piece of code that is
226 ; copied and fixed up once for each IDT entry that is hooked.
227 ;
228 InterruptEntryStub::
229 push 0 ; push vector number - will be modified before installed
230 db 0e9h ; jump rel32
231 dd 0 ; fixed up to relative address of CommonIdtEntry
232 InterruptEntryStubEnd:
233
234
235
236 ;------------------------------------------------------------------------------
237 ; CommonIdtEntry
238 ;
239 ; Abstract: This code is not a function, but is the common part for all IDT
240 ; vectors.
241 ;
242 CommonIdtEntry::
243 ;;
244 ;; At this point, the stub has saved the current application stack esp into AppRsp
245 ;; and switched stacks to the debug stack, where it pushed the vector number
246 ;;
247 ;; The application stack looks like this:
248 ;;
249 ;; ...
250 ;; (last application stack entry)
251 ;; [16 bytes alignment, do not care it]
252 ;; SS from interrupted task
253 ;; RSP from interrupted task
254 ;; rflags from interrupted task
255 ;; CS from interrupted task
256 ;; RIP from interrupted task
257 ;; Error code <-------------------- Only present for some exeption types
258 ;;
259 ;; Vector Number <----------------- pushed in our IDT Entry
260 ;;
261
262
263 ;; The stub switched us to the debug stack and pushed the interrupt number.
264 ;;
265 ;; Next, construct the context record. It will be build on the debug stack by
266 ;; pushing the registers in the correct order so as to create the context structure
267 ;; on the debug stack. The context record must be built from the end back to the
268 ;; beginning because the stack grows down...
269 ;
270 ;; For reference, the context record looks like this:
271 ;;
272 ;; typedef
273 ;; struct {
274 ;; UINT64 ExceptionData;
275 ;; FX_SAVE_STATE_X64 FxSaveState;
276 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
277 ;; UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
278 ;; UINT64 RFlags;
279 ;; UINT64 Ldtr, Tr;
280 ;; UINT64 Gdtr[2], Idtr[2];
281 ;; UINT64 Rip;
282 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
283 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
284 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
285 ;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
286
287 ;; NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
288 push rax
289 mov rax, qword ptr [rsp][8] ; save vector number
290 mov ExceptionNumber, rax ; save vector number
291 pop rax
292 add rsp, 8 ; pop vector number
293 mov AppRsp, rsp ; save stack top
294 mov rsp, offset DebugStackBegin ; switch to debugger stack
295 sub rsp, 8 ; leave space for vector number
296
297 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
298 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
299 push r15
300 push r14
301 push r13
302 push r12
303 push r11
304 push r10
305 push r9
306 push r8
307 push rax
308 push rcx
309 push rdx
310 push rbx
311 push rsp
312 push rbp
313 push rsi
314 push rdi
315
316 ;; Save interrupt state rflags register...
317 pushfq
318 pop rax
319 mov qword ptr Rflags, rax
320
321 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
322 ;; To do this, we check the exception number pushed by the stub, and cache the
323 ;; result in a variable since we'll need this again.
324 cmp ExceptionNumber, EXCPT64_DOUBLE_FAULT
325 jz ExtraPushOne
326 cmp ExceptionNumber, EXCPT64_INVALID_TSS
327 jz ExtraPushOne
328 cmp ExceptionNumber, EXCPT64_SEG_NOT_PRESENT
329 jz ExtraPushOne
330 cmp ExceptionNumber, EXCPT64_STACK_FAULT
331 jz ExtraPushOne
332 cmp ExceptionNumber, EXCPT64_GP_FAULT
333 jz ExtraPushOne
334 cmp ExceptionNumber, EXCPT64_PAGE_FAULT
335 jz ExtraPushOne
336 cmp ExceptionNumber, EXCPT64_ALIGNMENT_CHECK
337 jz ExtraPushOne
338 mov ExtraPush, 0
339 mov ExceptData, 0
340 jmp ExtraPushDone
341 ExtraPushOne:
342 mov ExtraPush, 1
343
344 ;; If there's some extra data, save it also, and modify the saved AppRsp to effectively
345 ;; pop this value off the application's stack.
346 mov rax, AppRsp
347 mov rbx, [rax]
348 mov ExceptData, rbx
349 add rax, 8
350 mov AppRsp, rax
351
352 ExtraPushDone:
353
354 ;; The "push" above pushed the debug stack rsp. Since what we're actually doing
355 ;; is building the context record on the debug stack, we need to save the pushed
356 ;; debug RSP, and replace it with the application's last stack entry...
357 mov rax, [rsp + 24]
358 mov DebugRsp, rax
359 mov rax, AppRsp
360 add rax, 40
361 ; application stack has ss, rsp, rflags, cs, & rip, so
362 ; last actual application stack entry is
363 ; 40 bytes into the application stack.
364 mov [rsp + 24], rax
365
366 ;; continue building context record
367 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
368 mov rax, ss
369 push rax
370
371 ; CS from application is one entry back in application stack
372 mov rax, AppRsp
373 movzx rax, word ptr [rax + 8]
374 push rax
375
376 mov rax, ds
377 push rax
378 mov rax, es
379 push rax
380 mov rax, fs
381 push rax
382 mov rax, gs
383 push rax
384
385 ;; UINT64 Rip;
386 ; Rip from application is on top of application stack
387 mov rax, AppRsp
388 push qword ptr [rax]
389
390 ;; UINT64 Gdtr[2], Idtr[2];
391 push 0
392 push 0
393 sidt fword ptr [rsp]
394 push 0
395 push 0
396 sgdt fword ptr [rsp]
397
398 ;; UINT64 Ldtr, Tr;
399 xor rax, rax
400 str ax
401 push rax
402 sldt ax
403 push rax
404
405 ;; UINT64 RFlags;
406 ;; Rflags from application is two entries back in application stack
407 mov rax, AppRsp
408 push qword ptr [rax + 16]
409
410 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
411 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
412 ;; ... while we're at it, make sure DE is also enabled...
413 mov rax, cr8
414 push rax
415 mov rax, cr4
416 or rax, 208h
417 mov cr4, rax
418 push rax
419 mov rax, cr3
420 push rax
421 mov rax, cr2
422 push rax
423 push 0
424 mov rax, cr0
425 push rax
426
427 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
428 mov rax, dr7
429 push rax
430 ;; clear Dr7 while executing debugger itself
431 xor rax, rax
432 mov dr7, rax
433
434 mov rax, dr6
435 push rax
436 ;; insure all status bits in dr6 are clear...
437 xor rax, rax
438 mov dr6, rax
439
440 mov rax, dr3
441 push rax
442 mov rax, dr2
443 push rax
444 mov rax, dr1
445 push rax
446 mov rax, dr0
447 push rax
448
449 ;; FX_SAVE_STATE_X64 FxSaveState;
450 sub rsp, 512
451 mov rdi, rsp
452 ; IMPORTANT!! The debug stack has been carefully constructed to
453 ; insure that rsp and rdi are 16 byte aligned when we get here.
454 ; They MUST be. If they are not, a GP fault will occur.
455 FXSTOR_RDI
456
457 ;; UINT64 ExceptionData;
458 mov rax, ExceptData
459 push rax
460
461 ; call to C code which will in turn call registered handler
462 ; pass in the vector number
463 mov rdx, rsp
464 mov rcx, ExceptionNumber
465 sub rsp, 40
466 call InterruptDistrubutionHub
467 add rsp, 40
468
469 ; restore context...
470 ;; UINT64 ExceptionData;
471 add rsp, 8
472
473 ;; FX_SAVE_STATE_X64 FxSaveState;
474 mov rsi, rsp
475 FXRSTOR_RSI
476 add rsp, 512
477
478 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
479 pop rax
480 mov dr0, rax
481 pop rax
482 mov dr1, rax
483 pop rax
484 mov dr2, rax
485 pop rax
486 mov dr3, rax
487 ;; skip restore of dr6. We cleared dr6 during the context save.
488 add rsp, 8
489 pop rax
490 mov dr7, rax
491
492 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
493 pop rax
494 mov cr0, rax
495 add rsp, 8
496 pop rax
497 mov cr2, rax
498 pop rax
499 mov cr3, rax
500 pop rax
501 mov cr4, rax
502 pop rax
503 mov cr8, rax
504
505 ;; UINT64 RFlags;
506 mov rax, AppRsp
507 pop qword ptr [rax + 16]
508
509 ;; UINT64 Ldtr, Tr;
510 ;; UINT64 Gdtr[2], Idtr[2];
511 ;; Best not let anyone mess with these particular registers...
512 add rsp, 48
513
514 ;; UINT64 Rip;
515 pop qword ptr [rax]
516
517 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
518 ;; NOTE - modified segment registers could hang the debugger... We
519 ;; could attempt to insulate ourselves against this possibility,
520 ;; but that poses risks as well.
521 ;;
522
523 pop rax
524 ; mov gs, rax
525 pop rax
526 ; mov fs, rax
527 pop rax
528 mov es, rax
529 pop rax
530 mov ds, rax
531 mov rax, AppRsp
532 pop qword ptr [rax + 8]
533 pop rax
534 mov ss, rax
535
536 ;; The next stuff to restore is the general purpose registers that were pushed
537 ;; using the "push" instruction.
538 ;;
539 ;; The value of RSP as stored in the context record is the application RSP
540 ;; including the 5 entries on the application stack caused by the exception
541 ;; itself. It may have been modified by the debug agent, so we need to
542 ;; determine if we need to relocate the application stack.
543
544 mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx
545 mov rax, AppRsp
546 add rax, 40
547 cmp rbx, rax
548 je NoAppStackMove
549
550 mov rax, AppRsp
551 mov rcx, [rax] ; RIP
552 mov [rbx], rcx
553
554 mov rcx, [rax + 8] ; CS
555 mov [rbx + 8], rcx
556
557 mov rcx, [rax + 16] ; RFLAGS
558 mov [rbx + 16], rcx
559
560 mov rcx, [rax + 24] ; RSP
561 mov [rbx + 24], rcx
562
563 mov rcx, [rax + 32] ; SS
564 mov [rbx + 32], rcx
565
566 mov rax, rbx ; modify the saved AppRsp to the new AppRsp
567 mov AppRsp, rax
568 NoAppStackMove:
569 mov rax, DebugRsp ; restore the DebugRsp on the debug stack
570 ; so our "pop" will not cause a stack switch
571 mov [rsp + 24], rax
572
573 cmp ExceptionNumber, 068h
574 jne NoChain
575
576 Chain:
577
578 ;; Restore rflags so when we chain, the flags will be exactly as if we were never here.
579 ;; We gin up the stack to do an iretq so we can get ALL the flags.
580 mov rax, AppRsp
581 mov rbx, [rax + 40]
582 push rbx
583 mov rax, ss
584 push rax
585 mov rax, rsp
586 add rax, 16
587 push rax
588 mov rax, AppRsp
589 mov rbx, [rax + 16]
590 and rbx, NOT 300h ; special handling for IF and TF
591 push rbx
592 mov rax, cs
593 push rax
594 mov rax, offset PhonyIretq
595 push rax
596 iretq
597 PhonyIretq:
598
599 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
600 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
601 pop rdi
602 pop rsi
603 pop rbp
604 pop rsp
605 pop rbx
606 pop rdx
607 pop rcx
608 pop rax
609 pop r8
610 pop r9
611 pop r10
612 pop r11
613 pop r12
614 pop r13
615 pop r14
616 pop r15
617
618 ;; Switch back to application stack
619 mov rsp, AppRsp
620
621 ;; Jump to original handler
622 jmp OrigVector
623
624 NoChain:
625 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
626 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
627 pop rdi
628 pop rsi
629 pop rbp
630 pop rsp
631 pop rbx
632 pop rdx
633 pop rcx
634 pop rax
635 pop r8
636 pop r9
637 pop r10
638 pop r11
639 pop r12
640 pop r13
641 pop r14
642 pop r15
643
644 ;; Switch back to application stack
645 mov rsp, AppRsp
646
647 ;; We're outa here...
648 iretq
649 text ENDS
650
651 END
652
653
654