1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
11 ; This is the assembly code for MP support
13 ;-------------------------------------------------------------------------------
16 extern ASM_PFX(InitializeFloatingPointUnits)
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
26 ;-------------------------------------------------------------------------------------
27 RendezvousFunnelProcStart:
28 ; At this point CS = 0x(vv00) and ip= 0x0.
30 mov ebp, eax ; save BIST information
40 mov si, MP_CPU_EXCHANGE_INFO_FIELD (BufferStart)
43 mov si, MP_CPU_EXCHANGE_INFO_FIELD (DataSegment)
47 ; Get start address of 32-bit code in low memory (<1MB)
49 mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeTransitionMemory)
51 mov si, MP_CPU_EXCHANGE_INFO_FIELD (GdtrProfile)
54 mov si, MP_CPU_EXCHANGE_INFO_FIELD (IdtrProfile)
58 ; Switch to protected mode
60 mov eax, cr0 ; Get control register 0
61 or eax, 000000003h ; Set PE bit (bit #0) & MP
64 ; Switch to 32-bit code in executable memory (>1MB)
68 ; Following code may be copied to memory with type of EfiBootServicesCode.
69 ; This is required at DXE phase if NX is enabled for EfiBootServicesCode of
73 Flat32Start: ; protected mode entry point
83 add edi, MP_CPU_EXCHANGE_INFO_FIELD (EnableExecuteDisable)
85 jz SkipEnableExecuteDisable
88 ; Enable IA32 PAE execute disable
97 add edi, MP_CPU_EXCHANGE_INFO_FIELD (Cr3)
109 SkipEnableExecuteDisable:
111 add edi, MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)
112 cmp dword [edi], 1 ; 1 == ApInitConfig
115 ; Increment the number of APs executing here as early as possible
116 ; This is decremented in C code when AP is finished executing
118 add edi, MP_CPU_EXCHANGE_INFO_FIELD (NumApsExecuting)
123 add edi, MP_CPU_EXCHANGE_INFO_FIELD (ApIndex)
125 lock xadd dword [edi], ebx ; EBX = ApIndex++
126 inc ebx ; EBX is CpuNumber
129 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackSize)
133 mul ecx ; EAX = StackSize * (CpuNumber + 1)
135 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackStart)
144 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY
150 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero
152 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX
153 jmp GetProcessorNumber
156 ; Processor is not x2APIC capable, so get 8-bit APIC ID
164 ; Get processor number for this AP
165 ; Note that BSP may become an AP due to SwitchBsp()
168 lea eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (CpuInfo)]
172 cmp dword [edi + CPU_INFO_IN_HOB.InitialApicId], edx ; APIC ID match?
174 add edi, CPU_INFO_IN_HOB_size
176 jmp GetNextProcNumber
179 mov esp, dword [edi + CPU_INFO_IN_HOB.ApTopOfStack]
183 ; Reserve 4 bytes for CpuMpData.
184 ; When the AP wakes up again via INIT-SIPI-SIPI, push 0 will cause the existing CpuMpData to be overwritten with 0.
185 ; CpuMpData is filled in via InitializeApData() during the first time INIT-SIPI-SIPI,
186 ; while overwirrten may occurs when under ApInHltLoop but InitFlag is not set to ApInitConfig.
187 ; Therefore reservation is implemented by sub esp instead of push 0.
190 push ebp ; push BIST data at top of AP stack
191 xor ebp, ebp ; clear ebp for call stack trace
195 mov eax, ASM_PFX(InitializeFloatingPointUnits)
196 call eax ; Call assembly function to initialize FPU per UEFI spec
198 push ebx ; Push ApIndex
200 add eax, MP_CPU_EXCHANGE_INFO_OFFSET
201 push eax ; push address of exchange info data buffer
204 add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)
207 call eax ; Invoke C function
209 jmp $ ; Never reach here
211 ;-------------------------------------------------------------------------------------
212 ;SwitchToRealProc procedure follows.
213 ;NOT USED IN 32 BIT MODE.
214 ;-------------------------------------------------------------------------------------
215 SwitchToRealProcStart:
216 jmp $ ; Never reach here
219 RendezvousFunnelProcEnd:
221 ;-------------------------------------------------------------------------------------
222 ; AsmRelocateApLoopGeneric (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);
224 ; The last three parameters (Pm16CodeSegment, SevEsAPJumpTable and WakeupBuffer) are
225 ; specific to SEV-ES support and are not applicable on IA32.
226 ;-------------------------------------------------------------------------------------
227 AsmRelocateApLoopGenericStart:
229 mov esp, [eax + 12] ; TopOfApStack
230 push dword [eax] ; push return address for stack trace
233 mov ebx, [eax + 8] ; ApTargetCState
234 mov ecx, [eax + 4] ; MwaitSupport
235 mov eax, [eax + 16] ; CountTofinish
236 lock dec dword [eax] ; (*CountTofinish)--
237 cmp cl, 1 ; Check mwait-monitor support
245 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
253 AsmRelocateApLoopGenericEnd:
255 ;-------------------------------------------------------------------------------------
256 ; AsmGetAddressMap (&AddressMap);
257 ;-------------------------------------------------------------------------------------
258 global ASM_PFX(AsmGetAddressMap)
259 ASM_PFX(AsmGetAddressMap):
264 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], RendezvousFunnelProcStart
265 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], Flat32Start - RendezvousFunnelProcStart
266 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
267 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddressGeneric], AsmRelocateApLoopGenericStart
268 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSizeGeneric], AsmRelocateApLoopGenericEnd - AsmRelocateApLoopGenericStart
269 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart
270 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start
271 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], 0
272 mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], 0
277 ;-------------------------------------------------------------------------------------
278 ;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
279 ;about to become an AP. It switches it'stack with the current AP.
280 ;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
281 ;-------------------------------------------------------------------------------------
282 global ASM_PFX(AsmExchangeRole)
283 ASM_PFX(AsmExchangeRole):
284 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
285 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
289 ; esi contains MyInfo pointer
292 ; edi contains OthersInfo pointer
295 ;Store EFLAGS to stack
298 ; Store the its StackPointer
299 mov [esi + CPU_EXCHANGE_ROLE_INFO.StackPointer],esp
301 ; update its switch state to STORED
302 mov byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
305 ; wait until the other CPU finish storing its state
306 cmp byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
309 jmp WaitForOtherStored
312 ; load its future StackPointer
313 mov esp, [edi + CPU_EXCHANGE_ROLE_INFO.StackPointer]
315 ; update the other CPU's switch state to LOADED
316 mov byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
319 ; wait until the other CPU finish loading new state,
320 ; otherwise the data in stack may corrupt
321 cmp byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
324 jmp WaitForOtherLoaded
327 ; since the other CPU already get the data it want, leave this procedure