mirror of https://github.com/acidanthera/audk.git
451 lines
13 KiB
C
451 lines
13 KiB
C
/** @file
|
|
|
|
TDX Dxe driver. This driver is dispatched early in DXE, due to being list
|
|
in APRIORI.
|
|
|
|
This module is responsible for:
|
|
- Sets max logical cpus based on TDINFO
|
|
- Sets PCI PCDs based on resource hobs
|
|
- Alter MATD table to record address of Mailbox
|
|
|
|
Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DxeServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Protocol/Cpu.h>
|
|
#include <Protocol/MpInitLibDepProtocols.h>
|
|
#include <Protocol/MemoryAccept.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <ConfidentialComputingGuestAttr.h>
|
|
#include <IndustryStandard/Tdx.h>
|
|
#include <Library/PlatformInitLib.h>
|
|
#include <Library/TdxLib.h>
|
|
#include <TdxAcpiTable.h>
|
|
#include <Library/MemEncryptTdxLib.h>
|
|
|
|
#define ALIGNED_2MB_MASK 0x1fffff
|
|
EFI_HANDLE mTdxDxeHandle = NULL;
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
TdxMemoryAccept (
|
|
IN EDKII_MEMORY_ACCEPT_PROTOCOL *This,
|
|
IN EFI_PHYSICAL_ADDRESS StartAddress,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 AcceptPageSize;
|
|
UINT64 StartAddress1;
|
|
UINT64 StartAddress2;
|
|
UINT64 StartAddress3;
|
|
UINT64 Length1;
|
|
UINT64 Length2;
|
|
UINT64 Length3;
|
|
UINT64 Pages;
|
|
|
|
AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
|
|
StartAddress1 = 0;
|
|
StartAddress2 = 0;
|
|
StartAddress3 = 0;
|
|
Length1 = 0;
|
|
Length2 = 0;
|
|
Length3 = 0;
|
|
|
|
if (Size == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (ALIGN_VALUE (StartAddress, SIZE_2MB) != StartAddress) {
|
|
StartAddress1 = StartAddress;
|
|
Length1 = ALIGN_VALUE (StartAddress, SIZE_2MB) - StartAddress;
|
|
if (Length1 >= Size) {
|
|
Length1 = Size;
|
|
}
|
|
|
|
StartAddress += Length1;
|
|
Size -= Length1;
|
|
}
|
|
|
|
if (Size > SIZE_2MB) {
|
|
StartAddress2 = StartAddress;
|
|
Length2 = Size & ~(UINT64)ALIGNED_2MB_MASK;
|
|
StartAddress += Length2;
|
|
Size -= Length2;
|
|
}
|
|
|
|
if (Size) {
|
|
StartAddress3 = StartAddress;
|
|
Length3 = Size;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (Length1 > 0) {
|
|
Pages = Length1 / SIZE_4KB;
|
|
Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (Length2 > 0) {
|
|
Pages = Length2 / AcceptPageSize;
|
|
Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (Length3 > 0) {
|
|
Pages = Length3 / SIZE_4KB;
|
|
Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
|
|
ASSERT (!EFI_ERROR (Status));
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EDKII_MEMORY_ACCEPT_PROTOCOL mMemoryAcceptProtocol = {
|
|
TdxMemoryAccept
|
|
};
|
|
|
|
VOID
|
|
SetPcdSettings (
|
|
EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
|
)
|
|
{
|
|
RETURN_STATUS PcdStatus;
|
|
|
|
PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, PlatformInfoHob->PcdConfidentialComputingGuestAttr);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSetBoolS (PcdSetNxForStack, PlatformInfoHob->PcdSetNxForStack);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"HostBridgeDevId=0x%x, CCAttr=0x%x, SetNxForStack=%x\n",
|
|
PlatformInfoHob->HostBridgeDevId,
|
|
PlatformInfoHob->PcdConfidentialComputingGuestAttr,
|
|
PlatformInfoHob->PcdSetNxForStack
|
|
));
|
|
|
|
PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"MaxCpuCount=0x%x, BootCpuCount=0x%x\n",
|
|
PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber,
|
|
PlatformInfoHob->PcdCpuBootLogicalProcessorNumber
|
|
));
|
|
|
|
PcdSet64S (PcdEmuVariableNvStoreReserved, PlatformInfoHob->PcdEmuVariableNvStoreReserved);
|
|
|
|
if (TdIsEnabled ()) {
|
|
PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
DEBUG ((DEBUG_INFO, "TdxSharedBitMask=0x%llx\n", PcdGet64 (PcdTdxSharedBitMask)));
|
|
}
|
|
|
|
PcdStatus = PcdSet64S (PcdPciMmio64Base, PlatformInfoHob->PcdPciMmio64Base);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
}
|
|
|
|
/**
|
|
Location of resource hob matching type and starting address
|
|
|
|
@param[in] Type The type of resource hob to locate.
|
|
|
|
@param[in] Start The resource hob must at least begin at address.
|
|
|
|
@retval pointer to resource Return pointer to a resource hob that matches or NULL.
|
|
**/
|
|
STATIC
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *
|
|
GetResourceDescriptor (
|
|
EFI_RESOURCE_TYPE Type,
|
|
EFI_PHYSICAL_ADDRESS Start,
|
|
EFI_PHYSICAL_ADDRESS End
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
|
|
|
|
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
|
|
while (Hob.Raw != NULL) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a:%d: resource type 0x%x %llx %llx\n",
|
|
__func__,
|
|
__LINE__,
|
|
Hob.ResourceDescriptor->ResourceType,
|
|
Hob.ResourceDescriptor->PhysicalStart,
|
|
Hob.ResourceDescriptor->ResourceLength
|
|
));
|
|
|
|
if ((Hob.ResourceDescriptor->ResourceType == Type) &&
|
|
(Hob.ResourceDescriptor->PhysicalStart >= Start) &&
|
|
((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
|
|
{
|
|
ResourceDescriptor = Hob.ResourceDescriptor;
|
|
break;
|
|
}
|
|
|
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
|
|
}
|
|
|
|
return ResourceDescriptor;
|
|
}
|
|
|
|
/**
|
|
Location of resource hob matching type and highest address below end
|
|
|
|
@param[in] Type The type of resource hob to locate.
|
|
|
|
@param[in] End The resource hob return is the closest to the End address
|
|
|
|
@retval pointer to resource Return pointer to a resource hob that matches or NULL.
|
|
**/
|
|
STATIC
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *
|
|
GetHighestResourceDescriptor (
|
|
EFI_RESOURCE_TYPE Type,
|
|
EFI_PHYSICAL_ADDRESS End
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
|
|
|
|
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
|
|
while (Hob.Raw != NULL) {
|
|
if ((Hob.ResourceDescriptor->ResourceType == Type) &&
|
|
(Hob.ResourceDescriptor->PhysicalStart < End))
|
|
{
|
|
if (!ResourceDescriptor ||
|
|
(ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
|
|
{
|
|
ResourceDescriptor = Hob.ResourceDescriptor;
|
|
}
|
|
}
|
|
|
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
|
|
}
|
|
|
|
return ResourceDescriptor;
|
|
}
|
|
|
|
/**
|
|
Set the shared bit for mmio region in Tdx guest.
|
|
|
|
In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
|
|
For direct access, the shared bit of the PageTableEntry should be set.
|
|
The mmio region information is retrieved from hob list.
|
|
|
|
@retval EFI_SUCCESS The shared bit is set successfully.
|
|
@retval EFI_UNSUPPORTED Setting the shared bit of memory region
|
|
is not supported
|
|
**/
|
|
EFI_STATUS
|
|
SetMmioSharedBit (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
|
|
Hob.Raw = (UINT8 *)GetHobList ();
|
|
|
|
//
|
|
// Parse the HOB list until end of list or matching type is found.
|
|
//
|
|
while (!END_OF_HOB_LIST (Hob)) {
|
|
if ( (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)
|
|
&& (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
|
|
{
|
|
MemEncryptTdxSetPageSharedBit (
|
|
0,
|
|
Hob.ResourceDescriptor->PhysicalStart,
|
|
EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
|
|
);
|
|
}
|
|
|
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
TdxDxeEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
RETURN_STATUS PcdStatus;
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *Res = NULL;
|
|
EFI_HOB_RESOURCE_DESCRIPTOR *MemRes = NULL;
|
|
EFI_HOB_PLATFORM_INFO *PlatformInfo = NULL;
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
UINT32 CpuMaxLogicalProcessorNumber;
|
|
TD_RETURN_DATA TdReturnData;
|
|
EFI_EVENT QemuAcpiTableEvent;
|
|
void *Registration;
|
|
|
|
GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
|
|
|
|
if (GuidHob == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
|
|
//
|
|
PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
|
|
ASSERT (PlatformInfo->HostBridgeDevId != 0);
|
|
PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
|
|
#ifdef TDX_PEI_LESS_BOOT
|
|
//
|
|
// For Pei-less boot, PlatformInfo contains more information and
|
|
// need to set PCDs based on these information.
|
|
//
|
|
SetPcdSettings (PlatformInfo);
|
|
#endif
|
|
|
|
if (!TdIsEnabled ()) {
|
|
//
|
|
// If it is Non-Td guest, we install gEfiMpInitLibMpDepProtocolGuid so that
|
|
// MpInitLib will be used in CpuDxe driver.
|
|
//
|
|
gBS->InstallProtocolInterface (
|
|
&ImageHandle,
|
|
&gEfiMpInitLibMpDepProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
SetMmioSharedBit ();
|
|
|
|
//
|
|
// It is Td guest, we install gEfiMpInitLibUpDepProtocolGuid so that
|
|
// MpInitLibUp will be used in CpuDxe driver.
|
|
//
|
|
gBS->InstallProtocolInterface (
|
|
&ImageHandle,
|
|
&gEfiMpInitLibUpDepProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Install MemoryAccept protocol for TDX
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&mTdxDxeHandle,
|
|
&gEdkiiMemoryAcceptProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mMemoryAcceptProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Install EdkiiMemoryAcceptProtocol failed.\n"));
|
|
}
|
|
|
|
//
|
|
// Call TDINFO to get actual number of cpus in domain
|
|
//
|
|
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
|
|
CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
|
|
|
|
//
|
|
// Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
|
|
// more than number of reported cpus, update.
|
|
//
|
|
if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
|
|
PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
}
|
|
|
|
//
|
|
// Register for protocol notifications to call the AlterAcpiTable(),
|
|
// the protocol will be installed in AcpiPlatformDxe when the ACPI
|
|
// table provided by Qemu is ready.
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
AlterAcpiTable,
|
|
NULL,
|
|
&QemuAcpiTableEvent
|
|
);
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gQemuAcpiTableNotifyProtocolGuid,
|
|
QemuAcpiTableEvent,
|
|
&Registration
|
|
);
|
|
|
|
#define INIT_PCDSET(NAME, RES) do {\
|
|
PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
|
|
ASSERT_RETURN_ERROR (PcdStatus); \
|
|
PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
|
|
ASSERT_RETURN_ERROR (PcdStatus); \
|
|
} while(0)
|
|
|
|
if (PlatformInfo) {
|
|
PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
|
|
|
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
|
|
INIT_PCDSET (PcdPciMmio64, Res);
|
|
}
|
|
|
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
|
|
INIT_PCDSET (PcdPciIo, Res);
|
|
}
|
|
|
|
//
|
|
// To find low mmio, first find top of low memory, and then search for io space.
|
|
//
|
|
if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
|
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
|
|
INIT_PCDSET (PcdPciMmio32, Res);
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|