2014-08-19 01:03:53 +02:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; @file
|
|
|
|
; This file includes all other code files to assemble the reset vector code
|
|
|
|
;
|
|
|
|
; Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>
|
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108
To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.
The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.
The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.
The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.
To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>
2021-01-07 19:48:13 +01:00
|
|
|
; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
|
2019-04-04 01:06:33 +02:00
|
|
|
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
2014-08-19 01:03:53 +02:00
|
|
|
;
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
;
|
|
|
|
; If neither ARCH_IA32 nor ARCH_X64 are defined, then try to include
|
|
|
|
; Base.h to use the C pre-processor to determine the architecture.
|
|
|
|
;
|
|
|
|
%ifndef ARCH_IA32
|
|
|
|
%ifndef ARCH_X64
|
|
|
|
#include <Base.h>
|
|
|
|
#if defined (MDE_CPU_IA32)
|
|
|
|
%define ARCH_IA32
|
|
|
|
#elif defined (MDE_CPU_X64)
|
|
|
|
%define ARCH_X64
|
|
|
|
#endif
|
|
|
|
%endif
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%ifdef ARCH_IA32
|
|
|
|
%ifdef ARCH_X64
|
|
|
|
%error "Only one of ARCH_IA32 or ARCH_X64 can be defined."
|
|
|
|
%endif
|
|
|
|
%elifdef ARCH_X64
|
|
|
|
%else
|
|
|
|
%error "Either ARCH_IA32 or ARCH_X64 must be defined."
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%include "CommonMacros.inc"
|
|
|
|
|
|
|
|
%include "PostCodes.inc"
|
|
|
|
|
|
|
|
%ifdef DEBUG_PORT80
|
|
|
|
%include "Port80Debug.asm"
|
|
|
|
%elifdef DEBUG_SERIAL
|
|
|
|
%include "SerialDebug.asm"
|
|
|
|
%else
|
|
|
|
%include "DebugDisabled.asm"
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%include "Ia32/SearchForBfvBase.asm"
|
|
|
|
%include "Ia32/SearchForSecEntry.asm"
|
|
|
|
|
|
|
|
%ifdef ARCH_X64
|
2016-11-04 14:32:39 +01:00
|
|
|
#include <AutoGen.h>
|
|
|
|
|
|
|
|
%if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
|
|
|
|
%error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
|
|
|
|
%endif
|
|
|
|
|
OvmfPkg: Create a GHCB page for use during Sec phase
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
A GHCB page is needed during the Sec phase, so this new page must be
created. Since the #VC exception handler routines assume that a per-CPU
variable area is immediately after the GHCB, this per-CPU variable area
must also be created. Since the GHCB must be marked as an un-encrypted,
or shared, page, an additional pagetable page is required to break down
the 2MB region where the GHCB page lives into 4K pagetable entries.
Create a new entry in the OVMF memory layout for the new page table
page and for the SEC GHCB and per-CPU variable pages. After breaking down
the 2MB page, update the GHCB page table entry to remove the encryption
mask.
The GHCB page will be used by the SEC #VC exception handler. The #VC
exception handler will fill in the necessary fields of the GHCB and exit
to the hypervisor using the VMGEXIT instruction. The hypervisor then
accesses the GHCB in order to perform the requested function.
Four new fixed PCDs are needed to support the SEC GHCB page:
- PcdOvmfSecGhcbBase UINT32 value that is the base address of the
GHCB used during the SEC phase.
- PcdOvmfSecGhcbSize UINT32 value that is the size, in bytes, of the
GHCB area used during the SEC phase.
- PcdOvmfSecGhcbPageTableBase UINT32 value that is address of a page
table page used to break down the 2MB page into
512 4K pages.
- PcdOvmfSecGhcbPageTableSize UINT32 value that is the size, in bytes,
of the page table page.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2020-08-12 22:21:40 +02:00
|
|
|
%if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
|
|
|
|
%error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
|
|
|
|
%error "This implementation inherently depends on PcdOvmfSecGhcbSize"
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%if ((FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) != \
|
|
|
|
((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21))
|
|
|
|
%error "This implementation inherently depends on PcdOvmfSecGhcbBase not straddling a 2MB boundary"
|
|
|
|
%endif
|
|
|
|
|
2016-11-04 14:32:39 +01:00
|
|
|
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
|
OvmfPkg: Create a GHCB page for use during Sec phase
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
A GHCB page is needed during the Sec phase, so this new page must be
created. Since the #VC exception handler routines assume that a per-CPU
variable area is immediately after the GHCB, this per-CPU variable area
must also be created. Since the GHCB must be marked as an un-encrypted,
or shared, page, an additional pagetable page is required to break down
the 2MB region where the GHCB page lives into 4K pagetable entries.
Create a new entry in the OVMF memory layout for the new page table
page and for the SEC GHCB and per-CPU variable pages. After breaking down
the 2MB page, update the GHCB page table entry to remove the encryption
mask.
The GHCB page will be used by the SEC #VC exception handler. The #VC
exception handler will fill in the necessary fields of the GHCB and exit
to the hypervisor using the VMGEXIT instruction. The hypervisor then
accesses the GHCB in order to perform the requested function.
Four new fixed PCDs are needed to support the SEC GHCB page:
- PcdOvmfSecGhcbBase UINT32 value that is the base address of the
GHCB used during the SEC phase.
- PcdOvmfSecGhcbSize UINT32 value that is the size, in bytes, of the
GHCB area used during the SEC phase.
- PcdOvmfSecGhcbPageTableBase UINT32 value that is address of a page
table page used to break down the 2MB page into
512 4K pages.
- PcdOvmfSecGhcbPageTableSize UINT32 value that is the size, in bytes,
of the page table page.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2020-08-12 22:21:40 +02:00
|
|
|
|
|
|
|
%define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
|
|
|
|
%define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
|
|
|
|
%define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
|
2020-08-12 22:21:41 +02:00
|
|
|
%define SEV_ES_WORK_AREA (FixedPcdGet32 (PcdSevEsWorkAreaBase))
|
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108
To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.
The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.
The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.
The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.
To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>
2021-01-07 19:48:13 +01:00
|
|
|
%define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8)
|
2021-01-07 19:48:15 +01:00
|
|
|
%define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
|
2020-08-12 22:21:41 +02:00
|
|
|
%define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
|
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108
To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.
The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.
The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.
The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.
To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>
2021-01-07 19:48:13 +01:00
|
|
|
%include "Ia32/Flat32ToFlat64.asm"
|
2014-08-19 01:03:53 +02:00
|
|
|
%include "Ia32/PageTables64.asm"
|
|
|
|
%endif
|
|
|
|
|
|
|
|
%include "Ia16/Real16ToFlat32.asm"
|
|
|
|
%include "Ia16/Init16.asm"
|
|
|
|
|
|
|
|
%include "Main.asm"
|
|
|
|
|
2020-08-12 22:21:42 +02:00
|
|
|
%define SEV_ES_AP_RESET_IP FixedPcdGet32 (PcdSevEsWorkAreaBase)
|
2020-11-30 21:28:17 +01:00
|
|
|
%define SEV_LAUNCH_SECRET_BASE FixedPcdGet32 (PcdSevLaunchSecretBase)
|
|
|
|
%define SEV_LAUNCH_SECRET_SIZE FixedPcdGet32 (PcdSevLaunchSecretSize)
|
2014-08-19 01:03:53 +02:00
|
|
|
%include "Ia16/ResetVectorVtf0.asm"
|
|
|
|
|