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