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