• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
50SECTION .data
51
52global ASM_PFX(OrigVector)
53global ASM_PFX(InterruptEntryStub)
54global ASM_PFX(StubSize)
55global ASM_PFX(CommonIdtEntry)
56global ASM_PFX(FxStorSupport)
57extern ASM_PFX(InterruptDistrubutionHub)
58
59ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
60AppRsp: dq 0x1111111111111111 ; ?
61DebugRsp: dq 0x2222222222222222 ; ?
62ExtraPush: dq 0x3333333333333333 ; ?
63ExceptData: dq 0x4444444444444444 ; ?
64Rflags: dq 0x5555555555555555 ; ?
65ASM_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
99align           16
100DebugStackEnd: 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                                        ;;
106ExceptionNumber: dq 0                   ;; first entry will be the vector number pushed by the stub
107
108DebugStackBegin: db "<<<< DbgStkBegin"  ;; initial debug ESP == DebugStackBegin, set in stub
109
110DEFAULT REL
111SECTION .text
112
113;------------------------------------------------------------------------------
114; BOOLEAN
115; FxStorSupport (
116;   void
117;   )
118;
119; Abstract: Returns TRUE if FxStor instructions are supported
120;
121global ASM_PFX(FxStorSupport)
122ASM_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;
145global ASM_PFX(Vect2Desc)
146ASM_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;
166ASM_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
170InterruptEntryStubEnd:
171
172;------------------------------------------------------------------------------
173; CommonIdtEntry
174;
175; Abstract: This code is not a function, but is the common part for all IDT
176;               vectors.
177;
178ASM_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
276ExtraPushOne:
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
287ExtraPushDone:
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
506NoAppStackMove:
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
514Chain:
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
535PhonyIretq:
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
562NoChain:
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
588