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