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
15EXCPT64_DIVIDE_ERROR     EQU    0
16EXCPT64_DEBUG            EQU    1
17EXCPT64_NMI              EQU    2
18EXCPT64_BREAKPOINT       EQU    3
19EXCPT64_OVERFLOW         EQU    4
20EXCPT64_BOUND            EQU    5
21EXCPT64_INVALID_OPCODE   EQU    6
22EXCPT64_DOUBLE_FAULT     EQU    8
23EXCPT64_INVALID_TSS      EQU   10
24EXCPT64_SEG_NOT_PRESENT  EQU   11
25EXCPT64_STACK_FAULT      EQU   12
26EXCPT64_GP_FAULT         EQU   13
27EXCPT64_PAGE_FAULT       EQU   14
28EXCPT64_FP_ERROR         EQU   16
29EXCPT64_ALIGNMENT_CHECK  EQU   17
30EXCPT64_MACHINE_CHECK    EQU   18
31EXCPT64_SIMD             EQU   19
32
33FXSTOR_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]
41FXSTOR_RDI               MACRO
42                         db 0fh, 0aeh, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [rdi]
43ENDM
44
45;; fxrstor [rsi]
46FXRSTOR_RSI              MACRO
47                         db 0fh, 0aeh, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [rsi]
48ENDM
49
50data SEGMENT
51
52public          OrigVector, InterruptEntryStub, StubSize, CommonIdtEntry, FxStorSupport
53
54StubSize        dd      InterruptEntryStubEnd - InterruptEntryStub
55AppRsp          dq      1111111111111111h ; ?
56DebugRsp        dq      2222222222222222h ; ?
57ExtraPush       dq      3333333333333333h ; ?
58ExceptData      dq      4444444444444444h ; ?
59Rflags          dq      5555555555555555h ; ?
60OrigVector      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
94align           16
95DebugStackEnd   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                                                ;;
101ExceptionNumber dq      ?                       ;; first entry will be the vector number pushed by the stub
102
103DebugStackBegin db      "<<<< DbgStkBegin"      ;; initial debug ESP == DebugStackBegin, set in stub
104
105data ENDS
106
107text SEGMENT
108
109externdef InterruptDistrubutionHub:near
110
111;------------------------------------------------------------------------------
112; BOOLEAN
113; FxStorSupport (
114;   void
115;   )
116;
117; Abstract: Returns TRUE if FxStor instructions are supported
118;
119FxStorSupport   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
132FxStorSupport   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;
143Vect2Desc       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
157Vect2Desc       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;
167InterruptEntryStub::
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
171InterruptEntryStubEnd:
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;
181CommonIdtEntry::
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
280ExtraPushOne:
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
291ExtraPushDone:
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
510NoAppStackMove:
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
518Chain:
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
539PhonyIretq:
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
566NoChain:
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
591text ENDS
592
593END
594
595
596
597