1;
2; Copyright (c) 2010, 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;
12; Module Name:
13;
14;    AsmDispatchExecute.asm
15;
16; Abstract:
17;
18;   This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
19;   transit back to long mode.
20;
21;-------------------------------------------------------------------------------
22    .code
23;----------------------------------------------------------------------------
24; Procedure:    AsmExecute32BitCode
25;
26; Input:        None
27;
28; Output:       None
29;
30; Prototype:    EFI_STATUS
31;               AsmExecute32BitCode (
32;                 IN UINT64           Function,
33;                 IN UINT64           Param1,
34;                 IN UINT64           Param2,
35;                 IN IA32_DESCRIPTOR  *InternalGdtr
36;                 );
37;
38;
39; Description:  A thunk function to execute 32-bit code in long mode.
40;
41;----------------------------------------------------------------------------
42AsmExecute32BitCode    PROC
43    ;
44    ; save orignal GDTR and CS
45    ;
46    mov     rax, ds
47    push    rax
48    mov     rax, cs
49    push    rax
50    sub     rsp, 10h
51    sgdt    fword ptr [rsp]
52    ;
53    ; load internal GDT
54    ;
55    lgdt    fword ptr [r9]
56    ;
57    ; Save general purpose register and rflag register
58    ;
59    pushfq
60    push    rdi
61    push    rsi
62    push    rbp
63    push    rbx
64
65    ;
66    ; save CR3
67    ;
68    mov     rax, cr3
69    mov     rbp, rax
70
71    ;
72    ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode
73    ;
74    mov     rax, 10h              ; load long mode selector
75    shl     rax, 32
76    mov     r9, OFFSET ReloadCS   ;Assume the ReloadCS is under 4G
77    or      rax, r9
78    push    rax
79    ;
80    ; Save parameters for 32-bit function call
81    ;
82    mov     rax, r8
83    shl     rax, 32
84    or      rax, rdx
85    push    rax
86    ;
87    ; save the 32-bit function entry and the return address into stack which will be
88    ; retrieve in compatibility mode.
89    ;
90    mov     rax, OFFSET ReturnBack   ;Assume the ReloadCS is under 4G
91    shl     rax, 32
92    or      rax, rcx
93    push    rax
94
95    ;
96    ; let rax save DS
97    ;
98    mov     rax, 018h
99
100    ;
101    ; Change to Compatible Segment
102    ;
103    mov     rcx, 08h               ; load compatible mode selector
104    shl     rcx, 32
105    mov     rdx, OFFSET Compatible ; assume address < 4G
106    or      rcx, rdx
107    push    rcx
108    retf
109
110Compatible:
111    ; reload DS/ES/SS to make sure they are correct referred to current GDT
112    mov     ds, ax
113    mov     es, ax
114    mov     ss, ax
115
116    ;
117    ; Disable paging
118    ;
119    mov     rcx, cr0
120    btc     ecx, 31
121    mov     cr0, rcx
122    ;
123    ; Clear EFER.LME
124    ;
125    mov     ecx, 0C0000080h
126    rdmsr
127    btc     eax, 8
128    wrmsr
129
130; Now we are in protected mode
131    ;
132    ; Call 32-bit function. Assume the function entry address and parameter value is less than 4G
133    ;
134    pop    rax                 ; Here is the function entry
135    ;
136    ; Now the parameter is at the bottom of the stack,  then call in to IA32 function.
137    ;
138    jmp   rax
139ReturnBack:
140    pop   rcx                  ; drop param1
141    pop   rcx                  ; drop param2
142
143    ;
144    ; restore CR4
145    ;
146    mov     rax, cr4
147    bts     eax, 5
148    mov     cr4, rax
149
150    ;
151    ; restore CR3
152    ;
153    mov     eax, ebp
154    mov     cr3, rax
155
156    ;
157    ; Set EFER.LME to re-enable ia32-e
158    ;
159    mov     ecx, 0C0000080h
160    rdmsr
161    bts     eax, 8
162    wrmsr
163    ;
164    ; Enable paging
165    ;
166    mov     rax, cr0
167    bts     eax, 31
168    mov     cr0, rax
169; Now we are in compatible mode
170
171    ;
172    ; Reload cs register
173    ;
174    retf
175ReloadCS:
176    ;
177    ; Now we're in Long Mode
178    ;
179    ;
180    ; Restore C register and eax hold the return status from 32-bit function.
181    ; Note: Do not touch rax from now which hold the return value from IA32 function
182    ;
183    pop     rbx
184    pop     rbp
185    pop     rsi
186    pop     rdi
187    popfq
188    ;
189    ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
190    ;
191    lgdt    fword ptr[rsp]
192    ;
193    ; drop GDT descriptor in stack
194    ;
195    add     rsp, 10h
196    ;
197    ; switch to orignal CS and GDTR
198    ;
199    pop     r9                 ; get  CS
200    shl     r9,  32            ; rcx[32..47] <- Cs
201    mov     rcx, OFFSET @F
202    or      rcx, r9
203    push    rcx
204    retf
205@@:
206    ;
207    ; Reload original DS/ES/SS
208    ;
209    pop     rcx
210    mov     ds, rcx
211    mov     es, rcx
212    mov     ss, rcx
213    ret
214AsmExecute32BitCode   ENDP
215
216    END
217