1*64580903SHongbo Zhang /* 2*64580903SHongbo Zhang * ARM SBSA Reference Platform emulation 3*64580903SHongbo Zhang * 4*64580903SHongbo Zhang * Copyright (c) 2018 Linaro Limited 5*64580903SHongbo Zhang * Written by Hongbo Zhang <hongbo.zhang@linaro.org> 6*64580903SHongbo Zhang * 7*64580903SHongbo Zhang * This program is free software; you can redistribute it and/or modify it 8*64580903SHongbo Zhang * under the terms and conditions of the GNU General Public License, 9*64580903SHongbo Zhang * version 2 or later, as published by the Free Software Foundation. 10*64580903SHongbo Zhang * 11*64580903SHongbo Zhang * This program is distributed in the hope it will be useful, but WITHOUT 12*64580903SHongbo Zhang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13*64580903SHongbo Zhang * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14*64580903SHongbo Zhang * more details. 15*64580903SHongbo Zhang * 16*64580903SHongbo Zhang * You should have received a copy of the GNU General Public License along with 17*64580903SHongbo Zhang * this program. If not, see <http://www.gnu.org/licenses/>. 18*64580903SHongbo Zhang */ 19*64580903SHongbo Zhang 20*64580903SHongbo Zhang #include "qemu/osdep.h" 21*64580903SHongbo Zhang #include "qapi/error.h" 22*64580903SHongbo Zhang #include "qemu/error-report.h" 23*64580903SHongbo Zhang #include "qemu/units.h" 24*64580903SHongbo Zhang #include "sysemu/numa.h" 25*64580903SHongbo Zhang #include "sysemu/sysemu.h" 26*64580903SHongbo Zhang #include "exec/address-spaces.h" 27*64580903SHongbo Zhang #include "exec/hwaddr.h" 28*64580903SHongbo Zhang #include "kvm_arm.h" 29*64580903SHongbo Zhang #include "hw/arm/boot.h" 30*64580903SHongbo Zhang #include "hw/boards.h" 31*64580903SHongbo Zhang #include "hw/intc/arm_gicv3_common.h" 32*64580903SHongbo Zhang 33*64580903SHongbo Zhang #define RAMLIMIT_GB 8192 34*64580903SHongbo Zhang #define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB) 35*64580903SHongbo Zhang 36*64580903SHongbo Zhang enum { 37*64580903SHongbo Zhang SBSA_FLASH, 38*64580903SHongbo Zhang SBSA_MEM, 39*64580903SHongbo Zhang SBSA_CPUPERIPHS, 40*64580903SHongbo Zhang SBSA_GIC_DIST, 41*64580903SHongbo Zhang SBSA_GIC_REDIST, 42*64580903SHongbo Zhang SBSA_SMMU, 43*64580903SHongbo Zhang SBSA_UART, 44*64580903SHongbo Zhang SBSA_RTC, 45*64580903SHongbo Zhang SBSA_PCIE, 46*64580903SHongbo Zhang SBSA_PCIE_MMIO, 47*64580903SHongbo Zhang SBSA_PCIE_MMIO_HIGH, 48*64580903SHongbo Zhang SBSA_PCIE_PIO, 49*64580903SHongbo Zhang SBSA_PCIE_ECAM, 50*64580903SHongbo Zhang SBSA_GPIO, 51*64580903SHongbo Zhang SBSA_SECURE_UART, 52*64580903SHongbo Zhang SBSA_SECURE_UART_MM, 53*64580903SHongbo Zhang SBSA_SECURE_MEM, 54*64580903SHongbo Zhang SBSA_AHCI, 55*64580903SHongbo Zhang SBSA_EHCI, 56*64580903SHongbo Zhang }; 57*64580903SHongbo Zhang 58*64580903SHongbo Zhang typedef struct MemMapEntry { 59*64580903SHongbo Zhang hwaddr base; 60*64580903SHongbo Zhang hwaddr size; 61*64580903SHongbo Zhang } MemMapEntry; 62*64580903SHongbo Zhang 63*64580903SHongbo Zhang typedef struct { 64*64580903SHongbo Zhang MachineState parent; 65*64580903SHongbo Zhang struct arm_boot_info bootinfo; 66*64580903SHongbo Zhang int smp_cpus; 67*64580903SHongbo Zhang void *fdt; 68*64580903SHongbo Zhang int fdt_size; 69*64580903SHongbo Zhang int psci_conduit; 70*64580903SHongbo Zhang } SBSAMachineState; 71*64580903SHongbo Zhang 72*64580903SHongbo Zhang #define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref") 73*64580903SHongbo Zhang #define SBSA_MACHINE(obj) \ 74*64580903SHongbo Zhang OBJECT_CHECK(SBSAMachineState, (obj), TYPE_SBSA_MACHINE) 75*64580903SHongbo Zhang 76*64580903SHongbo Zhang static const MemMapEntry sbsa_ref_memmap[] = { 77*64580903SHongbo Zhang /* 512M boot ROM */ 78*64580903SHongbo Zhang [SBSA_FLASH] = { 0, 0x20000000 }, 79*64580903SHongbo Zhang /* 512M secure memory */ 80*64580903SHongbo Zhang [SBSA_SECURE_MEM] = { 0x20000000, 0x20000000 }, 81*64580903SHongbo Zhang /* Space reserved for CPU peripheral devices */ 82*64580903SHongbo Zhang [SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 }, 83*64580903SHongbo Zhang [SBSA_GIC_DIST] = { 0x40060000, 0x00010000 }, 84*64580903SHongbo Zhang [SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 }, 85*64580903SHongbo Zhang [SBSA_UART] = { 0x60000000, 0x00001000 }, 86*64580903SHongbo Zhang [SBSA_RTC] = { 0x60010000, 0x00001000 }, 87*64580903SHongbo Zhang [SBSA_GPIO] = { 0x60020000, 0x00001000 }, 88*64580903SHongbo Zhang [SBSA_SECURE_UART] = { 0x60030000, 0x00001000 }, 89*64580903SHongbo Zhang [SBSA_SECURE_UART_MM] = { 0x60040000, 0x00001000 }, 90*64580903SHongbo Zhang [SBSA_SMMU] = { 0x60050000, 0x00020000 }, 91*64580903SHongbo Zhang /* Space here reserved for more SMMUs */ 92*64580903SHongbo Zhang [SBSA_AHCI] = { 0x60100000, 0x00010000 }, 93*64580903SHongbo Zhang [SBSA_EHCI] = { 0x60110000, 0x00010000 }, 94*64580903SHongbo Zhang /* Space here reserved for other devices */ 95*64580903SHongbo Zhang [SBSA_PCIE_PIO] = { 0x7fff0000, 0x00010000 }, 96*64580903SHongbo Zhang /* 32-bit address PCIE MMIO space */ 97*64580903SHongbo Zhang [SBSA_PCIE_MMIO] = { 0x80000000, 0x70000000 }, 98*64580903SHongbo Zhang /* 256M PCIE ECAM space */ 99*64580903SHongbo Zhang [SBSA_PCIE_ECAM] = { 0xf0000000, 0x10000000 }, 100*64580903SHongbo Zhang /* ~1TB PCIE MMIO space (4GB to 1024GB boundary) */ 101*64580903SHongbo Zhang [SBSA_PCIE_MMIO_HIGH] = { 0x100000000ULL, 0xFF00000000ULL }, 102*64580903SHongbo Zhang [SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES }, 103*64580903SHongbo Zhang }; 104*64580903SHongbo Zhang 105*64580903SHongbo Zhang static void sbsa_ref_init(MachineState *machine) 106*64580903SHongbo Zhang { 107*64580903SHongbo Zhang SBSAMachineState *sms = SBSA_MACHINE(machine); 108*64580903SHongbo Zhang MachineClass *mc = MACHINE_GET_CLASS(machine); 109*64580903SHongbo Zhang MemoryRegion *sysmem = get_system_memory(); 110*64580903SHongbo Zhang MemoryRegion *secure_sysmem = NULL; 111*64580903SHongbo Zhang MemoryRegion *ram = g_new(MemoryRegion, 1); 112*64580903SHongbo Zhang const CPUArchIdList *possible_cpus; 113*64580903SHongbo Zhang int n, sbsa_max_cpus; 114*64580903SHongbo Zhang 115*64580903SHongbo Zhang if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) { 116*64580903SHongbo Zhang error_report("sbsa-ref: CPU type other than the built-in " 117*64580903SHongbo Zhang "cortex-a57 not supported"); 118*64580903SHongbo Zhang exit(1); 119*64580903SHongbo Zhang } 120*64580903SHongbo Zhang 121*64580903SHongbo Zhang if (kvm_enabled()) { 122*64580903SHongbo Zhang error_report("sbsa-ref: KVM is not supported for this machine"); 123*64580903SHongbo Zhang exit(1); 124*64580903SHongbo Zhang } 125*64580903SHongbo Zhang 126*64580903SHongbo Zhang /* 127*64580903SHongbo Zhang * This machine has EL3 enabled, external firmware should supply PSCI 128*64580903SHongbo Zhang * implementation, so the QEMU's internal PSCI is disabled. 129*64580903SHongbo Zhang */ 130*64580903SHongbo Zhang sms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; 131*64580903SHongbo Zhang 132*64580903SHongbo Zhang sbsa_max_cpus = sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE; 133*64580903SHongbo Zhang 134*64580903SHongbo Zhang if (max_cpus > sbsa_max_cpus) { 135*64580903SHongbo Zhang error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " 136*64580903SHongbo Zhang "supported by machine 'sbsa-ref' (%d)", 137*64580903SHongbo Zhang max_cpus, sbsa_max_cpus); 138*64580903SHongbo Zhang exit(1); 139*64580903SHongbo Zhang } 140*64580903SHongbo Zhang 141*64580903SHongbo Zhang sms->smp_cpus = smp_cpus; 142*64580903SHongbo Zhang 143*64580903SHongbo Zhang if (machine->ram_size > sbsa_ref_memmap[SBSA_MEM].size) { 144*64580903SHongbo Zhang error_report("sbsa-ref: cannot model more than %dGB RAM", RAMLIMIT_GB); 145*64580903SHongbo Zhang exit(1); 146*64580903SHongbo Zhang } 147*64580903SHongbo Zhang 148*64580903SHongbo Zhang possible_cpus = mc->possible_cpu_arch_ids(machine); 149*64580903SHongbo Zhang for (n = 0; n < possible_cpus->len; n++) { 150*64580903SHongbo Zhang Object *cpuobj; 151*64580903SHongbo Zhang CPUState *cs; 152*64580903SHongbo Zhang 153*64580903SHongbo Zhang if (n >= smp_cpus) { 154*64580903SHongbo Zhang break; 155*64580903SHongbo Zhang } 156*64580903SHongbo Zhang 157*64580903SHongbo Zhang cpuobj = object_new(possible_cpus->cpus[n].type); 158*64580903SHongbo Zhang object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, 159*64580903SHongbo Zhang "mp-affinity", NULL); 160*64580903SHongbo Zhang 161*64580903SHongbo Zhang cs = CPU(cpuobj); 162*64580903SHongbo Zhang cs->cpu_index = n; 163*64580903SHongbo Zhang 164*64580903SHongbo Zhang numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), 165*64580903SHongbo Zhang &error_fatal); 166*64580903SHongbo Zhang 167*64580903SHongbo Zhang if (object_property_find(cpuobj, "reset-cbar", NULL)) { 168*64580903SHongbo Zhang object_property_set_int(cpuobj, 169*64580903SHongbo Zhang sbsa_ref_memmap[SBSA_CPUPERIPHS].base, 170*64580903SHongbo Zhang "reset-cbar", &error_abort); 171*64580903SHongbo Zhang } 172*64580903SHongbo Zhang 173*64580903SHongbo Zhang object_property_set_link(cpuobj, OBJECT(sysmem), "memory", 174*64580903SHongbo Zhang &error_abort); 175*64580903SHongbo Zhang 176*64580903SHongbo Zhang object_property_set_link(cpuobj, OBJECT(secure_sysmem), 177*64580903SHongbo Zhang "secure-memory", &error_abort); 178*64580903SHongbo Zhang 179*64580903SHongbo Zhang object_property_set_bool(cpuobj, true, "realized", &error_fatal); 180*64580903SHongbo Zhang object_unref(cpuobj); 181*64580903SHongbo Zhang } 182*64580903SHongbo Zhang 183*64580903SHongbo Zhang memory_region_allocate_system_memory(ram, NULL, "sbsa-ref.ram", 184*64580903SHongbo Zhang machine->ram_size); 185*64580903SHongbo Zhang memory_region_add_subregion(sysmem, sbsa_ref_memmap[SBSA_MEM].base, ram); 186*64580903SHongbo Zhang 187*64580903SHongbo Zhang sms->bootinfo.ram_size = machine->ram_size; 188*64580903SHongbo Zhang sms->bootinfo.kernel_filename = machine->kernel_filename; 189*64580903SHongbo Zhang sms->bootinfo.nb_cpus = smp_cpus; 190*64580903SHongbo Zhang sms->bootinfo.board_id = -1; 191*64580903SHongbo Zhang sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base; 192*64580903SHongbo Zhang arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo); 193*64580903SHongbo Zhang } 194*64580903SHongbo Zhang 195*64580903SHongbo Zhang static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx) 196*64580903SHongbo Zhang { 197*64580903SHongbo Zhang uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER; 198*64580903SHongbo Zhang return arm_cpu_mp_affinity(idx, clustersz); 199*64580903SHongbo Zhang } 200*64580903SHongbo Zhang 201*64580903SHongbo Zhang static const CPUArchIdList *sbsa_ref_possible_cpu_arch_ids(MachineState *ms) 202*64580903SHongbo Zhang { 203*64580903SHongbo Zhang SBSAMachineState *sms = SBSA_MACHINE(ms); 204*64580903SHongbo Zhang int n; 205*64580903SHongbo Zhang 206*64580903SHongbo Zhang if (ms->possible_cpus) { 207*64580903SHongbo Zhang assert(ms->possible_cpus->len == max_cpus); 208*64580903SHongbo Zhang return ms->possible_cpus; 209*64580903SHongbo Zhang } 210*64580903SHongbo Zhang 211*64580903SHongbo Zhang ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + 212*64580903SHongbo Zhang sizeof(CPUArchId) * max_cpus); 213*64580903SHongbo Zhang ms->possible_cpus->len = max_cpus; 214*64580903SHongbo Zhang for (n = 0; n < ms->possible_cpus->len; n++) { 215*64580903SHongbo Zhang ms->possible_cpus->cpus[n].type = ms->cpu_type; 216*64580903SHongbo Zhang ms->possible_cpus->cpus[n].arch_id = 217*64580903SHongbo Zhang sbsa_ref_cpu_mp_affinity(sms, n); 218*64580903SHongbo Zhang ms->possible_cpus->cpus[n].props.has_thread_id = true; 219*64580903SHongbo Zhang ms->possible_cpus->cpus[n].props.thread_id = n; 220*64580903SHongbo Zhang } 221*64580903SHongbo Zhang return ms->possible_cpus; 222*64580903SHongbo Zhang } 223*64580903SHongbo Zhang 224*64580903SHongbo Zhang static CpuInstanceProperties 225*64580903SHongbo Zhang sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index) 226*64580903SHongbo Zhang { 227*64580903SHongbo Zhang MachineClass *mc = MACHINE_GET_CLASS(ms); 228*64580903SHongbo Zhang const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); 229*64580903SHongbo Zhang 230*64580903SHongbo Zhang assert(cpu_index < possible_cpus->len); 231*64580903SHongbo Zhang return possible_cpus->cpus[cpu_index].props; 232*64580903SHongbo Zhang } 233*64580903SHongbo Zhang 234*64580903SHongbo Zhang static int64_t 235*64580903SHongbo Zhang sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx) 236*64580903SHongbo Zhang { 237*64580903SHongbo Zhang return idx % nb_numa_nodes; 238*64580903SHongbo Zhang } 239*64580903SHongbo Zhang 240*64580903SHongbo Zhang static void sbsa_ref_class_init(ObjectClass *oc, void *data) 241*64580903SHongbo Zhang { 242*64580903SHongbo Zhang MachineClass *mc = MACHINE_CLASS(oc); 243*64580903SHongbo Zhang 244*64580903SHongbo Zhang mc->init = sbsa_ref_init; 245*64580903SHongbo Zhang mc->desc = "QEMU 'SBSA Reference' ARM Virtual Machine"; 246*64580903SHongbo Zhang mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57"); 247*64580903SHongbo Zhang mc->max_cpus = 512; 248*64580903SHongbo Zhang mc->pci_allow_0_address = true; 249*64580903SHongbo Zhang mc->minimum_page_bits = 12; 250*64580903SHongbo Zhang mc->block_default_type = IF_IDE; 251*64580903SHongbo Zhang mc->no_cdrom = 1; 252*64580903SHongbo Zhang mc->default_ram_size = 1 * GiB; 253*64580903SHongbo Zhang mc->default_cpus = 4; 254*64580903SHongbo Zhang mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids; 255*64580903SHongbo Zhang mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props; 256*64580903SHongbo Zhang mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id; 257*64580903SHongbo Zhang } 258*64580903SHongbo Zhang 259*64580903SHongbo Zhang static const TypeInfo sbsa_ref_info = { 260*64580903SHongbo Zhang .name = TYPE_SBSA_MACHINE, 261*64580903SHongbo Zhang .parent = TYPE_MACHINE, 262*64580903SHongbo Zhang .class_init = sbsa_ref_class_init, 263*64580903SHongbo Zhang .instance_size = sizeof(SBSAMachineState), 264*64580903SHongbo Zhang }; 265*64580903SHongbo Zhang 266*64580903SHongbo Zhang static void sbsa_ref_machine_init(void) 267*64580903SHongbo Zhang { 268*64580903SHongbo Zhang type_register_static(&sbsa_ref_info); 269*64580903SHongbo Zhang } 270*64580903SHongbo Zhang 271*64580903SHongbo Zhang type_init(sbsa_ref_machine_init); 272