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