190 lines
7.1 KiB
Diff
190 lines
7.1 KiB
Diff
|
|
From 9eacd1a6df6861b76663e98133adb15059bf65cc Mon Sep 17 00:00:00 2001
|
||
|
|
From: gongchangsui <gongchangsui@outlook.com>
|
||
|
|
Date: Mon, 17 Mar 2025 02:40:50 -0400
|
||
|
|
Subject: [PATCH] arm: VirtCCA: CVM support UEFI boot
|
||
|
|
|
||
|
|
1. Add UEFI boot support for Confidential VMs.
|
||
|
|
2. Modify the base memory address of Confidential VMs from 3GB to 1GB.
|
||
|
|
3. Disable pflash boot support for Confidential VMs; use the`-bios`option to specify`QEMU_EFI.fd`during launch.
|
||
|
|
|
||
|
|
Signed-off-by: gongchangsui <gongchangsui@outlook.com>
|
||
|
|
---
|
||
|
|
hw/arm/boot.c | 38 ++++++++++++++++++++++++++++++++++++--
|
||
|
|
hw/arm/virt.c | 33 ++++++++++++++++++++++++++++++++-
|
||
|
|
include/hw/arm/boot.h | 3 +++
|
||
|
|
3 files changed, 71 insertions(+), 3 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
|
||
|
|
index 42110b0f18..6b2f46af4d 100644
|
||
|
|
--- a/hw/arm/boot.c
|
||
|
|
+++ b/hw/arm/boot.c
|
||
|
|
@@ -43,6 +43,9 @@
|
||
|
|
|
||
|
|
#define BOOTLOADER_MAX_SIZE (4 * KiB)
|
||
|
|
|
||
|
|
+#define UEFI_MAX_SIZE 0x8000000
|
||
|
|
+#define UEFI_LOADER_START 0x0
|
||
|
|
+#define DTB_MAX 0x200000
|
||
|
|
AddressSpace *arm_boot_address_space(ARMCPU *cpu,
|
||
|
|
const struct arm_boot_info *info)
|
||
|
|
{
|
||
|
|
@@ -1155,7 +1158,31 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
|
||
|
|
+static void arm_setup_confidential_firmware_boot(ARMCPU *cpu,
|
||
|
|
+ struct arm_boot_info *info,
|
||
|
|
+ const char *firmware_filename)
|
||
|
|
+{
|
||
|
|
+ ssize_t fw_size;
|
||
|
|
+ const char *fname;
|
||
|
|
+ AddressSpace *as = arm_boot_address_space(cpu, info);
|
||
|
|
+
|
||
|
|
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename);
|
||
|
|
+ if (!fname) {
|
||
|
|
+ error_report("Could not find firmware image '%s'", firmware_filename);
|
||
|
|
+ exit(EXIT_FAILURE);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fw_size = load_image_targphys_as(firmware_filename,
|
||
|
|
+ info->firmware_base,
|
||
|
|
+ info->firmware_max_size, as);
|
||
|
|
+
|
||
|
|
+ if (fw_size <= 0) {
|
||
|
|
+ error_report("could not load firmware '%s'", firmware_filename);
|
||
|
|
+ exit(EXIT_FAILURE);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info, const char *firmware_filename)
|
||
|
|
{
|
||
|
|
/* Set up for booting firmware (which might load a kernel via fw_cfg) */
|
||
|
|
|
||
|
|
@@ -1166,6 +1193,8 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
|
||
|
|
* DTB to the base of RAM for the bootloader to pick up.
|
||
|
|
*/
|
||
|
|
info->dtb_start = info->loader_start;
|
||
|
|
+ if (info->confidential)
|
||
|
|
+ tmm_add_ram_region(UEFI_LOADER_START, UEFI_MAX_SIZE, info->dtb_start, DTB_MAX , true);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (info->kernel_filename) {
|
||
|
|
@@ -1206,6 +1235,11 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (info->confidential) {
|
||
|
|
+ arm_setup_confidential_firmware_boot(cpu, info, firmware_filename);
|
||
|
|
+ kvm_load_user_data(UEFI_LOADER_START, UEFI_MAX_SIZE, info->loader_start, info->loader_start + DTB_MAX, info->ram_size,
|
||
|
|
+ (struct kvm_numa_info *)info->numa_info);
|
||
|
|
+ }
|
||
|
|
/*
|
||
|
|
* We will start from address 0 (typically a boot ROM image) in the
|
||
|
|
* same way as hardware. Leave env->boot_info NULL, so that
|
||
|
|
@@ -1282,7 +1316,7 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
|
||
|
|
|
||
|
|
/* Load the kernel. */
|
||
|
|
if (!info->kernel_filename || info->firmware_loaded) {
|
||
|
|
- arm_setup_firmware_boot(cpu, info);
|
||
|
|
+ arm_setup_firmware_boot(cpu, info, ms->firmware);
|
||
|
|
} else {
|
||
|
|
arm_setup_direct_kernel_boot(cpu, info);
|
||
|
|
}
|
||
|
|
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
||
|
|
index 8823f2ed1c..6ffb26e7e6 100644
|
||
|
|
--- a/hw/arm/virt.c
|
||
|
|
+++ b/hw/arm/virt.c
|
||
|
|
@@ -1398,6 +1398,9 @@ static void virt_flash_map1(PFlashCFI01 *flash,
|
||
|
|
qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
|
||
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||
|
|
|
||
|
|
+ if (virtcca_cvm_enabled()) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
memory_region_add_subregion(sysmem, base,
|
||
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||
|
|
0));
|
||
|
|
@@ -1433,6 +1436,10 @@ static void virt_flash_fdt(VirtMachineState *vms,
|
||
|
|
MachineState *ms = MACHINE(vms);
|
||
|
|
char *nodename;
|
||
|
|
|
||
|
|
+ if (virtcca_cvm_enabled()) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (sysmem == secure_sysmem) {
|
||
|
|
/* Report both flash devices as a single node in the DT */
|
||
|
|
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||
|
|
@@ -1468,6 +1475,23 @@ static void virt_flash_fdt(VirtMachineState *vms,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+static bool virt_confidential_firmware_init(VirtMachineState *vms,
|
||
|
|
+ MemoryRegion *sysmem)
|
||
|
|
+{
|
||
|
|
+ MemoryRegion *fw_ram;
|
||
|
|
+ hwaddr fw_base = vms->memmap[VIRT_FLASH].base;
|
||
|
|
+ hwaddr fw_size = vms->memmap[VIRT_FLASH].size;
|
||
|
|
+
|
||
|
|
+ if (!MACHINE(vms)->firmware) {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fw_ram = g_new(MemoryRegion, 1);
|
||
|
|
+ memory_region_init_ram(fw_ram, NULL, "fw_ram", fw_size, NULL);
|
||
|
|
+ memory_region_add_subregion(sysmem, fw_base, fw_ram);
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static bool virt_firmware_init(VirtMachineState *vms,
|
||
|
|
MemoryRegion *sysmem,
|
||
|
|
MemoryRegion *secure_sysmem)
|
||
|
|
@@ -1486,6 +1510,10 @@ static bool virt_firmware_init(VirtMachineState *vms,
|
||
|
|
|
||
|
|
pflash_blk0 = pflash_cfi01_get_blk(vms->flash[0]);
|
||
|
|
|
||
|
|
+ if (virtcca_cvm_enabled()) {
|
||
|
|
+ return virt_confidential_firmware_init(vms, sysmem);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
bios_name = MACHINE(vms)->firmware;
|
||
|
|
if (bios_name) {
|
||
|
|
char *fname;
|
||
|
|
@@ -2023,7 +2051,7 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
|
||
|
|
vms->memmap[VIRT_PCIE_MMIO] = (MemMapEntry) { 0x10000000, 0x2edf0000 };
|
||
|
|
vms->memmap[VIRT_KAE_DEVICE] = (MemMapEntry) { 0x3edf0000, 0x00200000 };
|
||
|
|
|
||
|
|
- vms->memmap[VIRT_MEM].base = 3 * GiB;
|
||
|
|
+ vms->memmap[VIRT_MEM].base = 1 * GiB;
|
||
|
|
vms->memmap[VIRT_MEM].size = ms->ram_size;
|
||
|
|
info_report("[qemu] fix VIRT_MEM range 0x%llx - 0x%llx\n", (unsigned long long)(vms->memmap[VIRT_MEM].base),
|
||
|
|
(unsigned long long)(vms->memmap[VIRT_MEM].base + ms->ram_size));
|
||
|
|
@@ -2822,6 +2850,9 @@ static void machvirt_init(MachineState *machine)
|
||
|
|
vms->bootinfo.get_dtb = machvirt_dtb;
|
||
|
|
vms->bootinfo.skip_dtb_autoload = true;
|
||
|
|
vms->bootinfo.firmware_loaded = firmware_loaded;
|
||
|
|
+ vms->bootinfo.firmware_base = vms->memmap[VIRT_FLASH].base;
|
||
|
|
+ vms->bootinfo.firmware_max_size = vms->memmap[VIRT_FLASH].size;
|
||
|
|
+ vms->bootinfo.confidential = virtcca_cvm_enabled();
|
||
|
|
vms->bootinfo.psci_conduit = vms->psci_conduit;
|
||
|
|
arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
|
||
|
|
|
||
|
|
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
|
||
|
|
index 4491b1f85b..06ca1d90b2 100644
|
||
|
|
--- a/include/hw/arm/boot.h
|
||
|
|
+++ b/include/hw/arm/boot.h
|
||
|
|
@@ -133,6 +133,9 @@ struct arm_boot_info {
|
||
|
|
bool secure_board_setup;
|
||
|
|
|
||
|
|
arm_endianness endianness;
|
||
|
|
+ hwaddr firmware_base;
|
||
|
|
+ hwaddr firmware_max_size;
|
||
|
|
+ bool confidential;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
--
|
||
|
|
2.41.0.windows.1
|
||
|
|
|