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