[edk2-devel] [PATCH 1/3] OvmfPkg/ResetVector: move SEV specific code in a separate file

Brijesh Singh via groups.io brijesh.singh=amd.com at groups.io
Tue Jul 27 11:16:42 UTC 2021


BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The PageTables64.asm was created to provide routines to set the CR3
register for 64-bit paging. During the SEV support, it grew to include a
lot of the SEV stuff. Before adding more SEV features, let's move all
the SEV-specific routines into a separate file.

No functionality change intended.

Cc: James Bottomley <jejb at linux.ibm.com>
Cc: Min Xu <min.m.xu at intel.com>
Cc: Jiewen Yao <jiewen.yao at intel.com>
Cc: Tom Lendacky <thomas.lendacky at amd.com>
Cc: Jordan Justen <jordan.l.justen at intel.com>
Cc: Ard Biesheuvel <ardb+tianocore at kernel.org>
Cc: Laszlo Ersek <lersek at redhat.com>
Cc: Erdem Aktas <erdemaktas at google.com>
Suggested-by: Laszlo Ersek <lersek at redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh at amd.com>
---
 .../Ia32/{PageTables64.asm => AmdSev.asm}     | 140 -------
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     | 391 ------------------
 OvmfPkg/ResetVector/ResetVector.nasmb         |   1 +
 3 files changed, 1 insertion(+), 531 deletions(-)
 copy OvmfPkg/ResetVector/Ia32/{PageTables64.asm => AmdSev.asm} (71%)

diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
similarity index 71%
copy from OvmfPkg/ResetVector/Ia32/PageTables64.asm
copy to OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 5fae8986d9da..b32dd3b5d656 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -10,33 +10,6 @@
 
 BITS    32
 
-%define PAGE_PRESENT            0x01
-%define PAGE_READ_WRITE         0x02
-%define PAGE_USER_SUPERVISOR    0x04
-%define PAGE_WRITE_THROUGH      0x08
-%define PAGE_CACHE_DISABLE     0x010
-%define PAGE_ACCESSED          0x020
-%define PAGE_DIRTY             0x040
-%define PAGE_PAT               0x080
-%define PAGE_GLOBAL           0x0100
-%define PAGE_2M_MBO            0x080
-%define PAGE_2M_PAT          0x01000
-
-%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
-                          PAGE_DIRTY + \
-                          PAGE_READ_WRITE + \
-                          PAGE_PRESENT)
-
-%define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
-                          PAGE_ACCESSED + \
-                          PAGE_DIRTY + \
-                          PAGE_READ_WRITE + \
-                          PAGE_PRESENT)
-
-%define PAGE_PDP_ATTR (PAGE_ACCESSED + \
-                       PAGE_READ_WRITE + \
-                       PAGE_PRESENT)
-
 ;
 ; SEV-ES #VC exception handler support
 ;
@@ -213,119 +186,6 @@ IsSevEsEnabled:
 SevEsDisabled:
     OneTimeCallRet IsSevEsEnabled
 
