On Fri, 15 Mar 2019 at 11:08, Hongbo Zhang <hongbo.zh...@linaro.org> wrote: > > For the Aarch64, there is one machine 'virt', it is primarily meant to > run on KVM and execute virtualization workloads, but we need an > environment as faithful as possible to physical hardware, for supporting > firmware and OS development for pysical Aarch64 machines. > > This patch introduces new machine type 'sbsa-ref' with main features: > - Based on 'virt' machine type. > - A new memory map. > - CPU type cortex-a57. > - EL2 and EL3 are enabled. > - GIC version 3. > - System bus AHCI controller. > - System bus EHCI controller.
Hello Hongbo, Apologies for bringing this up now, but I seem to remember that the EHCI does not support 64-bit DMA. Did you run into any issues with this? Or was this fixed in QEMU in the mean time? > - CDROM and hard disc on AHCI bus. > - E1000E ethernet card on PCIE bus. > - VGA display adaptor on PCIE bus. > - No virtio deivces. > - No fw_cfg device. > - No ACPI table supplied. > - Only minimal device tree nodes. > > Arm Trusted Firmware and UEFI porting to this are done accordingly, and > it should supply ACPI tables to load OS, the minimal device tree nodes > supplied from this platform are only to pass the dynamic info reflecting > command line input to firmware, not for loading OS. > > To make the review easier, this task is split into two patches, the > fundamental sceleton part and the peripheral devices part, this patch is > the first part. > > Signed-off-by: Hongbo Zhang <hongbo.zh...@linaro.org> > --- > default-configs/arm-softmmu.mak | 1 + > hw/arm/Kconfig | 3 + > hw/arm/Makefile.objs | 1 + > hw/arm/sbsa-ref.c | 303 > ++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 308 insertions(+) > create mode 100644 hw/arm/sbsa-ref.c > > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak > index 2a7efc1..4fbb6ac 100644 > --- a/default-configs/arm-softmmu.mak > +++ b/default-configs/arm-softmmu.mak > @@ -144,6 +144,7 @@ CONFIG_IOH3420=y > CONFIG_I82801B11=y > CONFIG_ACPI=y > CONFIG_ARM_VIRT=y > +CONFIG_SBSA_REF=y > CONFIG_SMBIOS=y > CONFIG_ASPEED_SOC=y > CONFIG_SMBUS_EEPROM=y > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig > index d298fbd..6654914 100644 > --- a/hw/arm/Kconfig > +++ b/hw/arm/Kconfig > @@ -38,6 +38,9 @@ config PXA2XX > config REALVIEW > bool > > +config SBSA_REF > + bool > + > config STELLARIS > bool > > diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs > index fa57c7c..fa812ec 100644 > --- a/hw/arm/Makefile.objs > +++ b/hw/arm/Makefile.objs > @@ -12,6 +12,7 @@ obj-$(CONFIG_NSERIES) += nseries.o > obj-$(CONFIG_OMAP) += omap_sx1.o palm.o > obj-$(CONFIG_PXA2XX) += gumstix.o spitz.o tosa.o z2.o > obj-$(CONFIG_REALVIEW) += realview.o > +obj-$(CONFIG_SBSA_REF) += sbsa-ref.o > obj-$(CONFIG_STELLARIS) += stellaris.o > obj-$(CONFIG_STRONGARM) += collie.o > obj-$(CONFIG_VERSATILE) += vexpress.o versatilepb.o > diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c > new file mode 100644 > index 0000000..b6d31f2 > --- /dev/null > +++ b/hw/arm/sbsa-ref.c > @@ -0,0 +1,303 @@ > +/* > + * ARM SBSA Reference Platform emulation > + * > + * Copyright (c) 2018 Linaro Limited > + * Written by Hongbo Zhang <hongbo.zh...@linaro.org> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2 or later, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > with > + * this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "qapi/error.h" > +#include "qemu/error-report.h" > +#include "qemu/units.h" > +#include "sysemu/numa.h" > +#include "sysemu/sysemu.h" > +#include "exec/address-spaces.h" > +#include "exec/hwaddr.h" > +#include "kvm_arm.h" > +#include "hw/arm/arm.h" > +#include "hw/boards.h" > +#include "hw/intc/arm_gicv3_common.h" > + > +#define RAMLIMIT_GB 8192 > +#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB) > + > +enum { > + SBSA_FLASH, > + SBSA_MEM, > + SBSA_CPUPERIPHS, > + SBSA_GIC_DIST, > + SBSA_GIC_REDIST, > + SBSA_SMMU, > + SBSA_UART, > + SBSA_RTC, > + SBSA_PCIE, > + SBSA_PCIE_MMIO, > + SBSA_PCIE_MMIO_HIGH, > + SBSA_PCIE_PIO, > + SBSA_PCIE_ECAM, > + SBSA_GPIO, > + SBSA_SECURE_UART, > + SBSA_SECURE_MEM, > + SBSA_AHCI, > + SBSA_EHCI, > +}; > + > +typedef struct MemMapEntry { > + hwaddr base; > + hwaddr size; > +} MemMapEntry; > + > +typedef struct { > + MachineState parent; > + struct arm_boot_info bootinfo; > + const MemMapEntry *memmap; > + const int *irqmap; > + int smp_cpus; > + void *fdt; > + int fdt_size; > + int psci_conduit; > +} SBSAMachineState; > + > +#define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref") > +#define SBSA_MACHINE(obj) \ > + OBJECT_CHECK(SBSAMachineState, (obj), TYPE_SBSA_MACHINE) > + > +static const MemMapEntry sbsa_ref_memmap[] = { > + /* 512M boot ROM */ > + [SBSA_FLASH] = { 0, 0x20000000 }, > + /* 512M secure memory */ > + [SBSA_SECURE_MEM] = { 0x20000000, 0x20000000 }, > + /* Space reserved for CPU peripheral devices */ > + [SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 }, > + [SBSA_GIC_DIST] = { 0x40060000, 0x00010000 }, > + [SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 }, > + [SBSA_UART] = { 0x60000000, 0x00001000 }, > + [SBSA_RTC] = { 0x60010000, 0x00001000 }, > + [SBSA_GPIO] = { 0x60020000, 0x00001000 }, > + [SBSA_SECURE_UART] = { 0x60030000, 0x00001000 }, > + [SBSA_SMMU] = { 0x60040000, 0x00020000 }, > + /* Space here reserved for more SMMUs */ > + [SBSA_AHCI] = { 0x60100000, 0x00010000 }, > + [SBSA_EHCI] = { 0x60110000, 0x00010000 }, > + /* Space here reserved for other devices */ > + [SBSA_PCIE_PIO] = { 0x7fff0000, 0x00010000 }, > + /* 256M PCIE ECAM space */ > + [SBSA_PCIE_ECAM] = { 0x80000000, 0x10000000 }, > + /* 32-bit address PCIE MMIO space */ > + [SBSA_PCIE_MMIO] = { 0x90000000, 0x70000000 }, Can we swap these around? I.e., MMIO first and then ECAM? That way, the MMIO base is aligned to the size of the largest BAR it can support (0x4000_0000), which is a bit cleaner, and less likely to cause problems with PCI resource allocators. > + /* ~1TB PCIE MMIO space (4GB to 1024GB boundary) */ > + [SBSA_PCIE_MMIO_HIGH] = { 0x100000000ULL, 0xFF00000000ULL }, > + [SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES }, > +}; > + > +static const int sbsa_ref_irqmap[] = { > + [SBSA_UART] = 1, > + [SBSA_RTC] = 2, > + [SBSA_PCIE] = 3, /* ... to 6 */ > + [SBSA_GPIO] = 7, > + [SBSA_SECURE_UART] = 8, > + [SBSA_AHCI] = 9, > + [SBSA_EHCI] = 10, > +}; > + > +static void sbsa_ref_init(MachineState *machine) > +{ > + SBSAMachineState *vms = SBSA_MACHINE(machine); > + MachineClass *mc = MACHINE_GET_CLASS(machine); > + MemoryRegion *sysmem = get_system_memory(); > + MemoryRegion *secure_sysmem = NULL; > + MemoryRegion *ram = g_new(MemoryRegion, 1); > + bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); > + const CPUArchIdList *possible_cpus; > + int n, sbsa_max_cpus; > + > + if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) { > + error_report("sbsa-ref: CPU type other than the built-in " > + "cortex-a57 not supported"); > + exit(1); > + } > + > + if (kvm_enabled()) { > + error_report("sbsa-ref: KVM is not supported at this machine"); > + exit(1); > + } > + > + if (machine->kernel_filename && firmware_loaded) { > + error_report("sbsa-ref: No fw_cfg device on this machine, " > + "so -kernel option is not supported when firmware > loaded, " > + "please load OS from hard disk instead"); > + exit(1); > + } > + > + /* > + * This machine has EL3 enabled, external firmware should supply PSCI > + * implementation, so the QEMU's internal PSCI is disabled. > + */ > + vms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; > + > + sbsa_max_cpus = vms->memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE; > + > + if (max_cpus > sbsa_max_cpus) { > + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " > + "supported by machine 'sbsa-ref' (%d)", > + max_cpus, sbsa_max_cpus); > + exit(1); > + } > + > + vms->smp_cpus = smp_cpus; > + > + if (machine->ram_size > vms->memmap[SBSA_MEM].size) { > + error_report("sbsa-ref: cannot model more than %dGB RAM", > RAMLIMIT_GB); > + exit(1); > + } > + > + secure_sysmem = g_new(MemoryRegion, 1); > + memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", > + UINT64_MAX); > + memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); > + > + possible_cpus = mc->possible_cpu_arch_ids(machine); > + for (n = 0; n < possible_cpus->len; n++) { > + Object *cpuobj; > + CPUState *cs; > + > + if (n >= smp_cpus) { > + break; > + } > + > + cpuobj = object_new(possible_cpus->cpus[n].type); > + object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, > + "mp-affinity", NULL); > + > + cs = CPU(cpuobj); > + cs->cpu_index = n; > + > + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], > DEVICE(cpuobj), > + &error_fatal); > + > + if (object_property_find(cpuobj, "reset-cbar", NULL)) { > + object_property_set_int(cpuobj, > vms->memmap[SBSA_CPUPERIPHS].base, > + "reset-cbar", &error_abort); > + } > + > + object_property_set_link(cpuobj, OBJECT(sysmem), "memory", > + &error_abort); > + > + object_property_set_link(cpuobj, OBJECT(secure_sysmem), > + "secure-memory", &error_abort); > + > + object_property_set_bool(cpuobj, true, "realized", &error_fatal); > + object_unref(cpuobj); > + } > + > + memory_region_allocate_system_memory(ram, NULL, "sbsa-ref.ram", > + machine->ram_size); > + memory_region_add_subregion(sysmem, vms->memmap[SBSA_MEM].base, ram); > + > + vms->bootinfo.ram_size = machine->ram_size; > + vms->bootinfo.kernel_filename = machine->kernel_filename; > + vms->bootinfo.nb_cpus = smp_cpus; > + vms->bootinfo.board_id = -1; > + vms->bootinfo.loader_start = vms->memmap[SBSA_MEM].base; > + vms->bootinfo.firmware_loaded = firmware_loaded; > + arm_load_kernel(ARM_CPU(first_cpu), &vms->bootinfo); > +} > + > +static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *vms, int idx) > +{ > + uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER; > + return arm_cpu_mp_affinity(idx, clustersz); > +} > + > +static const CPUArchIdList *sbsa_ref_possible_cpu_arch_ids(MachineState *ms) > +{ > + SBSAMachineState *vms = SBSA_MACHINE(ms); > + int n; > + > + if (ms->possible_cpus) { > + assert(ms->possible_cpus->len == max_cpus); > + return ms->possible_cpus; > + } > + > + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + > + sizeof(CPUArchId) * max_cpus); > + ms->possible_cpus->len = max_cpus; > + for (n = 0; n < ms->possible_cpus->len; n++) { > + ms->possible_cpus->cpus[n].type = ms->cpu_type; > + ms->possible_cpus->cpus[n].arch_id = > + sbsa_ref_cpu_mp_affinity(vms, n); > + ms->possible_cpus->cpus[n].props.has_thread_id = true; > + ms->possible_cpus->cpus[n].props.thread_id = n; > + } > + return ms->possible_cpus; > +} > + > +static CpuInstanceProperties > +sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index) > +{ > + MachineClass *mc = MACHINE_GET_CLASS(ms); > + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); > + > + assert(cpu_index < possible_cpus->len); > + return possible_cpus->cpus[cpu_index].props; > +} > + > +static int64_t > +sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx) > +{ > + return idx % nb_numa_nodes; > +} > + > +static void sbsa_ref_instance_init(Object *obj) > +{ > + SBSAMachineState *vms = SBSA_MACHINE(obj); > + > + vms->memmap = sbsa_ref_memmap; > + vms->irqmap = sbsa_ref_irqmap; > +} > + > +static void sbsa_ref_class_init(ObjectClass *oc, void *data) > +{ > + MachineClass *mc = MACHINE_CLASS(oc); > + > + mc->init = sbsa_ref_init; > + mc->desc = "QEMU 'SBSA Reference' ARM Virtual Machine"; > + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57"); > + mc->max_cpus = 512; > + mc->pci_allow_0_address = true; > + mc->minimum_page_bits = 12; > + mc->block_default_type = IF_IDE; > + mc->no_cdrom = 1; > + mc->default_ram_size = 1 * GiB; > + mc->default_cpus = 4; > + mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids; > + mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props; > + mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id; > +} > + > +static const TypeInfo sbsa_ref_info = { > + .name = TYPE_SBSA_MACHINE, > + .parent = TYPE_MACHINE, > + .instance_size = sizeof(SBSAMachineState), > + .instance_init = sbsa_ref_instance_init, > + .class_init = sbsa_ref_class_init, > +}; > + > +static void sbsa_ref_machine_init(void) > +{ > + type_register_static(&sbsa_ref_info); > +} > + > +type_init(sbsa_ref_machine_init); > -- > 2.7.4 >