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