-;
-; Modified:  EAX, EBX, ECX, EDX
-;
-SetCr3ForPageTables64:
-
-    OneTimeCall   CheckSevFeatures
-    xor     edx, edx
-    test    eax, eax
-    jz      SevNotActive
-
-    ; If SEV is enabled, C-bit is always above 31
-    sub     eax, 32
-    bts     edx, eax
-
-SevNotActive:
-
-    ;
-    ; For OVMF, build some initial page tables at
-    ; PcdOvmfSecPageTablesBase - (PcdOvmfSecPageTablesBase + 0x6000).
-    ;
-    ; This range should match with PcdOvmfSecPageTablesSize which is
-    ; declared in the FDF files.
-    ;
-    ; At the end of PEI, the pages tables will be rebuilt into a
-    ; more permanent location by DxeIpl.
-    ;
-
-    mov     ecx, 6 * 0x1000 / 4
-    xor     eax, eax
-clearPageTablesMemoryLoop:
-    mov     dword[ecx * 4 + PT_ADDR (0) - 4], eax
-    loop    clearPageTablesMemoryLoop
-
-    ;
-    ; Top level Page Directory Pointers (1 * 512GB entry)
-    ;
-    mov     dword[PT_ADDR (0)], PT_ADDR (0x1000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (4)], edx
-
-    ;
-    ; Next level Page Directory Pointers (4 * 1GB entries => 4GB)
-    ;
-    mov     dword[PT_ADDR (0x1000)], PT_ADDR (0x2000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x1004)], edx
-    mov     dword[PT_ADDR (0x1008)], PT_ADDR (0x3000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x100C)], edx
-    mov     dword[PT_ADDR (0x1010)], PT_ADDR (0x4000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x1014)], edx
-    mov     dword[PT_ADDR (0x1018)], PT_ADDR (0x5000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x101C)], edx
-
-    ;
-    ; Page Table Entries (2048 * 2MB entries => 4GB)
-    ;
-    mov     ecx, 0x800
-pageTableEntriesLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 21
-    add     eax, PAGE_2M_PDE_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000 - 8)], eax
-    mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
-    loop    pageTableEntriesLoop
-
-    OneTimeCall   IsSevEsEnabled
-    test    eax, eax
-    jz      SetCr3
-
-    ;
-    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
-    ; This requires the 2MB page for this range be broken down into 512 4KB
-    ; pages.  All will be marked encrypted, except for the GHCB.
-    ;
-    mov     ecx, (GHCB_BASE >> 21)
-    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
-
-    ;
-    ; Page Table Entries (512 * 4KB entries => 2MB)
-    ;
-    mov     ecx, 512
-pageTableEntries4kLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 12
-    add     eax, GHCB_BASE & 0xFFE0_0000
-    add     eax, PAGE_4K_PDE_ATTR
-    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
-    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
-    loop    pageTableEntries4kLoop
-
-    ;
-    ; Clear the encryption bit from the GHCB entry
-    ;
-    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
-    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
-
-    mov     ecx, GHCB_SIZE / 4
-    xor     eax, eax
-clearGhcbMemoryLoop:
-    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
-    loop    clearGhcbMemoryLoop
-
-SetCr3:
-    ;
-    ; Set CR3 now that the paging structures are available
-    ;
-    mov     eax, PT_ADDR (0)
-    mov     cr3, eax
-
-    OneTimeCallRet SetCr3ForPageTables64
-
-;
 ; Start of #VC exception handling routines
 ;
 
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9da..eacdb69ddb9f 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,182 +37,6 @@ BITS    32
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
 
