]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
UefiCpuPkg/MpInitLib: Enhance waiting for AP initialization logic.
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Ia32 / MpFuncs.nasm
CommitLineData
d94e5f67
JF
1;------------------------------------------------------------------------------ ;\r
2; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
3; This program and the accompanying materials\r
4; are licensed and made available under the terms and conditions of the BSD License\r
5; which accompanies this distribution. The full text of the license may be found at\r
6; http://opensource.org/licenses/bsd-license.php.\r
7;\r
8; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10;\r
11; Module Name:\r
12;\r
13; MpFuncs.nasm\r
14;\r
15; Abstract:\r
16;\r
17; This is the assembly code for MP support\r
18;\r
19;-------------------------------------------------------------------------------\r
20\r
21%include "MpEqu.inc"\r
22extern ASM_PFX(InitializeFloatingPointUnits)\r
23\r
24SECTION .text\r
25\r
26;-------------------------------------------------------------------------------------\r
27;RendezvousFunnelProc procedure follows. All APs execute their procedure. This\r
28;procedure serializes all the AP processors through an Init sequence. It must be\r
29;noted that APs arrive here very raw...ie: real mode, no stack.\r
30;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
31;IS IN MACHINE CODE.\r
32;-------------------------------------------------------------------------------------\r
33global ASM_PFX(RendezvousFunnelProc)\r
34ASM_PFX(RendezvousFunnelProc):\r
35RendezvousFunnelProcStart:\r
36; At this point CS = 0x(vv00) and ip= 0x0.\r
37BITS 16\r
38 mov ebp, eax ; save BIST information\r
39\r
40 mov ax, cs\r
41 mov ds, ax\r
42 mov es, ax\r
43 mov ss, ax\r
44 xor ax, ax\r
45 mov fs, ax\r
46 mov gs, ax\r
47\r
48 mov si, BufferStartLocation\r
49 mov ebx, [si]\r
50\r
51 mov si, ModeOffsetLocation\r
52 mov eax, [si]\r
53 mov si, CodeSegmentLocation\r
54 mov edx, [si]\r
55 mov di, ax\r
56 sub di, 02h\r
57 mov [di], dx\r
58 sub di, 04h\r
59 add eax, ebx\r
60 mov [di],eax\r
61\r
62 mov si, DataSegmentLocation\r
63 mov edx, [si]\r
64\r
65 mov si, GdtrLocation\r
66o32 lgdt [cs:si]\r
67\r
68 mov si, IdtrLocation\r
69o32 lidt [cs:si]\r
70\r
71 xor ax, ax\r
72 mov ds, ax\r
73\r
8396e2dd
JF
74 mov eax, cr0 ; Get control register 0\r
75 or eax, 000000003h ; Set PE bit (bit #0) & MP\r
d94e5f67
JF
76 mov cr0, eax\r
77\r
78 jmp 0:strict dword 0 ; far jump to protected mode\r
79BITS 32\r
80Flat32Start: ; protected mode entry point\r
81 mov ds, dx\r
82 mov es, dx\r
83 mov fs, dx\r
84 mov gs, dx\r
85 mov ss, dx\r
86\r
87 mov esi, ebx\r
5c66d125 88\r
0594ec41
ED
89 ; Increment the number of APs executing here as early as possible\r
90 ; This is decremented in C code when AP is finished executing\r
91 mov edi, esi\r
92 add edi, NumApsExecutingLocation\r
93 lock inc dword [edi]\r
94\r
5c66d125
JF
95 mov edi, esi\r
96 add edi, EnableExecuteDisableLocation\r
97 cmp byte [edi], 0\r
98 jz SkipEnableExecuteDisable\r
99\r
100 ;\r
101 ; Enable IA32 PAE execute disable\r
102 ;\r
103\r
104 mov ecx, 0xc0000080\r
105 rdmsr\r
106 bts eax, 11\r
107 wrmsr\r
108\r
109 mov edi, esi\r
110 add edi, Cr3Location\r
111 mov eax, dword [edi]\r
112 mov cr3, eax\r
113\r
114 mov eax, cr4\r
115 bts eax, 5\r
116 mov cr4, eax\r
117\r
118 mov eax, cr0\r
119 bts eax, 31\r
120 mov cr0, eax\r
121\r
122SkipEnableExecuteDisable:\r
845c5be1
JF
123 mov edi, esi\r
124 add edi, InitFlagLocation\r
125 cmp dword [edi], 1 ; 1 == ApInitConfig\r
126 jnz GetApicId\r
5c66d125 127\r
845c5be1 128 ; AP init\r
d94e5f67
JF
129 mov edi, esi\r
130 add edi, LockLocation\r
131 mov eax, NotVacantFlag\r
132\r
133TestLock:\r
134 xchg [edi], eax\r
135 cmp eax, NotVacantFlag\r
136 jz TestLock\r
137\r
845c5be1 138 mov ecx, esi\r
37676b9f 139 add ecx, ApIndexLocation\r
845c5be1
JF
140 inc dword [ecx]\r
141 mov ebx, [ecx]\r
142\r
143Releaselock:\r
144 mov eax, VacantFlag\r
145 xchg [edi], eax\r
d94e5f67 146\r
d94e5f67
JF
147 mov edi, esi\r
148 add edi, StackSizeLocation\r
149 mov eax, [edi]\r
845c5be1
JF
150 mov ecx, ebx\r
151 inc ecx\r
152 mul ecx ; EAX = StackSize * (CpuNumber + 1)\r
d94e5f67
JF
153 mov edi, esi\r
154 add edi, StackStartAddressLocation\r
155 add eax, [edi]\r
156 mov esp, eax\r
845c5be1
JF
157 jmp CProcedureInvoke\r
158\r
159GetApicId:\r
160 mov eax, 0\r
161 cpuid\r
162 cmp eax, 0bh\r
1cbd8330
LE
163 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
164\r
165 mov eax, 0bh\r
166 xor ecx, ecx\r
167 cpuid\r
168 test ebx, 0ffffh\r
169 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero\r
170\r
171 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX\r
172 jmp GetProcessorNumber\r
173\r
174NoX2Apic:\r
845c5be1
JF
175 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
176 mov eax, 1\r
177 cpuid\r
178 shr ebx, 24\r
179 mov edx, ebx\r
845c5be1 180\r
845c5be1
JF
181GetProcessorNumber:\r
182 ;\r
183 ; Get processor number for this AP\r
184 ; Note that BSP may become an AP due to SwitchBsp()\r
185 ;\r
186 xor ebx, ebx\r
187 lea eax, [esi + CpuInfoLocation]\r
188 mov edi, [eax]\r
d94e5f67 189\r
845c5be1
JF
190GetNextProcNumber:\r
191 cmp [edi], edx ; APIC ID match?\r
192 jz ProgramStack\r
dd3fa0cd 193 add edi, 20\r
845c5be1
JF
194 inc ebx\r
195 jmp GetNextProcNumber \r
d94e5f67 196\r
845c5be1
JF
197ProgramStack:\r
198 mov esp, [edi + 12]\r
199 \r
d94e5f67
JF
200CProcedureInvoke:\r
201 push ebp ; push BIST data at top of AP stack\r
202 xor ebp, ebp ; clear ebp for call stack trace\r
203 push ebp\r
204 mov ebp, esp\r
205\r
206 mov eax, ASM_PFX(InitializeFloatingPointUnits)\r
207 call eax ; Call assembly function to initialize FPU per UEFI spec\r
208\r
37676b9f 209 push ebx ; Push ApIndex\r
d94e5f67
JF
210 mov eax, esi\r
211 add eax, LockLocation\r
212 push eax ; push address of exchange info data buffer\r
213\r
214 mov edi, esi\r
215 add edi, ApProcedureLocation\r
216 mov eax, [edi]\r
217\r
8396e2dd 218 call eax ; Invoke C function\r
d94e5f67 219\r
8396e2dd 220 jmp $ ; Never reach here\r
d94e5f67
JF
221RendezvousFunnelProcEnd:\r
222\r
76157021 223;-------------------------------------------------------------------------------------\r
9f91cb01 224; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);\r
76157021
JF
225;-------------------------------------------------------------------------------------\r
226global ASM_PFX(AsmRelocateApLoop)\r
227ASM_PFX(AsmRelocateApLoop):\r
228AsmRelocateApLoopStart:\r
bf2786dc
JF
229 mov eax, esp\r
230 mov esp, [eax + 16] ; TopOfApStack\r
231 push dword [eax] ; push return address for stack trace\r
232 push ebp\r
233 mov ebp, esp\r
234 mov ebx, [eax + 8] ; ApTargetCState\r
235 mov ecx, [eax + 4] ; MwaitSupport\r
9f91cb01
JF
236 mov eax, [eax + 20] ; CountTofinish\r
237 lock dec dword [eax] ; (*CountTofinish)--\r
bf2786dc 238 cmp cl, 1 ; Check mwait-monitor support\r
76157021
JF
239 jnz HltLoop\r
240MwaitLoop:\r
241 mov eax, esp\r
242 xor ecx, ecx\r
243 xor edx, edx\r
244 monitor\r
bf2786dc 245 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
76157021
JF
246 shl eax, 4\r
247 mwait\r
248 jmp MwaitLoop\r
249HltLoop:\r
250 cli\r
251 hlt\r
252 jmp HltLoop\r
76157021
JF
253AsmRelocateApLoopEnd:\r
254\r
d94e5f67
JF
255;-------------------------------------------------------------------------------------\r
256; AsmGetAddressMap (&AddressMap);\r
257;-------------------------------------------------------------------------------------\r
258global ASM_PFX(AsmGetAddressMap)\r
259ASM_PFX(AsmGetAddressMap):\r
260 pushad\r
261 mov ebp,esp\r
262\r
263 mov ebx, [ebp + 24h]\r
264 mov dword [ebx], RendezvousFunnelProcStart\r
265 mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart\r
266 mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
f7f85d83
JF
267 mov dword [ebx + 0Ch], AsmRelocateApLoopStart\r
268 mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
d94e5f67
JF
269\r
270 popad\r
271 ret\r
272\r
273;-------------------------------------------------------------------------------------\r
274;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
275;about to become an AP. It switches it'stack with the current AP.\r
276;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
277;-------------------------------------------------------------------------------------\r
278global ASM_PFX(AsmExchangeRole)\r
279ASM_PFX(AsmExchangeRole):\r
280 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
281 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
282 pushad\r
283 mov ebp,esp\r
284\r
285 ; esi contains MyInfo pointer\r
286 mov esi, [ebp + 24h]\r
287\r
288 ; edi contains OthersInfo pointer\r
289 mov edi, [ebp + 28h]\r
290\r
291 ;Store EFLAGS, GDTR and IDTR register to stack\r
292 pushfd\r
293 mov eax, cr4\r
294 push eax ; push cr4 firstly\r
295 mov eax, cr0\r
296 push eax\r
297\r
298 sgdt [esi + 8]\r
299 sidt [esi + 14]\r
300\r
301 ; Store the its StackPointer\r
302 mov [esi + 4],esp\r
303\r
304 ; update its switch state to STORED\r
305 mov byte [esi], CPU_SWITCH_STATE_STORED\r
306\r
307WaitForOtherStored:\r
308 ; wait until the other CPU finish storing its state\r
309 cmp byte [edi], CPU_SWITCH_STATE_STORED\r
310 jz OtherStored\r
311 pause\r
312 jmp WaitForOtherStored\r
313\r
314OtherStored:\r
315 ; Since another CPU already stored its state, load them\r
316 ; load GDTR value\r
317 lgdt [edi + 8]\r
318\r
319 ; load IDTR value\r
320 lidt [edi + 14]\r
321\r
322 ; load its future StackPointer\r
323 mov esp, [edi + 4]\r
324\r
325 ; update the other CPU's switch state to LOADED\r
326 mov byte [edi], CPU_SWITCH_STATE_LOADED\r
327\r
328WaitForOtherLoaded:\r
329 ; wait until the other CPU finish loading new state,\r
330 ; otherwise the data in stack may corrupt\r
331 cmp byte [esi], CPU_SWITCH_STATE_LOADED\r
332 jz OtherLoaded\r
333 pause\r
334 jmp WaitForOtherLoaded\r
335\r
336OtherLoaded:\r
337 ; since the other CPU already get the data it want, leave this procedure\r
338 pop eax\r
339 mov cr0, eax\r
340 pop eax\r
341 mov cr4, eax\r
342 popfd\r
343\r
344 popad\r
345 ret\r