;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;\r
; Module Name:\r
;\r
mov eax, cr4\r
bts eax, 5\r
+\r
+ mov esi, Enable5LevelPagingLocation\r
+ cmp byte [ebx + esi], 0\r
+ jz SkipEnable5LevelPaging\r
+\r
+ ;\r
+ ; Enable 5 Level Paging\r
+ ;\r
+ bts eax, 12 ; Set LA57=1.\r
+\r
+SkipEnable5LevelPaging:\r
+\r
mov cr4, eax\r
\r
;\r
add edi, StackStartAddressLocation\r
add rax, qword [edi]\r
mov rsp, rax\r
+\r
+ lea edi, [esi + SevEsIsEnabledLocation]\r
+ cmp byte [edi], 1 ; SevEsIsEnabled\r
+ jne CProcedureInvoke\r
+\r
+ ;\r
+ ; program GHCB\r
+ ; Each page after the GHCB is a per-CPU page, so the calculation programs\r
+ ; a GHCB to be every 8KB.\r
+ ;\r
+ mov eax, SIZE_4KB\r
+ shl eax, 1 ; EAX = SIZE_4K * 2\r
+ mov ecx, ebx\r
+ mul ecx ; EAX = SIZE_4K * 2 * CpuNumber\r
+ mov edi, esi\r
+ add edi, GhcbBaseLocation\r
+ add rax, qword [edi]\r
+ mov rdx, rax\r
+ shr rdx, 32\r
+ mov rcx, 0xc0010130\r
+ wrmsr\r
jmp CProcedureInvoke\r
\r
GetApicId:\r
+ lea edi, [esi + SevEsIsEnabledLocation]\r
+ cmp byte [edi], 1 ; SevEsIsEnabled\r
+ jne DoCpuid\r
+\r
+ ;\r
+ ; Since we don't have a stack yet, we can't take a #VC\r
+ ; exception. Use the GHCB protocol to perform the CPUID\r
+ ; calls.\r
+ ;\r
+ mov rcx, 0xc0010130\r
+ rdmsr\r
+ shl rdx, 32\r
+ or rax, rdx\r
+ mov rdi, rax ; RDI now holds the original GHCB GPA\r
+\r
+ mov rdx, 0 ; CPUID function 0\r
+ mov rax, 0 ; RAX register requested\r
+ or rax, 4\r
+ wrmsr\r
+ rep vmmcall\r
+ rdmsr\r
+ cmp edx, 0bh\r
+ jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
+\r
+ mov rdx, 0bh ; CPUID function 0x0b\r
+ mov rax, 040000000h ; RBX register requested\r
+ or rax, 4\r
+ wrmsr\r
+ rep vmmcall\r
+ rdmsr\r
+ test edx, 0ffffh\r
+ jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero\r
+\r
+ mov rdx, 0bh ; CPUID function 0x0b\r
+ mov rax, 0c0000000h ; RDX register requested\r
+ or rax, 4\r
+ wrmsr\r
+ rep vmmcall\r
+ rdmsr\r
+\r
+ ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX\r
+ jmp RestoreGhcb\r
+\r
+NoX2ApicSevEs:\r
+ ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
+ mov rdx, 1 ; CPUID function 1\r
+ mov rax, 040000000h ; RBX register requested\r
+ or rax, 4\r
+ wrmsr\r
+ rep vmmcall\r
+ rdmsr\r
+ shr edx, 24\r
+\r
+RestoreGhcb:\r
+ mov rbx, rdx ; Save x2APIC/APIC ID\r
+\r
+ mov rdx, rdi ; RDI holds the saved GHCB GPA\r
+ shr rdx, 32\r
+ mov eax, edi\r
+ wrmsr\r
+\r
+ mov rdx, rbx\r
+\r
+ ; x2APIC ID or APIC ID is in EDX\r
+ jmp GetProcessorNumber\r
+\r
+DoCpuid:\r
mov eax, 0\r
cpuid\r
cmp eax, 0bh\r
;\r
xor ebx, ebx\r
lea eax, [esi + CpuInfoLocation]\r
- mov edi, [eax]\r
+ mov rdi, [eax]\r
\r
GetNextProcNumber:\r
- cmp dword [edi], edx ; APIC ID match?\r
+ cmp dword [rdi], edx ; APIC ID match?\r
jz ProgramStack\r
- add edi, 20\r
+ add rdi, 20\r
inc ebx\r
jmp GetNextProcNumber\r
\r
ProgramStack:\r
- mov rsp, qword [edi + 12]\r
+ mov rsp, qword [rdi + 12]\r
\r
CProcedureInvoke:\r
push rbp ; Push BIST data at top of AP stack\r
RendezvousFunnelProcEnd:\r
\r
;-------------------------------------------------------------------------------------\r
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);\r
+;SwitchToRealProc procedure follows.\r
+;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC\r
+;IS IN MACHINE CODE.\r
+; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)\r
+; rcx - Buffer Start\r
+; rdx - Code16 Selector Offset\r
+; r8 - Code32 Selector Offset\r
+; r9 - Stack Start\r
+;-------------------------------------------------------------------------------------\r
+global ASM_PFX(SwitchToRealProc)\r
+ASM_PFX(SwitchToRealProc):\r
+SwitchToRealProcStart:\r
+BITS 64\r
+ cli\r
+\r
+ ;\r
+ ; Get RDX reset value before changing stacks since the\r
+ ; new stack won't be able to accomodate a #VC exception.\r
+ ;\r
+ push rax\r
+ push rbx\r
+ push rcx\r
+ push rdx\r
+\r
+ mov rax, 1\r
+ cpuid\r
+ mov rsi, rax ; Save off the reset value for RDX\r
+\r
+ pop rdx\r
+ pop rcx\r
+ pop rbx\r
+ pop rax\r
+\r
+ ;\r
+ ; Establish stack below 1MB\r
+ ;\r
+ mov rsp, r9\r
+\r
+ ;\r
+ ; Push ultimate Reset Vector onto the stack\r
+ ;\r
+ mov rax, rcx\r
+ shr rax, 4\r
+ push word 0x0002 ; RFLAGS\r
+ push ax ; CS\r
+ push word 0x0000 ; RIP\r
+ push word 0x0000 ; For alignment, will be discarded\r
+\r
+ ;\r
+ ; Get address of "16-bit operand size" label\r
+ ;\r
+ lea rbx, [PM16Mode]\r
+\r
+ ;\r
+ ; Push addresses used to change to compatibility mode\r
+ ;\r
+ lea rax, [CompatMode]\r
+ push r8\r
+ push rax\r
+\r
+ ;\r
+ ; Clear R8 - R15, for reset, before going into 32-bit mode\r
+ ;\r
+ xor r8, r8\r
+ xor r9, r9\r
+ xor r10, r10\r
+ xor r11, r11\r
+ xor r12, r12\r
+ xor r13, r13\r
+ xor r14, r14\r
+ xor r15, r15\r
+\r
+ ;\r
+ ; Far return into 32-bit mode\r
+ ;\r
+o64 retf\r
+\r
+BITS 32\r
+CompatMode:\r
+ ;\r
+ ; Set up stack to prepare for exiting protected mode\r
+ ;\r
+ push edx ; Code16 CS\r
+ push ebx ; PM16Mode label address\r
+\r
+ ;\r
+ ; Disable paging\r
+ ;\r
+ mov eax, cr0 ; Read CR0\r
+ btr eax, 31 ; Set PG=0\r
+ mov cr0, eax ; Write CR0\r
+\r
+ ;\r
+ ; Disable long mode\r
+ ;\r
+ mov ecx, 0c0000080h ; EFER MSR number\r
+ rdmsr ; Read EFER\r
+ btr eax, 8 ; Set LME=0\r
+ wrmsr ; Write EFER\r
+\r
+ ;\r
+ ; Disable PAE\r
+ ;\r
+ mov eax, cr4 ; Read CR4\r
+ btr eax, 5 ; Set PAE=0\r
+ mov cr4, eax ; Write CR4\r
+\r
+ mov edx, esi ; Restore RDX reset value\r
+\r
+ ;\r
+ ; Switch to 16-bit operand size\r
+ ;\r
+ retf\r
+\r
+BITS 16\r
+ ;\r
+ ; At entry to this label\r
+ ; - RDX will have its reset value\r
+ ; - On the top of the stack\r
+ ; - Alignment data (two bytes) to be discarded\r
+ ; - IP for Real Mode (two bytes)\r
+ ; - CS for Real Mode (two bytes)\r
+ ;\r
+ ; This label is also used with AsmRelocateApLoop. During MP finalization,\r
+ ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of\r
+ ; the WakeupBuffer, allowing a parked AP to be booted by an OS.\r
+ ;\r
+PM16Mode:\r
+ mov eax, cr0 ; Read CR0\r
+ btr eax, 0 ; Set PE=0\r
+ mov cr0, eax ; Write CR0\r
+\r
+ pop ax ; Discard alignment data\r
+\r
+ ;\r
+ ; Clear registers (except RDX and RSP) before going into 16-bit mode\r
+ ;\r
+ xor eax, eax\r
+ xor ebx, ebx\r
+ xor ecx, ecx\r
+ xor esi, esi\r
+ xor edi, edi\r
+ xor ebp, ebp\r
+\r
+ iret\r
+\r
+SwitchToRealProcEnd:\r
+\r
+;-------------------------------------------------------------------------------------\r
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
;-------------------------------------------------------------------------------------\r
global ASM_PFX(AsmRelocateApLoop)\r
ASM_PFX(AsmRelocateApLoop):\r
AsmRelocateApLoopStart:\r
+BITS 64\r
+ cmp qword [rsp + 56], 0 ; SevEsAPJumpTable\r
+ je NoSevEs\r
+\r
+ ;\r
+ ; Perform some SEV-ES related setup before leaving 64-bit mode\r
+ ;\r
+ push rcx\r
+ push rdx\r
+\r
+ ;\r
+ ; Get the RDX reset value using CPUID\r
+ ;\r
+ mov rax, 1\r
+ cpuid\r
+ mov rsi, rax ; Save off the reset value for RDX\r
+\r
+ ;\r
+ ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call\r
+ ; - Must be done while in 64-bit long mode so that writes to\r
+ ; the GHCB memory will be unencrypted.\r
+ ; - No NAE events can be generated once this is set otherwise\r
+ ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.\r
+ ;\r
+ mov rcx, 0xc0010130\r
+ rdmsr ; Retrieve current GHCB address\r
+ shl rdx, 32\r
+ or rdx, rax\r
+\r
+ mov rdi, rdx\r
+ xor rax, rax\r
+ mov rcx, 0x800\r
+ shr rcx, 3\r
+ rep stosq ; Clear the GHCB\r
+\r
+ mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD\r
+ mov [rdx + 0x390], rax\r
+ mov rax, 114 ; Set SwExitCode valid bit\r
+ bts [rdx + 0x3f0], rax\r
+ inc rax ; Set SwExitInfo1 valid bit\r
+ bts [rdx + 0x3f0], rax\r
+ inc rax ; Set SwExitInfo2 valid bit\r
+ bts [rdx + 0x3f0], rax\r
+\r
+ pop rdx\r
+ pop rcx\r
+\r
+NoSevEs:\r
cli ; Disable interrupt before switching to 32-bit mode\r
mov rax, [rsp + 40] ; CountTofinish\r
lock dec dword [rax] ; (*CountTofinish)--\r
- mov rsp, r9\r
- push rcx\r
- push rdx\r
\r
- lea rsi, [PmEntry] ; rsi <- The start address of transition code\r
+ mov r10, [rsp + 48] ; Pm16CodeSegment\r
+ mov rax, [rsp + 56] ; SevEsAPJumpTable\r
+ mov rbx, [rsp + 64] ; WakeupBuffer\r
+ mov rsp, r9 ; TopOfApStack\r
+\r
+ push rax ; Save SevEsAPJumpTable\r
+ push rbx ; Save WakeupBuffer\r
+ push r10 ; Save Pm16CodeSegment\r
+ push rcx ; Save MwaitSupport\r
+ push rdx ; Save ApTargetCState\r
+\r
+ lea rax, [PmEntry] ; rax <- The start address of transition code\r
\r
push r8\r
- push rsi\r
- DB 0x48\r
- retf\r
+ push rax\r
+\r
+ ;\r
+ ; Clear R8 - R15, for reset, before going into 32-bit mode\r
+ ;\r
+ xor r8, r8\r
+ xor r9, r9\r
+ xor r10, r10\r
+ xor r11, r11\r
+ xor r12, r12\r
+ xor r13, r13\r
+ xor r14, r14\r
+ xor r15, r15\r
+\r
+ ;\r
+ ; Far return into 32-bit mode\r
+ ;\r
+o64 retf\r
+\r
BITS 32\r
PmEntry:\r
mov eax, cr0\r
btr eax, 31 ; Clear CR0.PG\r
mov cr0, eax ; Disable paging and caches\r
\r
- mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx\r
mov ecx, 0xc0000080\r
rdmsr\r
and ah, ~ 1 ; Clear LME\r
add esp, 4\r
pop ecx,\r
add esp, 4\r
+\r
+MwaitCheck:\r
cmp cl, 1 ; Check mwait-monitor support\r
jnz HltLoop\r
mov ebx, edx ; Save C-State to ebx\r
shl eax, 4\r
mwait\r
jmp MwaitLoop\r
+\r
HltLoop:\r
+ pop edx ; PM16CodeSegment\r
+ add esp, 4\r
+ pop ebx ; WakeupBuffer\r
+ add esp, 4\r
+ pop eax ; SevEsAPJumpTable\r
+ add esp, 4\r
+ cmp eax, 0 ; Check for SEV-ES\r
+ je DoHlt\r
+\r
+ cli\r
+ ;\r
+ ; SEV-ES is enabled, use VMGEXIT (GHCB information already\r
+ ; set by caller)\r
+ ;\r
+BITS 64\r
+ rep vmmcall\r
+BITS 32\r
+\r
+ ;\r
+ ; Back from VMGEXIT AP_HLT_LOOP\r
+ ; Push the FLAGS/CS/IP values to use\r
+ ;\r
+ push word 0x0002 ; EFLAGS\r
+ xor ecx, ecx\r
+ mov cx, [eax + 2] ; CS\r
+ push cx\r
+ mov cx, [eax] ; IP\r
+ push cx\r
+ push word 0x0000 ; For alignment, will be discarded\r
+\r
+ push edx\r
+ push ebx\r
+\r
+ mov edx, esi ; Restore RDX reset value\r
+\r
+ retf\r
+\r
+DoHlt:\r
cli\r
hlt\r
- jmp HltLoop\r
+ jmp DoHlt\r
+\r
BITS 64\r
AsmRelocateApLoopEnd:\r
\r
mov qword [rcx + 18h], rax\r
mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart\r
+ mov qword [rcx + 30h], SwitchToRealProcEnd - SwitchToRealProcStart ; SwitchToRealSize\r
+ mov qword [rcx + 38h], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset\r
+ mov qword [rcx + 40h], SwitchToRealProcStart - Flat32Start ; SwitchToRealNoNxOffset\r
+ mov qword [rcx + 48h], PM16Mode - RendezvousFunnelProcStart ; SwitchToRealPM16ModeOffset\r
+ mov qword [rcx + 50h], SwitchToRealProcEnd - PM16Mode ; SwitchToRealPM16ModeSize\r
ret\r
\r
;-------------------------------------------------------------------------------------\r