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