]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
OvmfPkg/SecMain: move SEV specific routines in AmdSev.c
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / 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
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
2fba7d4e 46 mov si, MP_CPU_EXCHANGE_INFO_FIELD (BufferStart)\r
d94e5f67
JF
47 mov ebx, [si]\r
48\r
2fba7d4e 49 mov si, MP_CPU_EXCHANGE_INFO_FIELD (DataSegment)\r
f32bfe6d
JW
50 mov edx, [si]\r
51\r
52 ;\r
53 ; Get start address of 32-bit code in low memory (<1MB)\r
54 ;\r
2fba7d4e 55 mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeTransitionMemory)\r
d94e5f67 56\r
2fba7d4e 57 mov si, MP_CPU_EXCHANGE_INFO_FIELD (GdtrProfile)\r
d94e5f67
JF
58o32 lgdt [cs:si]\r
59\r
2fba7d4e 60 mov si, MP_CPU_EXCHANGE_INFO_FIELD (IdtrProfile)\r
d94e5f67
JF
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
2fba7d4e 88 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (EnableExecuteDisable)\r
f32bfe6d
JW
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 103\r
2fba7d4e 104 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Enable5LevelPaging)\r
09f69a87
RN
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
2fba7d4e 120 mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Cr3) ; Save CR3 in ecx\r
f32bfe6d 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
2fba7d4e 142 mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeHighMemory)\r
f32bfe6d
JW
143 add edi, ebx\r
144 jmp far [edi]\r
145\r
d94e5f67
JF
146BITS 64\r
147LongModeStart:\r
845c5be1 148 mov esi, ebx\r
2fba7d4e 149 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)]\r
845c5be1
JF
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
2fba7d4e 156 add edi, MP_CPU_EXCHANGE_INFO_FIELD (NumApsExecuting)\r
0594ec41
ED
157 lock inc dword [edi]\r
158\r
845c5be1 159 ; AP init\r
62f2cf57 160 mov edi, esi\r
2fba7d4e 161 add edi, MP_CPU_EXCHANGE_INFO_FIELD (ApIndex)\r
62f2cf57
RN
162 mov ebx, 1\r
163 lock xadd dword [edi], ebx ; EBX = ApIndex++\r
164 inc ebx ; EBX is CpuNumber\r
d94e5f67 165\r
845c5be1 166 ; program stack\r
d94e5f67 167 mov edi, esi\r
2fba7d4e 168 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackSize)\r
845c5be1
JF
169 mov eax, dword [edi]\r
170 mov ecx, ebx\r
171 inc ecx\r
172 mul ecx ; EAX = StackSize * (CpuNumber + 1)\r
d94e5f67 173 mov edi, esi\r
2fba7d4e 174 add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackStart)\r
d94e5f67
JF
175 add rax, qword [edi]\r
176 mov rsp, rax\r
7b7508ad 177\r
2fba7d4e 178 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
7b7508ad
TL
179 cmp byte [edi], 1 ; SevEsIsEnabled\r
180 jne CProcedureInvoke\r
181\r
182 ;\r
183 ; program GHCB\r
184 ; Each page after the GHCB is a per-CPU page, so the calculation programs\r
185 ; a GHCB to be every 8KB.\r
186 ;\r
187 mov eax, SIZE_4KB\r
188 shl eax, 1 ; EAX = SIZE_4K * 2\r
189 mov ecx, ebx\r
190 mul ecx ; EAX = SIZE_4K * 2 * CpuNumber\r
191 mov edi, esi\r
2fba7d4e 192 add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)\r
7b7508ad
TL
193 add rax, qword [edi]\r
194 mov rdx, rax\r
195 shr rdx, 32\r
196 mov rcx, 0xc0010130\r
197 wrmsr\r
845c5be1
JF
198 jmp CProcedureInvoke\r
199\r
200GetApicId:\r
2fba7d4e 201 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
7b7508ad
TL
202 cmp byte [edi], 1 ; SevEsIsEnabled\r
203 jne DoCpuid\r
204\r
205 ;\r
206 ; Since we don't have a stack yet, we can't take a #VC\r
207 ; exception. Use the GHCB protocol to perform the CPUID\r
208 ; calls.\r
209 ;\r
210 mov rcx, 0xc0010130\r
211 rdmsr\r
212 shl rdx, 32\r
213 or rax, rdx\r
214 mov rdi, rax ; RDI now holds the original GHCB GPA\r
215\r
216 mov rdx, 0 ; CPUID function 0\r
217 mov rax, 0 ; RAX register requested\r
218 or rax, 4\r
219 wrmsr\r
220 rep vmmcall\r
221 rdmsr\r
222 cmp edx, 0bh\r
223 jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
224\r
225 mov rdx, 0bh ; CPUID function 0x0b\r
226 mov rax, 040000000h ; RBX register requested\r
227 or rax, 4\r
228 wrmsr\r
229 rep vmmcall\r
230 rdmsr\r
231 test edx, 0ffffh\r
232 jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero\r
233\r
234 mov rdx, 0bh ; CPUID function 0x0b\r
235 mov rax, 0c0000000h ; RDX register requested\r
236 or rax, 4\r
237 wrmsr\r
238 rep vmmcall\r
239 rdmsr\r
240\r
241 ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX\r
242 jmp RestoreGhcb\r
243\r
244NoX2ApicSevEs:\r
245 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
246 mov rdx, 1 ; CPUID function 1\r
247 mov rax, 040000000h ; RBX register requested\r
248 or rax, 4\r
249 wrmsr\r
250 rep vmmcall\r
251 rdmsr\r
252 shr edx, 24\r
253\r
254RestoreGhcb:\r
255 mov rbx, rdx ; Save x2APIC/APIC ID\r
256\r
257 mov rdx, rdi ; RDI holds the saved GHCB GPA\r
258 shr rdx, 32\r
259 mov eax, edi\r
260 wrmsr\r
261\r
262 mov rdx, rbx\r
263\r
264 ; x2APIC ID or APIC ID is in EDX\r
265 jmp GetProcessorNumber\r
266\r
267DoCpuid:\r
845c5be1
JF
268 mov eax, 0\r
269 cpuid\r
270 cmp eax, 0bh\r
1cbd8330
LE
271 jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
272\r
273 mov eax, 0bh\r
274 xor ecx, ecx\r
275 cpuid\r
276 test ebx, 0ffffh\r
277 jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero\r
278\r
279 ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX\r
280 jmp GetProcessorNumber\r
281\r
282NoX2Apic:\r
845c5be1
JF
283 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
284 mov eax, 1\r
285 cpuid\r
286 shr ebx, 24\r
287 mov edx, ebx\r
845c5be1 288\r
845c5be1
JF
289GetProcessorNumber:\r
290 ;\r
291 ; Get processor number for this AP\r
292 ; Note that BSP may become an AP due to SwitchBsp()\r
293 ;\r
294 xor ebx, ebx\r
2fba7d4e 295 lea eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (CpuInfo)]\r
edd74ad3 296 mov rdi, [eax]\r
d94e5f67 297\r
845c5be1 298GetNextProcNumber:\r
2fba7d4e 299 cmp dword [rdi + CPU_INFO_IN_HOB.InitialApicId], edx ; APIC ID match?\r
845c5be1 300 jz ProgramStack\r
2fba7d4e 301 add rdi, CPU_INFO_IN_HOB_size\r
845c5be1 302 inc ebx\r
7367cc6c 303 jmp GetNextProcNumber\r
845c5be1
JF
304\r
305ProgramStack:\r
2fba7d4e 306 mov rsp, qword [rdi + CPU_INFO_IN_HOB.ApTopOfStack]\r
d94e5f67
JF
307\r
308CProcedureInvoke:\r
8396e2dd
JF
309 push rbp ; Push BIST data at top of AP stack\r
310 xor rbp, rbp ; Clear ebp for call stack trace\r
d94e5f67
JF
311 push rbp\r
312 mov rbp, rsp\r
313\r
2fba7d4e 314 mov rax, qword [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitializeFloatingPointUnits)]\r
d94e5f67
JF
315 sub rsp, 20h\r
316 call rax ; Call assembly function to initialize FPU per UEFI spec\r
317 add rsp, 20h\r
318\r
37676b9f 319 mov edx, ebx ; edx is ApIndex\r
d94e5f67 320 mov ecx, esi\r
2fba7d4e 321 add ecx, MP_CPU_EXCHANGE_INFO_OFFSET ; rcx is address of exchange info data buffer\r
d94e5f67
JF
322\r
323 mov edi, esi\r
2fba7d4e 324 add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)\r
d94e5f67
JF
325 mov rax, qword [edi]\r
326\r
327 sub rsp, 20h\r
8396e2dd 328 call rax ; Invoke C function\r
d94e5f67 329 add rsp, 20h\r
8396e2dd 330 jmp $ ; Should never reach here\r
d94e5f67
JF
331\r
332RendezvousFunnelProcEnd:\r
333\r
7b7508ad
TL
334;-------------------------------------------------------------------------------------\r
335;SwitchToRealProc procedure follows.\r
336;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC\r
337;IS IN MACHINE CODE.\r
338; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)\r
339; rcx - Buffer Start\r
340; rdx - Code16 Selector Offset\r
341; r8 - Code32 Selector Offset\r
342; r9 - Stack Start\r
343;-------------------------------------------------------------------------------------\r
344global ASM_PFX(SwitchToRealProc)\r
345ASM_PFX(SwitchToRealProc):\r
346SwitchToRealProcStart:\r
347BITS 64\r
348 cli\r
349\r
350 ;\r
351 ; Get RDX reset value before changing stacks since the\r
352 ; new stack won't be able to accomodate a #VC exception.\r
353 ;\r
354 push rax\r
355 push rbx\r
356 push rcx\r
357 push rdx\r
358\r
359 mov rax, 1\r
360 cpuid\r
361 mov rsi, rax ; Save off the reset value for RDX\r
362\r
363 pop rdx\r
364 pop rcx\r
365 pop rbx\r
366 pop rax\r
367\r
368 ;\r
369 ; Establish stack below 1MB\r
370 ;\r
371 mov rsp, r9\r
372\r
373 ;\r
374 ; Push ultimate Reset Vector onto the stack\r
375 ;\r
376 mov rax, rcx\r
377 shr rax, 4\r
378 push word 0x0002 ; RFLAGS\r
379 push ax ; CS\r
380 push word 0x0000 ; RIP\r
381 push word 0x0000 ; For alignment, will be discarded\r
382\r
383 ;\r
384 ; Get address of "16-bit operand size" label\r
385 ;\r
386 lea rbx, [PM16Mode]\r
387\r
388 ;\r
389 ; Push addresses used to change to compatibility mode\r
390 ;\r
391 lea rax, [CompatMode]\r
392 push r8\r
393 push rax\r
394\r
395 ;\r
396 ; Clear R8 - R15, for reset, before going into 32-bit mode\r
397 ;\r
398 xor r8, r8\r
399 xor r9, r9\r
400 xor r10, r10\r
401 xor r11, r11\r
402 xor r12, r12\r
403 xor r13, r13\r
404 xor r14, r14\r
405 xor r15, r15\r
406\r
407 ;\r
408 ; Far return into 32-bit mode\r
409 ;\r
410o64 retf\r
411\r
412BITS 32\r
413CompatMode:\r
414 ;\r
415 ; Set up stack to prepare for exiting protected mode\r
416 ;\r
417 push edx ; Code16 CS\r
418 push ebx ; PM16Mode label address\r
419\r
420 ;\r
421 ; Disable paging\r
422 ;\r
423 mov eax, cr0 ; Read CR0\r
424 btr eax, 31 ; Set PG=0\r
425 mov cr0, eax ; Write CR0\r
426\r
427 ;\r
428 ; Disable long mode\r
429 ;\r
430 mov ecx, 0c0000080h ; EFER MSR number\r
431 rdmsr ; Read EFER\r
432 btr eax, 8 ; Set LME=0\r
433 wrmsr ; Write EFER\r
434\r
435 ;\r
436 ; Disable PAE\r
437 ;\r
438 mov eax, cr4 ; Read CR4\r
439 btr eax, 5 ; Set PAE=0\r
440 mov cr4, eax ; Write CR4\r
441\r
442 mov edx, esi ; Restore RDX reset value\r
443\r
444 ;\r
445 ; Switch to 16-bit operand size\r
446 ;\r
447 retf\r
448\r
449BITS 16\r
450 ;\r
451 ; At entry to this label\r
452 ; - RDX will have its reset value\r
453 ; - On the top of the stack\r
454 ; - Alignment data (two bytes) to be discarded\r
455 ; - IP for Real Mode (two bytes)\r
456 ; - CS for Real Mode (two bytes)\r
457 ;\r
20da7ca4
TL
458 ; This label is also used with AsmRelocateApLoop. During MP finalization,\r
459 ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of\r
460 ; the WakeupBuffer, allowing a parked AP to be booted by an OS.\r
461 ;\r
7b7508ad
TL
462PM16Mode:\r
463 mov eax, cr0 ; Read CR0\r
464 btr eax, 0 ; Set PE=0\r
465 mov cr0, eax ; Write CR0\r
466\r
467 pop ax ; Discard alignment data\r
468\r
469 ;\r
470 ; Clear registers (except RDX and RSP) before going into 16-bit mode\r
471 ;\r
472 xor eax, eax\r
473 xor ebx, ebx\r
474 xor ecx, ecx\r
475 xor esi, esi\r
476 xor edi, edi\r
477 xor ebp, ebp\r
478\r
479 iret\r
480\r
481SwitchToRealProcEnd:\r
482\r
76157021 483;-------------------------------------------------------------------------------------\r
20da7ca4 484; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
76157021
JF
485;-------------------------------------------------------------------------------------\r
486global ASM_PFX(AsmRelocateApLoop)\r
487ASM_PFX(AsmRelocateApLoop):\r
488AsmRelocateApLoopStart:\r
7b7508ad 489BITS 64\r
20da7ca4
TL
490 cmp qword [rsp + 56], 0 ; SevEsAPJumpTable\r
491 je NoSevEs\r
492\r
493 ;\r
494 ; Perform some SEV-ES related setup before leaving 64-bit mode\r
495 ;\r
496 push rcx\r
497 push rdx\r
498\r
499 ;\r
500 ; Get the RDX reset value using CPUID\r
501 ;\r
502 mov rax, 1\r
503 cpuid\r
504 mov rsi, rax ; Save off the reset value for RDX\r
505\r
506 ;\r
507 ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call\r
508 ; - Must be done while in 64-bit long mode so that writes to\r
509 ; the GHCB memory will be unencrypted.\r
510 ; - No NAE events can be generated once this is set otherwise\r
511 ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.\r
512 ;\r
513 mov rcx, 0xc0010130\r
514 rdmsr ; Retrieve current GHCB address\r
515 shl rdx, 32\r
516 or rdx, rax\r
517\r
518 mov rdi, rdx\r
519 xor rax, rax\r
520 mov rcx, 0x800\r
521 shr rcx, 3\r
522 rep stosq ; Clear the GHCB\r
523\r
524 mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD\r
525 mov [rdx + 0x390], rax\r
fb2a1a36
TL
526 mov rax, 114 ; Set SwExitCode valid bit\r
527 bts [rdx + 0x3f0], rax\r
528 inc rax ; Set SwExitInfo1 valid bit\r
529 bts [rdx + 0x3f0], rax\r
530 inc rax ; Set SwExitInfo2 valid bit\r
531 bts [rdx + 0x3f0], rax\r
20da7ca4
TL
532\r
533 pop rdx\r
534 pop rcx\r
535\r
536NoSevEs:\r
a7bbe9d2 537 cli ; Disable interrupt before switching to 32-bit mode\r
9f91cb01
JF
538 mov rax, [rsp + 40] ; CountTofinish\r
539 lock dec dword [rax] ; (*CountTofinish)--\r
76157021 540\r
20da7ca4
TL
541 mov r10, [rsp + 48] ; Pm16CodeSegment\r
542 mov rax, [rsp + 56] ; SevEsAPJumpTable\r
543 mov rbx, [rsp + 64] ; WakeupBuffer\r
544 mov rsp, r9 ; TopOfApStack\r
545\r
546 push rax ; Save SevEsAPJumpTable\r
547 push rbx ; Save WakeupBuffer\r
548 push r10 ; Save Pm16CodeSegment\r
549 push rcx ; Save MwaitSupport\r
550 push rdx ; Save ApTargetCState\r
551\r
552 lea rax, [PmEntry] ; rax <- The start address of transition code\r
76157021
JF
553\r
554 push r8\r
20da7ca4
TL
555 push rax\r
556\r
557 ;\r
558 ; Clear R8 - R15, for reset, before going into 32-bit mode\r
559 ;\r
560 xor r8, r8\r
561 xor r9, r9\r
562 xor r10, r10\r
563 xor r11, r11\r
564 xor r12, r12\r
565 xor r13, r13\r
566 xor r14, r14\r
567 xor r15, r15\r
568\r
569 ;\r
570 ; Far return into 32-bit mode\r
571 ;\r
572o64 retf\r
573\r
76157021
JF
574BITS 32\r
575PmEntry:\r
576 mov eax, cr0\r
577 btr eax, 31 ; Clear CR0.PG\r
578 mov cr0, eax ; Disable paging and caches\r
579\r
76157021
JF
580 mov ecx, 0xc0000080\r
581 rdmsr\r
582 and ah, ~ 1 ; Clear LME\r
583 wrmsr\r
584 mov eax, cr4\r
585 and al, ~ (1 << 5) ; Clear PAE\r
586 mov cr4, eax\r
587\r
588 pop edx\r
589 add esp, 4\r
590 pop ecx,\r
591 add esp, 4\r
20da7ca4
TL
592\r
593MwaitCheck:\r
76157021
JF
594 cmp cl, 1 ; Check mwait-monitor support\r
595 jnz HltLoop\r
596 mov ebx, edx ; Save C-State to ebx\r
597MwaitLoop:\r
a7bbe9d2 598 cli\r
76157021
JF
599 mov eax, esp ; Set Monitor Address\r
600 xor ecx, ecx ; ecx = 0\r
601 xor edx, edx ; edx = 0\r
602 monitor\r
76157021 603 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
f56379f3 604 shl eax, 4\r
76157021
JF
605 mwait\r
606 jmp MwaitLoop\r
20da7ca4 607\r
76157021 608HltLoop:\r
20da7ca4
TL
609 pop edx ; PM16CodeSegment\r
610 add esp, 4\r
611 pop ebx ; WakeupBuffer\r
612 add esp, 4\r
613 pop eax ; SevEsAPJumpTable\r
614 add esp, 4\r
615 cmp eax, 0 ; Check for SEV-ES\r
616 je DoHlt\r
617\r
618 cli\r
619 ;\r
620 ; SEV-ES is enabled, use VMGEXIT (GHCB information already\r
621 ; set by caller)\r
622 ;\r
623BITS 64\r
624 rep vmmcall\r
625BITS 32\r
626\r
627 ;\r
628 ; Back from VMGEXIT AP_HLT_LOOP\r
629 ; Push the FLAGS/CS/IP values to use\r
630 ;\r
631 push word 0x0002 ; EFLAGS\r
632 xor ecx, ecx\r
633 mov cx, [eax + 2] ; CS\r
634 push cx\r
635 mov cx, [eax] ; IP\r
636 push cx\r
637 push word 0x0000 ; For alignment, will be discarded\r
638\r
639 push edx\r
640 push ebx\r
641\r
642 mov edx, esi ; Restore RDX reset value\r
643\r
644 retf\r
645\r
646DoHlt:\r
76157021
JF
647 cli\r
648 hlt\r
20da7ca4
TL
649 jmp DoHlt\r
650\r
76157021
JF
651BITS 64\r
652AsmRelocateApLoopEnd:\r
653\r
d94e5f67
JF
654;-------------------------------------------------------------------------------------\r
655; AsmGetAddressMap (&AddressMap);\r
656;-------------------------------------------------------------------------------------\r
657global ASM_PFX(AsmGetAddressMap)\r
658ASM_PFX(AsmGetAddressMap):\r
3b2928b4 659 lea rax, [ASM_PFX(RendezvousFunnelProc)]\r
2fba7d4e
RN
660 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], rax\r
661 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], LongModeStart - RendezvousFunnelProcStart\r
662 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
3b2928b4 663 lea rax, [ASM_PFX(AsmRelocateApLoop)]\r
2fba7d4e
RN
664 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], rax\r
665 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
666 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart\r
667 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealSize], SwitchToRealProcEnd - SwitchToRealProcStart\r
668 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealOffset], SwitchToRealProcStart - RendezvousFunnelProcStart\r
669 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start\r
670 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], PM16Mode - RendezvousFunnelProcStart\r
671 mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], SwitchToRealProcEnd - PM16Mode\r
d94e5f67
JF
672 ret\r
673\r
674;-------------------------------------------------------------------------------------\r
675;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is\r
8396e2dd 676;about to become an AP. It switches its stack with the current AP.\r
d94e5f67
JF
677;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);\r
678;-------------------------------------------------------------------------------------\r
679global ASM_PFX(AsmExchangeRole)\r
680ASM_PFX(AsmExchangeRole):\r
681 ; DO NOT call other functions in this function, since 2 CPU may use 1 stack\r
682 ; at the same time. If 1 CPU try to call a function, stack will be corrupted.\r
683\r
684 push rax\r
685 push rbx\r
686 push rcx\r
687 push rdx\r
688 push rsi\r
689 push rdi\r
690 push rbp\r
691 push r8\r
692 push r9\r
693 push r10\r
694 push r11\r
695 push r12\r
696 push r13\r
697 push r14\r
698 push r15\r
699\r
700 mov rax, cr0\r
701 push rax\r
702\r
703 mov rax, cr4\r
704 push rax\r
705\r
706 ; rsi contains MyInfo pointer\r
707 mov rsi, rcx\r
708\r
709 ; rdi contains OthersInfo pointer\r
710 mov rdi, rdx\r
711\r
712 ;Store EFLAGS, GDTR and IDTR regiter to stack\r
713 pushfq\r
2fba7d4e
RN
714 sgdt [rsi + CPU_EXCHANGE_ROLE_INFO.Gdtr]\r
715 sidt [rsi + CPU_EXCHANGE_ROLE_INFO.Idtr]\r
d94e5f67
JF
716\r
717 ; Store the its StackPointer\r
2fba7d4e 718 mov [rsi + CPU_EXCHANGE_ROLE_INFO.StackPointer], rsp\r
d94e5f67
JF
719\r
720 ; update its switch state to STORED\r
2fba7d4e 721 mov byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
722\r
723WaitForOtherStored:\r
724 ; wait until the other CPU finish storing its state\r
2fba7d4e 725 cmp byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED\r
d94e5f67
JF
726 jz OtherStored\r
727 pause\r
728 jmp WaitForOtherStored\r
729\r
730OtherStored:\r
731 ; Since another CPU already stored its state, load them\r
732 ; load GDTR value\r
2fba7d4e 733 lgdt [rdi + CPU_EXCHANGE_ROLE_INFO.Gdtr]\r
d94e5f67
JF
734\r
735 ; load IDTR value\r
2fba7d4e 736 lidt [rdi + CPU_EXCHANGE_ROLE_INFO.Idtr]\r
d94e5f67
JF
737\r
738 ; load its future StackPointer\r
2fba7d4e 739 mov rsp, [rdi + CPU_EXCHANGE_ROLE_INFO.StackPointer]\r
d94e5f67
JF
740\r
741 ; update the other CPU's switch state to LOADED\r
2fba7d4e 742 mov byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
743\r
744WaitForOtherLoaded:\r
745 ; wait until the other CPU finish loading new state,\r
746 ; otherwise the data in stack may corrupt\r
2fba7d4e 747 cmp byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED\r
d94e5f67
JF
748 jz OtherLoaded\r
749 pause\r
750 jmp WaitForOtherLoaded\r
751\r
752OtherLoaded:\r
753 ; since the other CPU already get the data it want, leave this procedure\r
754 popfq\r
755\r
756 pop rax\r
757 mov cr4, rax\r
758\r
759 pop rax\r
760 mov cr0, rax\r
761\r
762 pop r15\r
763 pop r14\r
764 pop r13\r
765 pop r12\r
766 pop r11\r
767 pop r10\r
768 pop r9\r
769 pop r8\r
770 pop rbp\r
771 pop rdi\r
772 pop rsi\r
773 pop rdx\r
774 pop rcx\r
775 pop rbx\r
776 pop rax\r
777\r
778 ret\r