-;
-; SEV-ES #VC exception handler support
-;
-; #VC handler local variable locations
-;
-%define VC_CPUID_RESULT_EAX         0
-%define VC_CPUID_RESULT_EBX         4
-%define VC_CPUID_RESULT_ECX         8
-%define VC_CPUID_RESULT_EDX        12
-%define VC_GHCB_MSR_EDX            16
-%define VC_GHCB_MSR_EAX            20
-%define VC_CPUID_REQUEST_REGISTER  24
-%define VC_CPUID_FUNCTION          28
-
-; #VC handler total local variable size
-;
-%define VC_VARIABLE_SIZE           32
-
-; #VC handler GHCB CPUID request/response protocol values
-;
-%define GHCB_CPUID_REQUEST          4
-%define GHCB_CPUID_RESPONSE         5
-%define GHCB_CPUID_REGISTER_SHIFT  30
-%define CPUID_INSN_LEN              2
-
-
-; Check if Secure Encrypted Virtualization (SEV) features are enabled.
-;
-; Register usage is tight in this routine, so multiple calls for the
-; same CPUID and MSR data are performed to keep things simple.
-;
-; Modified:  EAX, EBX, ECX, EDX, ESP
-;
-; If SEV is enabled then EAX will be at least 32.
-; If SEV is disabled then EAX will be zero.
-;
-CheckSevFeatures:
-    ; Set the first byte of the workarea to zero to communicate to the SEC
-    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
-    ; instruction will trigger a #VC exception where the first byte of the
-    ; workarea will be set to one or, if CPUID is not being intercepted,
-    ; the MSR check below will set the first byte of the workarea to one.
-    mov     byte[SEV_ES_WORK_AREA], 0
-
-    ;
-    ; Set up exception handlers to check for SEV-ES
-    ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
-    ;   stack usage)
-    ;   Establish exception handlers
-    ;
-    mov       esp, SEV_ES_VC_TOP_OF_STACK
-    mov       eax, ADDR_OF(Idtr)
-    lidt      [cs:eax]
-
-    ; Check if we have a valid (0x8000_001F) CPUID leaf
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x80000000
-    cpuid
-
-    ; This check should fail on Intel or Non SEV AMD CPUs. In future if
-    ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
-    ; same bit definition.
-    cmp       eax, 0x8000001f
-    jl        NoSev
-
-    ; Check for SEV memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 1
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 1
-    jnc       NoSev
-
-    ; Check if SEV memory encryption is enabled
-    ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 0
-    jnc       NoSev
-
-    ; Check for SEV-ES memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 3
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 3
-    jnc       GetSevEncBit
-
-    ; Check if SEV-ES is enabled
-    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 1
-    jnc       GetSevEncBit
-
-    ; Set the first byte of the workarea to one to communicate to the SEC
-    ; phase that SEV-ES is enabled.
-    mov       byte[SEV_ES_WORK_AREA], 1
-
-GetSevEncBit:
-    ; Get pte bit position to enable memory encryption
-    ; CPUID Fn8000_001F[EBX] - Bits 5:0
-    ;
-    and       ebx, 0x3f
-    mov       eax, ebx
-
-    ; The encryption bit position is always above 31
-    sub       ebx, 32
-    jns       SevSaveMask
-
-    ; Encryption bit was reported as 31 or below, enter a HLT loop
-SevEncBitLowHlt:
-    cli
-    hlt
-    jmp       SevEncBitLowHlt
-
-SevSaveMask:
-    xor       edx, edx
-    bts       edx, ebx
-
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK], 0
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
-    jmp       SevExit
-
-NoSev:
-    ;
-    ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
-    ;
-    cmp       byte[SEV_ES_WORK_AREA], 0
-    jz        NoSevPass
-
-    ;
-    ; A #VC was received, yet CPUID indicates no SEV-ES support, something
-    ; isn't right.
-    ;
-NoSevEsVcHlt:
-    cli
-    hlt
-    jmp       NoSevEsVcHlt
-
-NoSevPass:
-    xor       eax, eax
-
-SevExit:
-    ;
-    ; Clear exception handlers and stack
-    ;
-    push      eax
-    mov       eax, ADDR_OF(IdtrClear)
-    lidt      [cs:eax]
-    pop       eax
-    mov       esp, 0
-
-    OneTimeCallRet CheckSevFeatures
-
-; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
-; is enabled.
-;
-; Modified:  EAX
-;
-; If SEV-ES is enabled then EAX will be non-zero.
-; If SEV-ES is disabled then EAX will be zero.
-;
-IsSevEsEnabled:
-    xor       eax, eax
-
-    ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
-    ; SEV-ES is enabled.
-    cmp       byte[SEV_ES_WORK_AREA], 1
-    jne       SevEsDisabled
-
-    mov       eax, 1
-
-SevEsDisabled:
-    OneTimeCallRet IsSevEsEnabled
-
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
@@ -324,218 +148,3 @@ SetCr3:
     mov     cr3, eax
 
     OneTimeCallRet SetCr3ForPageTables64
