EFI_STATUS
EFIAPI
AmdSevDxeEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS                       Status;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *AllDescMap;
  UINTN                            NumEntries;
  UINTN                            Index;

  //
  // Do nothing when SEV is not enabled
  //
  if (!MemEncryptSevIsEnabled ()) {
    return EFI_UNSUPPORTED;
  }

  //
  // Iterate through the GCD map and clear the C-bit from MMIO and NonExistent
  // memory space. The NonExistent memory space will be used for mapping the MMIO
  // space added later (eg PciRootBridge). By clearing both known MMIO and
  // NonExistent memory space can gurantee that current and furture MMIO adds
  // will have C-bit cleared.
  //
  Status = gDS->GetMemorySpaceMap (&NumEntries, &AllDescMap);
  if (!EFI_ERROR (Status)) {
    for (Index = 0; Index < NumEntries; Index++) {
      CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;

      Desc = &AllDescMap[Index];
      if (Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo ||
          Desc->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
        Status = MemEncryptSevClearPageEncMask (0,
                                                Desc->BaseAddress,
                                                EFI_SIZE_TO_PAGES(Desc->Length),
                                                FALSE);
        ASSERT_EFI_ERROR (Status);
      }
    }

    FreePool (AllDescMap);
  }

  return EFI_SUCCESS;
}
Пример #2
0
/**
  Provides the controller-specific addresses required to access system memory
  from a DMA bus master. On SEV guest, the DMA operations must be performed on
  shared buffer hence we allocate a bounce buffer to map the HostAddress to a
  DeviceAddress. The Encryption attribute is removed from the DeviceAddress
  buffer.

  @param  This                  The protocol instance pointer.
  @param  Operation             Indicates if the bus master is going to read or
                                write to system memory.
  @param  HostAddress           The system memory address to map to the PCI
                                controller.
  @param  NumberOfBytes         On input the number of bytes to map. On output
                                the number of bytes that were mapped.
  @param  DeviceAddress         The resulting map address for the bus master
                                PCI controller to use to access the hosts
                                HostAddress.
  @param  Mapping               A resulting value to pass to Unmap().

  @retval EFI_SUCCESS           The range was mapped for the returned
                                NumberOfBytes.
  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common
                                buffer.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
                                lack of resources.
  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested
                                address.

**/
EFI_STATUS
EFIAPI
IoMmuMap (
  IN     EDKII_IOMMU_PROTOCOL                       *This,
  IN     EDKII_IOMMU_OPERATION                      Operation,
  IN     VOID                                       *HostAddress,
  IN OUT UINTN                                      *NumberOfBytes,
  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
  OUT    VOID                                       **Mapping
  )
{
  EFI_STATUS                                        Status;
  LIST_ENTRY                                        *RecycledMapInfo;
  MAP_INFO                                          *MapInfo;
  EFI_ALLOCATE_TYPE                                 AllocateType;
  COMMON_BUFFER_HEADER                              *CommonBufferHeader;
  VOID                                              *DecryptionSource;

  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
      Mapping == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
  // called later.
  //
  RecycledMapInfo = GetFirstNode (&mRecycledMapInfos);
  if (RecycledMapInfo == &mRecycledMapInfos) {
    //
    // No recycled MAP_INFO structure, allocate a new one.
    //
    MapInfo = AllocatePool (sizeof (MAP_INFO));
    if (MapInfo == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Failed;
    }
  } else {
    MapInfo = CR (RecycledMapInfo, MAP_INFO, Link, MAP_INFO_SIG);
    RemoveEntryList (RecycledMapInfo);
  }

  //
  // Initialize the MAP_INFO structure, except the PlainTextAddress field
  //
  ZeroMem (&MapInfo->Link, sizeof MapInfo->Link);
  MapInfo->Signature         = MAP_INFO_SIG;
  MapInfo->Operation         = Operation;
  MapInfo->NumberOfBytes     = *NumberOfBytes;
  MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
  MapInfo->CryptedAddress    = (UINTN)HostAddress;

  //
  // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
  // plaintext buffer, according to Operation. We also set "DecryptionSource".
  //
  MapInfo->PlainTextAddress = MAX_ADDRESS;
  AllocateType = AllocateAnyPages;
  DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress;
  switch (Operation) {
  //
  // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
  // is necessary regardless of whether the original (crypted) buffer crosses
  // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
  // The only variable is whether the plaintext buffer should be under 4GB.
  //
  case EdkiiIoMmuOperationBusMasterRead:
  case EdkiiIoMmuOperationBusMasterWrite:
    MapInfo->PlainTextAddress = BASE_4GB - 1;
    AllocateType = AllocateMaxAddress;
    //
    // fall through
    //
  case EdkiiIoMmuOperationBusMasterRead64:
  case EdkiiIoMmuOperationBusMasterWrite64:
    //
    // Allocate the implicit plaintext bounce buffer.
    //
    Status = gBS->AllocatePages (
                    AllocateType,
                    EfiBootServicesData,
                    MapInfo->NumberOfPages,
                    &MapInfo->PlainTextAddress
                    );
    if (EFI_ERROR (Status)) {
      goto FreeMapInfo;
    }
    break;

  //
  // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a
  // stash buffer (for in-place decryption) have been allocated already, with
  // AllocateBuffer(). We only check whether the address of the to-be-plaintext
  // buffer is low enough for the requested operation.
  //
  case EdkiiIoMmuOperationBusMasterCommonBuffer:
    if ((MapInfo->CryptedAddress > BASE_4GB) ||
        (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >
         BASE_4GB - MapInfo->CryptedAddress)) {
      //
      // CommonBuffer operations cannot be remapped. If the common buffer is
      // above 4GB, then it is not possible to generate a mapping, so return an
      // error.
      //
      Status = EFI_UNSUPPORTED;
      goto FreeMapInfo;
    }
    //
    // fall through
    //
  case EdkiiIoMmuOperationBusMasterCommonBuffer64:
    //
    // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().
    //
    MapInfo->PlainTextAddress = MapInfo->CryptedAddress;
    //
    // Stash the crypted data.
    //
    CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
                           (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE
                           );
    ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
    CopyMem (
      CommonBufferHeader->StashBuffer,
      (VOID *)(UINTN)MapInfo->CryptedAddress,
      MapInfo->NumberOfBytes
      );
    //
    // Point "DecryptionSource" to the stash buffer so that we decrypt
    // it to the original location, after the switch statement.
    //
    DecryptionSource = CommonBufferHeader->StashBuffer;
    break;

  default:
    //
    // Operation is invalid
    //
    Status = EFI_INVALID_PARAMETER;
    goto FreeMapInfo;
  }

  //
  // Clear the memory encryption mask on the plaintext buffer.
  //
  Status = MemEncryptSevClearPageEncMask (
             0,
             MapInfo->PlainTextAddress,
             MapInfo->NumberOfPages,
             TRUE
             );
  ASSERT_EFI_ERROR (Status);
  if (EFI_ERROR (Status)) {
    CpuDeadLoop ();
  }

  //
  // If this is a read operation from the Bus Master's point of view,
  // then copy the contents of the real buffer into the mapped buffer
  // so the Bus Master can read the contents of the real buffer.
  //
  // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt
  // the original data (from the stash buffer) back to the original location.
  //
  if (Operation == EdkiiIoMmuOperationBusMasterRead ||
      Operation == EdkiiIoMmuOperationBusMasterRead64 ||
      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
    CopyMem (
      (VOID *) (UINTN) MapInfo->PlainTextAddress,
      DecryptionSource,
      MapInfo->NumberOfBytes
      );
  }

  //
  // Populate output parameters.
  //
  *DeviceAddress = MapInfo->PlainTextAddress;
  *Mapping       = MapInfo;

  DEBUG ((
    DEBUG_VERBOSE,
    "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n",
    __FUNCTION__,
    MapInfo->PlainTextAddress,
    MapInfo->CryptedAddress,
    (UINT64)MapInfo->NumberOfPages,
    (UINT64)MapInfo->NumberOfBytes
    ));

  return EFI_SUCCESS;

FreeMapInfo:
  FreePool (MapInfo);

Failed:
  *NumberOfBytes = 0;
  return Status;
}