On 06/28/18 08:16, Zeng, Star wrote:
> 1) My understanding is Variable Driver is managing the variable region in 
> flash although the flash read/write/erase operations are done in flash 
> driver. Current Variable Driver needs the address (to variable region) be 
> converted to virtual address for runtime, and it does not assume flash driver 
> to set the runtime attribute for variable region, but do it by itself.
> 
> 2) I agree this approach. If the runtime attribute has been set by flash 
> driver, Variable Driver has no need to do that.

Great, thank you!

Yesterday, after I sent my email(s), I got concerned for a moment,
because it wasn't clear to me what *runtime driver* actually owned the
flash range.

However, the FVB protocol itself must be provided by a runtime driver on
UEFI/PI platforms where the variable write service implementation --
indirectly or directly -- depends on FVB, for flash writes. Indeed in
edk2, we have at least the following FVB drivers:

$ git grep -l -E \
    -e 'EfiFirmwareVolumeBlock2?ProtocolGuid' --and -e 'PROD'

EmulatorPkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
Nt32Pkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf
Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmmDxe.inf

All of them are DXE_RUNTIME_DRIVER modules [*] and they all call
EfiConvertPointer().

[*] "Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmmDxe.inf" is marked as a
DXE_DRIVER (not runtime), and indeed it doesn't call
EfiConvertPointer(). I don't know what this driver is good for; the INF
file is not included in any DSC file in edk2. I guess it can be used for
flash access on an SMM platform as long as you never boot an OS / never
call ExitBootServices(). In that case however, runtime aspects have no
meaning at all.

Thanks!
Laszlo