-
-;
-; Start of #VC exception handling routines
-;
-
-SevEsIdtNotCpuid:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   1 - #VC was not for CPUID
-    ;
-    mov     eax, 1
-    jmp     SevEsIdtTerminate
-
-SevEsIdtNoCpuidResponse:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   2 - GHCB_CPUID_RESPONSE not received
-    ;
-    mov     eax, 2
-
-SevEsIdtTerminate:
-    ;
-    ; Use VMGEXIT to request termination. At this point the reason code is
-    ; located in EAX, so shift it left 16 bits to the proper location.
-    ;
-    ; EAX[11:0]  => 0x100 - request termination
-    ; EAX[15:12] => 0x1   - OVMF
-    ; EAX[23:16] => 0xXX  - REASON CODE
-    ;
-    shl     eax, 16
-    or      eax, 0x1100
-    xor     edx, edx
-    mov     ecx, 0xc0010130
-    wrmsr
-    ;
-    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
-    ; mode, so work around this by temporarily switching to 64-bit mode.
-    ;
-BITS    64
-    rep     vmmcall
-BITS    32
-
-    ;
-    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
-    ;
-SevEsIdtHlt:
-    hlt
-    jmp     SevEsIdtHlt
-    iret
-
-    ;
-    ; Total stack usage for the #VC handler is 44 bytes:
-    ;   - 12 bytes for the exception IRET (after popping error code)
-    ;   - 32 bytes for the local variables.
-    ;
-SevEsIdtVmmComm:
-    ;
-    ; If we're here, then we are an SEV-ES guest and this
-    ; was triggered by a CPUID instruction
-    ;
-    ; Set the first byte of the workarea to one to communicate that
-    ; a #VC was taken.
-    mov     byte[SEV_ES_WORK_AREA], 1
-
-    pop     ecx                     ; Error code
-    cmp     ecx, 0x72               ; Be sure it was CPUID
-    jne     SevEsIdtNotCpuid
-
-    ; Set up local variable room on the stack
-    ;   CPUID function         : + 28
-    ;   CPUID request register : + 24
-    ;   GHCB MSR (EAX)         : + 20
-    ;   GHCB MSR (EDX)         : + 16
-    ;   CPUID result (EDX)     : + 12
-    ;   CPUID result (ECX)     : + 8
-    ;   CPUID result (EBX)     : + 4
-    ;   CPUID result (EAX)     : + 0
-    sub     esp, VC_VARIABLE_SIZE
-
-    ; Save the CPUID function being requested
-    mov     [esp + VC_CPUID_FUNCTION], eax
-
-    ; The GHCB CPUID protocol uses the following mapping to request
-    ; a specific register:
-    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
-    ;
-    ; Set EAX as the first register to request. This will also be used as a
-    ; loop variable to request all register values (EAX to EDX).
-    xor     eax, eax
-    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
-
-    ; Save current GHCB MSR value
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     [esp + VC_GHCB_MSR_EAX], eax
-    mov     [esp + VC_GHCB_MSR_EDX], edx
-
-NextReg:
-    ;
-    ; Setup GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID function
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID request protocol
-    ;
-    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
-    cmp     eax, 4
-    jge     VmmDone
-
-    shl     eax, GHCB_CPUID_REGISTER_SHIFT
-    or      eax, GHCB_CPUID_REQUEST
-    mov     edx, [esp + VC_CPUID_FUNCTION]
-    mov     ecx, 0xc0010130
-    wrmsr
-
-    ;
-    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
-    ; mode, so work around this by temporarily switching to 64-bit mode.
-    ;
-BITS    64
-    rep     vmmcall
-BITS    32
-
-    ;
-    ; Read GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID register value
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID response protocol
-    ;
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     ecx, eax
-    and     ecx, 0xfff
-    cmp     ecx, GHCB_CPUID_RESPONSE
-    jne     SevEsIdtNoCpuidResponse
-
-    ; Save returned value
-    shr     eax, GHCB_CPUID_REGISTER_SHIFT
-    mov     [esp + eax * 4], edx
-
-    ; Next register
-    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
-
-    jmp     NextReg
-
-VmmDone:
-    ;
-    ; At this point we have all CPUID register values. Restore the GHCB MSR,
-    ; set the return register values and return.
-    ;
-    mov     eax, [esp + VC_GHCB_MSR_EAX]
-    mov     edx, [esp + VC_GHCB_MSR_EDX]
-    mov     ecx, 0xc0010130
-    wrmsr
-
-    mov     eax, [esp + VC_CPUID_RESULT_EAX]
-    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
-    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
-    mov     edx, [esp + VC_CPUID_RESULT_EDX]
-
-    add     esp, VC_VARIABLE_SIZE
-
-    ; Update the EIP value to skip over the now handled CPUID instruction
-    ; (the CPUID instruction has a length of 2)
-    add     word [esp], CPUID_INSN_LEN
-    iret
-
-ALIGN   2
-
-Idtr:
-    dw      IDT_END - IDT_BASE - 1  ; Limit
-    dd      ADDR_OF(IDT_BASE)       ; Base
-
-IdtrClear:
-    dw      0                       ; Limit
-    dd      0                       ; Base
-
-ALIGN   16
-
-;
-; The Interrupt Descriptor Table (IDT)
-;   This will be used to determine if SEV-ES is enabled.  Upon execution
-;   of the CPUID instruction, a VMM Communication Exception will occur.
-;   This will tell us if SEV-ES is enabled.  We can use the current value
-;   of the GHCB MSR to determine the SEV attributes.
-;
-IDT_BASE:
-;
-; Vectors 0 - 28 (No handlers)
-;
-%rep 29
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-;
-; Vector 29 (VMM Communication Exception)
-;
-    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
-;
-; Vectors 30 - 31 (No handlers)
-;
-%rep 2
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-IDT_END:
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 5fbacaed5f9d..8a3269cfc212 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -77,6 +77,7 @@
   %define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/Flat32ToFlat64.asm"
+%include "Ia32/AmdSev.asm"
 %include "Ia32/PageTables64.asm"
 %endif
 
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#78211): https://edk2.groups.io/g/devel/message/78211
Mute This Topic: https://groups.io/mt/84479271/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list