diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index b389ef762203e4cf84342937b4af892cb6f5be4c..120fe0d0a1b942c9ff914977b06b624985282c64 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -60,6 +60,9 @@ #include "hw/acpi/viot.h" #include "kvm_arm.h" #include "hw/virtio/virtio-acpi.h" +#ifdef CONFIG_UB +#include "hw/ub/ub_acpi.h" +#endif #define ARM_SPI_BASE 32 @@ -679,6 +682,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } else { rc_mapping_count = 1; } + +#ifdef CONFIG_UB + nb_nodes += 3; /* UBC0, UMU0, PMU0 */ +#endif + /* Number of IORT Nodes */ build_append_int_noprefix(table_data, nb_nodes, 4); @@ -788,6 +796,10 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_iort_rmr_nodes(table_data, smmu_idmaps, smmu_offset, &id); } +#ifdef CONFIG_UB + acpi_iort_add_ub(table_data); +#endif + acpi_table_end(linker, &table); g_array_free(smmu_idmaps, true); g_array_free(its_idmaps, true); @@ -1318,6 +1330,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_dsdt_add_tpm(scope, vms); #endif +#ifdef CONFIG_UB + acpi_dsdt_add_ub(scope); +#endif + aml_append(dsdt, scope); /* copy AML table into ACPI tables blob */ @@ -1365,7 +1381,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; build_dsdt(tables_blob, tables->linker, vms); - +#ifdef CONFIG_UB + acpi_add_table(table_offsets, tables_blob); + build_ubrt(tables_blob, tables->linker, vms); +#endif /* FADT MADT PPTT GTDT MCFG SPCR DBG2 pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); build_fadt_rev6(tables_blob, tables->linker, vms, dsdt); @@ -1474,8 +1493,6 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) " or PCI bridges."); } acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); - - /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index b2091406849961e161cf6d6b216a2e600fc2c91b..a27d3b5fc33a3fc004ea7d74e7b591c5b0ab5b15 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -90,9 +90,14 @@ #include "qemu/log.h" #ifdef CONFIG_UB #include "hw/ub/ub.h" +#include "hw/ub/ub_bus.h" #include "hw/ub/ub_ubc.h" +#include "hw/ub/hisi/ub_mem.h" +#include "hw/ub/ub_acpi.h" #include "hw/ub/hisi/ubc.h" #include "hw/ub/hisi/ub_fm.h" +#include "hw/ub/ub_ummu.h" +#include "hw/ub/ub_common.h" #endif // CONFIG_UB #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ @@ -213,6 +218,16 @@ static MemMapEntry extended_memmap[] = { [VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB }, /* Second PCIe window */ [VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB }, +#ifdef CONFIG_UB + /* ub mmio window */ + [VIRT_HIGH_UB_MMIO] = { 0x0, UBIOS_MMIOS_SIZE_PER_UBC * UBIOS_UBC_TABLE_CNT}, + /* ub idev fers window */ + [VIRT_UB_IDEV_ERS] = { 0x0, 512 * GiB}, + [VIRT_UBC_BASE_REG] = { 0x0, BASE_REG_SIZE}, /* now only support one UBC */ + [VIRT_UBIOS_INFO_TABLE] = { 0x0, UBIOS_TABLE_SIZE}, + [VIRT_UB_MEM_CC] = { 0x0, UB_MEM_SPACE_SIZE}, + [VIRT_UB_MEM_NC] = { 0x0, UB_MEM_SPACE_SIZE}, +#endif // CONFIG_UB }; static const int a15irqmap[] = { @@ -376,6 +391,20 @@ static void create_fdt(VirtMachineState *vms) } } +#ifdef CONFIG_UB +static void create_ubios_info_table_fdt(VirtMachineState *vms, MemoryRegion *machine_ram) +{ + MachineState *ms = MACHINE(vms); + + qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,ubios-information-table", + vms->memmap[VIRT_UBIOS_INFO_TABLE].base); + qemu_log("create fdt for ubios-information-table 0x%lx\n", + vms->memmap[VIRT_UBIOS_INFO_TABLE].base); + + ub_init_ubios_info_table(vms, ROUND_UP(UBIOS_TABLE_SIZE, 4 * KiB)); +} +#endif // CONFIG_UB + static void fdt_add_timer_nodes(const VirtMachineState *vms) { /* On real hardware these interrupts are level-triggered. @@ -1725,11 +1754,41 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) static void create_ub(VirtMachineState *vms) { DeviceState *ubc; + MemoryRegion *mmio_reg; + MemoryRegion *mmio_alias; ubc = qdev_new(TYPE_BUS_CONTROLLER); qdev_prop_set_uint32(ubc, "ub-bus-controller-msgq-reg-size", UBC_MSGQ_REG_SIZE); qdev_prop_set_uint32(ubc, "ub-bus-controller-fm-msgq-reg-size", FM_MSGQ_REG_SIZE); sysbus_realize_and_unref(SYS_BUS_DEVICE(ubc), &error_fatal); + + /* in ub_bus_controller_realize will call sysbus_init_mmio init memory_region in order, + * 0: msgq_reg_mem + * 1: fm_msgq_reg_mem + * 2: ub controller io_mmio + * sysbus_mmio_map get inited memory_region by index 0, msgq_reg_mem + */ + sysbus_mmio_map(SYS_BUS_DEVICE(ubc), 0, + vms->memmap[VIRT_UBC_BASE_REG].base + UBC_MSGQ_REG_OFFSET); + /* sysbus_mmio_map get inited memory_region by index 1, fm_msgq_reg_mem */ + sysbus_mmio_map(SYS_BUS_DEVICE(ubc), 1, + vms->memmap[VIRT_UBC_BASE_REG].base + FM_MSGQ_REG_OFFSET); + mmio_alias = g_new0(MemoryRegion, 1); + /* here get inited memory_region by index 3, ub controller io_mmio */ + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(ubc), 2); + memory_region_init_alias(mmio_alias, OBJECT(ubc), "ub-mmio", + mmio_reg, vms->memmap[VIRT_HIGH_UB_MMIO].base, + vms->memmap[VIRT_HIGH_UB_MMIO].size); + memory_region_add_subregion(get_system_memory(), + vms->memmap[VIRT_HIGH_UB_MMIO].base, + mmio_alias); + + mmio_alias = g_new0(MemoryRegion, 1); + memory_region_init_alias(mmio_alias, OBJECT(ubc), "ub-idev-fers-as", + mmio_reg, vms->memmap[VIRT_UB_IDEV_ERS].base, + vms->memmap[VIRT_UB_IDEV_ERS].size); + memory_region_add_subregion(get_system_memory(), + vms->memmap[VIRT_UB_IDEV_ERS].base, mmio_alias); } #endif // CONFIG_UB static void create_pcie(VirtMachineState *vms) @@ -2040,6 +2099,14 @@ static inline bool *virt_get_high_memmap_enabled(VirtMachineState *vms, &vms->highmem_redists, &vms->highmem_ecam, &vms->highmem_mmio, +#ifdef CONFIG_UB + &vms->highmem_ub_mmio, + &vms->highmem_idev_ers, + &vms->highmem_ubc_base_reg, + &vms->highmem_ubios_info_table, + &vms->highmem_ub_mem_cc, + &vms->highmem_ub_mem_nc, +#endif // CONFIG_UB }; assert(ARRAY_SIZE(extended_memmap) - VIRT_LOWMEMMAP_LAST == @@ -2056,6 +2123,9 @@ static void virt_set_high_memmap(VirtMachineState *vms, bool *region_enabled, fits; int i; +#ifdef CONFIG_UB + ub_set_gpa_bits((uint8_t)pa_bits); +#endif for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { region_enabled = virt_get_high_memmap_enabled(vms, i); region_base = ROUND_UP(base, extended_memmap[i].size); @@ -2074,6 +2144,10 @@ static void virt_set_high_memmap(VirtMachineState *vms, */ fits = (region_base + region_size) <= BIT_ULL(pa_bits); *region_enabled &= fits; +#ifdef CONFIG_UB + qemu_log("%d base 0x%lx size 0x%lx enable %u highmem_compact %u\n", i, + region_base, region_size, *region_enabled, vms->highmem_compact); +#endif if (vms->highmem_compact && !*region_enabled) { continue; } @@ -2152,8 +2226,8 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) /* Base address of the high IO region */ memtop = base = device_memory_base + ROUND_UP(device_memory_size, GiB); if (memtop > BIT_ULL(pa_bits)) { - error_report("Addressing limited to %d bits, but memory exceeds it by %llu bytes\n", - pa_bits, memtop - BIT_ULL(pa_bits)); + error_report("Addressing limited to %d bits, but memory exceeds it by %llu bytes\n", + pa_bits, memtop - BIT_ULL(pa_bits)); exit(EXIT_FAILURE); } if (base < device_memory_base) { @@ -2861,6 +2935,16 @@ static void machvirt_init(MachineState *machine) machine->ram); virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem); +#ifdef CONFIG_UB + qemu_log("memory_region_add_reservation 0x%lx size %ld round up %ld\n", + vms->memmap[VIRT_UBIOS_INFO_TABLE].base, UBIOS_TABLE_SIZE, + ROUND_UP(UBIOS_TABLE_SIZE, 4 * KiB)); + memory_region_add_reservation_with_ram(get_system_memory(), + OBJECT(machine->memdev), "ubios-information-table", + vms->memmap[VIRT_UBIOS_INFO_TABLE].base, + ROUND_UP(UBIOS_TABLE_SIZE, 4 * KiB)); + create_ubios_info_table_fdt(vms, machine->ram); +#endif // CONFIG_UB create_gic(vms, sysmem); @@ -3995,6 +4079,50 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) return requested_pa_size | rme_vm_type | type; } +#ifdef CONFIG_UB +static bool virt_get_ummu(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->ummu; +} + +static void virt_set_ummu(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->ummu = value; +} + +static bool virt_ub_get_cluster_mode(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->ub_cluster_mode; +} + +static void virt_ub_set_cluster_mode(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->ub_cluster_mode = value; +} + +static bool virt_ub_get_fm_deployment_info(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->fm_deployment; +} + +static void virt_ub_set_fm_deployment_info(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->fm_deployment = value; +} +#endif // CONFIG_UB + static void virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -4169,6 +4297,17 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "x-target-impl-cpus", "Describe target cpu impl in the format midr1:revidr1-midr2:revidr2" "Maximum 4 midr:revidr pair is supported"); +#ifdef CONFIG_UB + object_class_property_add_bool(oc, "ummu", virt_get_ummu, virt_set_ummu); + object_class_property_add_bool(oc, "ub-cluster-mode", virt_ub_get_cluster_mode, + virt_ub_set_cluster_mode); + object_class_property_set_description(oc, "ub-cluster-mode", + "Set on/off to enable/disable ub cluster mode"); + object_class_property_add_bool(oc, "fm-deployment", virt_ub_get_fm_deployment_info, + virt_ub_set_fm_deployment_info); + object_class_property_set_description(oc, "fm-deployment", + "Set on/off to support FM msg queue or not"); +#endif // CONFIG_UB } static char *virt_get_kvm_type(Object *obj, Error **errp G_GNUC_UNUSED) @@ -4235,6 +4374,17 @@ static void virt_instance_init(Object *obj) /* MTE is disabled by default. */ vms->mte = false; +#ifdef CONFIG_UB + vms->highmem_ub_mmio = true; + vms->highmem_idev_ers = true; + vms->highmem_ubc_base_reg = true; + vms->highmem_ubios_info_table = true; + vms->highmem_ub_mem_cc = true; + vms->highmem_ub_mem_nc = true; + vms->ub_cluster_mode = false; + vms->fm_deployment = false; +#endif + vms->irqmap = a15irqmap; virt_flash_create(vms); diff --git a/hw/ub/meson.build b/hw/ub/meson.build index 39fd4b7c776e0a40361ee741e9d21151589e1c87..e1146704e67aaebe746e7e0e9fbfbd3d5d3859e3 100644 --- a/hw/ub/meson.build +++ b/hw/ub/meson.build @@ -2,6 +2,7 @@ ub_ss = ss.source_set() ub_ss.add(files( 'ub.c', 'ub_ubc.c', + 'ub_acpi.c', )) system_ss.add_all(when: 'CONFIG_HW_UB', if_true: ub_ss) subdir('hisi') diff --git a/hw/ub/ub.c b/hw/ub/ub.c index 0c494fc9f9faf77c94b38fa59e19bb4160b8926d..974df5d0f7eede65af7a1c8564e4e246d40e97b6 100644 --- a/hw/ub/ub.c +++ b/hw/ub/ub.c @@ -28,6 +28,94 @@ #include "hw/ub/ub_ubc.h" #include "qemu/log.h" #include "qapi/error.h" +#include "hw/ub/ub_bus.h" +#include "hw/ub/ub_ubc.h" +#include "migration/vmstate.h" + + +QLIST_HEAD(, BusControllerState) ub_bus_controllers; + +static void ubbus_dev_print(Monitor *mon, DeviceState *dev, int indent) +{ +} + +static char *ubbus_get_dev_path(DeviceState *dev) +{ + return NULL; +} + +static char *ubbus_get_fw_dev_path(DeviceState *dev) +{ + return NULL; +} + +static const VMStateDescription vmstate_ubbus = { + .name = TYPE_UB_BUS, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void ub_bus_realize(BusState *qbus, Error **errp) +{ + UBBus *bus = UB_BUS(qbus); + + vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ubbus, bus); +} + +void ub_save_ubc_list(BusControllerState *s) +{ + QLIST_INSERT_HEAD(&ub_bus_controllers, s, node); +} + +static void ub_bus_unrealize(BusState *qbus) +{ + UBBus *bus = UB_BUS(qbus); + + vmstate_unregister(NULL, &vmstate_ubbus, bus); +} + +static void ubbus_reset(BusState *qbus) +{ +} + +UBBus *ub_register_root_bus(DeviceState *parent, const char *name, + MemoryRegion *io_mmio) +{ + UBBus *bus; + + bus = UB_BUS(qbus_new(TYPE_UB_BUS, parent, name)); + bus->address_space_mem = io_mmio; + + return bus; +} + +void ub_unregister_root_bus(UBBus *bus) +{ + qbus_unrealize(BUS(bus)); +} + +static void ub_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->print_dev = ubbus_dev_print; + k->get_dev_path = ubbus_get_dev_path; + k->get_fw_dev_path = ubbus_get_fw_dev_path; + k->realize = ub_bus_realize; + k->unrealize = ub_bus_unrealize; + k->reset = ubbus_reset; +} + +static const TypeInfo ub_bus_info = { + .name = TYPE_UB_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(UBBus), + .class_size = sizeof(UBBusClass), + .class_init = ub_bus_class_init, +}; static UBDevice *do_ub_register_device(UBDevice *ub_dev, const char *name, Error **errp) { @@ -101,6 +189,7 @@ static const TypeInfo ub_device_type_info = { static void ub_register_types(void) { + type_register_static(&ub_bus_info); type_register_static(&ub_device_type_info); } @@ -160,3 +249,17 @@ bool ub_device_get_guid_from_str(UbGuid *guid, char *guid_str) guid->seq_num = seq_num & 0xFFFFFFFFFFFFFFFF; return true; } + +/* container_of cannot be used here because 'bus' is a pointer member. */ +BusControllerState *container_of_ubbus(UBBus *bus) +{ + BusControllerState *ubc = NULL; + + QLIST_FOREACH(ubc, &ub_bus_controllers, node) { + if (bus == ubc->bus) { + return ubc; + } + } + + return NULL; +} \ No newline at end of file diff --git a/hw/ub/ub_acpi.c b/hw/ub/ub_acpi.c new file mode 100644 index 0000000000000000000000000000000000000000..f9e38a2da3db2a971907ed5169eb46c4123889e5 --- /dev/null +++ b/hw/ub/ub_acpi.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * 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 . + */ +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/cutils.h" +#include "qemu/units.h" +#include "hw/arm/virt.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/ub/ub.h" +#include "hw/ub/ub_bus.h" +#include "hw/ub/ub_ubc.h" +#include "hw/ub/ub_acpi.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qapi/util.h" +#include "qapi/qmp/qstring.h" +#include "hw/ub/ub_ummu.h" +#include "hw/ub/hisi/ub_mem.h" +#include "hw/ub/hisi/ub_fm.h" +#include "hw/ub/hisi/ubc.h" +#include "hw/acpi/aml-build.h" +#include "hw/ub/ub_common.h" +#define UBIOS_VERSION 1 +#define DTS_SIG_UBCTL "bus controller" +#define DTS_SIG_UMMU "ummu" +#define DTS_SIG_RSV_MEM "rsv_mem" + +static uint8_t gpa_bits; +void ub_set_gpa_bits(uint8_t bits) +{ + gpa_bits = bits; +} + +static void ub_init_table_header(DtsTableHeader *header, + const char *name, + uint32_t size, uint16_t version) +{ + strncpy(header->name, name, sizeof(header->name) - 1); + header->total_size = size; + header->version = version; + header->remain_size = 0; + qemu_log("%s total_size %u\n", name, size); +} + +static void ub_init_vendor_info(UbcVendorInfo *vendor_info, VirtMachineState *vms) +{ + uint16_t mar_id; + uint64_t base_reg = vms->memmap[VIRT_UBC_BASE_REG].base; + uint64_t addr_cc = vms->memmap[VIRT_UB_MEM_CC].base; + uint64_t addr_nc = vms->memmap[VIRT_UB_MEM_NC].base; + UbMemDecoderInfo *mem_info; + uint64_t local_reg_offset[] = { + BA0_OFFSET, + BA1_OFFSET, + BA2_OFFSET, + BA3_OFFSET, + BA4_OFFSET, + }; + uint64_t mar_space_size[] = { + UB_MEM_MAR0_SPACE_SIZE, + UB_MEM_MAR1_SPACE_SIZE, + UB_MEM_MAR2_SPACE_SIZE, + UB_MEM_MAR3_SPACE_SIZE, + UB_MEM_MAR4_SPACE_SIZE, + }; + + memset(vendor_info, 0, sizeof(UbcVendorInfo)); + vendor_info->ub_mem_ver = 0; + vendor_info->max_addr_bits = gpa_bits; + /* now only support one UBC */ + vendor_info->cmd_queue_base = vms->memmap[VIRT_UBC_BASE_REG].base + CMDQ_BASE_ADDR; + vendor_info->event_queue_base = vms->memmap[VIRT_UBC_BASE_REG].base + EVTQ_BASE_ADDR; + vendor_info->vendor_feature_sets = 0; + + for (mar_id = 0; mar_id < MAR_NUM_ONE_UDIE; mar_id++) { + mem_info = &vendor_info->mem_info[mar_id]; + mem_info->decode_addr = base_reg + local_reg_offset[mar_id] + MAR_OFFSET; + mem_info->cc_base_addr = mar_space_size[mar_id] ? + addr_cc >> MB_SIZE_OFFSET : 0; + mem_info->cc_base_size = mar_space_size[mar_id] >> MB_SIZE_OFFSET; + mem_info->nc_base_addr = mar_space_size[mar_id] ? + addr_nc >> MB_SIZE_OFFSET : 0; + mem_info->nc_base_size = mar_space_size[mar_id] >> MB_SIZE_OFFSET; + addr_cc += mar_space_size[mar_id]; + addr_nc += mar_space_size[mar_id]; + qemu_log("MAR%u decode_addr 0x%lx, cc ba 0x%x size 0x%x," + " nc ba 0x%x size 0x%x\n", + mar_id, mem_info->decode_addr, + mem_info->cc_base_addr, mem_info->cc_base_size, + mem_info->nc_base_addr, mem_info->nc_base_size); + } +} + +static void ub_init_ubc_node(uint16_t ubc_count, UbcNode *ubc, VirtMachineState *vms) +{ + uint16_t i; + uint64_t ub_mmio_addr = vms->memmap[VIRT_HIGH_UB_MMIO].base; + for (i = 0; i < ubc_count; i++) { + (ubc + i)->interrupt_id_start = UBC_INTERRUPT_ID_START + i * UBC_INTERRUPT_ID_CNT; + (ubc + i)->interrupt_id_end = (ubc + i)->interrupt_id_start + UBC_INTERRUPT_ID_CNT - 1; + (ubc + i)->gpa_base = ub_mmio_addr + i * UBIOS_MMIOS_SIZE_PER_UBC; + (ubc + i)->gpa_size = UBIOS_MMIOS_SIZE_PER_UBC; + (ubc + i)->memory_size_limit = gpa_bits; + (ubc + i)->dma_cca = 1; /* 1: DMA(Y) CCA(Y) */ + (ubc + i)->ummu_mapping = UBIOS_UMMU_TABLE_CNT ? 0 : 0xffff; + (ubc + i)->proximity_domain = 0; + (ubc + i)->msg_queue_base = vms->memmap[VIRT_UBC_BASE_REG].base + + UBC_MSGQ_REG_OFFSET; + (ubc + i)->msg_queue_size = UBC_MSGQ_REG_SIZE; + (ubc + i)->msg_queue_depth = HI_MSGQ_DEPTH; + (ubc + i)->msg_queue_interrupt = UBC_QUEUE_INTERRUPT_DEFAULT; + /* + * Interrupt attributes + * BIT0: Triggering + * ACPI_LEVEL_SENSITIVE 0x00 + * ACPI_EDGE_SENSITIVE 0x01 + * BIT1: Polarity + * ACPI_ACTIVE_HIGH 0x00 + * ACPI_ACTIVE_LOW 0x01 + */ + (ubc + i)->msg_queue_interrupt_attr = 0x0; + memset(&(ubc + i)->ubc_info, 0, sizeof(UbGuid)); + ub_init_vendor_info((UbcVendorInfo *)&(ubc + i)->vendor_info, vms); + qemu_log("init ubc_table[%d]=0x%lx, interrupt_id=[0x%x-0x%x]\n", + i, (ubc + i)->gpa_base, (ubc + i)->interrupt_id_start, + (ubc + i)->interrupt_id_end); + } +} + +static void ub_init_ubios_ubc_table(DtsSubUbcTable *ubc_table, VirtMachineState *vms) +{ + UbcNode *ubc = NULL; + + ubc_table->ubc_count = UBIOS_UBC_TABLE_CNT; + ub_init_table_header(&ubc_table->header, DTS_SIG_UBCTL, + UBIOS_UBC_TABLE_SIZE(ubc_table->ubc_count), + UBIOS_VERSION); + ubc_table->local_cna_start = LOCAL_CNA_START; + ubc_table->local_cna_end = LOCAL_CNA_END; + ubc_table->local_eid_start = LOCAL_EID_START; + ubc_table->local_eid_end = LOCAL_EID_END; + ubc_table->feature_set = 0; + /* ubc_table->cluster_mode + * System working mode + * 0: single-node system + * 1: cluster mode + */ + ubc_table->cluster_mode = vms->ub_cluster_mode; + qemu_log("init ub cluster mode %u\n", ubc_table->cluster_mode); + ubc = (UbcNode *)ubc_table->node; + ub_init_ubc_node(ubc_table->ubc_count, ubc, vms); +} + +static void ub_init_ummu_vendor_info(UbMemMmuInfo *vendor_info, VirtMachineState *vms) +{ + vendor_info->valid_bits = UB_MEM_VALID_VALUE; + vendor_info->protection_table_bits = 0xa; + vendor_info->translation_table_bits = 0x11; + vendor_info->ext_reg_base = (vms->memmap[VIRT_UBC_BASE_REG].base | UMMU_OFFSET | UB_MEM_REG_BASE); + vendor_info->ext_reg_size = UMMU_EXT_REG_SIZE; + qemu_log("ummu vendor info reg_base=0x%lx\n", vendor_info->ext_reg_base); +} + +static void ub_init_ubios_ummu_table(DtsSubUmmuTable *ummu_table, VirtMachineState *vms) +{ + uint16_t i; + UmmuNode *ummu = NULL; + UbMemMmuInfo *vendor_info = NULL; + + ummu_table->count = UBIOS_UMMU_TABLE_CNT; + ub_init_table_header(&ummu_table->header, DTS_SIG_UMMU, + UBIOS_UMMU_TABLE_SIZE(ummu_table->count), + UBIOS_VERSION); + ummu = (UmmuNode *)ummu_table->node; + for (i = 0; i < ummu_table->count; i++) { + (ummu + i)->base_addr = vms->memmap[VIRT_UBC_BASE_REG].base + UMMU_REG_OFFSET + + i * SINGLE_UMMU_REG_SIZE; + (ummu + i)->addr_size = UMMU_REG_SIZE; + (ummu + i)->interrupt_id = UMMU_INTERRUPT_ID; + (ummu + i)->proximity_domain = 0; + (ummu + i)->its_index = 0; + (ummu + i)->pmu_addr = (ummu + i)->base_addr + SINGLE_UMMU_REG_SIZE; + (ummu + i)->pmu_size = SINGLE_UMMU_PMU_REG_SIZE; + (ummu + i)->pmu_interrupt_id = UMMU_INTERRUPT_ID + 1; + (ummu + i)->min_tid = UMMU_RESERVED_TID_NUM + 1; + (ummu + i)->max_tid = 0xFFFFF; + (ummu + i)->vender_id = VENDER_ID_HUAWEI; + + vendor_info = (UbMemMmuInfo *)(ummu + i)->vender_info; + ub_init_ummu_vendor_info(vendor_info, vms); + qemu_log("init ummu_table[%d]=0x%lx,pmu_addr=0x%lx,pmu_size=0x%lx,pmu_interrupt_id=0x%x\n", + i, (ummu + i)->base_addr, (ummu + i)->pmu_addr, + (ummu + i)->pmu_size, (ummu + i)->pmu_interrupt_id); + } +} + +static void ub_init_ubios_rsv_mem_table(DtsRsvMemTable *rsv_mem_table, VirtMachineState *vms) +{ + MemRange *mem_range; + rsv_mem_table->count = UBIOS_UMMU_TABLE_CNT; + ub_init_table_header(&rsv_mem_table->header, DTS_SIG_RSV_MEM, + UBIOS_RSV_MEM_TABLE_SIZE(rsv_mem_table->count), + UBIOS_VERSION); + mem_range = (MemRange *)rsv_mem_table->node; + mem_range->flags = 0x1; /* direct mapping */ + memset(mem_range->reserved, 0, sizeof(mem_range->reserved)); + mem_range->base = 0x8000000; /* MSI_IOVA_BASE */ + mem_range->size = 0x100000; /* MSI_IOVA_LENGTH */ +} + +void ub_init_ubios_info_table(VirtMachineState *vms, uint64_t total_size) +{ + uint64_t ubios_info_tables = vms->memmap[VIRT_UBIOS_INFO_TABLE].base; + uint64_t ubc_tables_addr = ubios_info_tables + UBIOS_INFO_TABLE_SIZE; + uint64_t ummu_tables_addr; + uint64_t size = total_size; + DtsRootTable *ubios = (DtsRootTable *)cpu_physical_memory_map(ubios_info_tables, + &size, true); + DtsSubUbcTable *ubc_table = (DtsSubUbcTable *)(ubios + 1); + uint64_t ubc_table_size; + DtsSubUmmuTable *ummu_table; + uint64_t ummu_table_size; + uint64_t rsv_mem_tables_addr; + DtsRsvMemTable *rsv_mem_table; + + if (!ubios || size != total_size) { + if (ubios) { + cpu_physical_memory_unmap(ubios, size, true, size); + } + qemu_log("cpu_physical_memory_map failed, size %lu total %lu ptr %p\n", + size, total_size, ubios); + return; + } + qemu_log("ubios_info_tables=0x%lx, ubc_tables_addr=0x%lx," + "ubios table size=%lu, UBIOS_UBC_TABLE_CNT %u," + "UBIOS_UMMU_TABLE_CNT %u\n", + ubios_info_tables, ubc_tables_addr, total_size, + UBIOS_UBC_TABLE_CNT, UBIOS_UMMU_TABLE_CNT); + memset(ubios, 0, sizeof(DtsRootTable)); + ub_init_table_header(&ubios->header, "ubios root", + sizeof(DtsRootTable), UBIOS_VERSION); + /* init ubc table */ + ubios->tables[ubios->count] = ubc_tables_addr; + ub_init_ubios_ubc_table(ubc_table, vms); + qemu_log("ubc ubios->tables[%u] = 0x%lx ubc_table = 0x%lx \n", + ubios->count, ubc_tables_addr, (uint64_t)ubc_table); + ubios->count++; + ubc_table_size = UBIOS_UBC_TABLE_SIZE(ubc_table->ubc_count); + + /* init ummu table */ + ummu_tables_addr = ubc_tables_addr + ALIGN_UP(ubc_table_size, UB_ALIGNMENT); + ummu_table = (DtsSubUmmuTable *)((uint8_t *)(ubc_table) + + ALIGN_UP(ubc_table_size, UB_ALIGNMENT)); + ubios->tables[ubios->count] = ummu_tables_addr; + ub_init_ubios_ummu_table(ummu_table, vms); + qemu_log("ummu ubios->tables[%u] = 0x%lx ummu_table=0x%lx\n", + ubios->count, ummu_tables_addr, (uint64_t)ummu_table); + ubios->count++; + ummu_table_size = UBIOS_UMMU_TABLE_SIZE(UBIOS_UMMU_TABLE_CNT); + + /* init rsv mem table */ + rsv_mem_tables_addr = ummu_tables_addr + ALIGN_UP(ummu_table_size, UB_ALIGNMENT); + rsv_mem_table = (DtsRsvMemTable *)((uint8_t *)(ummu_table) + + ALIGN_UP(ummu_table_size, UB_ALIGNMENT)); + ubios->tables[ubios->count] = rsv_mem_tables_addr; + ub_init_ubios_rsv_mem_table(rsv_mem_table, vms); + ubios->count++; + + cpu_physical_memory_unmap(ubios, size, true, size); +} + +void ub_set_ubinfo_in_ubc_table(VirtMachineState *vms) +{ + uint64_t ubios_info_tables = vms->memmap[VIRT_UBIOS_INFO_TABLE].base; + uint64_t total_size = ROUND_UP(UBIOS_TABLE_SIZE, 4 * KiB); + uint64_t size = total_size; + UBBus *bus = vms->ub_bus; + + if (!bus) { + qemu_log("there is no ub bus\n"); + return; + } + + BusControllerState *ubc = container_of_ubbus(bus); + UbGuid guid = ubc->ubc_dev->parent.guid; + DtsRootTable *ubios = (DtsRootTable *)cpu_physical_memory_map(ubios_info_tables, + &size, true); + DtsSubUbcTable *ubc_table = (DtsSubUbcTable *)(ubios + 1); + UbcNode *ubc_node = (UbcNode *)ubc_table->node; + + if (!ubios || size != total_size) { + if (ubios) { + cpu_physical_memory_unmap(ubios, size, true, size); + } + qemu_log("cpu_physical_memory_map failed, size %lu total %lu ptr %p\n", + size, total_size, ubios); + return; + } + /* The virtual machine currently supports only one ub controller. */ + ubc_node->ubc_info = guid; + + cpu_physical_memory_unmap(ubios, size, true, size); +} + +void build_ubrt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +{ + /* 3 subtables: ubc, ummu, UB Reserved Memory */ + uint8_t table_cnt = 3; + uint64_t ubios_info_tables = vms->memmap[VIRT_UBIOS_INFO_TABLE].base; + uint64_t ubc_tables_addr = ubios_info_tables + UBIOS_INFO_TABLE_SIZE; + uint64_t ubc_table_size = UBIOS_UBC_TABLE_SIZE(UBIOS_UBC_TABLE_CNT); + uint64_t ummu_tables_addr = ubc_tables_addr + ALIGN_UP(ubc_table_size, UB_ALIGNMENT); + uint64_t ummu_table_size = UBIOS_UMMU_TABLE_SIZE(UBIOS_UMMU_TABLE_CNT); + uint64_t rsv_mem_tables_addr = ummu_tables_addr + ALIGN_UP(ummu_table_size, UB_ALIGNMENT); + AcpiTable table = { .sig = "UBRT", .rev = 0, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, table_cnt, 4); + + build_append_int_noprefix(table_data, ACPI_UB_TABLE_TYPE_BUS_CONTROLLER, 1); + build_append_int_noprefix(table_data, 0, 7); + build_append_int_noprefix(table_data, ubc_tables_addr, 8); + + build_append_int_noprefix(table_data, ACPI_UB_TABLE_TYPE_UMMU, 1); + build_append_int_noprefix(table_data, 0, 7); + build_append_int_noprefix(table_data, ummu_tables_addr, 8); + + build_append_int_noprefix(table_data, ACPI_UB_TABLE_TYPE_RSV_MEM, 1); + build_append_int_noprefix(table_data, 0, 7); + build_append_int_noprefix(table_data, rsv_mem_tables_addr, 8); + + acpi_table_end(linker, &table); + qemu_log("init UBRT: ubc_tbl=0x%lx, ummu_tbl=0x%lx, rsv_mem_tbl=0x%lx\n", + ubc_tables_addr, ummu_tables_addr, rsv_mem_tables_addr); +} + +void acpi_dsdt_add_ub(Aml *scope) +{ + Aml *dev_ubc = aml_device("UBC0"); + Aml *dev_ummu = aml_device("UMU0"); + Aml *dev_pmu = aml_device("PMU0"); + + aml_append(dev_ubc, aml_name_decl("_HID", aml_string("HISI0541"))); + aml_append(dev_ubc, aml_name_decl("_UID", aml_int(0))); + aml_append(scope, dev_ubc); + + aml_append(dev_ummu, aml_name_decl("_HID", aml_string("HISI0551"))); + aml_append(dev_ummu, aml_name_decl("_UID", aml_int(0))); + aml_append(scope, dev_ummu); + + aml_append(dev_pmu, aml_name_decl("_HID", aml_string("HISI0571"))); + aml_append(dev_pmu, aml_name_decl("_UID", aml_int(0))); + aml_append(scope, dev_pmu); +} + +void acpi_iort_add_ub(GArray *table_data) +{ + char name_ubc[11] = "\\_SB_.UBC0"; + char name_ummu[11] = "\\_SB_.UMU0"; + char name_pmu[11] = "\\_SB_.PMU0"; + int name_ubc_len = sizeof(name_ubc); + int name_ummu_len = sizeof(name_ummu); + int name_pmu_len = sizeof(name_pmu); + + /* Table 16 UBC */ + build_append_int_noprefix(table_data, 1 /* Named component */, 1); /* Type */ + build_append_int_noprefix(table_data, 0x40, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 1); /* Revision */ + build_append_int_noprefix(table_data, 0, 4); /* Identifier */ + build_append_int_noprefix(table_data, 1, 4); /* Number of ID mappings */ + build_append_int_noprefix(table_data, 0x2c, 4); /* Reference to ID Array */ + /* Named component specific data */ + build_append_int_noprefix(table_data, 0, 4); /* Node Flags */ + build_append_int_noprefix(table_data, 0, 4); /* Memory access properties: Cache Coherency */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Hints */ + build_append_int_noprefix(table_data, 0, 2); /* Memory access properties: Reserved */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Memory Flags */ + build_append_int_noprefix(table_data, 0, 1); /* Memory Size Limit */ + g_array_append_vals(table_data, name_ubc, name_ubc_len); /* Device object name */ + build_append_int_noprefix(table_data, 0, 4); /* Padding */ + build_append_int_noprefix(table_data, 0, 4); /* Input base */ + build_append_int_noprefix(table_data, 1, 4); /* Number of IDs */ + build_append_int_noprefix(table_data, UBC_INTERRUPT_ID_START, 4); /* Output base */ + build_append_int_noprefix(table_data, 0x30, 4); /* Output Reference */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ + + /* Table 16 UMMU */ + build_append_int_noprefix(table_data, 1 /* Named component */, 1); /* Type */ + build_append_int_noprefix(table_data, 0x40, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 1); /* Revision */ + build_append_int_noprefix(table_data, 0, 4); /* Identifier */ + build_append_int_noprefix(table_data, 1, 4); /* Number of ID mappings */ + build_append_int_noprefix(table_data, 0x2c, 4); /* Reference to ID Array */ + /* Named component specific data */ + build_append_int_noprefix(table_data, 0, 4); /* Node Flags */ + build_append_int_noprefix(table_data, 0, 4); /* Memory access properties: Cache Coherency */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Hints */ + build_append_int_noprefix(table_data, 0, 2); /* Memory access properties: Reserved */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Memory Flags */ + build_append_int_noprefix(table_data, 0, 1); /* Memory Size Limit */ + g_array_append_vals(table_data, name_ummu, name_ummu_len); /* Device object name */ + build_append_int_noprefix(table_data, 0, 4); /* Padding */ + build_append_int_noprefix(table_data, 0, 4); /* Input base */ + build_append_int_noprefix(table_data, 1, 4); /* Number of IDs */ + build_append_int_noprefix(table_data, UMMU_INTERRUPT_ID, 4); /* Output base */ + build_append_int_noprefix(table_data, 0x30, 4); /* Output Reference */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ + + /* Table 16 PMU */ + build_append_int_noprefix(table_data, 1 /* Named component */, 1); /* Type */ + build_append_int_noprefix(table_data, 0x40, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 1); /* Revision */ + build_append_int_noprefix(table_data, 0, 4); /* Identifier */ + build_append_int_noprefix(table_data, 1, 4); /* Number of ID mappings */ + build_append_int_noprefix(table_data, 0x2c, 4); /* Reference to ID Array */ + /* Named component specific data */ + build_append_int_noprefix(table_data, 0, 4); /* Node Flags */ + build_append_int_noprefix(table_data, 0, 4); /* Memory access properties: Cache Coherency */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Hints */ + build_append_int_noprefix(table_data, 0, 2); /* Memory access properties: Reserved */ + build_append_int_noprefix(table_data, 0, 1); /* Memory access properties: Memory Flags */ + build_append_int_noprefix(table_data, 0, 1); /* Memory Size Limit */ + g_array_append_vals(table_data, name_pmu, name_pmu_len); /* Device object name */ + build_append_int_noprefix(table_data, 0, 4); /* Padding */ + build_append_int_noprefix(table_data, 0, 4); /* Input base */ + build_append_int_noprefix(table_data, 1, 4); /* Number of IDs */ + build_append_int_noprefix(table_data, UMMU_INTERRUPT_ID + 1, 4); /* Output base */ + build_append_int_noprefix(table_data, 0x30, 4); /* Output Reference */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ +} diff --git a/hw/ub/ub_ubc.c b/hw/ub/ub_ubc.c index a0bc907ec8011cc2aaaf04f160e595542f9c5b7d..e371f4f35a8b7dc57523e8f7175d05aa82299d81 100644 --- a/hw/ub/ub_ubc.c +++ b/hw/ub/ub_ubc.c @@ -123,6 +123,8 @@ static void ub_bus_controller_realize(DeviceState *dev, Error **errp) memory_region_init(&s->io_mmio, OBJECT(s), "UB_MMIO", UINT64_MAX); sysbus_init_mmio(sysdev, &s->io_mmio); + s->bus = ub_register_root_bus(dev, name, &s->io_mmio); + ub_save_ubc_list(s); g_free(name); } @@ -132,6 +134,7 @@ static void ub_bus_controller_unrealize(DeviceState *dev) SysBusDevice *sysdev = SYS_BUS_DEVICE(dev); g_free(sysdev->parent_obj.id); QLIST_REMOVE(s, node); + ub_unregister_root_bus(s->bus); ub_reg_free(dev); } @@ -162,6 +165,17 @@ const VMStateDescription vmstate_ub_bus_controller = { } }; +const VMStateDescription vmstate_ub_bus_controller_dev = { + .name = TYPE_BUS_CONTROLLER_DEV, + .needed = ub_bus_controller_needed, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + /* support migration later */ + VMSTATE_END_OF_LIST() + } +}; + static void ub_bus_controller_class_init(ObjectClass *class, void *data) { DeviceClass *dc = DEVICE_CLASS(class); @@ -191,8 +205,69 @@ static const TypeInfo ub_bus_controller_type_info = { .class_init = ub_bus_controller_class_init, }; +static bool ub_ubc_is_empty(UBBus *bus) +{ + UBDevice *dev; + QLIST_FOREACH(dev, &bus->devices, node) { + if (dev->dev_type == UB_TYPE_IBUS_CONTROLLER) { + return false; + } + } + return true; +} + +static void ub_bus_controller_dev_realize(UBDevice *dev, Error **errp) +{ + UBBus *bus = UB_BUS(qdev_get_parent_bus(DEVICE(dev))); + BusControllerState *ubc = container_of_ubbus(bus); + VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); + + vms->ub_bus = bus; + + if (!ub_ubc_is_empty(bus)) { + qemu_log("ubc realize repetitively\n"); + error_setg(errp, "ubc realize repetitively"); + return; + } + + ubc->ubc_dev = BUS_CONTROLLER_DEV(dev); + if (dev->guid.type != UB_GUID_TYPE_IBUS_CONTROLLER) { + qemu_log("%s device type set error, expect: %u, actual: %u\n", + dev->qdev.id, UB_GUID_TYPE_IBUS_CONTROLLER, dev->guid.type); + error_setg(errp, "%s device type set error, expect: %u, actual: %u\n", + dev->qdev.id, UB_GUID_TYPE_IBUS_CONTROLLER, dev->guid.type); + return; + } + + dev->dev_type = UB_TYPE_IBUS_CONTROLLER; +} + +static Property ub_bus_controller_dev_properties[] = { + DEFINE_PROP_UB_DEV_GUID("bus_instance_guid", BusControllerDev, bus_instance_guid), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ub_bus_controller_dev_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + UBDeviceClass *uc = UB_DEVICE_CLASS(class); + + device_class_set_props(dc, ub_bus_controller_dev_properties); + uc->realize = ub_bus_controller_dev_realize; + dc->vmsd = &vmstate_ub_bus_controller_dev; +} + +static const TypeInfo ub_bus_controller_dev_type_info = { + .name = TYPE_BUS_CONTROLLER_DEV, + .parent = TYPE_UB_DEVICE, + .instance_size = sizeof(BusControllerDev), + .class_size = sizeof(BusControllerDevClass), + .class_init = ub_bus_controller_dev_class_init, +}; + static void ub_bus_controller_register_types(void) { type_register_static(&ub_bus_controller_type_info); + type_register_static(&ub_bus_controller_dev_type_info); } type_init(ub_bus_controller_register_types) diff --git a/include/exec/memory.h b/include/exec/memory.h index c5edf864e1131d8eb06eb66187620033ce8654e9..89d676e049fee38cf5c765ec232f671c8f637069 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -269,6 +269,12 @@ extern uint64_t virtcca_cvm_gpa_start; extern uint64_t virtcca_cvm_ram_size; +void memory_region_add_reservation_with_ram(MemoryRegion *mr, + Object *owner, + const char *name, + hwaddr offset, + uint64_t size); + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, IOMMUNotifierFlag flags, hwaddr start, hwaddr end, diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index fee7c27e0c18c8810b6f86179d56d4ad4a52813c..7f0d3ed39d2209a6977f74a80eaadf906750b23a 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -39,6 +39,7 @@ #include "sysemu/kvm.h" #include "hw/intc/arm_gicv3_common.h" #include "qom/object.h" +#include "hw/ub/ub_bus.h" #define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 @@ -154,6 +155,14 @@ enum { VIRT_HIGH_GIC_REDIST2 = VIRT_LOWMEMMAP_LAST, VIRT_HIGH_PCIE_ECAM, VIRT_HIGH_PCIE_MMIO, +#ifdef CONFIG_UB + VIRT_HIGH_UB_MMIO, + VIRT_UB_IDEV_ERS, + VIRT_UBC_BASE_REG, + VIRT_UBIOS_INFO_TABLE, + VIRT_UB_MEM_CC, + VIRT_UB_MEM_NC, +#endif // CONFIG_UB }; typedef enum VirtIOMMUType { @@ -219,6 +228,18 @@ struct VirtMachineState { bool highmem_ecam; bool highmem_mmio; bool highmem_redists; +#ifdef CONFIG_UB + bool highmem_ub_mmio; + bool highmem_idev_ers; + bool highmem_ubc_base_reg; + bool highmem_ubios_info_table; + bool highmem_ub_mem_cc; + bool highmem_ub_mem_nc; + bool ummu; + bool ub_cluster_mode; + bool fm_deployment; + UBBus *ub_bus; +#endif // CONFIG_UB bool its; bool tcg_its; bool virt; diff --git a/include/hw/ub/hisi/ub_mem.h b/include/hw/ub/hisi/ub_mem.h new file mode 100644 index 0000000000000000000000000000000000000000..aaf30322c5ab7e39f8e36180fbbebbc69f8429f7 --- /dev/null +++ b/include/hw/ub/hisi/ub_mem.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * 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 . + */ + +#ifndef HW_UB_MEM_H +#define HW_UB_MEM_H + +/* + * + * +---------------------------------------------------------+ + * | CPU Die | + * | +-------------+-------------+---------------+ | + * | | A | B | C | AddrSpace| + * |__+-/-----------+-----------\-+--------------\+ _________| + * / \ \ + * +-----------------/---------------------------\----------------\-------------+ + * | +-------------/ +-----------+ +-----------+ \------------+ +-\----------+ | + * | | MAR0(Master)| |MAR0(Slave)| |MAR1(Slave)| |MAR1(Master)| |MAR2(Master)| | + * | +-------------+ +-----------+ +-----------+ +------------+ +------------+ | + * | +---------------------------+ +--------------------------+ +------------+ | + * | | MAR0 | | MAR1 | | MAR2 | | + * | | +-----------+ +---------+ | | +---------+ +----------+ | | +--------+ | | + * | | | NL0 | | NL1 | | | | NL2 | | NL3 | | | | NL4 | | | + * | | +-----------+ +---------+ | | +---------+ +----------+ | | +--------+ | | + * | | +----+ +----+ +---+ +---+ | | +---+ +---+ +---+ +----+ | | +--------+ | | + * | | | | | | | | | | | | | | | | | | | | | | | | | | + * | | +----+ +----+ +---+ +---+ | | +---+ +---+ +---+ +----+ | | +--------+ | | + * +----------------------------------------------------------------------------+ +*/ +#define MAR_NUM_ONE_UDIE 5 +#define DECODER0_MARID 0 +#define DECODER_SLAVE_MARID0 1 +#define DECODER_SLAVE_MARID1 2 +#define DECODER1_MARID 3 +#define DECODER2_MARID 4 +#define MB_SIZE_OFFSET 20 +#define UB_MEM_MAR0_SPACE_SIZE (512 * GiB) +#define UB_MEM_MAR1_SPACE_SIZE (0) +#define UB_MEM_MAR2_SPACE_SIZE (0) +#define UB_MEM_MAR3_SPACE_SIZE (512 * GiB) +#define UB_MEM_MAR4_SPACE_SIZE (1024 * GiB) +#define UB_MEM_SPACE_SIZE (UB_MEM_MAR0_SPACE_SIZE + \ + UB_MEM_MAR1_SPACE_SIZE + \ + UB_MEM_MAR2_SPACE_SIZE + \ + UB_MEM_MAR3_SPACE_SIZE + \ + UB_MEM_MAR4_SPACE_SIZE) +#define UB_MEM_REG_SHIFT 16 +#define UMMU_EXT_REG_SIZE 0x100 +#define UB_MEM_VALID_VALUE 0 +#define UB_MEM_VALID_MASK GENMASK_ULL(2, 0) +#define UB_MEM_REG_BASE 0x800000 +#define UMMU_MEM_START_ADDR 0x0 +#define START_PTE_ADDR_MASK GENMASK(26, 0) +#define START_ATE_ADDR_MASK GENMASK(22, 0) +#define UMMU_MEM_LEN_GRANU 0x4 +#define MEM_GRANU_MASK GENMASK(19, 17) +#define MEM_GRANU_SHIFT 17 +#define MEM_LEN_MASK GENMASK(16, 0) +#define UMMU_MEM_BTE 0x8 +#define MEM_BTE_MASK GENMASK(16, 0) +#define UMMU_MEM_INDEX 0xC +#define MEM_INDEX_RSV_MASK GENMASK(31, 20) +#define MEM_WR_MASK (1UL << 19) +#define MEM_TYPE_MASK (1UL << 18) +#define MEM_VLD_MASK (1UL << 17) +#define MEM_PTE_INDEX_MASK GENMASK(9, 0) +#define MEM_ATE_INDEX_MASK GENMASK(16, 0) +#define UMMU_MEM_DTLB_INVLD 0x10 +#define MEM_DTLB_INVLD_MASK (1UL) +typedef struct UbMemMmuInfo { + /* valid bits + * bit0: protection_table_bits + * bit1: translation_table_bits + * bit2: ummu_reg_addr_bits + * other reserved + */ + uint64_t valid_bits; + uint32_t protection_table_bits; + uint32_t translation_table_bits; + uint64_t ext_reg_base; + uint64_t ext_reg_size; + uint8_t reserved[48]; +} UbMemMmuInfo; + +typedef struct UbMemDecoderInfo { + uint64_t decode_addr; + uint32_t cc_base_addr; + uint32_t cc_base_size; + uint32_t nc_base_addr; + uint32_t nc_base_size; +} UbMemDecoderInfo; + +typedef struct UbcVendorInfo { + uint32_t ub_mem_ver; + uint8_t max_addr_bits; + uint8_t reserved1[3]; + UbMemDecoderInfo mem_info[MAR_NUM_ONE_UDIE]; + uint64_t cmd_queue_base; /* IO Decoder CMD queue */ + uint64_t event_queue_base; /* IO Decoder Event queue */ + uint8_t vendor_feature_sets; /* bit0: management plane deployment 0(enable) 1(disable) */ + uint8_t reserved2[111]; +} UbcVendorInfo; + +/* hisi memory */ +typedef struct UbMemBlockHw { + /* DW0 */ + uint32_t valid : 1; + uint32_t mem_base : 9; + uint32_t mem_limit : 9; + uint32_t one_path : 1; + uint32_t wr_delay_comp : 1; + uint32_t reduce_delay_comp : 1; + uint32_t cmo_delay_comp : 1; + uint32_t so : 1; + uint32_t lb_0 : 8; + /* DW1 */ + uint32_t token_id0 : 20; + uint32_t dcna0_l : 12; + /* DW2 */ + uint32_t dcna0_h : 4; + uint32_t uba_base0_l : 28; + /* DW3 */ + uint32_t uba_base0_h : 15; + uint32_t pa_0 : 1; + uint32_t rsv : 16; +} UbMemBlockHw; + +#define MAX_BLOCKS 4 +typedef struct UbMemPageEntry { + UbMemBlockHw blocks[MAX_BLOCKS]; +} UbMemPageEntry; + +typedef enum UbMemEntryGranule { + GRANULE_1GB = 0, + GRANULE_2GB = 1, + GRANULE_4GB = 2, + GRANULE_8GB = 3, + GRANULE_16GB = 4, + GRANULE_32GB = 5, + GRANULE_64GB = 6, + GRANULE_128GB = 7, + GRANULE_256GB = 8, + GRANULE_512GB = 9, + GRANULE_1TB = 10, +} UbMemEntryGranule; +#endif diff --git a/include/hw/ub/hisi/ubc.h b/include/hw/ub/hisi/ubc.h index fdaeae7b3e2ecc43b5b9300fbfe316cfa7d60284..c34693accbad367f63c00ee63f201685f6efe9f1 100644 --- a/include/hw/ub/hisi/ubc.h +++ b/include/hw/ub/hisi/ubc.h @@ -45,4 +45,143 @@ #define UBC_INTERRUPT_ID_CNT 0x1000 #define VENDER_ID_HUAWEI 0xCC08 +/* + * Local Register layout + * + * +-----------------------------+ + * | rsv 15M | + * +-----------------------------+ + * | 16th 1M CCUM | + * +-----------------------------+ 0xf00_0000 + * | 15th 16M UMMU | + * +-----------------------------+ 0xe00_0000 + * | 14th 16M NL4 | + * +-----------------------------+ 0xd00_0000 + * | 13th 16M BA4 | + * +-----------------------------+ 0xc00_0000 + * | 12th 16M NL3 | + * +-----------------------------+ 0xb00_0000 + * | 11th 16M BA3 | + * +-----------------------------+ 0xa00_0000 + * | 10th 16M NL2 | + * +-----------------------------+ 0x900_0000 + * | 9th 16M BA2 | + * +-----------------------------+ 0x800_000 + * | 8th 16M NL1 | + * +-----------------------------+ 0x700_0000 + * | 7th 16M BA1 | + * +-----------------------------+ 0x600_0000 + * | 6th 16M NL0 | + * +-----------------------------+ 0x500_0000 + * | 5th 16M TA | + * +-----------------------------+ 0x400_0000 + * | 4th 16M BA0 | + * +-----------------------------+ 0x300_0000 + * | 3th 16M TP | + * +-----------------------------+ 0x200_0000 + * | 2rd 16M MISC | + * +-----------------------------+ 0x100_0000 + * | 1st 16M | + * +-----------------------------+ 0x000_0000 + */ +#define FST_OFFSET 0x0000000 +#define MISC_OFFSET 0x1000000 +#define TP_OFFSET 0x2000000 +#define BA0_OFFSET 0x3000000 +#define TA_OFFSET 0x4000000 +#define NL0_OFFSET 0x5000000 +#define BA1_OFFSET 0x6000000 +#define NL1_OFFSET 0x7000000 +#define BA2_OFFSET 0x8000000 +#define NL2_OFFSET 0x9000000 +#define BA3_OFFSET 0xa000000 +#define NL3_OFFSET 0xb000000 +#define BA4_OFFSET 0xc000000 +#define NL4_OFFSET 0xd000000 +#define UMMU_OFFSET 0xe000000 +#define CCUM_OFFSET 0xf000000 +#define LOCAL_REG_TYPE_SHIFT 24 +#define LOCAL_REG_TYPE_MASK GENMASK_ULL(27, 24) +#define LOCAL_REG_MEMBER_MASK GENMASK_ULL(23, 0) +#define LOCAL_REG_ADDR_2_TYPE(addr) (((addr) & LOCAL_REG_TYPE_MASK) >> LOCAL_REG_TYPE_SHIFT) +#define BA_REG_MEMBER_MASK GENMASK_ULL(19, 16) +#define BA_REG_DATA_MASK GENMASK_ULL(15, 0) +#define TOP_REG_OFFSET (0x00 * 64 * KiB) +#define RXDMA_OFFSET (0x01 * 64 * KiB) +#define TXDMA_OFFSET (0x02 * 64 * KiB) +#define MASTER_OFFSET (0x03 * 64 * KiB) +#define LSAD_OFFSET (0x04 * 64 * KiB) +#define SMAP_OFFSET (0x0a * 64 * KiB) +#define P2P_OFFSET (0x0c * 64 * KiB) +#define MAR_OFFSET (0x0d * 64 * KiB) +#define MAR_DECODE_OFFSET (0x0e * 64 * KiB) /* mem decoder table */ +#define UB_RAS_OFFSET (0x12 * 64 * KiB) +#define CCUA_OFFSET (0x14 * 64 * KiB) + +/* references LinQuickCV100_UBOMMU_nManager */ +#define TP_UBOMMU0_OFFSET 0x180000 +#define TP_UBOMMU1_OFFSET 0x190000 +#define TP_UBOMMU2_OFFSET 0x1c0000 +#define TP_UBOMMU3_OFFSET 0x1d0000 +#define TP_UBOMMU4_OFFSET 0x1e0000 +#define TP_UBOMMU5_OFFSET 0x1f0000 +#define TP_UBOMMU0_SELF_REG_OFFSET 0 +#define TP_UBOMMU0_PMCG_OFFSET 0x3000 +#define TP_UBOMMU0_PROTOCOL_OFFSET 0x4000 +#define TP_UBOMMU0_CMDQ_OFFSET 0xc000 +#define TP_UBOMMU0_EVENTQ_OFFSET 0xe000 +#define SELF_ICG_CFG_OFFSET 0x0 +#define UBOMMU_MEM_INIT_OFFSET 0x1804 +#define DECODER_REG_BASE (TP_OFFSET + TP_UBOMMU0_OFFSET + \ + TP_UBOMMU0_SELF_REG_OFFSET) /* 0x2180000 */ +#define CMDQ_BASE_ADDR (TP_OFFSET + TP_UBOMMU0_OFFSET + \ + TP_UBOMMU0_CMDQ_OFFSET) /* 0x218c000 */ +#define EVTQ_BASE_ADDR (TP_OFFSET + TP_UBOMMU0_OFFSET + \ + TP_UBOMMU0_EVENTQ_OFFSET) /* 0x218e000 */ + +#define DECODER_SELF_ICG_CFG_OFFSET (DECODER_REG_BASE + \ + SELF_ICG_CFG_OFFSET) /* 0x2180000 */ +#define DECODER_SELF_MEM_INIT_OFFSET (DECODER_REG_BASE + \ + UBOMMU_MEM_INIT_OFFSET) /* 0x2181804 */ +#define DECODER_MEM_INIT_DONE_VAL 0x3F +#define DECODER_MEM_INIT_DONE_SHIFT 16 + +#define SQ_ADDR_L 0x0 +#define SQ_ADDR_H 0x4 +#define SQ_PI 0x8 +#define SQ_CI 0xc +#define SQ_DEPTH 0x10 +#define SQ_STATUS 0x14 +#define RQ_ADDR_L 0x40 +#define RQ_ADDR_H 0x44 +#define RQ_PI 0x48 +#define RQ_CI 0x4c +#define RQ_DEPTH 0x50 +#define RQ_ENTRY_SIZE 0x54 +#define RQ_STATUS 0x58 +#define CQ_ADDR_L 0x70 +#define CQ_ADDR_H 0x74 +#define CQ_PI 0x78 +#define CQ_CI 0x7c +#define CQ_DEPTH 0x80 +#define CQ_STATUS 0x84 +#define CQ_INT_MASK 0x88 +#define CQ_INT_STATUS 0x8c +#define CQ_INT_RO 0x90 +#define CQ_INT_SET 0x94 +#define MSGQ_RST 0xB0 + +#define HI_MSG_SQE_PLD_SIZE 0x800 /* 2K */ +#define HI_MSG_RQE_SIZE 0x800 /* 2K */ +#define HI_MSGQ_DEPTH 16 +#define HI_SQ_CFG_DEPTH HI_MSGQ_DEPTH +#define HI_RQ_CFG_DEPTH HI_MSGQ_DEPTH +#define HI_CQ_CFG_DEPTH HI_MSGQ_DEPTH +#define HI_FM_MSG_ID_MIN 128 +#define HI_FM_MSG_ID_MAX 191 +#define MAP_COMMAND_MASK 0xff +#define HI_FM_MSG_MAX (HI_SQ_CFG_DEPTH - 1) +#define HI_MSGQ_MAX_DEPTH 1024 +#define HI_MSGQ_MIN_DEPTH 4 + #endif diff --git a/include/hw/ub/ub_acpi.h b/include/hw/ub/ub_acpi.h new file mode 100644 index 0000000000000000000000000000000000000000..3579256444cbcf0c0061c8a99d3f81ea1bdbe28c --- /dev/null +++ b/include/hw/ub/ub_acpi.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * 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 . + */ + +#ifndef HW_UB_ACPI_H +#define HW_UB_ACPI_H +#include "hw/arm/virt.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/utils.h" +#include "hw/ub/ub.h" + +#define DTS_TABLE_HEADER_RESERVE_LEN 3 +#define DTS_ROOT_TABLE_RESERVE_LEN 6 +#define DTS_TABLE_HEADER_NAME_LEN 16 +/* ummu reserved tid num , don't modify */ +#define UMMU_RESERVED_TID_NUM 64 +typedef struct DtsTableHeader { + char name[DTS_TABLE_HEADER_NAME_LEN]; + uint32_t total_size; + uint8_t version; + uint8_t reserved[DTS_TABLE_HEADER_RESERVE_LEN]; + uint32_t remain_size; + uint32_t checksum; +} DtsTableHeader; + +/* DTS UBIOS INFO TABLE */ +typedef struct DtsRootTable { + DtsTableHeader header; + uint16_t count; + uint8_t reserved[DTS_ROOT_TABLE_RESERVE_LEN]; + uint64_t tables[3]; +} DtsRootTable; + +#define UBC_QUEUE_INTERRUPT_DEFAULT 443 + +#define UBC_VENDOR_INFO_LEN 256 +/* ub controller block */ +typedef struct UbcNode { + uint32_t interrupt_id_start; + uint32_t interrupt_id_end; + uint64_t gpa_base; + uint64_t gpa_size; + uint8_t memory_size_limit; + uint8_t dma_cca; /* 0: DMA(y) CCA(N) ; 1: DMA(Y) CCA(Y); other: DMA(N) */ + uint16_t ummu_mapping; + uint16_t proximity_domain; + uint8_t reserved1[2]; + uint64_t msg_queue_base; + uint64_t msg_queue_size; + uint16_t msg_queue_depth; + uint16_t msg_queue_interrupt; + uint8_t msg_queue_interrupt_attr; + uint8_t reserved2[59]; + UbGuid ubc_info; /* UB controller's GUID */ + uint8_t vendor_info[UBC_VENDOR_INFO_LEN]; /* vendor private info */ +} UbcNode; + +#define UMMU_VEND_LEN 80 +typedef struct UmmuNode { + uint64_t base_addr; + uint64_t addr_size; + uint32_t interrupt_id; + uint16_t proximity_domain; + uint16_t its_index; + uint64_t pmu_addr; + uint64_t pmu_size; + uint32_t pmu_interrupt_id; + uint32_t min_tid; + uint32_t max_tid; + uint8_t reserved2[26]; + uint16_t vender_id; + uint8_t vender_info[UMMU_VEND_LEN]; +} UmmuNode; + +/* UMMU table */ +typedef struct DtsSubUmmuTable { + DtsTableHeader header; + uint32_t count; + uint32_t flag; + UmmuNode node[0]; +} DtsSubUmmuTable; + +#define LOCAL_CNA_START 1 +#define LOCAL_CNA_END 65535 +#define LOCAL_EID_START 1 +#define LOCAL_EID_END 65535 + +/* UB Controller table */ +typedef struct DtsSubUbcTable { + DtsTableHeader header; + uint32_t local_cna_start; + uint32_t local_cna_end; + uint32_t local_eid_start; + uint32_t local_eid_end; + uint8_t feature_set; + uint8_t reserved[3]; + uint16_t cluster_mode; + uint16_t ubc_count; + UbcNode node[0]; +} DtsSubUbcTable; + +typedef struct MemRange { + uint8_t flags; + uint8_t reserved[7]; + uint64_t base; + uint64_t size; +} MemRange; +/* UB Reserved Memory table */ +typedef struct DtsRsvMemTable { + DtsTableHeader header; + uint16_t count; + uint8_t reserved[6]; + MemRange node[0]; +} DtsRsvMemTable; + +/* UBRT subtable */ +typedef struct UbrtSubtable { + uint8_t type; + uint8_t reserved[7]; + uint64_t pointer; +} UbrtSubtable; + +typedef struct acpi_table_header { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table_id[8]; + uint32_t oem_revision; + char asl_compiler_id[4]; + uint32_t asl_compiler_revision; +} ACPI_TABLE_HEADER; + +/* UBRT table */ +typedef struct AcpiUbrtTable { + ACPI_TABLE_HEADER header; + uint32_t count; + UbrtSubtable subtables[]; +} AcpiUbrtTable; +#define ACPI_UB_TABLE_TYPE_BUS_CONTROLLER 0 +#define ACPI_UB_TABLE_TYPE_UMMU 1 +#define ACPI_UB_TABLE_TYPE_RSV_MEM 2 +#define ACPI_UB_TABLE_TYPE_VIRTUAL_BUS 3 +#define ACPI_UB_TABLE_TYPE_CALL_ID_SERVICE 4 +#define ACPI_UB_TABLE_TYPE_DEVICE 5 +#define ACPI_UB_TABLE_TYPE_TOPOLOGY 6 + +#define UBIOS_UBC_TABLE_CNT 1 +#define UBIOS_UMMU_TABLE_CNT 1 +#define UBIOS_MMIOS_SIZE_PER_UBC (512 * GiB) +#define UBIOS_INFO_TABLE_SIZE (sizeof(DtsRootTable)) +#define UBIOS_UBC_TABLE_SIZE(cnt) (sizeof(DtsSubUbcTable) + (cnt) * sizeof(UbcNode)) +#define UBIOS_UMMU_TABLE_SIZE(cnt) (sizeof(DtsSubUmmuTable) + (cnt) * sizeof(UmmuNode)) +#define UBIOS_RSV_MEM_TABLE_SIZE(cnt) (sizeof(DtsRsvMemTable) + (cnt) * sizeof(MemRange)) + +#define UBIOS_TABLE_SIZE (UBIOS_INFO_TABLE_SIZE + \ + UBIOS_UBC_TABLE_SIZE(UBIOS_UBC_TABLE_CNT) + \ + UBIOS_UMMU_TABLE_SIZE(UBIOS_UMMU_TABLE_CNT) + \ + UBIOS_RSV_MEM_TABLE_SIZE(UBIOS_UMMU_TABLE_CNT)) + +void ub_init_ubios_info_table(VirtMachineState *vms, uint64_t total_size); +void ub_set_gpa_bits(uint8_t bits); +void build_ubrt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms); +void ub_set_ubinfo_in_ubc_table(VirtMachineState *vms); +void acpi_dsdt_add_ub(Aml *scope); +void acpi_iort_add_ub(GArray *table_data); +#endif \ No newline at end of file diff --git a/include/hw/ub/ub_bus.h b/include/hw/ub/ub_bus.h index ef78305cb08082bf1dfa3fe766852d2528d38b98..4fbc9407d552eab3c271b94cdc664cca30ed154d 100644 --- a/include/hw/ub/ub_bus.h +++ b/include/hw/ub/ub_bus.h @@ -36,4 +36,12 @@ struct UBBus { #define TYPE_UB_BUS "UB_BUS" OBJECT_DECLARE_TYPE(UBBus, UBBusClass, UB_BUS) +UBBus *ub_register_root_bus(DeviceState *parent, const char *name, + MemoryRegion *io_mmio); +void ub_unregister_root_bus(UBBus *bus); +UBDevice *ub_find_device_by_eid(UBBus *bus, uint32_t eid); +static inline UBBus *ub_get_bus(const UBDevice *dev) +{ + return UB_BUS(qdev_get_parent_bus(DEVICE(dev))); +} #endif diff --git a/include/hw/ub/ub_common.h b/include/hw/ub/ub_common.h index d52dc7e6514e77b08e57c040784e4dac26d3414c..1336ea3ed35454d8aebcaa29442a7548aef61a43 100644 --- a/include/hw/ub/ub_common.h +++ b/include/hw/ub/ub_common.h @@ -285,4 +285,34 @@ #define LOOP_HELPER(macro, n) LOOP##n(macro) #define LOOP(macro, n) LOOP_HELPER(macro, n) +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +#define for_each_set_bit_from(bit, addr, size) \ + for ((bit) = find_next_bit((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +#define EID_HIGH(eid) (((eid) >> 12) & 0xff) +#define EID_LOW(eid) ((eid) & 0xfff) +#define EID_GEN(eid_h, eid_l) ((eid_h) << 12 | (eid_l)) + +#define UB_ALIGNMENT 64 + +/* Round number down to multiple */ +#define ALIGN_DOWN(n, m) ((n) / (m) * (m)) + +/* Round number up to multiple */ +#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m)) +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +#define BITS_PER_LONG_LONG 64 +#define GENMASK_ULL(h, l) \ + (((~0ULL) - (1ULL << (l)) + 1) & \ + (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) +#define DASH_SZ 3 + #endif diff --git a/include/hw/ub/ub_ubc.h b/include/hw/ub/ub_ubc.h index 5e791fbcf310b151825e21136ec9f19eb6ece527..af0f4b1a7fec3cc8242f72b2b3a3177561f90fd5 100644 --- a/include/hw/ub/ub_ubc.h +++ b/include/hw/ub/ub_ubc.h @@ -20,6 +20,21 @@ #include "hw/sysbus.h" #include "qom/object.h" +#include "hw/ub/hisi/ubc.h" +#include "hw/ub/ub_bus.h" + +#define TYPE_BUS_CONTROLLER_DEV "ubc" +OBJECT_DECLARE_TYPE(BusControllerDev, BusControllerDevClass, BUS_CONTROLLER_DEV) + +typedef struct BusControllerDev { + UBDevice parent; + UbGuid bus_instance_guid; + int bus_instance_lock_fd; +} BusControllerDev; + +struct BusControllerDevClass { + UBDeviceClass parent_class; +}; #define TYPE_BUS_CONTROLLER "ub-bus-controller" OBJECT_DECLARE_TYPE(BusControllerState, BusControllerClass, BUS_CONTROLLER) @@ -37,6 +52,8 @@ struct BusControllerState { MemoryRegion io_mmio; /* ub mmio hpa memory region */ uint32_t mmio_size; bool mig_enabled; + BusControllerDev *ubc_dev; + UBBus *bus; QLIST_ENTRY(BusControllerState) node; }; @@ -44,4 +61,6 @@ struct BusControllerClass { SysBusDeviceClass parent_class; }; +void ub_save_ubc_list(BusControllerState *s); +BusControllerState *container_of_ubbus(UBBus *bus); #endif diff --git a/include/hw/ub/ub_ummu.h b/include/hw/ub/ub_ummu.h new file mode 100644 index 0000000000000000000000000000000000000000..f8b65a0bbe861af11f709e1b790c9fd5b4fdb30a --- /dev/null +++ b/include/hw/ub/ub_ummu.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * 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 . + */ + +#ifndef UB_UMMU_H +#define UB_UMMU_H + +#include "hw/sysbus.h" +#include "qom/object.h" +#include "hw/ub/hisi/ubc.h" +#include "hw/ub/ub_bus.h" +#include "hw/ub/ub_ubc.h" + +#define UMMU_INTERRUPT_ID 0x8989 // UMMU DEVICE ID need allocate later + +#endif diff --git a/system/memory.c b/system/memory.c index bf331d0e7ba93cc472cb77acfee778903f0c0a89..e663467aa02494b6c91746ab08c4eea2eb840a96 100644 --- a/system/memory.c +++ b/system/memory.c @@ -3727,6 +3727,26 @@ void memory_region_init_rom_device(MemoryRegion *mr, vmstate_register_ram(mr, owner_dev); } +void memory_region_add_reservation_with_ram(MemoryRegion *mr, + Object *owner, + const char *name, + hwaddr offset, + uint64_t size) +{ + Error *local_err = NULL; + uint32_t ram_flags = 0; + MemoryRegion *resved = g_malloc(sizeof(*resved)); + char *mrname = g_strdup_printf("%s-reservedmemory", name ? name : "(none)"); + + memory_region_init_ram_flags_nomigrate(resved, owner, mrname, size, ram_flags, &local_err); + + memory_region_add_subregion(mr, offset, resved); + g_free(mrname); + if (local_err) { + error_report_err(local_err); + } +} + /* * Support system builds with CONFIG_FUZZ using a weak symbol and a stub for * the fuzz_dma_read_cb callback diff --git a/tests/data/acpi/virt/DSDT b/tests/data/acpi/virt/DSDT index 404bc5ac2188d885e28b6c80d499193865cf1c9c..afa7f3b07da5ce6be2894bc70e3de114523591b2 100644 Binary files a/tests/data/acpi/virt/DSDT and b/tests/data/acpi/virt/DSDT differ diff --git a/tests/data/acpi/virt/DSDT.acpihmatvirt b/tests/data/acpi/virt/DSDT.acpihmatvirt index 5f9c0b2d3cdc55949c32d564c92309aa54529d8d..4500a1699b7f4e19b9dabd9d00d23029a793074d 100644 Binary files a/tests/data/acpi/virt/DSDT.acpihmatvirt and b/tests/data/acpi/virt/DSDT.acpihmatvirt differ diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp index d85565e3b7801de346e302e6e88bc76d88f33f27..abaa7a991b065b8d708dd37fbb37eccac509108e 100644 Binary files a/tests/data/acpi/virt/DSDT.memhp and b/tests/data/acpi/virt/DSDT.memhp differ diff --git a/tests/data/acpi/virt/DSDT.pxb b/tests/data/acpi/virt/DSDT.pxb index ccb43ab242521cdfc80f6d6b170d2e0818186632..430e9bde9817dfd8fc92b1fcd245c88584b82330 100644 Binary files a/tests/data/acpi/virt/DSDT.pxb and b/tests/data/acpi/virt/DSDT.pxb differ diff --git a/tests/data/acpi/virt/DSDT.topology b/tests/data/acpi/virt/DSDT.topology index 27fee07b86f6ab1b5672960b9e040fdc82185137..879719377d5a4ff2a517e81ff5b834af63f40c48 100644 Binary files a/tests/data/acpi/virt/DSDT.topology and b/tests/data/acpi/virt/DSDT.topology differ diff --git a/tests/data/acpi/virt/IORT b/tests/data/acpi/virt/IORT index 9f0958b3df5aa6b9c3092885f79a20d82da8f011..fff55657387637bb0a77f303a058fd7a9d987fac 100644 Binary files a/tests/data/acpi/virt/IORT and b/tests/data/acpi/virt/IORT differ diff --git a/tests/data/acpi/virt/UBRT b/tests/data/acpi/virt/UBRT new file mode 100644 index 0000000000000000000000000000000000000000..8314e7e8a31d07d87d810c5148bf2291360c5e21 Binary files /dev/null and b/tests/data/acpi/virt/UBRT differ