]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
UefiCpuPkg/MpInitLib: Add CPU MP data flag to indicate if SEV-ES is enabled
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / MpFuncs.nasm
CommitLineData
d94e5f67 1;------------------------------------------------------------------------------ ;\r
09f69a87 2; Copyright (c) 2015 - 2019, 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
18DEFAULT REL\r
19\r
20SECTION .text\r
21\r
22;-------------------------------------------------------------------------------------\r
23;RendezvousFunnelProc procedure follows. All APs execute their procedure. This\r
24;procedure serializes all the AP processors through an Init sequence. It must be\r
25;noted that APs arrive here very raw...ie: real mode, no stack.\r
26;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
27;IS IN MACHINE CODE.\r
28;-------------------------------------------------------------------------------------\r
29global ASM_PFX(RendezvousFunnelProc)\r
30ASM_PFX(RendezvousFunnelProc):\r
31RendezvousFunnelProcStart:\r
32; At this point CS = 0x(vv00) and ip= 0x0.\r
33; Save BIST information to ebp firstly\r
34\r
35BITS 16\r
36 mov ebp, eax ; Save BIST information\r
37\r
38 mov ax, cs\r
39 mov ds, ax\r
40 mov es, ax\r
41 mov ss, ax\r
42 xor ax, ax\r
43 mov fs, ax\r
44 mov gs, ax\r
45\r
46 mov si, BufferStartLocation\r
47 mov ebx, [si]\r
48\r
f32bfe6d
JW
49 mov si, DataSegmentLocation\r
50 mov edx, [si]\r
51\r
52 ;\r
53 ; Get start address of 32-bit code in low memory (<1MB)\r
54 ;\r
55 mov edi, ModeTransitionMemoryLocation\r
d94e5f67
JF
56\r
57 mov si, GdtrLocation\r
58o32 lgdt [cs:si]\r
59\r
60 mov si, IdtrLocation\r
61o32 lidt [cs:si]\r
62\r
f32bfe6d
JW
63 ;\r
64 ; Switch to protected mode\r
65 ;\r
66 mov eax, cr0 ; Get control register 0\r
67 or eax, 000000003h ; Set PE bit (bit #0) & MP\r
68 mov cr0, eax\r
69\r
70 ; Switch to 32-bit code (>1MB)\r
71o32 jmp far [cs:di]\r
72\r
73;\r
74; Following code must be copied to memory with type of EfiBootServicesCode.\r
75; This is required if NX is enabled for EfiBootServicesCode of memory.\r
76;\r
77BITS 32\r
78Flat32Start: ; protected mode entry point\r
79 mov ds, dx\r
80 mov es, dx\r
81 mov fs, dx\r
82 mov gs, dx\r
83 mov ss, dx\r
5c66d125
JF
84\r
85 ;\r
86 ; Enable execute disable bit\r
87 ;\r
f32bfe6d
JW
88 mov esi, EnableExecuteDisableLocation\r
89 cmp byte [ebx + esi], 0\r
90 jz SkipEnableExecuteDisableBit\r
91\r
5c66d125
JF
92 mov ecx, 0c0000080h ; EFER MSR number\r
93 rdmsr ; Read EFER\r
94 bts eax, 11 ; Enable Execute Disable Bit\r
95 wrmsr ; Write EFER\r
96\r
97SkipEnableExecuteDisableBit:\r
f32bfe6d
JW
98 ;\r
99 ; Enable PAE\r
100 ;\r
d94e5f67
JF
101 mov eax, cr4\r
102 bts eax, 5\r
09f69a87
RN
103\r
104 mov esi, Enable5LevelPagingLocation\r
105 cmp byte [ebx + esi], 0\r
106 jz SkipEnable5LevelPaging\r
107\r
108 ;\r
109 ; Enable 5 Level Paging\r
110 ;\r
111 bts eax, 12 ; Set LA57=1.\r
112\r
113SkipEnable5LevelPaging:\r
114\r
d94e5f67
JF
115 mov cr4, eax\r
116\r
f32bfe6d
JW
117 ;\r
118 ; Load page table\r
119 ;\r
120 mov esi, Cr3Location ; Save CR3 in ecx\r
121 mov ecx, [ebx + esi]\r
d94e5f67
JF
122 mov cr3, ecx ; Load CR3\r
123\r
f32bfe6d
JW
124 ;\r
125 ; Enable long mode\r
126 ;\r
d94e5f67
JF
127 mov ecx, 0c0000080h ; EFER MSR number\r
128 rdmsr ; Read EFER\r
129 bts eax, 8 ; Set LME=1\r
130 wrmsr ; Write EFER\r
131\r
f32bfe6d
JW
132 ;\r
133 ; Enable paging\r
134 ;\r
d94e5f67
JF
135 mov eax, cr0 ; Read CR0\r
136 bts eax, 31 ; Set PG=1\r
137 mov cr0, eax ; Write CR0\r
138\r
f32bfe6d
JW
139 ;\r
140 ; Far jump to 64-bit code\r
141 ;\r
142 mov edi, ModeHighMemoryLocation\r
143 add edi, ebx\r
144 jmp far [edi]\r
145\r
d94e5f67
JF
146BITS 64\r
147LongModeStart:\r
845c5be1
JF
148 mov esi, ebx\r
149 lea edi, [esi + InitFlagLocation]\r
150 cmp qword [edi], 1 ; ApInitConfig\r
151 jnz GetApicId\r
152\r
0594ec41
ED
153 ; Increment the number of APs executing here as early as possible\r
154 ; This is decremented in C code when AP is finished executing\r
155 mov edi, esi\r
156 add edi, NumApsExecutingLocation\r
157 lock inc dword [edi]\r
158\r
845c5be1 159 ; AP init\r
d94e5f67
JF
160 mov edi, esi\r
161 add edi, LockLocation\r
162 mov rax, NotVacantFlag\r
163\r
164TestLock:\r
165 xchg qword [edi], rax\r
166 cmp rax, NotVacantFlag\r
167 jz TestLock\r
168\r
37676b9f 169 lea ecx, [esi + ApIndexLocation]\r
845c5be1
JF
170 inc dword [ecx]\r
171 mov ebx, [ecx]\r
d94e5f67 172\r
845c5be1
JF
173Releaselock:\r
174 mov rax, VacantFlag\r
175 xchg qword [edi], rax\r
176 ; program stack\r
d94e5f67
JF
177 mov edi, esi\r
178 add edi, StackSizeLocation\r
845c5be1
JF
179 mov eax, dword [edi]\r
180 mov ecx, ebx\r
181 inc ecx\r
182 mul ecx ; EAX = StackSize * (CpuNumber + 1)\r
d94e5f67
JF
183 mov edi, esi\r
184 add edi, StackStartAddressLocation\r
185 add rax, qword [edi]\r
186 mov rsp, rax\r
845c5be1
JF
187 jmp CProcedureInvoke\r
188\r
189GetApicId:\r
190 mov eax, 0\r
191 cpuid\r
192 cmp eax, 0bh\r
1cbd8330
LE
193 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
194\r
195 mov eax, 0bh\r
196 xor ecx, ecx\r
197 cpuid\r
198 test ebx, 0ffffh\r
199 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero\r
200\r
201 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX\r
202 jmp GetProcessorNumber\r
203\r
204NoX2Apic:\r
845c5be1
JF
205 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
206 mov eax, 1\r
207 cpuid\r
208 shr ebx, 24\r
209 mov edx, ebx\r
845c5be1 210\r
845c5be1
JF
211GetProcessorNumber:\r
212 ;\r
213 ; Get processor number for this AP\r
214 ; Note that BSP may become an AP due to SwitchBsp()\r
215 ;\r
216 xor ebx, ebx\r
217 lea eax, [esi + CpuInfoLocation]\r
218 mov edi, [eax]\r
d94e5f67 219\r
845c5be1
JF
220GetNextProcNumber:\r
221 cmp dword [edi], edx ; APIC ID match?\r
222 jz ProgramStack\r
dd3fa0cd 223 add edi, 20\r
845c5be1 224 inc ebx\r
7367cc6c 225 jmp GetNextProcNumber\r
845c5be1
JF
226\r
227ProgramStack:\r
dd3fa0cd 228 mov rsp, qword [edi + 12]\r
d94e5f67
JF
229\r
230CProcedureInvoke:\r
8396e2dd
JF
231 push rbp ; Push BIST data at top of AP stack\r
232 xor rbp, rbp ; Clear ebp for call stack trace\r
d94e5f67
JF
233 push rbp\r
234 mov rbp, rsp\r
235\r
3b2928b4 236 mov rax, qword [esi + InitializeFloatingPointUnitsAddress]\r
d94e5f67
JF
237 sub rsp, 20h\r
238 call rax ; Call assembly function to initialize FPU per UEFI spec\r
239 add rsp, 20h\r
240\r
37676b9f 241 mov edx, ebx ; edx is ApIndex\r
d94e5f67
JF
242 mov ecx, esi\r
243 add ecx, LockLocation ; rcx is address of exchange info data buffer\r
244\r
245 mov edi, esi\r
246 add edi, ApProcedureLocation\r
247 mov rax, qword [edi]\r
248\r
249 sub rsp, 20h\r
8396e2dd 250 call rax ; Invoke C function\r
d94e5f67 251 add rsp, 20h\r
8396e2dd 252 jmp $ ; Should never reach here\r
d94e5f67
JF
253\r
254RendezvousFunnelProcEnd:\r
255\r
76157021 256;-------------------------------------------------------------------------------------\r
9f91cb01 257; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);\r
76157021
JF
258;-------------------------------------------------------------------------------------\r
259global ASM_PFX(AsmRelocateApLoop)\r
260ASM_PFX(AsmRelocateApLoop):\r
261AsmRelocateApLoopStart:\r
a7bbe9d2 262 cli ; Disable interrupt before switching to 32-bit mode\r
9f91cb01
JF
263 mov rax, [rsp + 40] ; CountTofinish\r
264 lock dec dword [rax] ; (*CountTofinish)--\r
bf2786dc 265 mov rsp, r9\r
76157021
JF
266 push rcx\r
267 push rdx\r
268\r
269 lea rsi, [PmEntry] ; rsi <- The start address of transition code\r
270\r
271 push r8\r
272 push rsi\r
273 DB 0x48\r
274 retf\r
275BITS 32\r
276PmEntry:\r
277 mov eax, cr0\r
278 btr eax, 31 ; Clear CR0.PG\r
279 mov cr0, eax ; Disable paging and caches\r
280\r
281 mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx\r
282 mov ecx, 0xc0000080\r
283 rdmsr\r
284 and ah, ~ 1 ; Clear LME\r
285 wrmsr\r
286 mov eax, cr4\r
287 and al, ~ (1 << 5) ; Clear PAE\r
288 mov cr4, eax\r
289\r
290 pop edx\r
291 add esp, 4\r
292 pop ecx,\r
293 add esp, 4\r
294 cmp cl, 1 ; Check mwait-monitor support\r
295 jnz HltLoop\r
296 mov ebx, edx ; Save C-State to ebx\r
297MwaitLoop:\r
a7bbe9d2 298 cli\r
76157021
JF
299 mov eax, esp ; Set Monitor Address\r
300 xor ecx, ecx ; ecx = 0\r
301 xor edx, edx ; edx = 0\r
302 monitor\r
76157021 303 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
f56379f3 304 shl eax, 4\r
76157021
JF
305 mwait\r
306 jmp MwaitLoop\r
307HltLoop:\r
308 cli\r
309 hlt\r
310 jmp HltLoop\r
76157021
JF
311BITS 64\r
312AsmRelocateApLoopEnd:\r
313\r
d94e5f67
JF
314;-------------------------------------------------------------------------------------\r
315; AsmGetAddressMap (&AddressMap);\r
316;-------------------------------------------------------------------------------------\r
317global ASM_PFX(AsmGetAddressMap)\r
318ASM_PFX(AsmGetAddressMap):\r
3b2928b4 319 lea rax, [ASM_PFX(RendezvousFunnelProc)]\r
d94e5f67
JF
320 mov qword [rcx], rax\r
321 mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart\r
322 mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
3b2928b4 323 lea rax, [ASM_PFX(AsmRelocateApLoop)]\r
f7f85d83
JF
324 mov qword [rcx + 18h], rax\r
325 mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
f32bfe6d 326 mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart\r
d94e5f67
JF
327 ret\r
328\r
329;-------------------------------------------------------------------------------------\r
330;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
8396e2dd 331;about to become an AP. It switches its stack with the current AP.\r
d94e5f67
JF
332;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
333;-------------------------------------------------------------------------------------\r
334global ASM_PFX(AsmExchangeRole)\r
335ASM_PFX(AsmExchangeRole):\r
336 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
337 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
338\r
339 push rax\r
340 push rbx\r
341 push rcx\r
342 push rdx\r
343 push rsi\r
344 push rdi\r
345 push rbp\r
346 push r8\r
347 push r9\r
348 push r10\r
349 push r11\r
350 push r12\r
351 push r13\r
352 push r14\r
353 push r15\r
354\r
355 mov rax, cr0\r
356 push rax\r
357\r
358 mov rax, cr4\r
359 push rax\r
360\r
361 ; rsi contains MyInfo pointer\r
362 mov rsi, rcx\r
363\r
364 ; rdi contains OthersInfo pointer\r
365 mov rdi, rdx\r
366\r
367 ;Store EFLAGS, GDTR and IDTR regiter to stack\r
368 pushfq\r
369 sgdt [rsi + 16]\r
370 sidt [rsi + 26]\r
371\r
372 ; Store the its StackPointer\r
373 mov [rsi + 8], rsp\r
374\r
375 ; update its switch state to STORED\r
376 mov byte [rsi], CPU_SWITCH_STATE_STORED\r
377\r
378WaitForOtherStored:\r
379 ; wait until the other CPU finish storing its state\r
380 cmp byte [rdi], CPU_SWITCH_STATE_STORED\r
381 jz OtherStored\r
382 pause\r
383 jmp WaitForOtherStored\r
384\r
385OtherStored:\r
386 ; Since another CPU already stored its state, load them\r
387 ; load GDTR value\r
388 lgdt [rdi + 16]\r
389\r
390 ; load IDTR value\r
391 lidt [rdi + 26]\r
392\r
393 ; load its future StackPointer\r
394 mov rsp, [rdi + 8]\r
395\r
396 ; update the other CPU's switch state to LOADED\r
397 mov byte [rdi], CPU_SWITCH_STATE_LOADED\r
398\r
399WaitForOtherLoaded:\r
400 ; wait until the other CPU finish loading new state,\r
401 ; otherwise the data in stack may corrupt\r
402 cmp byte [rsi], CPU_SWITCH_STATE_LOADED\r
403 jz OtherLoaded\r
404 pause\r
405 jmp WaitForOtherLoaded\r
406\r
407OtherLoaded:\r
408 ; since the other CPU already get the data it want, leave this procedure\r
409 popfq\r
410\r
411 pop rax\r
412 mov cr4, rax\r
413\r
414 pop rax\r
415 mov cr0, rax\r
416\r
417 pop r15\r
418 pop r14\r
419 pop r13\r
420 pop r12\r
421 pop r11\r
422 pop r10\r
423 pop r9\r
424 pop r8\r
425 pop rbp\r
426 pop rdi\r
427 pop rsi\r
428 pop rdx\r
429 pop rcx\r
430 pop rbx\r
431 pop rax\r
432\r
433 ret\r