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