BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275 Use the MemEncryptSevClearMmioPageEncMask() to clear memory encryption mask for the Mmio address range. Cc: James Bottomley <jejb@linux.ibm.com> Cc: Min Xu <min.m.xu@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Erdem Aktas <erdemaktas@google.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Message-Id: <20210519181949.6574-12-brijesh.singh@amd.com>
		
			
				
	
	
		
			245 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**@file
 | |
|   Functions related to the Firmware Volume Block service whose
 | |
|   implementation is specific to the runtime DXE driver build.
 | |
| 
 | |
|   Copyright (C) 2015, Red Hat, Inc.
 | |
|   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| **/
 | |
| 
 | |
| #include <Guid/EventGroup.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/DevicePathLib.h>
 | |
| #include <Library/DxeServicesTableLib.h>
 | |
| #include <Library/MemEncryptSevLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiRuntimeLib.h>
 | |
| #include <Protocol/DevicePath.h>
 | |
| #include <Protocol/FirmwareVolumeBlock.h>
 | |
| 
 | |
| #include "FwBlockService.h"
 | |
| #include "QemuFlash.h"
 | |
| 
 | |
| VOID
 | |
| InstallProtocolInterfaces (
 | |
|   IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                         Status;
 | |
|   EFI_HANDLE                         FwbHandle;
 | |
|   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
 | |
| 
 | |
|   ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
 | |
| 
 | |
|   //
 | |
|   // Find a handle with a matching device path that has supports FW Block
 | |
|   // protocol
 | |
|   //
 | |
|   Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                   &FvbDevice->DevicePath, &FwbHandle);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // LocateDevicePath fails so install a new interface and device path
 | |
|     //
 | |
|     FwbHandle = NULL;
 | |
|     DEBUG ((DEBUG_INFO, "Installing QEMU flash FVB\n"));
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &FwbHandle,
 | |
|                     &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                     &FvbDevice->FwVolBlockInstance,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     FvbDevice->DevicePath,
 | |
|                     NULL
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
 | |
|     //
 | |
|     // Device already exists, so reinstall the FVB protocol
 | |
|     //
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     FwbHandle,
 | |
|                     &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                     (VOID**)&OldFwbInterface
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO, "Reinstalling FVB for QEMU flash region\n"));
 | |
|     Status = gBS->ReinstallProtocolInterface (
 | |
|                     FwbHandle,
 | |
|                     &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                     OldFwbInterface,
 | |
|                     &FvbDevice->FwVolBlockInstance
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   } else {
 | |
|     //
 | |
|     // There was a FVB protocol on an End Device Path node
 | |
|     //
 | |
|     ASSERT (FALSE);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| FvbVirtualAddressChangeEvent (
 | |
|   IN EFI_EVENT        Event,
 | |
|   IN VOID             *Context
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
| 
 | |
|     Fixup internal data so that EFI and SAL can be call in virtual mode.
 | |
|     Call the passed in Child Notify event and convert the mFvbModuleGlobal
 | |
|     date items to there virtual address.
 | |
| 
 | |
|   Arguments:
 | |
| 
 | |
|     (Standard EFI notify event - EFI_EVENT_NOTIFY)
 | |
| 
 | |
|   Returns:
 | |
| 
 | |
|     None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FW_VOL_INSTANCE *FwhInstance;
 | |
|   UINTN               Index;
 | |
| 
 | |
|   FwhInstance = mFvbModuleGlobal->FvInstance;
 | |
|   EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance);
 | |
| 
 | |
|   //
 | |
|   // Convert the base address of all the instances
 | |
|   //
 | |
|   Index       = 0;
 | |
|   while (Index < mFvbModuleGlobal->NumFv) {
 | |
|     EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase);
 | |
|     FwhInstance = (EFI_FW_VOL_INSTANCE *)
 | |
|       (
 | |
|         (UINTN) ((UINT8 *) FwhInstance) +
 | |
|         FwhInstance->VolumeHeader.HeaderLength +
 | |
|         (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
 | |
|       );
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
 | |
|   QemuFlashConvertPointers ();
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| InstallVirtualAddressChangeHandler (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   EFI_EVENT  VirtualAddressChangeEvent;
 | |
| 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   FvbVirtualAddressChangeEvent,
 | |
|                   NULL,
 | |
|                   &gEfiEventVirtualAddressChangeGuid,
 | |
|                   &VirtualAddressChangeEvent
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| MarkIoMemoryRangeForRuntimeAccess (
 | |
|   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
 | |
|   IN UINTN                               Length
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_GCD_MEMORY_SPACE_DESCRIPTOR     GcdDescriptor;
 | |
| 
 | |
|   //
 | |
|   // Mark flash region as runtime memory
 | |
|   //
 | |
|   Status = gDS->RemoveMemorySpace (
 | |
|                   BaseAddress,
 | |
|                   Length
 | |
|                   );
 | |
| 
 | |
|   Status = gDS->AddMemorySpace (
 | |
|                   EfiGcdMemoryTypeMemoryMappedIo,
 | |
|                   BaseAddress,
 | |
|                   Length,
 | |
|                   EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gDS->AllocateMemorySpace (
 | |
|                   EfiGcdAllocateAddress,
 | |
|                   EfiGcdMemoryTypeMemoryMappedIo,
 | |
|                   0,
 | |
|                   Length,
 | |
|                   &BaseAddress,
 | |
|                   gImageHandle,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gDS->SetMemorySpaceAttributes (
 | |
|                   BaseAddress,
 | |
|                   Length,
 | |
|                   GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // When SEV is active, AmdSevDxe mapped the BaseAddress with C=0 but
 | |
|   // SetMemorySpaceAttributes() remaps the range with C=1. Let's restore
 | |
|   // the mapping so that both guest and hyervisor can access the flash
 | |
|   // memory range.
 | |
|   //
 | |
|   if (MemEncryptSevIsEnabled ()) {
 | |
|     Status = MemEncryptSevClearMmioPageEncMask (
 | |
|                0,
 | |
|                BaseAddress,
 | |
|                EFI_SIZE_TO_PAGES (Length)
 | |
|                );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| SetPcdFlashNvStorageBaseAddresses (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   RETURN_STATUS PcdStatus;
 | |
| 
 | |
|   //
 | |
|   // Set several PCD values to point to flash
 | |
|   //
 | |
|   PcdStatus = PcdSet64S (
 | |
|     PcdFlashNvStorageVariableBase64,
 | |
|     (UINTN) PcdGet32 (PcdOvmfFlashNvStorageVariableBase)
 | |
|     );
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
|   PcdStatus = PcdSet32S (
 | |
|     PcdFlashNvStorageFtwWorkingBase,
 | |
|     PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase)
 | |
|     );
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
|   PcdStatus = PcdSet32S (
 | |
|     PcdFlashNvStorageFtwSpareBase,
 | |
|     PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase)
 | |
|     );
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
| }
 |