On Fri, 15 Mar 2019 at 18:41, Ard Biesheuvel <ard.biesheu...@linaro.org> wrote: > > 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? > Hi Ard, Which EHCI do you mean? This time I use a newly introduced system bus EHCI, commit 114529f7 and I only tested USB mouse and key board, didn't test DMA function.
> > > - 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. > Yes sure. > > + /* ~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 > >