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
24SECTION .text
25
26;-------------------------------------------------------------------------------------
27;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This
28;procedure serializes all the AP processors through an Init sequence. It must be
29;noted that APs arrive here very raw...ie: real mode, no stack.
30;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
31;IS IN MACHINE CODE.
32;-------------------------------------------------------------------------------------
33global ASM_PFX(RendezvousFunnelProc)
34ASM_PFX(RendezvousFunnelProc):
35RendezvousFunnelProcStart:
36; At this point CS = 0x(vv00) and ip= 0x0.
37BITS 16
38    mov        ebp, eax                        ; save BIST information
39
40    mov        ax, cs
41    mov        ds, ax
42    mov        es, ax
43    mov        ss, ax
44    xor        ax, ax
45    mov        fs, ax
46    mov        gs, ax
47
48    mov        si,  BufferStartLocation
49    mov        ebx, [si]
50
51    mov        di,  PmodeOffsetLocation
52    mov        eax, [di]
53    mov        di,  ax
54    sub        di,  06h
55    add        eax, ebx
56    mov        [di],eax
57
58    mov        si, GdtrLocation
59o32 lgdt       [cs:si]
60
61    mov        si, IdtrLocation
62o32 lidt       [cs:si]
63
64    xor        ax,  ax
65    mov        ds,  ax
66
67    mov        eax, cr0                        ;Get control register 0
68    or         eax, 000000003h                 ;Set PE bit (bit #0) & MP
69    mov        cr0, eax
70
71    jmp        PROTECT_MODE_CS:strict dword 0  ; far jump to protected mode
72BITS 32
73Flat32Start:                                   ; protected mode entry point
74    mov        ax, PROTECT_MODE_DS
75    mov        ds, ax
76    mov        es, ax
77    mov        fs, ax
78    mov        gs, ax
79    mov        ss, ax
80
81    mov        esi, ebx
82    mov        edi, esi
83    add        edi, LockLocation
84    mov        eax, NotVacantFlag
85
86TestLock:
87    xchg       [edi], eax
88    cmp        eax, NotVacantFlag
89    jz         TestLock
90
91    mov        edi, esi
92    add        edi, NumApsExecutingLoction
93    inc        dword [edi]
94    mov        ebx, [edi]
95
96ProgramStack:
97    mov        edi, esi
98    add        edi, StackSizeLocation
99    mov        eax, [edi]
100    mov        edi, esi
101    add        edi, StackStartAddressLocation
102    add        eax, [edi]
103    mov        esp, eax
104    mov        [edi], eax
105
106Releaselock:
107    mov        eax, VacantFlag
108    mov        edi, esi
109    add        edi, LockLocation
110    xchg       [edi], eax
111
112CProcedureInvoke:
113    push       ebp               ; push BIST data at top of AP stack
114    xor        ebp, ebp          ; clear ebp for call stack trace
115    push       ebp
116    mov        ebp, esp
117
118    mov        eax, ASM_PFX(InitializeFloatingPointUnits)
119    call       eax               ; Call assembly function to initialize FPU per UEFI spec
120
121    push       ebx               ; Push NumApsExecuting
122    mov        eax, esi
123    add        eax, LockLocation
124    push       eax               ; push address of exchange info data buffer
125
126    mov        edi, esi
127    add        edi, ApProcedureLocation
128    mov        eax, [edi]
129
130    call       eax               ; invoke C function
131
132    jmp        $                 ; never reach here
133RendezvousFunnelProcEnd:
134
135;-------------------------------------------------------------------------------------
136;  AsmGetAddressMap (&AddressMap);
137;-------------------------------------------------------------------------------------
138global ASM_PFX(AsmGetAddressMap)
139ASM_PFX(AsmGetAddressMap):
140    pushad
141    mov        ebp,esp
142
143    mov        ebx,  [ebp + 24h]
144    mov        dword [ebx], RendezvousFunnelProcStart
145    mov        dword [ebx +  4h], Flat32Start - RendezvousFunnelProcStart
146    mov        dword [ebx +  8h], 0
147    mov        dword [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
148
149    popad
150    ret
151
152;-------------------------------------------------------------------------------------
153;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
154;about to become an AP. It switches it'stack with the current AP.
155;AsmExchangeRole (IN   CPU_EXCHANGE_INFO    *MyInfo, IN   CPU_EXCHANGE_INFO    *OthersInfo);
156;-------------------------------------------------------------------------------------
157global ASM_PFX(AsmExchangeRole)
158ASM_PFX(AsmExchangeRole):
159    ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
160    ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
161    pushad
162    mov        ebp,esp
163
164    ; esi contains MyInfo pointer
165    mov        esi, [ebp + 24h]
166
167    ; edi contains OthersInfo pointer
168    mov        edi, [ebp + 28h]
169
170    ;Store EFLAGS, GDTR and IDTR register to stack
171    pushfd
172    mov        eax, cr4
173    push       eax       ; push cr4 firstly
174    mov        eax, cr0
175    push       eax
176
177    sgdt       [esi + 8]
178    sidt       [esi + 14]
179
180    ; Store the its StackPointer
181    mov        [esi + 4],esp
182
183    ; update its switch state to STORED
184    mov        byte [esi], CPU_SWITCH_STATE_STORED
185
186WaitForOtherStored:
187    ; wait until the other CPU finish storing its state
188    cmp        byte [edi], CPU_SWITCH_STATE_STORED
189    jz         OtherStored
190    pause
191    jmp        WaitForOtherStored
192
193OtherStored:
194    ; Since another CPU already stored its state, load them
195    ; load GDTR value
196    lgdt       [edi + 8]
197
198    ; load IDTR value
199    lidt       [edi + 14]
200
201    ; load its future StackPointer
202    mov        esp, [edi + 4]
203
204    ; update the other CPU's switch state to LOADED
205    mov        byte [edi], CPU_SWITCH_STATE_LOADED
206
207WaitForOtherLoaded:
208    ; wait until the other CPU finish loading new state,
209    ; otherwise the data in stack may corrupt
210    cmp        byte [esi], CPU_SWITCH_STATE_LOADED
211    jz         OtherLoaded
212    pause
213    jmp        WaitForOtherLoaded
214
215OtherLoaded:
216    ; since the other CPU already get the data it want, leave this procedure
217    pop        eax
218    mov        cr0, eax
219    pop        eax
220    mov        cr4, eax
221    popfd
222
223    popad
224    ret
225
226global ASM_PFX(AsmInitializeGdt)
227ASM_PFX(AsmInitializeGdt):
228  push         ebp
229  mov          ebp, esp
230  pushad
231  mov          edi, [ebp + 8]      ; Load GDT register
232
233  lgdt         [edi]      ; and update the GDTR
234
235  push         PROTECT_MODE_CS
236  mov          eax, ASM_PFX(SetCodeSelectorFarJump)
237  push         eax
238  retf
239ASM_PFX(SetCodeSelectorFarJump):
240  mov          ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too
241  mov          ds, ax
242  mov          es, ax
243  mov          fs, ax
244  mov          gs, ax
245  mov          ss, ax
246
247  popad
248  pop          ebp
249  ret
250