Tom Lendacky 437eb3f7a8 OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198

The flash detection routine will attempt to determine how the flash
device behaves (e.g. ROM, RAM, Flash). But when SEV-ES is enabled and
the flash device behaves as a ROM device (meaning it is marked read-only
by the hypervisor), this check may result in an infinite nested page fault
because of the attempted write. Since the instruction cannot be emulated
when SEV-ES is enabled, the RIP is never advanced, resulting in repeated
nested page faults.

When SEV-ES is enabled, exit the flash detection early and assume that
the FD behaves as Flash. This will result in QemuFlashWrite() being called
to store EFI variables, which will also result in an infinite nested page
fault when the write is performed. In this case, update QemuFlashWrite()
to use the VMGEXIT MMIO write support to have the hypervisor perform the
write without having to emulate the instruction.

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-17 02:46:39 +00:00

107 lines
2.5 KiB
C

/** @file
OVMF support for QEMU system firmware flash device
Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __QEMU_FLASH_H__
#define __QEMU_FLASH_H__
#include <Protocol/FirmwareVolumeBlock.h>
extern UINT8 *mFlashBase;
/**
Read from QEMU Flash
@param[in] Lba The starting logical block index to read from.
@param[in] Offset Offset into the block at which to begin reading.
@param[in] NumBytes On input, indicates the requested read size. On
output, indicates the actual number of bytes read
@param[in] Buffer Pointer to the buffer to read into.
**/
EFI_STATUS
QemuFlashRead (
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINTN *NumBytes,
IN UINT8 *Buffer
);
/**
Write to QEMU Flash
@param[in] Lba The starting logical block index to write to.
@param[in] Offset Offset into the block at which to begin writing.
@param[in] NumBytes On input, indicates the requested write size. On
output, indicates the actual number of bytes written
@param[in] Buffer Pointer to the data to write.
**/
EFI_STATUS
QemuFlashWrite (
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINTN *NumBytes,
IN UINT8 *Buffer
);
/**
Erase a QEMU Flash block
@param Lba The logical block index to erase.
**/
EFI_STATUS
QemuFlashEraseBlock (
IN EFI_LBA Lba
);
/**
Initializes QEMU flash memory support
@retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
@retval EFI_SUCCESS The QEMU flash device is supported.
**/
EFI_STATUS
QemuFlashInitialize (
VOID
);
VOID
QemuFlashConvertPointers (
VOID
);
VOID
QemuFlashBeforeProbe (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINTN FdBlockSize,
IN UINTN FdBlockCount
);
/**
Write to QEMU Flash
@param[in] Ptr Pointer to the location to write.
@param[in] Value The value to write.
**/
VOID
QemuFlashPtrWrite (
IN volatile UINT8 *Ptr,
IN UINT8 Value
);
#endif