]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
UefiCpuPkg: Has APs in 64 bit long-mode before booting to OS.
[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 181CProcedureInvoke:\r
9ab2b34d
YX
182 ;\r
183 ; Reserve 4 bytes for CpuMpData.\r
184 ; When the AP wakes up again via INIT-SIPI-SIPI, push 0 will cause the existing CpuMpData to be overwritten with 0.\r
185 ; CpuMpData is filled in via InitializeApData() during the first time INIT-SIPI-SIPI,\r
186 ; while overwirrten may occurs when under ApInHltLoop but InitFlag is not set to ApInitConfig.\r
187 ; Therefore reservation is implemented by sub esp instead of push 0.\r
188 ;\r
189 sub esp, 4\r
d94e5f67
JF
190 push ebp ; push BIST data at top of AP stack\r
191 xor ebp, ebp ; clear ebp for call stack trace\r
192 push ebp\r
193 mov ebp, esp\r
194\r
195 mov eax, ASM_PFX(InitializeFloatingPointUnits)\r
196 call eax ; Call assembly function to initialize FPU per UEFI spec\r
197\r
37676b9f 198 push ebx ; Push ApIndex\r
d94e5f67 199 mov eax, esi\r
2fba7d4e 200 add eax, MP_CPU_EXCHANGE_INFO_OFFSET\r
d94e5f67
JF
201 push eax ; push address of exchange info data buffer\r
202\r
203 mov edi, esi\r
2fba7d4e 204 add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)\r
d94e5f67
JF
205 mov eax, [edi]\r
206\r
8396e2dd 207 call eax ; Invoke C function\r
d94e5f67 208\r
8396e2dd 209 jmp $ ; Never reach here\r
d94e5f67 210\r
7b7508ad
TL
211;-------------------------------------------------------------------------------------\r
212;SwitchToRealProc procedure follows.\r
213;NOT USED IN 32 BIT MODE.\r
214;-------------------------------------------------------------------------------------\r
7b7508ad
TL
215SwitchToRealProcStart:\r
216 jmp $ ; Never reach here\r
217SwitchToRealProcEnd:\r
218\r
b4d7b9d2
RN
219RendezvousFunnelProcEnd:\r
220\r
76157021 221;-------------------------------------------------------------------------------------\r
20da7ca4
TL
222; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
223;\r
224; The last three parameters (Pm16CodeSegment, SevEsAPJumpTable and WakeupBuffer) are\r
225; specific to SEV-ES support and are not applicable on IA32.\r
76157021 226;-------------------------------------------------------------------------------------\r
76157021 227AsmRelocateApLoopStart:\r
bf2786dc
JF
228 mov eax, esp\r
229 mov esp, [eax + 16] ; TopOfApStack\r
230 push dword [eax] ; push return address for stack trace\r
231 push ebp\r
232 mov ebp, esp\r
233 mov ebx, [eax + 8] ; ApTargetCState\r
234 mov ecx, [eax + 4] ; MwaitSupport\r
9f91cb01
JF
235 mov eax, [eax + 20] ; CountTofinish\r
236 lock dec dword [eax] ; (*CountTofinish)--\r
bf2786dc 237 cmp cl, 1 ; Check mwait-monitor support\r
76157021
JF
238 jnz HltLoop\r
239MwaitLoop:\r
a7bbe9d2 240 cli\r
76157021
JF
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
2fba7d4e
RN
264 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], RendezvousFunnelProcStart\r
265 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], Flat32Start - RendezvousFunnelProcStart\r
266 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
267 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], AsmRelocateApLoopStart\r
268 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
269 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart\r
2fba7d4e
RN
270 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start\r
271 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], 0\r
272 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], 0\r
d94e5f67
JF
273\r
274 popad\r
275 ret\r
276\r
277;-------------------------------------------------------------------------------------\r
278;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
279;about to become an AP. It switches it'stack with the current AP.\r
280;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
281;-------------------------------------------------------------------------------------\r
282global ASM_PFX(AsmExchangeRole)\r
283ASM_PFX(AsmExchangeRole):\r
284 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
285 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
286 pushad\r
287 mov ebp,esp\r
288\r
289 ; esi contains MyInfo pointer\r
290 mov esi, [ebp + 24h]\r
291\r
292 ; edi contains OthersInfo pointer\r
293 mov edi, [ebp + 28h]\r
294\r
d1abb876 295 ;Store EFLAGS to stack\r
d94e5f67 296 pushfd\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
d94e5f67 312 ; load its future StackPointer\r
2fba7d4e 313 mov esp, [edi + CPU_EXCHANGE_ROLE_INFO.StackPointer]\r
d94e5f67
JF
314\r
315 ; update the other CPU's switch state to LOADED\r
2fba7d4e 316 mov byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
317\r
318WaitForOtherLoaded:\r
319 ; wait until the other CPU finish loading new state,\r
320 ; otherwise the data in stack may corrupt\r
2fba7d4e 321 cmp byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
322 jz OtherLoaded\r
323 pause\r
324 jmp WaitForOtherLoaded\r
325\r
326OtherLoaded:\r
327 ; since the other CPU already get the data it want, leave this procedure\r
d94e5f67
JF
328 popfd\r
329\r
330 popad\r
331 ret\r