On Thu, May 12, 2022 at 11:17:50AM +0800, Xiaoyao Li <xiaoyao.li@xxxxxxxxx> wrote: > The TD HOB list is used to pass the information from VMM to TDVF. The TD > HOB must include PHIT HOB and Resource Descriptor HOB. More details can > be found in TDVF specification and PI specification. > > Build the TD HOB in TDX's machine_init_done callback. Because HOB is introduced first time, please expand HOB. > Co-developed-by: Isaku Yamahata <isaku.yamahata@xxxxxxxxx> > Signed-off-by: Isaku Yamahata <isaku.yamahata@xxxxxxxxx> > Co-developed-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> > Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> > Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx> > --- > hw/i386/meson.build | 2 +- > hw/i386/tdvf-hob.c | 212 ++++++++++++++++++++++++++++++++++++++++++ > hw/i386/tdvf-hob.h | 25 +++++ > hw/i386/uefi.h | 198 +++++++++++++++++++++++++++++++++++++++ > target/i386/kvm/tdx.c | 16 ++++ > 5 files changed, 452 insertions(+), 1 deletion(-) > create mode 100644 hw/i386/tdvf-hob.c > create mode 100644 hw/i386/tdvf-hob.h > create mode 100644 hw/i386/uefi.h > > diff --git a/hw/i386/meson.build b/hw/i386/meson.build > index 97f3b50503b0..b59e0d35bba3 100644 > --- a/hw/i386/meson.build > +++ b/hw/i386/meson.build > @@ -28,7 +28,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files( > 'port92.c')) > i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'), > if_false: files('pc_sysfw_ovmf-stubs.c')) > -i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c')) > +i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c')) > > subdir('kvm') > subdir('xen') > diff --git a/hw/i386/tdvf-hob.c b/hw/i386/tdvf-hob.c > new file mode 100644 > index 000000000000..31160e9f95c5 > --- /dev/null > +++ b/hw/i386/tdvf-hob.c > @@ -0,0 +1,212 @@ > +/* > + * SPDX-License-Identifier: GPL-2.0-or-later > + > + * Copyright (c) 2020 Intel Corporation > + * Author: Isaku Yamahata <isaku.yamahata at gmail.com> > + * <isaku.yamahata at intel.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "e820_memory_layout.h" > +#include "hw/i386/pc.h" > +#include "hw/i386/x86.h" > +#include "hw/pci/pcie_host.h" > +#include "sysemu/kvm.h" > +#include "tdvf-hob.h" > +#include "uefi.h" > + > +typedef struct TdvfHob { > + hwaddr hob_addr; > + void *ptr; > + int size; > + > + /* working area */ > + void *current; > + void *end; > +} TdvfHob; > + > +static uint64_t tdvf_current_guest_addr(const TdvfHob *hob) > +{ > + return hob->hob_addr + (hob->current - hob->ptr); > +} > + > +static void tdvf_align(TdvfHob *hob, size_t align) > +{ > + hob->current = QEMU_ALIGN_PTR_UP(hob->current, align); > +} > + > +static void *tdvf_get_area(TdvfHob *hob, uint64_t size) > +{ > + void *ret; > + > + if (hob->current + size > hob->end) { > + error_report("TD_HOB overrun, size = 0x%" PRIx64, size); > + exit(1); > + } > + > + ret = hob->current; > + hob->current += size; > + tdvf_align(hob, 8); > + return ret; > +} > + > +static void tdvf_hob_add_mmio_resource(TdvfHob *hob, uint64_t start, > + uint64_t end) > +{ > + EFI_HOB_RESOURCE_DESCRIPTOR *region; > + > + if (!start) { > + return; > + } > + > + region = tdvf_get_area(hob, sizeof(*region)); > + *region = (EFI_HOB_RESOURCE_DESCRIPTOR) { > + .Header = { > + .HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, > + .HobLength = cpu_to_le16(sizeof(*region)), > + .Reserved = cpu_to_le32(0), > + }, > + .Owner = EFI_HOB_OWNER_ZERO, > + .ResourceType = cpu_to_le32(EFI_RESOURCE_MEMORY_MAPPED_IO), > + .ResourceAttribute = cpu_to_le32(EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO), > + .PhysicalStart = cpu_to_le64(start), > + .ResourceLength = cpu_to_le64(end - start), > + }; > +} > + > +static void tdvf_hob_add_mmio_resources(TdvfHob *hob) > +{ > + MachineState *ms = MACHINE(qdev_get_machine()); > + X86MachineState *x86ms = X86_MACHINE(ms); > + PCIHostState *pci_host; > + uint64_t start, end; > + uint64_t mcfg_base, mcfg_size; > + Object *host; > + > + /* Effectively PCI hole + other MMIO devices. */ > + tdvf_hob_add_mmio_resource(hob, x86ms->below_4g_mem_size, > + APIC_DEFAULT_ADDRESS); > + > + /* Stolen from acpi_get_i386_pci_host(), there's gotta be an easier way. */ > + pci_host = OBJECT_CHECK(PCIHostState, > + object_resolve_path("/machine/i440fx", NULL), > + TYPE_PCI_HOST_BRIDGE); > + if (!pci_host) { > + pci_host = OBJECT_CHECK(PCIHostState, > + object_resolve_path("/machine/q35", NULL), > + TYPE_PCI_HOST_BRIDGE); > + } > + g_assert(pci_host); > + > + host = OBJECT(pci_host); > + > + /* PCI hole above 4gb. */ > + start = object_property_get_uint(host, PCI_HOST_PROP_PCI_HOLE64_START, > + NULL); > + end = object_property_get_uint(host, PCI_HOST_PROP_PCI_HOLE64_END, NULL); > + tdvf_hob_add_mmio_resource(hob, start, end); > + > + /* MMCFG region */ > + mcfg_base = object_property_get_uint(host, PCIE_HOST_MCFG_BASE, NULL); > + mcfg_size = object_property_get_uint(host, PCIE_HOST_MCFG_SIZE, NULL); > + if (mcfg_base && mcfg_base != PCIE_BASE_ADDR_UNMAPPED && mcfg_size) { > + tdvf_hob_add_mmio_resource(hob, mcfg_base, mcfg_base + mcfg_size); > + } > +} > + > +static void tdvf_hob_add_memory_resources(TdxGuest *tdx, TdvfHob *hob) > +{ > + EFI_HOB_RESOURCE_DESCRIPTOR *region; > + EFI_RESOURCE_ATTRIBUTE_TYPE attr; > + EFI_RESOURCE_TYPE resource_type; > + > + TdxRamEntry *e; > + int i; > + > + for (i = 0; i < tdx->nr_ram_entries; i++) { > + e = &tdx->ram_entries[i]; > + > + if (e->type == TDX_RAM_UNACCEPTED) { > + resource_type = EFI_RESOURCE_MEMORY_UNACCEPTED; > + attr = EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED; > + } else if (e->type == TDX_RAM_ADDED){ > + resource_type = EFI_RESOURCE_SYSTEM_MEMORY; > + attr = EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE; > + } else { > + error_report("unknown TDXRAMENTRY type %d", e->type); > + exit(1); > + } > + > + region = tdvf_get_area(hob, sizeof(*region)); > + *region = (EFI_HOB_RESOURCE_DESCRIPTOR) { > + .Header = { > + .HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, > + .HobLength = cpu_to_le16(sizeof(*region)), > + .Reserved = cpu_to_le32(0), > + }, > + .Owner = EFI_HOB_OWNER_ZERO, > + .ResourceType = cpu_to_le32(resource_type), > + .ResourceAttribute = cpu_to_le32(attr), > + .PhysicalStart = e->address, nitpick: cpu_to_le64() for consistency. My bad. > + .ResourceLength = e->length, ditto. Thanks, > + }; > + } > +} > + > +void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob) > +{ > + TdvfHob hob = { > + .hob_addr = td_hob->address, > + .size = td_hob->size, > + .ptr = td_hob->mem_ptr, > + > + .current = td_hob->mem_ptr, > + .end = td_hob->mem_ptr + td_hob->size, > + }; > + > + EFI_HOB_GENERIC_HEADER *last_hob; > + EFI_HOB_HANDOFF_INFO_TABLE *hit; > + > + /* Note, Efi{Free}Memory{Bottom,Top} are ignored, leave 'em zeroed. */ > + hit = tdvf_get_area(&hob, sizeof(*hit)); > + *hit = (EFI_HOB_HANDOFF_INFO_TABLE) { > + .Header = { > + .HobType = EFI_HOB_TYPE_HANDOFF, > + .HobLength = cpu_to_le16(sizeof(*hit)), > + .Reserved = cpu_to_le32(0), > + }, > + .Version = cpu_to_le32(EFI_HOB_HANDOFF_TABLE_VERSION), > + .BootMode = cpu_to_le32(0), > + .EfiMemoryTop = cpu_to_le64(0), > + .EfiMemoryBottom = cpu_to_le64(0), > + .EfiFreeMemoryTop = cpu_to_le64(0), > + .EfiFreeMemoryBottom = cpu_to_le64(0), > + .EfiEndOfHobList = cpu_to_le64(0), /* initialized later */ > + }; > + > + tdvf_hob_add_memory_resources(tdx, &hob); > + > + tdvf_hob_add_mmio_resources(&hob); > + > + last_hob = tdvf_get_area(&hob, sizeof(*last_hob)); > + *last_hob = (EFI_HOB_GENERIC_HEADER) { > + .HobType = EFI_HOB_TYPE_END_OF_HOB_LIST, > + .HobLength = cpu_to_le16(sizeof(*last_hob)), > + .Reserved = cpu_to_le32(0), > + }; > + hit->EfiEndOfHobList = tdvf_current_guest_addr(&hob); > +} > diff --git a/hw/i386/tdvf-hob.h b/hw/i386/tdvf-hob.h > new file mode 100644 > index 000000000000..f0494e8c4af8 > --- /dev/null > +++ b/hw/i386/tdvf-hob.h > @@ -0,0 +1,25 @@ > +#ifndef HW_I386_TD_HOB_H > +#define HW_I386_TD_HOB_H > + > +#include "hw/i386/tdvf.h" > +#include "hw/i386/uefi.h" > +#include "target/i386/kvm/tdx.h" > + > +void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob); > + > +#define EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE \ > + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ > + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ > + EFI_RESOURCE_ATTRIBUTE_TESTED) > + > +#define EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED \ > + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ > + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ > + EFI_RESOURCE_ATTRIBUTE_TESTED) > + > +#define EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO \ > + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ > + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ > + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE) > + > +#endif > diff --git a/hw/i386/uefi.h b/hw/i386/uefi.h > new file mode 100644 > index 000000000000..b15aba796156 > --- /dev/null > +++ b/hw/i386/uefi.h > @@ -0,0 +1,198 @@ > +/* > + * Copyright (C) 2020 Intel Corporation > + * > + * Author: Isaku Yamahata <isaku.yamahata at gmail.com> > + * <isaku.yamahata at intel.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + * > + */ > + > +#ifndef HW_I386_UEFI_H > +#define HW_I386_UEFI_H > + > +/***************************************************************************/ > +/* > + * basic EFI definitions > + * supplemented with UEFI Specification Version 2.8 (Errata A) > + * released February 2020 > + */ > +/* UEFI integer is little endian */ > + > +typedef struct { > + uint32_t Data1; > + uint16_t Data2; > + uint16_t Data3; > + uint8_t Data4[8]; > +} EFI_GUID; > + > +typedef enum { > + EfiReservedMemoryType, > + EfiLoaderCode, > + EfiLoaderData, > + EfiBootServicesCode, > + EfiBootServicesData, > + EfiRuntimeServicesCode, > + EfiRuntimeServicesData, > + EfiConventionalMemory, > + EfiUnusableMemory, > + EfiACPIReclaimMemory, > + EfiACPIMemoryNVS, > + EfiMemoryMappedIO, > + EfiMemoryMappedIOPortSpace, > + EfiPalCode, > + EfiPersistentMemory, > + EfiUnacceptedMemoryType, > + EfiMaxMemoryType > +} EFI_MEMORY_TYPE; > + > +#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009 > + > +#define EFI_HOB_TYPE_HANDOFF 0x0001 > +#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002 > +#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003 > +#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004 > +#define EFI_HOB_TYPE_FV 0x0005 > +#define EFI_HOB_TYPE_CPU 0x0006 > +#define EFI_HOB_TYPE_MEMORY_POOL 0x0007 > +#define EFI_HOB_TYPE_FV2 0x0009 > +#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED 0x000A > +#define EFI_HOB_TYPE_UEFI_CAPSULE 0x000B > +#define EFI_HOB_TYPE_FV3 0x000C > +#define EFI_HOB_TYPE_UNUSED 0xFFFE > +#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF > + > +typedef struct { > + uint16_t HobType; > + uint16_t HobLength; > + uint32_t Reserved; > +} EFI_HOB_GENERIC_HEADER; > + > +typedef uint64_t EFI_PHYSICAL_ADDRESS; > +typedef uint32_t EFI_BOOT_MODE; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + uint32_t Version; > + EFI_BOOT_MODE BootMode; > + EFI_PHYSICAL_ADDRESS EfiMemoryTop; > + EFI_PHYSICAL_ADDRESS EfiMemoryBottom; > + EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop; > + EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom; > + EFI_PHYSICAL_ADDRESS EfiEndOfHobList; > +} EFI_HOB_HANDOFF_INFO_TABLE; > + > +#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000 > +#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001 > +#define EFI_RESOURCE_IO 0x00000002 > +#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003 > +#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004 > +#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005 > +#define EFI_RESOURCE_IO_RESERVED 0x00000006 > +#define EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007 > +#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000008 > + > +#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001 > +#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002 > +#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004 > +#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008 > +#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010 > +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020 > +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040 > +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080 > +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100 > +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200 > +#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400 > +#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800 > +#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000 > +#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000 > +#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000 > +#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000 > +#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000 > +#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000 > +#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED 0x00040000 > +#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00080000 > +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE 0x00100000 > +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE 0x00200000 > +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE 0x00400000 > +#define EFI_RESOURCE_ATTRIBUTE_PERSISTENT 0x00800000 > +#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE 0x01000000 > +#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000 > + > +typedef uint32_t EFI_RESOURCE_TYPE; > +typedef uint32_t EFI_RESOURCE_ATTRIBUTE_TYPE; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + EFI_GUID Owner; > + EFI_RESOURCE_TYPE ResourceType; > + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; > + EFI_PHYSICAL_ADDRESS PhysicalStart; > + uint64_t ResourceLength; > +} EFI_HOB_RESOURCE_DESCRIPTOR; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + EFI_GUID Name; > + > + /* guid specific data follows */ > +} EFI_HOB_GUID_TYPE; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + uint64_t Length; > +} EFI_HOB_FIRMWARE_VOLUME; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + uint64_t Length; > + EFI_GUID FvName; > + EFI_GUID FileName; > +} EFI_HOB_FIRMWARE_VOLUME2; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + uint64_t Length; > + uint32_t AuthenticationStatus; > + bool ExtractedFv; > + EFI_GUID FvName; > + EFI_GUID FileName; > +} EFI_HOB_FIRMWARE_VOLUME3; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + uint8_t SizeOfMemorySpace; > + uint8_t SizeOfIoSpace; > + uint8_t Reserved[6]; > +} EFI_HOB_CPU; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > +} EFI_HOB_MEMORY_POOL; > + > +typedef struct { > + EFI_HOB_GENERIC_HEADER Header; > + > + EFI_PHYSICAL_ADDRESS BaseAddress; > + uint64_t Length; > +} EFI_HOB_UEFI_CAPSULE; > + > +#define EFI_HOB_OWNER_ZERO \ > + ((EFI_GUID){ 0x00000000, 0x0000, 0x0000, \ > + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }) > + > +#endif > diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c > index e7071bfe4c9c..3e18ace90bf7 100644 > --- a/target/i386/kvm/tdx.c > +++ b/target/i386/kvm/tdx.c > @@ -22,6 +22,7 @@ > #include "hw/i386/e820_memory_layout.h" > #include "hw/i386/x86.h" > #include "hw/i386/tdvf.h" > +#include "hw/i386/tdvf-hob.h" > #include "kvm_i386.h" > #include "tdx.h" > > @@ -130,6 +131,19 @@ static void get_tdx_capabilities(void) > tdx_caps = caps; > } > > +static TdxFirmwareEntry *tdx_get_hob_entry(TdxGuest *tdx) > +{ > + TdxFirmwareEntry *entry; > + > + for_each_tdx_fw_entry(&tdx->tdvf, entry) { > + if (entry->type == TDVF_SECTION_TYPE_TD_HOB) { > + return entry; > + } > + } > + error_report("TDVF metadata doesn't specify TD_HOB location."); > + exit(1); > +} > + > static void tdx_add_ram_entry(uint64_t address, uint64_t length, uint32_t type) > { > uint32_t nr_entries = tdx_guest->nr_ram_entries; > @@ -249,6 +263,8 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) > > qsort(tdx_guest->ram_entries, tdx_guest->nr_ram_entries, > sizeof(TdxRamEntry), &tdx_ram_entry_compare); > + > + tdvf_hob_create(tdx_guest, tdx_get_hob_entry(tdx_guest)); > } > > static Notifier tdx_machine_done_notify = { > -- > 2.27.0 > > -- Isaku Yamahata <isaku.yamahata@xxxxxxxxx>