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