xref: /qemu/hw/arm/sbsa-ref.c (revision 64580903c2b3aee08d74d64e6248a313b246cb69)
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