> 
> 
> Thanks,
> Star
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Laszlo 
> Ersek
> Sent: Wednesday, June 27, 2018 8:54 PM
> To: Brijesh Singh <brijesh.si...@amd.com>; edk2-devel@lists.01.org
> Cc: Tom Lendacky <thomas.lenda...@amd.com>; Dong, Eric <eric.d...@intel.com>; 
> Zeng, Star <star.z...@intel.com>; Justen, Jordan L <jordan.l.jus...@intel.com>
> Subject: Re: [edk2] [RFC PATCH 1/1] OvmfPkg/QemuFlash: Fix Runtime variable 
> access when SEV is enabled
> 
> On 06/26/18 21:46, Brijesh Singh wrote:
>> Problem statement:
>> ------------------
>> Fedora-28 contains 4.16 kernel -- which has all the required support 
>> to run as an SEV guest.  When the installer is launched from SEV guest 
>> then it fails to install the bootloader. The installer was failing to 
>> update the 'BootOrder' UEFI runtime variable.
>>
>> Root Cause Analysis
>> --------------------
>> Since QemuFlash storage memory is accessed by both guest and 
>> hypervisor hence we need to map this memory range as unencrypted. 
>> AmdSevDxe maps the range as "unencrypted" but later 
>> FtwNotificationEvent() in 
>> MdeModule/Universal/Variable/RuntimeDxe/VariableDxe.c resets the mapping and 
>> the memory region gets remapped as "encrypted".
> 
> Is this a new issue, or has it always been there, and we just failed to 
> notice it?
> 
> BTW, I don't understand why FtwNotificationEvent() in 
> "MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c" has to mark the 
> flash range as EFI_MEMORY_RUNTIME. I thought that this action belonged in the 
> flash driver itself, and we do that already in 
> MarkMemoryRangeForRuntimeAccess(), in file 
> "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c".
> 
> The variable driver does not own the pflash chip (the pflash driver owns it), 
> so I believe the variable driver shouldn't mess with the mapping attributes.
> 
> Here's a suggestion -- Star, Eric, can you please comment? In the
> FtwNotificationEvent() function, after we get the memory descriptor for the 
> pflash range, first check whether EFI_MEMORY_RUNTIME is already set.
> If it is, don't do anything; if it isn't, add the attribute.
> 
> This should cause no observable change on any non-SEV platform, and it should 
> remove the gDS->SetMemorySpaceAttributes() call for OVMF (where it breaks 
> things for SEV).
> 
>> After that, any access
>> to the flash will end up going through the encryption engine. I did 
>> try hacking EDK2 to restore the C-bit
> 
> (I continue to be annoyed that the memory encryption bit is not exposed in 
> the GCD memory space attributes explicitly.)
> 
>> but that was not sufficient because UEFI runtime services are mapped 
>> as "encrypted" in OS page table
> 
> What do you mean here? Runtime services *code* or runtime services *data*? 
> Code must obviously be remain encrypted (otherwise we cannot execute it in 
> SEV). Runtime Services Data should also be mapped as encrypted (it is normal 
> RAM that is not used for guest<->hypervisor exchange).
> 
>> hence we end up accessing the flash as encrypted when OS requests to update 
>> the variables.
> 
> I don't understand the "hence" here; I don't see how the implication follows. 
> runtime services code and data should be encrypted. Runtime MMIO should be 
> un-encrypted.
> 
> Ohh, wait, in MarkMemoryRangeForRuntimeAccess(), we use 
> "EfiGcdMemoryTypeSystemMemory". I don't have a clue why that is a good idea. 
> That should have been EfiGcdMemoryTypeMemoryMappedIo.
> 
> ... Anyway, I think first we should go with the "check EFI_MEMORY_RUNTIME 
> attribute before setting it", in FtwNotificationEvent().
> 
>>
>> A possible solution
>> ---------------------
>> To solve the issue, after QemuFlash is probed, I allocate an encrypted 
>> buffer and initialize this buffer with the contents from the flash memory.
>> When SEV is enabled, we use newly allocated encrypted buffer in
>> FwInstance->FvBase instead of the original flash region. The idea is 
>> FwInstance->if
>> caller grabs the FwInstance->FvBase pointer and tries to access the 
>> FvVolumeHeader then it should get the data from the encrypted buffer.
>> But if caller wants read/writes to/from the flash device then we 
>> internally use the original "unencrypted" flash region to access the data.
> 
> No, this is neither safe, nor a desirable design.
> 
> Safety: all accesses (via both pointers and FVB protocol members) that 
> higher-level drives *think* go to the pflash chip must *actually* go to the 
> pflash chip.
> 
> Design: it had taken us years to get rid of various memory-emulated fake 
> variable stores. They *all* suck in one way or another, with various obscure 
> UEFI spec incompatibilities and corner cases. A strictly pflash-based 
> varstore is not what we should compromise on.
> 
>> With this
>> patch, I have verified that OS is able to update the runtime variable 
>> and
>> FC-28 installer is successfully able to complete the installation process.
>>
>> If you all agree with approach then I can rework any feedbacks and 
>> remove the rfc tag from the patch. If you have better suggestions then 
>> I am open to explore those as well.
> 
> I'd like to understand the following:
> 
> (1) why does FtwNotificationEvent() set the EFI_MEMORY_RUNTIME attribute 
> itself, for the pflash range? -- in my opinion, that belongs in the flash 
> driver.
> 
> (2) Whether Star and Eric agree with setting the EFI_MEMORY_RUNTIME attribute 
> in FtwNotificationEvent() only if the attribute is not already present.
> 
> (3) The implication that you describe, between runtime services/code being 
> mapped encrypted, and restoring the C-bit failing.
> 
> (4) Whether we should modify MarkMemoryRangeForRuntimeAccess() to install the 
> range into GCD as MMIO. (I feel *very* uncomfortable about this, however; the 
> current code has existed as-is for years, and regressions look very risky.)
> 
> My strong preference would be a patch for (2).
> 
> Thanks,
> Laszlo
> 
>> Cc: Laszlo Ersek <ler...@redhat.com>
>> Contributed-under: TianoCore Contribution Agreement 1.1
>> Signed-off-by: Brijesh Singh <brijesh.si...@amd.com>
>> ---
>>  .../FvbServicesRuntimeDxe.inf                      |  1 +
>>  .../FwBlockService.c                               | 37 
>> +++++++++++++++++++---
>>  2 files changed, 34 insertions(+), 4 deletions(-)
>>
>> diff --git 
>> a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf 
>> b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> index d7b4ec06c4e6..6bb5c2093790 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> @@ -54,6 +54,7 @@ [LibraryClasses]
>>    DevicePathLib
>>    DxeServicesTableLib
>>    MemoryAllocationLib
>> +  MemEncryptSevLib
>>    PcdLib
>>    UefiBootServicesTableLib
>>    UefiDriverEntryPoint
>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c 
>> b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> index 558b395dff4a..e82b4ff70961 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> @@ -36,6 +36,7 @@
>>  #include <Library/DxeServicesTableLib.h>  #include 
>> <Library/MemoryAllocationLib.h>  #include 
>> <Library/UefiBootServicesTableLib.h>
>> +#include <Library/MemEncryptSevLib.h>
>>  
>>  #include "FwBlockService.h"
>>  #include "QemuFlash.h"
>> @@ -966,6 +967,7 @@ FvbInitialize (
>>    UINTN                               Length;
>>    UINTN                               NumOfBlocks;
>>    RETURN_STATUS                       PcdStatus;
>> +  EFI_PHYSICAL_ADDRESS                CryptedAddress;
>>  
>>    if (EFI_ERROR (QemuFlashInitialize ())) {
>>      //
>> @@ -986,6 +988,24 @@ FvbInitialize (
>>    BaseAddress = (UINTN) PcdGet32 (PcdOvmfFdBaseAddress);
>>    Length = PcdGet32 (PcdOvmfFirmwareFdSize);
>>  
>> +  //
>> +  // When SEV is enabled, allocate a encrypted buffer which will 
>> + contain a  // encrypted copy of the Flash image.
>> +  //
>> +  if (MemEncryptSevIsEnabled ()) {
>> +    Status = gBS->AllocatePages (
>> +                    AllocateAnyPages,
>> +                    EfiRuntimeServicesData,
>> +                    EFI_SIZE_TO_PAGES(PcdGet32 (PcdOvmfFirmwareFdSize)),
>> +                    &CryptedAddress
>> +                    );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    CopyMem((VOID *)CryptedAddress, (VOID *)BaseAddress, Length);
>> +
>> +    BaseAddress = CryptedAddress;
>> +  }
>> +
>>    Status = InitializeVariableFvHeader ();
>>    if (EFI_ERROR (Status)) {
>>      DEBUG ((EFI_D_INFO,
>> @@ -1091,24 +1111,33 @@ FvbInitialize (
>>    //
>>    InstallProtocolInterfaces (FvbDevice);
>>  
>> -  MarkMemoryRangeForRuntimeAccess (BaseAddress, Length);
>> +  MarkMemoryRangeForRuntimeAccess (
>> +    (UINTN) PcdGet32 (PcdOvmfFdBaseAddress),
>> +    Length
>> +    );
>>  
>>    //
>>    // Set several PCD values to point to flash
>>    //
>>    PcdStatus = PcdSet64S (
>>      PcdFlashNvStorageVariableBase64,
>> -    (UINTN) PcdGet32 (PcdOvmfFlashNvStorageVariableBase)
>> +    BaseAddress
>>      );
>>    ASSERT_RETURN_ERROR (PcdStatus);
>>    PcdStatus = PcdSet32S (
>>      PcdFlashNvStorageFtwWorkingBase,
>> -    PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase)
>> +    BaseAddress +
>> +    PcdGet32(PcdFlashNvStorageVariableSize) +
>> +    PcdGet32(PcdOvmfFlashNvStorageEventLogSize)
>>      );
>> +
>>    ASSERT_RETURN_ERROR (PcdStatus);
>>    PcdStatus = PcdSet32S (
>>      PcdFlashNvStorageFtwSpareBase,
>> -    PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase)
>> +    BaseAddress +
>> +    PcdGet32(PcdFlashNvStorageVariableSize) +
>> +    PcdGet32(PcdOvmfFlashNvStorageEventLogSize) +
>> +    PcdGet32(PcdFlashNvStorageFtwWorkingSize)
>>      );
>>    ASSERT_RETURN_ERROR (PcdStatus);
>>  
>>
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to