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