]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
UefiCpuPkg/MpInitLib: support 64-bit AP stack addresses
[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
JF
88\r
89 mov edi, esi\r
90 add edi, EnableExecuteDisableLocation\r
91 cmp byte [edi], 0\r
92 jz SkipEnableExecuteDisable\r
93\r
94 ;\r
95 ; Enable IA32 PAE execute disable\r
96 ;\r
97\r
98 mov ecx, 0xc0000080\r
99 rdmsr\r
100 bts eax, 11\r
101 wrmsr\r
102\r
103 mov edi, esi\r
104 add edi, Cr3Location\r
105 mov eax, dword [edi]\r
106 mov cr3, eax\r
107\r
108 mov eax, cr4\r
109 bts eax, 5\r
110 mov cr4, eax\r
111\r
112 mov eax, cr0\r
113 bts eax, 31\r
114 mov cr0, eax\r
115\r
116SkipEnableExecuteDisable:\r
845c5be1
JF
117 mov edi, esi\r
118 add edi, InitFlagLocation\r
119 cmp dword [edi], 1 ; 1 == ApInitConfig\r
120 jnz GetApicId\r
5c66d125 121\r
845c5be1 122 ; AP init\r
d94e5f67
JF
123 mov edi, esi\r
124 add edi, LockLocation\r
125 mov eax, NotVacantFlag\r
126\r
127TestLock:\r
128 xchg [edi], eax\r
129 cmp eax, NotVacantFlag\r
130 jz TestLock\r
131\r
845c5be1
JF
132 mov ecx, esi\r
133 add ecx, NumApsExecutingLocation\r
134 inc dword [ecx]\r
135 mov ebx, [ecx]\r
136\r
137Releaselock:\r
138 mov eax, VacantFlag\r
139 xchg [edi], eax\r
d94e5f67 140\r
d94e5f67
JF
141 mov edi, esi\r
142 add edi, StackSizeLocation\r
143 mov eax, [edi]\r
845c5be1
JF
144 mov ecx, ebx\r
145 inc ecx\r
146 mul ecx ; EAX = StackSize * (CpuNumber + 1)\r
d94e5f67
JF
147 mov edi, esi\r
148 add edi, StackStartAddressLocation\r
149 add eax, [edi]\r
150 mov esp, eax\r
845c5be1
JF
151 jmp CProcedureInvoke\r
152\r
153GetApicId:\r
154 mov eax, 0\r
155 cpuid\r
156 cmp eax, 0bh\r
157 jnb X2Apic\r
158 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
159 mov eax, 1\r
160 cpuid\r
161 shr ebx, 24\r
162 mov edx, ebx\r
163 jmp GetProcessorNumber\r
164\r
165X2Apic:\r
166 ; Processor is x2APIC capable, so get 32-bit x2APIC ID\r
167 mov eax, 0bh\r
168 xor ecx, ecx\r
169 cpuid \r
170 ; edx save x2APIC ID\r
171 \r
172GetProcessorNumber:\r
173 ;\r
174 ; Get processor number for this AP\r
175 ; Note that BSP may become an AP due to SwitchBsp()\r
176 ;\r
177 xor ebx, ebx\r
178 lea eax, [esi + CpuInfoLocation]\r
179 mov edi, [eax]\r
d94e5f67 180\r
845c5be1
JF
181GetNextProcNumber:\r
182 cmp [edi], edx ; APIC ID match?\r
183 jz ProgramStack\r
dd3fa0cd 184 add edi, 20\r
845c5be1
JF
185 inc ebx\r
186 jmp GetNextProcNumber \r
d94e5f67 187\r
845c5be1
JF
188ProgramStack:\r
189 mov esp, [edi + 12]\r
190 \r
d94e5f67
JF
191CProcedureInvoke:\r
192 push ebp ; push BIST data at top of AP stack\r
193 xor ebp, ebp ; clear ebp for call stack trace\r
194 push ebp\r
195 mov ebp, esp\r
196\r
197 mov eax, ASM_PFX(InitializeFloatingPointUnits)\r
198 call eax ; Call assembly function to initialize FPU per UEFI spec\r
199\r
200 push ebx ; Push NumApsExecuting\r
201 mov eax, esi\r
202 add eax, LockLocation\r
203 push eax ; push address of exchange info data buffer\r
204\r
205 mov edi, esi\r
206 add edi, ApProcedureLocation\r
207 mov eax, [edi]\r
208\r
8396e2dd 209 call eax ; Invoke C function\r
d94e5f67 210\r
8396e2dd 211 jmp $ ; Never reach here\r
d94e5f67
JF
212RendezvousFunnelProcEnd:\r
213\r
76157021
JF
214;-------------------------------------------------------------------------------------\r
215; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment);\r
216;-------------------------------------------------------------------------------------\r
217global ASM_PFX(AsmRelocateApLoop)\r
218ASM_PFX(AsmRelocateApLoop):\r
219AsmRelocateApLoopStart:\r
220 cmp byte [esp + 4], 1\r
221 jnz HltLoop\r
222MwaitLoop:\r
223 mov eax, esp\r
224 xor ecx, ecx\r
225 xor edx, edx\r
226 monitor\r
227 mov eax, [esp + 8] ; Mwait Cx, Target C-State per eax[7:4]\r
228 shl eax, 4\r
229 mwait\r
230 jmp MwaitLoop\r
231HltLoop:\r
232 cli\r
233 hlt\r
234 jmp HltLoop\r
235 ret\r
236AsmRelocateApLoopEnd:\r
237\r
d94e5f67
JF
238;-------------------------------------------------------------------------------------\r
239; AsmGetAddressMap (&AddressMap);\r
240;-------------------------------------------------------------------------------------\r
241global ASM_PFX(AsmGetAddressMap)\r
242ASM_PFX(AsmGetAddressMap):\r
243 pushad\r
244 mov ebp,esp\r
245\r
246 mov ebx, [ebp + 24h]\r
247 mov dword [ebx], RendezvousFunnelProcStart\r
248 mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart\r
249 mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
f7f85d83
JF
250 mov dword [ebx + 0Ch], AsmRelocateApLoopStart\r
251 mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
d94e5f67
JF
252\r
253 popad\r
254 ret\r
255\r
256;-------------------------------------------------------------------------------------\r
257;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
258;about to become an AP. It switches it'stack with the current AP.\r
259;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
260;-------------------------------------------------------------------------------------\r
261global ASM_PFX(AsmExchangeRole)\r
262ASM_PFX(AsmExchangeRole):\r
263 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
264 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
265 pushad\r
266 mov ebp,esp\r
267\r
268 ; esi contains MyInfo pointer\r
269 mov esi, [ebp + 24h]\r
270\r
271 ; edi contains OthersInfo pointer\r
272 mov edi, [ebp + 28h]\r
273\r
274 ;Store EFLAGS, GDTR and IDTR register to stack\r
275 pushfd\r
276 mov eax, cr4\r
277 push eax ; push cr4 firstly\r
278 mov eax, cr0\r
279 push eax\r
280\r
281 sgdt [esi + 8]\r
282 sidt [esi + 14]\r
283\r
284 ; Store the its StackPointer\r
285 mov [esi + 4],esp\r
286\r
287 ; update its switch state to STORED\r
288 mov byte [esi], CPU_SWITCH_STATE_STORED\r
289\r
290WaitForOtherStored:\r
291 ; wait until the other CPU finish storing its state\r
292 cmp byte [edi], CPU_SWITCH_STATE_STORED\r
293 jz OtherStored\r
294 pause\r
295 jmp WaitForOtherStored\r
296\r
297OtherStored:\r
298 ; Since another CPU already stored its state, load them\r
299 ; load GDTR value\r
300 lgdt [edi + 8]\r
301\r
302 ; load IDTR value\r
303 lidt [edi + 14]\r
304\r
305 ; load its future StackPointer\r
306 mov esp, [edi + 4]\r
307\r
308 ; update the other CPU's switch state to LOADED\r
309 mov byte [edi], CPU_SWITCH_STATE_LOADED\r
310\r
311WaitForOtherLoaded:\r
312 ; wait until the other CPU finish loading new state,\r
313 ; otherwise the data in stack may corrupt\r
314 cmp byte [esi], CPU_SWITCH_STATE_LOADED\r
315 jz OtherLoaded\r
316 pause\r
317 jmp WaitForOtherLoaded\r
318\r
319OtherLoaded:\r
320 ; since the other CPU already get the data it want, leave this procedure\r
321 pop eax\r
322 mov cr0, eax\r
323 pop eax\r
324 mov cr4, eax\r
325 popfd\r
326\r
327 popad\r
328 ret\r