diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index a8e29f148e1bbd5f0bcd26b1d46a2eefb87e9b9b..57c6718b77217f366955c6ba8d01eb32577b7e7d 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2390,6 +2390,7 @@ static int kvm_init(MachineState *ms) qemu_mutex_init(&kml_slots_lock); s = KVM_STATE(ms->accelerator); + kvm_state = s; /* * On systems where the kernel can support different base page @@ -2609,8 +2610,6 @@ static int kvm_init(MachineState *ms) #endif } - kvm_state = s; - ret = kvm_arch_init(ms, s); if (ret < 0) { goto err; @@ -3528,7 +3527,7 @@ int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target) return r; } -int kvm_load_user_data(hwaddr loader_start, hwaddr image_end, hwaddr initrd_start, hwaddr dtb_end, hwaddr ram_size, +int kvm_load_user_data(hwaddr loader_start, hwaddr dtb_info, hwaddr data_start, hwaddr data_size, hwaddr ram_size, struct kvm_numa_info *numa_info) { KVMState *state = kvm_state; @@ -3536,9 +3535,9 @@ int kvm_load_user_data(hwaddr loader_start, hwaddr image_end, hwaddr initrd_star int ret; data.loader_start = loader_start; - data.image_end = image_end; - data.initrd_start = initrd_start; - data.dtb_end = dtb_end; + data.dtb_info = dtb_info; + data.data_start = data_start; + data.data_size = data_size; data.ram_size = ram_size; memcpy(&data.numa_info, numa_info, sizeof(struct kvm_numa_info)); diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 891fe4ac4acb0cf826786e182742cd6b12be572d..ce63a372a3fce4733c1adb02f7940766ba1ba2d5 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -27,6 +27,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendFile, MEMORY_BACKEND_FILE) bool virtcca_shared_hugepage_mapped = false; uint64_t virtcca_cvm_ram_size = 0; +uint64_t virtcca_cvm_gpa_start = 0; struct HostMemoryBackendFile { HostMemoryBackend parent_obj; @@ -101,8 +102,16 @@ virtcca_shared_backend_memory_alloc(char *mem_path, uint32_t ram_flags, Error ** error_report("parse virtcca share memory path failed"); exit(1); } - if (virtcca_cvm_ram_size >= VIRTCCA_SHARED_HUGEPAGE_MAX_SIZE) { - size = VIRTCCA_SHARED_HUGEPAGE_MAX_SIZE; + + /* + * 1) CVM_GPA_START = 3GB --> fix size = 1GB + * 2) CVM_GPA_START = 1GB && ram_size >= 3GB --> size = 3GB + * 3) CVM_GPA_START = 1GB && ram_size < 3GB --> size = ram_size + */ + if (virtcca_cvm_gpa_start != DEFAULT_VM_GPA_START) { + size = VIRTCCA_SHARED_HUGEPAGE_ADDR_LIMIT - virtcca_cvm_gpa_start; + } else if (virtcca_cvm_ram_size >= VIRTCCA_SHARED_HUGEPAGE_ADDR_LIMIT - DEFAULT_VM_GPA_START) { + size = VIRTCCA_SHARED_HUGEPAGE_ADDR_LIMIT - DEFAULT_VM_GPA_START; } virtcca_shared_hugepage = g_new(MemoryRegion, 1); @@ -172,7 +181,9 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) fb->mem_path, fb->offset, errp); g_free(name); - if (virtcca_cvm_enabled() && backend->share && !virtcca_shared_hugepage_mapped) { + if (virtcca_cvm_enabled() && backend->share && + (strcmp(fb->mem_path, "/dev/shm") != 0) && + !virtcca_shared_hugepage_mapped) { virtcca_shared_backend_memory_alloc(fb->mem_path, ram_flags, errp); } #endif diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 42110b0f183194ffcff3e97c54b47b2c8427cd76..b10d7cc6e511f36d2781fd872d6ebb3b35921123 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) { @@ -1146,17 +1149,51 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, if (kvm_enabled() && virtcca_cvm_enabled()) { if (info->dtb_limit == 0) { - info->dtb_limit = info->dtb_start + 0x200000; + info->dtb_limit = info->dtb_start + DTB_MAX; } - kvm_load_user_data(info->loader_start, image_high_addr, info->initrd_start, - info->dtb_limit, info->ram_size, (struct kvm_numa_info *)info->numa_info); + kvm_load_user_data(info->loader_start, 0x1, info->dtb_start, + info->dtb_limit - info->dtb_start, info->ram_size, (struct kvm_numa_info *)info->numa_info); tmm_add_ram_region(info->loader_start, image_high_addr - info->loader_start, info->initrd_start, info->dtb_limit - info->initrd_start, true); } } -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) { + uint64_t tmi_version = 0; + if (kvm_ioctl(kvm_state, KVM_GET_TMI_VERSION, &tmi_version) < 0) { + error_report("please check the kernel version!"); + exit(EXIT_FAILURE); + } + if (tmi_version < MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM) { + error_report("please check the tmi version!"); + exit(EXIT_FAILURE); + } + 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(1); + } + + 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(1); + } +} + +static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info, const char *firmware_filename) +{ + hwaddr mmio_start, mmio_size; /* Set up for booting firmware (which might load a kernel via fw_cfg) */ if (have_dtb(info)) { @@ -1166,6 +1203,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 +1245,12 @@ 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); + virtcca_kvm_get_mmio_addr(&mmio_start, &mmio_size); + kvm_load_user_data(info->loader_start, DTB_MAX, mmio_start, mmio_size, 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 +1327,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-acpi-build.c b/hw/arm/virt-acpi-build.c index 076781423b85643903bf04d77eee4d14335e569a..f78331d69f87a7df595c34be9ae3722aff707eba 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -58,6 +58,7 @@ #include "migration/vmstate.h" #include "hw/acpi/ghes.h" #include "hw/acpi/viot.h" +#include "kvm_arm.h" #define ARM_SPI_BASE 32 @@ -405,6 +406,54 @@ static void acpi_dsdt_add_virtio(Aml *scope, } } +static void acpi_dsdt_add_hisi_sec(Aml *scope, + const MemMapEntry *virtio_mmio_memmap, + int dev_id) +{ + hwaddr size = 0x10000; + + /* + * Calculate the base address for the sec device node. + * Each device group contains one sec device and one hpre device,spaced by 2 * size. + */ + hwaddr base = virtio_mmio_memmap->base + dev_id * 2 * size; + + Aml *dev = aml_device("SE%02u", dev_id); + aml_append(dev, aml_name_decl("_HID", aml_string("SEC07"))); + aml_append(dev, aml_name_decl("_UID", aml_int(dev_id))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + + aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_hisi_hpre(Aml *scope, + const MemMapEntry *virtio_mmio_memmap, + int dev_id) +{ + hwaddr size = 0x10000; + + /* + * Calculate the base address for the hpre device node. + * Each hpre device follows the corresponding sec device by an additional offset of size. + */ + hwaddr base = virtio_mmio_memmap->base + dev_id * 2 * size + size; + + Aml *dev = aml_device("HP%02u", dev_id); + aml_append(dev, aml_name_decl("_HID", aml_string("HPRE07"))); + aml_append(dev, aml_name_decl("_UID", aml_int(dev_id))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + + aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, uint32_t irq, VirtMachineState *vms) { @@ -1201,6 +1250,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); + + if (virtcca_cvm_enabled()) { + int kae_num = tmm_get_kae_num(); + for (int i = 0; i < kae_num; i++) { + acpi_dsdt_add_hisi_sec(scope, &memmap[VIRT_KAE_DEVICE], i); + acpi_dsdt_add_hisi_hpre(scope, &memmap[VIRT_KAE_DEVICE], i); + } + } + if (vms->acpi_dev) { build_ged_aml(scope, "\\_SB."GED_DEVICE, HOTPLUG_HANDLER(vms->acpi_dev), diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8823f2ed1caeee965015ed9bae6bccab38fbeebd..03cdca653deca39aad858a4a9ed0ff5c62ce64dc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -176,6 +176,12 @@ static const MemMapEntry base_memmap[] = { [VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES }, }; +void virtcca_kvm_get_mmio_addr(hwaddr *mmio_start, hwaddr *mmio_size) +{ + *mmio_start = base_memmap[VIRT_PCIE_MMIO].base; + *mmio_size = base_memmap[VIRT_PCIE_MMIO].size; +} + /* * Highmem IO Regions: This memory map is floating, located after the RAM. * Each MemMapEntry base (GPA) will be dynamically computed, depending on the @@ -1398,6 +1404,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 +1442,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 +1481,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 +1516,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; @@ -2022,8 +2056,14 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) /* support kae vf device tree nodes */ vms->memmap[VIRT_PCIE_MMIO] = (MemMapEntry) { 0x10000000, 0x2edf0000 }; vms->memmap[VIRT_KAE_DEVICE] = (MemMapEntry) { 0x3edf0000, 0x00200000 }; - - vms->memmap[VIRT_MEM].base = 3 * GiB; + uint64_t tmi_version = 0; + if (kvm_ioctl(kvm_state, KVM_GET_TMI_VERSION, &tmi_version) < 0) { + warn_report("can not get tmi version"); + } + if (tmi_version < MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM) { + vms->memmap[VIRT_MEM].base = 3 * GiB; + } + virtcca_cvm_gpa_start = vms->memmap[VIRT_MEM].base; 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 +2862,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/hw/core/numa.c b/hw/core/numa.c index e7c48dab61d23664d6798d2db270a3a8af83f205..98d896e68704465a7785d90ee67f0318060d41ac 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -655,7 +655,7 @@ static void virtcca_shared_memory_configuration(MachineState *ms) memory_region_init_alias(alias_mr, NULL, "alias-mr", virtcca_shared_hugepage, 0, int128_get64(virtcca_shared_hugepage->size)); memory_region_add_subregion(address_space_virtcca_shared_memory.root, - VIRTCCA_GPA_START, alias_mr); + virtcca_cvm_gpa_start, alias_mr); } void numa_complete_configuration(MachineState *ms) @@ -728,7 +728,8 @@ void numa_complete_configuration(MachineState *ms) memory_region_init(ms->ram, OBJECT(ms), mc->default_ram_id, ms->ram_size); numa_init_memdev_container(ms, ms->ram); - if (virtcca_cvm_enabled() && virtcca_shared_hugepage->ram_block) { + if (virtcca_cvm_enabled() && virtcca_shared_hugepage && + virtcca_shared_hugepage->ram_block) { virtcca_shared_memory_configuration(ms); } } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 8b95558013e9bc020af4d5120c51ed89a1a2837e..4bf0b03977e05125bccddbe3dc603b3e21b1c667 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1617,7 +1617,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - if (virtcca_cvm_enabled()) { + if (virtcca_cvm_enabled() && virtcca_shared_hugepage && virtcca_shared_hugepage->ram_block) { memory_listener_register(&hdev->memory_listener, &address_space_virtcca_shared_memory); } else { diff --git a/include/exec/memory.h b/include/exec/memory.h index 33778f5c641b98f394ad37946b5aca4e0af553fa..c14dc69d277bde140bd13d310ac1be5e2672d668 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -243,14 +243,17 @@ typedef struct IOMMUTLBEvent { /* RAM FD is opened read-only */ #define RAM_READONLY_FD (1 << 11) -/* The GPA range of the VirtCCA bounce buffer is from 1GB to 4GB. */ -#define VIRTCCA_SHARED_HUGEPAGE_MAX_SIZE 0xc0000000ULL +/* The address limit of the VirtCCA bounce buffer is 4GB. */ +#define VIRTCCA_SHARED_HUGEPAGE_ADDR_LIMIT 0x100000000ULL /* The VirtCCA shared hugepage memory granularity is 1GB */ #define VIRTCCA_SHARED_HUGEPAGE_ALIGN 0x40000000ULL -/* The GPA starting address of the VirtCCA CVM is 1GB */ -#define VIRTCCA_GPA_START 0x40000000ULL +/* The default GPA starting address of VM is 1GB */ +#define DEFAULT_VM_GPA_START 0x40000000ULL + +/* The GPA starting address of the VirtCCA CVM is 1GB or 3GB */ +extern uint64_t virtcca_cvm_gpa_start; extern uint64_t virtcca_cvm_ram_size; diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index 4491b1f85b52e5a810fe4863bbb0d008b8307fa7..06ca1d90b222483ffb769ab3c83f6056f0ebbb11 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; }; /** diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 552fdcb18f290e4e7a2217ba03a8dc73a5463674..d69a71cbec1346a997e3203a587ddc25eb89ed3f 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -597,4 +597,6 @@ struct kvm_cap_arm_tmm_populate_region_args { #endif +#define MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM 0x20001 + #endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 05e499b45b9f19435d91f0ea5ce64c172115bd7e..713109eea9a86fca31decae9f9aa339b4fc3ee1f 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1503,9 +1503,15 @@ struct kvm_numa_info { struct kvm_user_data { __u64 loader_start; - __u64 image_end; - __u64 initrd_start; - __u64 dtb_end; + /* + * When the lowest bit of dtb_info is 0, the value of dtb_info represents the size of the DTB, + * and data_start and data_size represent the address base and size of the MMIO. + * When the lowest bit of dtb_info is 1, data_start and data_size represent the address base + * and size of the DTB. + */ + __u64 dtb_info; + __u64 data_start; + __u64 data_size; __u64 ram_size; struct kvm_numa_info numa_info; }; @@ -2413,4 +2419,7 @@ struct kvm_s390_zpci_op { /* flags for kvm_s390_zpci_op->u.reg_aen.flags */ #define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) +/* get tmi version */ +#define KVM_GET_TMI_VERSION _IOR(KVMIO, 0xd2, uint64_t) + #endif /* __LINUX_KVM_H */ diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 88291453ba476a26a4b5583f79a553857aa061f5..76ed52b65b61cbc9ded41a780e9dcd33a3578953 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -487,3 +487,32 @@ { 'command': 'xen-event-inject', 'data': { 'port': 'uint32' }, 'if': 'TARGET_I386' } + +## +# @VirtccaCapability: +# +# The struct describes capability for VIRTCCA feature. +# +# Since: 8.2.0 +## +{ 'struct': 'VirtccaCapability', + 'data': { 'enabled': 'bool' }, + 'if': 'TARGET_AARCH64' } + +## +# @query-virtcca-capabilities: +# +# This command is used to get the VIRTCCA capabilities, and is supported +# on HISI AARCH64 platforms only. +# +# Returns: VirtccaCapability objects. +# +# Since: 8.2.0 +# +# Example: +# +# -> { "execute": "query-virtcca-capabilities" } +# <- { "return": { "enabled": true } } +## +{ 'command': 'query-virtcca-capabilities', 'returns': 'VirtccaCapability', + 'if': 'TARGET_AARCH64' } \ No newline at end of file diff --git a/target/arm/kvm-tmm.c b/target/arm/kvm-tmm.c index ea6bcc0f40631ef4c0013140a0e7f5bbb58d355b..d18ac1089647fbf035a896c469e6d2901dda3ce7 100644 --- a/target/arm/kvm-tmm.c +++ b/target/arm/kvm-tmm.c @@ -15,11 +15,13 @@ #include "kvm_arm.h" #include "migration/blocker.h" #include "qapi/error.h" +#include "qapi/qapi-commands-misc-target.h" #include "qom/object_interfaces.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "hw/loader.h" #include "linux-headers/asm-arm64/kvm.h" +#include #define TYPE_TMM_GUEST "tmm-guest" OBJECT_DECLARE_SIMPLE_TYPE(TmmGuest, TMM_GUEST) @@ -27,6 +29,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TmmGuest, TMM_GUEST) #define TMM_PAGE_SIZE qemu_real_host_page_size() #define TMM_MAX_PMU_CTRS 0x20 #define TMM_MAX_CFG 6 +#define TMM_MEMORY_INFO_SYSFS "/sys/kernel/tmm/memory_info" typedef struct { uint32_t kae_vf_num; @@ -406,3 +409,33 @@ static void tmm_register_types(void) type_register_static(&tmm_guest_info); } type_init(tmm_register_types); + +static VirtccaCapability *virtcca_get_capabilities(Error **errp) +{ + VirtccaCapability *cap = NULL; + uint64_t tmi_version = 0; + int rc = 0; + + if (kvm_ioctl(kvm_state, KVM_GET_TMI_VERSION, &tmi_version) < 0) { + error_setg(errp, "VIRTCCA is not enabled in KVM"); + return NULL; + } + + rc = access(TMM_MEMORY_INFO_SYSFS, R_OK); + if (rc < 0) { + error_setg_errno(errp, errno, "VIRTCCA: Failed to read %s", + TMM_MEMORY_INFO_SYSFS); + return NULL; + } + + cap = g_new0(VirtccaCapability, 1); + + cap->enabled = true; + + return cap; +} + +VirtccaCapability *qmp_query_virtcca_capabilities(Error **errp) +{ + return virtcca_get_capabilities(errp); +} \ No newline at end of file diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 31457a57f73a68ad58c6ea888b4660e59c7926a3..62fbb713f4f8a3a4c03ec7d5e86c51fa1015caf0 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -73,6 +73,8 @@ int kvm_arm_vcpu_finalize(CPUState *cs, int feature); void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, uint64_t attr, int dev_fd, uint64_t addr_ormask); +void virtcca_kvm_get_mmio_addr(hwaddr *mmio_start, hwaddr *mmio_size); + /** * kvm_arm_init_cpreg_list: * @cpu: ARMCPU