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>
346 lines
11 KiB
C
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;
|
|
}
|