Files
system76-edk2/OvmfPkg/TdxDxe/TdxDxe.c
Min M Xu 7cc7c52670 OvmfPkg: Set default Pci PCDs in Tdx guest
In previous implementation below Pci related PCDs were set based on the
ResourceDescriptor passed in TdHob.
 - PcdPciMmio64Base / PcdPciMmio64Size
 - PcdPciMmio32Base / PcdPciMmio32Size
 - PcdPciIoBase / PcdPciIoSize

The PCDs will not be set if TdHob doesn't include these information. This
patch set the PCDs with the information initialized in PlatformInitLib
by default. Then TdxDxe will check the ResourceDescriptor in TdHob and
reset them if they're included.

Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-09-06 06:39:59 +00:00

346 lines
11 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 <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>
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
));
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
);
//
// 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;
}