]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.asm
A complement fix for revision 11664 to update GCC assembly files : clear the directio...
[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 - 2011, 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 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 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
397 cld
398
399 ;; UINT64 ExceptionData;
400 mov rax, ExceptData
401 push rax
402
403 ; call to C code which will in turn call registered handler
404 ; pass in the vector number
405 mov rdx, rsp
406 mov rcx, ExceptionNumber
407 sub rsp, 40
408 call InterruptDistrubutionHub
409 add rsp, 40
410
411 ; restore context...
412 ;; UINT64 ExceptionData;
413 add rsp, 8
414
415 ;; FX_SAVE_STATE_X64 FxSaveState;
416 mov rsi, rsp
417 FXRSTOR_RSI
418 add rsp, 512
419
420 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
421 pop rax
422 mov dr0, rax
423 pop rax
424 mov dr1, rax
425 pop rax
426 mov dr2, rax
427 pop rax
428 mov dr3, rax
429 ;; skip restore of dr6. We cleared dr6 during the context save.
430 add rsp, 8
431 pop rax
432 mov dr7, rax
433
434 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
435 pop rax
436 mov cr0, rax
437 add rsp, 8
438 pop rax
439 mov cr2, rax
440 pop rax
441 mov cr3, rax
442 pop rax
443 mov cr4, rax
444 pop rax
445 mov cr8, rax
446
447 ;; UINT64 RFlags;
448 mov rax, AppRsp
449 pop qword ptr [rax + 16]
450
451 ;; UINT64 Ldtr, Tr;
452 ;; UINT64 Gdtr[2], Idtr[2];
453 ;; Best not let anyone mess with these particular registers...
454 add rsp, 48
455
456 ;; UINT64 Rip;
457 pop qword ptr [rax]
458
459 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
460 ;; NOTE - modified segment registers could hang the debugger... We
461 ;; could attempt to insulate ourselves against this possibility,
462 ;; but that poses risks as well.
463 ;;
464
465 pop rax
466 ; mov gs, rax
467 pop rax
468 ; mov fs, rax
469 pop rax
470 mov es, rax
471 pop rax
472 mov ds, rax
473 mov rax, AppRsp
474 pop qword ptr [rax + 8]
475 pop rax
476 mov ss, rax
477
478 ;; The next stuff to restore is the general purpose registers that were pushed
479 ;; using the "push" instruction.
480 ;;
481 ;; The value of RSP as stored in the context record is the application RSP
482 ;; including the 5 entries on the application stack caused by the exception
483 ;; itself. It may have been modified by the debug agent, so we need to
484 ;; determine if we need to relocate the application stack.
485
486 mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx
487 mov rax, AppRsp
488 mov rax, QWORD PTR [rax + 24]
489 cmp rbx, rax
490 je NoAppStackMove
491
492 mov rax, AppRsp
493 mov rcx, [rax] ; RIP
494 mov [rbx], rcx
495
496 mov rcx, [rax + 8] ; CS
497 mov [rbx + 8], rcx
498
499 mov rcx, [rax + 16] ; RFLAGS
500 mov [rbx + 16], rcx
501
502 mov rcx, [rax + 24] ; RSP
503 mov [rbx + 24], rcx
504
505 mov rcx, [rax + 32] ; SS
506 mov [rbx + 32], rcx
507
508 mov rax, rbx ; modify the saved AppRsp to the new AppRsp
509 mov AppRsp, rax
510 NoAppStackMove:
511 mov rax, DebugRsp ; restore the DebugRsp on the debug stack
512 ; so our "pop" will not cause a stack switch
513 mov [rsp + 24], rax
514
515 cmp ExceptionNumber, 068h
516 jne NoChain
517
518 Chain:
519
520 ;; Restore rflags so when we chain, the flags will be exactly as if we were never here.
521 ;; We gin up the stack to do an iretq so we can get ALL the flags.
522 mov rax, AppRsp
523 mov rbx, [rax + 40]
524 push rbx
525 mov rax, ss
526 push rax
527 mov rax, rsp
528 add rax, 16
529 push rax
530 mov rax, AppRsp
531 mov rbx, [rax + 16]
532 and rbx, NOT 300h ; special handling for IF and TF
533 push rbx
534 mov rax, cs
535 push rax
536 mov rax, offset PhonyIretq
537 push rax
538 iretq
539 PhonyIretq:
540
541 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
542 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
543 pop rdi
544 pop rsi
545 pop rbp
546 pop rsp
547 pop rbx
548 pop rdx
549 pop rcx
550 pop rax
551 pop r8
552 pop r9
553 pop r10
554 pop r11
555 pop r12
556 pop r13
557 pop r14
558 pop r15
559
560 ;; Switch back to application stack
561 mov rsp, AppRsp
562
563 ;; Jump to original handler
564 jmp OrigVector
565
566 NoChain:
567 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
568 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
569 pop rdi
570 pop rsi
571 pop rbp
572 pop rsp
573 pop rbx
574 pop rdx
575 pop rcx
576 pop rax
577 pop r8
578 pop r9
579 pop r10
580 pop r11
581 pop r12
582 pop r13
583 pop r14
584 pop r15
585
586 ;; Switch back to application stack
587 mov rsp, AppRsp
588
589 ;; We're outa here...
590 iretq
591 text ENDS
592
593 END
594
595
596