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
44SECTION .data
45
46global ASM_PFX(OrigVector)
47global ASM_PFX(InterruptEntryStub)
48global ASM_PFX(StubSize)
49global ASM_PFX(CommonIdtEntry)
50global ASM_PFX(FxStorSupport)
51extern ASM_PFX(InterruptDistrubutionHub)
52
53ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
54AppRsp: dq 0x1111111111111111 ; ?
55DebugRsp: dq 0x2222222222222222 ; ?
56ExtraPush: dq 0x3333333333333333 ; ?
57ExceptData: dq 0x4444444444444444 ; ?
58Rflags: dq 0x5555555555555555 ; ?
59ASM_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
93align           16
94DebugStackEnd: 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                                        ;;
100ExceptionNumber: dq 0                   ;; first entry will be the vector number pushed by the stub
101
102DebugStackBegin: db "<<<< DbgStkBegin"  ;; initial debug ESP == DebugStackBegin, set in stub
103
104DEFAULT REL
105SECTION .text
106
107;------------------------------------------------------------------------------
108; BOOLEAN
109; FxStorSupport (
110;   void
111;   )
112;
113; Abstract: Returns TRUE if FxStor instructions are supported
114;
115global ASM_PFX(FxStorSupport)
116ASM_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;
139global ASM_PFX(Vect2Desc)
140ASM_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;
160ASM_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
164InterruptEntryStubEnd:
165
166;------------------------------------------------------------------------------
167; CommonIdtEntry
168;
169; Abstract: This code is not a function, but is the common part for all IDT
170;               vectors.
171;
172ASM_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
270ExtraPushOne:
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
281ExtraPushDone:
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
500NoAppStackMove:
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
508Chain:
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
529PhonyIretq:
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
556NoChain:
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
582