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