]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
UefiCpuPkg/MpInitLib: Simplify logic in SwitchBsp
[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 202\r
7b7508ad
TL
203;-------------------------------------------------------------------------------------\r
204;SwitchToRealProc procedure follows.\r
205;NOT USED IN 32 BIT MODE.\r
206;-------------------------------------------------------------------------------------\r
7b7508ad
TL
207SwitchToRealProcStart:\r
208 jmp $ ; Never reach here\r
209SwitchToRealProcEnd:\r
210\r
b4d7b9d2
RN
211RendezvousFunnelProcEnd:\r
212\r
76157021 213;-------------------------------------------------------------------------------------\r
20da7ca4
TL
214; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
215;\r
216; The last three parameters (Pm16CodeSegment, SevEsAPJumpTable and WakeupBuffer) are\r
217; specific to SEV-ES support and are not applicable on IA32.\r
76157021 218;-------------------------------------------------------------------------------------\r
76157021 219AsmRelocateApLoopStart:\r
bf2786dc
JF
220 mov eax, esp\r
221 mov esp, [eax + 16] ; TopOfApStack\r
222 push dword [eax] ; push return address for stack trace\r
223 push ebp\r
224 mov ebp, esp\r
225 mov ebx, [eax + 8] ; ApTargetCState\r
226 mov ecx, [eax + 4] ; MwaitSupport\r
9f91cb01
JF
227 mov eax, [eax + 20] ; CountTofinish\r
228 lock dec dword [eax] ; (*CountTofinish)--\r
bf2786dc 229 cmp cl, 1 ; Check mwait-monitor support\r
76157021
JF
230 jnz HltLoop\r
231MwaitLoop:\r
a7bbe9d2 232 cli\r
76157021
JF
233 mov eax, esp\r
234 xor ecx, ecx\r
235 xor edx, edx\r
236 monitor\r
bf2786dc 237 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
76157021
JF
238 shl eax, 4\r
239 mwait\r
240 jmp MwaitLoop\r
241HltLoop:\r
242 cli\r
243 hlt\r
244 jmp HltLoop\r
76157021
JF
245AsmRelocateApLoopEnd:\r
246\r
d94e5f67
JF
247;-------------------------------------------------------------------------------------\r
248; AsmGetAddressMap (&AddressMap);\r
249;-------------------------------------------------------------------------------------\r
250global ASM_PFX(AsmGetAddressMap)\r
251ASM_PFX(AsmGetAddressMap):\r
252 pushad\r
253 mov ebp,esp\r
254\r
255 mov ebx, [ebp + 24h]\r
2fba7d4e
RN
256 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], RendezvousFunnelProcStart\r
257 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], Flat32Start - RendezvousFunnelProcStart\r
258 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
259 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], AsmRelocateApLoopStart\r
260 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
261 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart\r
2fba7d4e
RN
262 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start\r
263 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], 0\r
264 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], 0\r
d94e5f67
JF
265\r
266 popad\r
267 ret\r
268\r
269;-------------------------------------------------------------------------------------\r
270;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
271;about to become an AP. It switches it'stack with the current AP.\r
272;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
273;-------------------------------------------------------------------------------------\r
274global ASM_PFX(AsmExchangeRole)\r
275ASM_PFX(AsmExchangeRole):\r
276 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
277 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
278 pushad\r
279 mov ebp,esp\r
280\r
281 ; esi contains MyInfo pointer\r
282 mov esi, [ebp + 24h]\r
283\r
284 ; edi contains OthersInfo pointer\r
285 mov edi, [ebp + 28h]\r
286\r
d1abb876 287 ;Store EFLAGS to stack\r
d94e5f67 288 pushfd\r
d94e5f67
JF
289\r
290 ; Store the its StackPointer\r
2fba7d4e 291 mov [esi + CPU_EXCHANGE_ROLE_INFO.StackPointer],esp\r
d94e5f67
JF
292\r
293 ; update its switch state to STORED\r
2fba7d4e 294 mov byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
295\r
296WaitForOtherStored:\r
297 ; wait until the other CPU finish storing its state\r
2fba7d4e 298 cmp byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
299 jz OtherStored\r
300 pause\r
301 jmp WaitForOtherStored\r
302\r
303OtherStored:\r
d94e5f67 304 ; load its future StackPointer\r
2fba7d4e 305 mov esp, [edi + CPU_EXCHANGE_ROLE_INFO.StackPointer]\r
d94e5f67
JF
306\r
307 ; update the other CPU's switch state to LOADED\r
2fba7d4e 308 mov byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
309\r
310WaitForOtherLoaded:\r
311 ; wait until the other CPU finish loading new state,\r
312 ; otherwise the data in stack may corrupt\r
2fba7d4e 313 cmp byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
314 jz OtherLoaded\r
315 pause\r
316 jmp WaitForOtherLoaded\r
317\r
318OtherLoaded:\r
319 ; since the other CPU already get the data it want, leave this procedure\r
d94e5f67
JF
320 popfd\r
321\r
322 popad\r
323 ret\r