• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1;------------------------------------------------------------------------------ ;
2; Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
3; This program and the accompanying materials
4; are licensed and made available under the terms and conditions of the BSD License
5; which accompanies this distribution.  The full text of the license may be found at
6; http://opensource.org/licenses/bsd-license.php.
7;
8; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10;
11; Module Name:
12;
13;   ExceptionHandlerAsm.Asm
14;
15; Abstract:
16;
17;   x64 CPU Exception Handler
18;
19; Notes:
20;
21;------------------------------------------------------------------------------
22
23;
24; CommonExceptionHandler()
25;
26
27extern ASM_PFX(mErrorCodeFlag)    ; Error code flags for exceptions
28extern ASM_PFX(mDoFarReturnFlag)  ; Do far return flag
29extern ASM_PFX(CommonExceptionHandler)
30
31SECTION .data
32
33DEFAULT REL
34SECTION .text
35
36ALIGN   8
37
38AsmIdtVectorBegin:
39%rep  32
40    db      0x6a        ; push  #VectorNum
41    db      ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
42    push    rax
43    mov     rax, ASM_PFX(CommonInterruptEntry)
44    jmp     rax
45%endrep
46AsmIdtVectorEnd:
47
48HookAfterStubHeaderBegin:
49    db      0x6a        ; push
50@VectorNum:
51    db      0          ; 0 will be fixed
52    push    rax
53    mov     rax, HookAfterStubHeaderEnd
54    jmp     rax
55HookAfterStubHeaderEnd:
56    mov     rax, rsp
57    and     sp,  0xfff0        ; make sure 16-byte aligned for exception context
58    sub     rsp, 0x18           ; reserve room for filling exception data later
59    push    rcx
60    mov     rcx, [rax + 8]
61    bt      [ASM_PFX(mErrorCodeFlag)], ecx
62    jnc     .0
63    push    qword [rsp]             ; push additional rcx to make stack alignment
64.0:
65    xchg    rcx, [rsp]        ; restore rcx, save Exception Number in stack
66    push    qword [rax]             ; push rax into stack to keep code consistence
67
68;---------------------------------------;
69; CommonInterruptEntry                  ;
70;---------------------------------------;
71; The follow algorithm is used for the common interrupt routine.
72; Entry from each interrupt with a push eax and eax=interrupt number
73; Stack frame would be as follows as specified in IA32 manuals:
74;
75; +---------------------+ <-- 16-byte aligned ensured by processor
76; +    Old SS           +
77; +---------------------+
78; +    Old RSP          +
79; +---------------------+
80; +    RFlags           +
81; +---------------------+
82; +    CS               +
83; +---------------------+
84; +    RIP              +
85; +---------------------+
86; +    Error Code       +
87; +---------------------+
88; +   Vector Number     +
89; +---------------------+
90; +    RBP              +
91; +---------------------+ <-- RBP, 16-byte aligned
92; The follow algorithm is used for the common interrupt routine.
93global ASM_PFX(CommonInterruptEntry)
94ASM_PFX(CommonInterruptEntry):
95    cli
96    pop     rax
97    ;
98    ; All interrupt handlers are invoked through interrupt gates, so
99    ; IF flag automatically cleared at the entry point
100    ;
101    xchg    rcx, [rsp]      ; Save rcx into stack and save vector number into rcx
102    and     rcx, 0xFF
103    cmp     ecx, 32         ; Intel reserved vector for exceptions?
104    jae     NoErrorCode
105    bt      [ASM_PFX(mErrorCodeFlag)], ecx
106    jc      HasErrorCode
107
108NoErrorCode:
109
110    ;
111    ; Push a dummy error code on the stack
112    ; to maintain coherent stack map
113    ;
114    push    qword [rsp]
115    mov     qword [rsp + 8], 0
116HasErrorCode:
117    push    rbp
118    mov     rbp, rsp
119    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
120    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
121
122    ;
123    ; Stack:
124    ; +---------------------+ <-- 16-byte aligned ensured by processor
125    ; +    Old SS           +
126    ; +---------------------+
127    ; +    Old RSP          +
128    ; +---------------------+
129    ; +    RFlags           +
130    ; +---------------------+
131    ; +    CS               +
132    ; +---------------------+
133    ; +    RIP              +
134    ; +---------------------+
135    ; +    Error Code       +
136    ; +---------------------+
137    ; + RCX / Vector Number +
138    ; +---------------------+
139    ; +    RBP              +
140    ; +---------------------+ <-- RBP, 16-byte aligned
141    ;
142
143    ;
144    ; Since here the stack pointer is 16-byte aligned, so
145    ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
146    ; is 16-byte aligned
147    ;
148
149;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
150;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
151    push r15
152    push r14
153    push r13
154    push r12
155    push r11
156    push r10
157    push r9
158    push r8
159    push rax
160    push qword [rbp + 8]   ; RCX
161    push rdx
162    push rbx
163    push qword [rbp + 48]  ; RSP
164    push qword [rbp]       ; RBP
165    push rsi
166    push rdi
167
168;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
169    movzx   rax, word [rbp + 56]
170    push    rax                      ; for ss
171    movzx   rax, word [rbp + 32]
172    push    rax                      ; for cs
173    mov     rax, ds
174    push    rax
175    mov     rax, es
176    push    rax
177    mov     rax, fs
178    push    rax
179    mov     rax, gs
180    push    rax
181
182    mov     [rbp + 8], rcx               ; save vector number
183
184;; UINT64  Rip;
185    push    qword [rbp + 24]
186
187;; UINT64  Gdtr[2], Idtr[2];
188    xor     rax, rax
189    push    rax
190    push    rax
191    sidt    [rsp]
192    xchg    rax, [rsp + 2]
193    xchg    rax, [rsp]
194    xchg    rax, [rsp + 8]
195
196    xor     rax, rax
197    push    rax
198    push    rax
199    sgdt    [rsp]
200    xchg    rax, [rsp + 2]
201    xchg    rax, [rsp]
202    xchg    rax, [rsp + 8]
203
204;; UINT64  Ldtr, Tr;
205    xor     rax, rax
206    str     ax
207    push    rax
208    sldt    ax
209    push    rax
210
211;; UINT64  RFlags;
212    push    qword [rbp + 40]
213
214;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
215    mov     rax, cr8
216    push    rax
217    mov     rax, cr4
218    or      rax, 0x208
219    mov     cr4, rax
220    push    rax
221    mov     rax, cr3
222    push    rax
223    mov     rax, cr2
224    push    rax
225    xor     rax, rax
226    push    rax
227    mov     rax, cr0
228    push    rax
229
230;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
231    mov     rax, dr7
232    push    rax
233    mov     rax, dr6
234    push    rax
235    mov     rax, dr3
236    push    rax
237    mov     rax, dr2
238    push    rax
239    mov     rax, dr1
240    push    rax
241    mov     rax, dr0
242    push    rax
243
244;; FX_SAVE_STATE_X64 FxSaveState;
245    sub rsp, 512
246    mov rdi, rsp
247    db 0xf, 0xae, 0x7 ;fxsave [rdi]
248
249;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
250    cld
251
252;; UINT32  ExceptionData;
253    push    qword [rbp + 16]
254
255;; Prepare parameter and call
256    mov     rcx, [rbp + 8]
257    mov     rdx, rsp
258    ;
259    ; Per X64 calling convention, allocate maximum parameter stack space
260    ; and make sure RSP is 16-byte aligned
261    ;
262    sub     rsp, 4 * 8 + 8
263    mov     rax, ASM_PFX(CommonExceptionHandler)
264    call    rax
265    add     rsp, 4 * 8 + 8
266
267    cli
268;; UINT64  ExceptionData;
269    add     rsp, 8
270
271;; FX_SAVE_STATE_X64 FxSaveState;
272
273    mov rsi, rsp
274    db 0xf, 0xae, 0xE ; fxrstor [rsi]
275    add rsp, 512
276
277;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
278;; Skip restoration of DRx registers to support in-circuit emualators
279;; or debuggers set breakpoint in interrupt/exception context
280    add     rsp, 8 * 6
281
282;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
283    pop     rax
284    mov     cr0, rax
285    add     rsp, 8   ; not for Cr1
286    pop     rax
287    mov     cr2, rax
288    pop     rax
289    mov     cr3, rax
290    pop     rax
291    mov     cr4, rax
292    pop     rax
293    mov     cr8, rax
294
295;; UINT64  RFlags;
296    pop     qword [rbp + 40]
297
298;; UINT64  Ldtr, Tr;
299;; UINT64  Gdtr[2], Idtr[2];
300;; Best not let anyone mess with these particular registers...
301    add     rsp, 48
302
303;; UINT64  Rip;
304    pop     qword [rbp + 24]
305
306;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;
307    pop     rax
308    ; mov     gs, rax ; not for gs
309    pop     rax
310    ; mov     fs, rax ; not for fs
311    ; (X64 will not use fs and gs, so we do not restore it)
312    pop     rax
313    mov     es, rax
314    pop     rax
315    mov     ds, rax
316    pop     qword [rbp + 32]  ; for cs
317    pop     qword [rbp + 56]  ; for ss
318
319;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
320;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
321    pop     rdi
322    pop     rsi
323    add     rsp, 8               ; not for rbp
324    pop     qword [rbp + 48] ; for rsp
325    pop     rbx
326    pop     rdx
327    pop     rcx
328    pop     rax
329    pop     r8
330    pop     r9
331    pop     r10
332    pop     r11
333    pop     r12
334    pop     r13
335    pop     r14
336    pop     r15
337
338    mov     rsp, rbp
339    pop     rbp
340    add     rsp, 16
341    cmp     qword [rsp - 32], 0  ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
342    jz      DoReturn
343    cmp     qword [rsp - 40], 1  ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
344    jz      ErrorCode
345    jmp     qword [rsp - 32]
346ErrorCode:
347    sub     rsp, 8
348    jmp     qword [rsp - 24]
349
350DoReturn:
351    cmp     qword [ASM_PFX(mDoFarReturnFlag)], 0   ; Check if need to do far return instead of IRET
352    jz      DoIret
353    push    rax
354    mov     rax, rsp          ; save old RSP to rax
355    mov     rsp, [rsp + 0x20]
356    push    qword [rax + 0x10]       ; save CS in new location
357    push    qword [rax + 0x8]        ; save EIP in new location
358    push    qword [rax + 0x18]       ; save EFLAGS in new location
359    mov     rax, [rax]        ; restore rax
360    popfq                     ; restore EFLAGS
361    DB      0x48               ; prefix to composite "retq" with next "retf"
362    retf                      ; far return
363DoIret:
364    iretq
365
366;-------------------------------------------------------------------------------------
367;  GetTemplateAddressMap (&AddressMap);
368;-------------------------------------------------------------------------------------
369; comments here for definition of address map
370global ASM_PFX(AsmGetTemplateAddressMap)
371ASM_PFX(AsmGetTemplateAddressMap):
372    mov     rax, AsmIdtVectorBegin
373    mov     qword [rcx], rax
374    mov     qword [rcx + 0x8],  (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
375    mov     rax, HookAfterStubHeaderBegin
376    mov     qword [rcx + 0x10], rax
377    ret
378
379;-------------------------------------------------------------------------------------
380;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
381;-------------------------------------------------------------------------------------
382global ASM_PFX(AsmVectorNumFixup)
383ASM_PFX(AsmVectorNumFixup):
384    mov     rax, rdx
385    mov     [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
386    ret
387
388