]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
BaseTools: Align include guards policy
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / MpFuncs.nasm
index 87f2523e856faaeecd187058f5ac039665d86627..aecfd07bc077160a47e7e18a3346769b2fb8b6d1 100644 (file)
@@ -184,9 +184,97 @@ Releaselock:
     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
@@ -215,17 +303,17 @@ GetProcessorNumber:
     ;\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
@@ -254,31 +342,251 @@ CProcedureInvoke:
 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
@@ -291,6 +599,8 @@ PmEntry:
     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
@@ -304,10 +614,50 @@ MwaitLoop:
     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
@@ -324,6 +674,11 @@ ASM_PFX(AsmGetAddressMap):
     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