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