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