1;------------------------------------------------------------------------------ ;
2; Copyright (c) 2015, 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;   MpFuncs.nasm
14;
15; Abstract:
16;
17;   This is the assembly code for MP support
18;
19;-------------------------------------------------------------------------------
20
21%include "MpEqu.inc"
22extern ASM_PFX(InitializeFloatingPointUnits)
23
24DEFAULT REL
25
26SECTION .text
27
28;-------------------------------------------------------------------------------------
29;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This
30;procedure serializes all the AP processors through an Init sequence. It must be
31;noted that APs arrive here very raw...ie: real mode, no stack.
32;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
33;IS IN MACHINE CODE.
34;-------------------------------------------------------------------------------------
35global ASM_PFX(RendezvousFunnelProc)
36ASM_PFX(RendezvousFunnelProc):
37RendezvousFunnelProcStart:
38; At this point CS = 0x(vv00) and ip= 0x0.
39; Save BIST information to ebp firstly
40BITS 16
41
42    mov        eax, 1234h
43    mov        ebp, eax                        ; save BIST information
44
45    mov        ax, cs
46    mov        ds, ax
47    mov        es, ax
48    mov        ss, ax
49    xor        ax, ax
50    mov        fs, ax
51    mov        gs, ax
52
53    mov        si,  BufferStartLocation
54    mov        ebx, [si]
55
56    mov        di,  PmodeOffsetLocation
57    mov        eax, [di]
58    mov        di,  ax
59    sub        di,  06h
60    add        eax, ebx
61    mov        [di],eax
62
63    mov        di, LmodeOffsetLocation
64    mov        eax, [di]
65    mov        di,  ax
66    sub        di,  06h
67    add        eax, ebx
68    mov        [di],eax
69
70
71    mov        si, Cr3Location
72    mov        ecx,[si]                        ; ECX is keeping the value of CR3
73
74    mov        si, GdtrLocation
75o32 lgdt       [cs:si]
76
77    mov        si, IdtrLocation
78o32 lidt       [cs:si]
79
80
81    xor        ax,  ax
82    mov        ds,  ax
83
84    mov        eax, cr0                        ;Get control register 0
85    or         eax, 000000003h                 ;Set PE bit (bit #0) & MP
86    mov        cr0, eax
87
88    jmp        PROTECT_MODE_CS:strict dword 0  ; far jump to protected mode
89BITS 32
90Flat32Start:                                   ; protected mode entry point
91    mov        ax, PROTECT_MODE_DS
92    mov        ds, ax
93    mov        es, ax
94    mov        fs, ax
95    mov        gs, ax
96    mov        ss, ax
97
98    mov        eax, cr4
99    bts        eax, 5
100    mov        cr4, eax
101
102    mov        cr3, ecx
103
104
105    mov        ecx, 0c0000080h             ; EFER MSR number.
106    rdmsr                                  ; Read EFER.
107    bts        eax, 8                      ; Set LME=1.
108    wrmsr                                  ; Write EFER.
109
110    mov        eax, cr0                    ; Read CR0.
111    bts        eax, 31                     ; Set PG=1.
112    mov        cr0, eax                    ; Write CR0.
113
114    jmp        LONG_MODE_CS:strict dword 0 ; far jump to long mode
115BITS 64
116LongModeStart:
117    mov        ax,  LONG_MODE_DS
118    mov        ds,  ax
119    mov        es,  ax
120    mov        ss,  ax
121
122    mov        esi, ebx
123    mov        edi, esi
124    add        edi, LockLocation
125    mov        rax, NotVacantFlag
126
127TestLock:
128    xchg       qword [edi], rax
129    cmp        rax, NotVacantFlag
130    jz         TestLock
131
132    mov        edi, esi
133    add        edi, NumApsExecutingLoction
134    inc        dword [edi]
135    mov        ebx, [edi]
136
137ProgramStack:
138    mov        edi, esi
139    add        edi, StackSizeLocation
140    mov        rax, qword [edi]
141    mov        edi, esi
142    add        edi, StackStartAddressLocation
143    add        rax, qword [edi]
144    mov        rsp, rax
145    mov        qword [edi], rax
146
147Releaselock:
148    mov        rax, VacantFlag
149    mov        edi, esi
150    add        edi, LockLocation
151    xchg       qword [edi], rax
152
153CProcedureInvoke:
154    push       rbp               ; push BIST data at top of AP stack
155    xor        rbp, rbp          ; clear ebp for call stack trace
156    push       rbp
157    mov        rbp, rsp
158
159    mov        rax, ASM_PFX(InitializeFloatingPointUnits)
160    sub        rsp, 20h
161    call       rax               ; Call assembly function to initialize FPU per UEFI spec
162    add        rsp, 20h
163
164    mov        edx, ebx          ; edx is NumApsExecuting
165    mov        ecx, esi
166    add        ecx, LockLocation ; rcx is address of exchange info data buffer
167
168    mov        edi, esi
169    add        edi, ApProcedureLocation
170    mov        rax, qword [edi]
171
172    sub        rsp, 20h
173    call       rax               ; invoke C function
174    add        rsp, 20h
175
176RendezvousFunnelProcEnd:
177
178;-------------------------------------------------------------------------------------
179;  AsmGetAddressMap (&AddressMap);
180;-------------------------------------------------------------------------------------
181global ASM_PFX(AsmGetAddressMap)
182ASM_PFX(AsmGetAddressMap):
183    mov        rax, ASM_PFX(RendezvousFunnelProc)
184    mov        qword [rcx], rax
185    mov        qword [rcx +  8h], Flat32Start - RendezvousFunnelProcStart
186    mov        qword [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
187    mov        qword [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
188    ret
189
190;-------------------------------------------------------------------------------------
191;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
192;about to become an AP. It switches it'stack with the current AP.
193;AsmExchangeRole (IN   CPU_EXCHANGE_INFO    *MyInfo, IN   CPU_EXCHANGE_INFO    *OthersInfo);
194;-------------------------------------------------------------------------------------
195global ASM_PFX(AsmExchangeRole)
196ASM_PFX(AsmExchangeRole):
197    ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
198    ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
199
200    push       rax
201    push       rbx
202    push       rcx
203    push       rdx
204    push       rsi
205    push       rdi
206    push       rbp
207    push       r8
208    push       r9
209    push       r10
210    push       r11
211    push       r12
212    push       r13
213    push       r14
214    push       r15
215
216    mov        rax, cr0
217    push       rax
218
219    mov        rax, cr4
220    push       rax
221
222    ; rsi contains MyInfo pointer
223    mov        rsi, rcx
224
225    ; rdi contains OthersInfo pointer
226    mov        rdi, rdx
227
228    ;Store EFLAGS, GDTR and IDTR regiter to stack
229    pushfq
230    sgdt       [rsi + 16]
231    sidt       [rsi + 26]
232
233    ; Store the its StackPointer
234    mov        [rsi + 8], rsp
235
236    ; update its switch state to STORED
237    mov        byte [rsi], CPU_SWITCH_STATE_STORED
238
239WaitForOtherStored:
240    ; wait until the other CPU finish storing its state
241    cmp        byte [rdi], CPU_SWITCH_STATE_STORED
242    jz         OtherStored
243    pause
244    jmp        WaitForOtherStored
245
246OtherStored:
247    ; Since another CPU already stored its state, load them
248    ; load GDTR value
249    lgdt       [rdi + 16]
250
251    ; load IDTR value
252    lidt       [rdi + 26]
253
254    ; load its future StackPointer
255    mov        rsp, [rdi + 8]
256
257    ; update the other CPU's switch state to LOADED
258    mov        byte [rdi], CPU_SWITCH_STATE_LOADED
259
260WaitForOtherLoaded:
261    ; wait until the other CPU finish loading new state,
262    ; otherwise the data in stack may corrupt
263    cmp        byte [rsi], CPU_SWITCH_STATE_LOADED
264    jz         OtherLoaded
265    pause
266    jmp        WaitForOtherLoaded
267
268OtherLoaded:
269    ; since the other CPU already get the data it want, leave this procedure
270    popfq
271
272    pop        rax
273    mov        cr4, rax
274
275    pop        rax
276    mov        cr0, rax
277
278    pop        r15
279    pop        r14
280    pop        r13
281    pop        r12
282    pop        r11
283    pop        r10
284    pop        r9
285    pop        r8
286    pop        rbp
287    pop        rdi
288    pop        rsi
289    pop        rdx
290    pop        rcx
291    pop        rbx
292    pop        rax
293
294    ret
295
296global ASM_PFX(AsmInitializeGdt)
297ASM_PFX(AsmInitializeGdt):
298    push       rbp
299    mov        rbp, rsp
300
301    lgdt       [rcx]  ; update the GDTR
302
303    sub        rsp, 0x10
304    mov        rax, ASM_PFX(SetCodeSelectorFarJump)
305    mov        [rsp], rax
306    mov        rdx, LONG_MODE_CS
307    mov        [rsp + 4], dx    ; get new CS
308    jmp        far dword [rsp]  ; far jump with new CS
309ASM_PFX(SetCodeSelectorFarJump):
310    add        rsp, 0x10
311
312    mov        rax, LONG_MODE_DS          ; get new DS
313    mov        ds, ax
314    mov        es, ax
315    mov        fs, ax
316    mov        gs, ax
317    mov        ss, ax
318
319    pop        rbp
320
321  ret
322