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