]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppc/pnv.c
ppc/pnv: add skeleton PowerNV platform
[mirror_qemu.git] / hw / ppc / pnv.c
CommitLineData
9e933f4a
BH
1/*
2 * QEMU PowerPC PowerNV machine model
3 *
4 * Copyright (c) 2016, IBM Corporation.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "qemu/osdep.h"
21#include "qapi/error.h"
22#include "sysemu/sysemu.h"
23#include "sysemu/numa.h"
24#include "hw/hw.h"
25#include "target-ppc/cpu.h"
26#include "qemu/log.h"
27#include "hw/ppc/fdt.h"
28#include "hw/ppc/ppc.h"
29#include "hw/ppc/pnv.h"
30#include "hw/loader.h"
31#include "exec/address-spaces.h"
32#include "qemu/cutils.h"
33
34#include <libfdt.h>
35
36#define FDT_MAX_SIZE 0x00100000
37
38#define FW_FILE_NAME "skiboot.lid"
39#define FW_LOAD_ADDR 0x0
40#define FW_MAX_SIZE 0x00400000
41
42#define KERNEL_LOAD_ADDR 0x20000000
43#define INITRD_LOAD_ADDR 0x40000000
44
45/*
46 * On Power Systems E880 (POWER8), the max cpus (threads) should be :
47 * 4 * 4 sockets * 12 cores * 8 threads = 1536
48 * Let's make it 2^11
49 */
50#define MAX_CPUS 2048
51
52/*
53 * Memory nodes are created by hostboot, one for each range of memory
54 * that has a different "affinity". In practice, it means one range
55 * per chip.
56 */
57static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
58 hwaddr size)
59{
60 char *mem_name;
61 uint64_t mem_reg_property[2];
62 int off;
63
64 mem_reg_property[0] = cpu_to_be64(start);
65 mem_reg_property[1] = cpu_to_be64(size);
66
67 mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
68 off = fdt_add_subnode(fdt, 0, mem_name);
69 g_free(mem_name);
70
71 _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
72 _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
73 sizeof(mem_reg_property))));
74 _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
75}
76
77static void *powernv_create_fdt(MachineState *machine)
78{
79 const char plat_compat[] = "qemu,powernv\0ibm,powernv";
80 PnvMachineState *pnv = POWERNV_MACHINE(machine);
81 void *fdt;
82 char *buf;
83 int off;
84
85 fdt = g_malloc0(FDT_MAX_SIZE);
86 _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
87
88 /* Root node */
89 _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
90 _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
91 _FDT((fdt_setprop_string(fdt, 0, "model",
92 "IBM PowerNV (emulated by qemu)")));
93 _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
94 sizeof(plat_compat))));
95
96 buf = qemu_uuid_unparse_strdup(&qemu_uuid);
97 _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
98 if (qemu_uuid_set) {
99 _FDT((fdt_property_string(fdt, "system-id", buf)));
100 }
101 g_free(buf);
102
103 off = fdt_add_subnode(fdt, 0, "chosen");
104 if (machine->kernel_cmdline) {
105 _FDT((fdt_setprop_string(fdt, off, "bootargs",
106 machine->kernel_cmdline)));
107 }
108
109 if (pnv->initrd_size) {
110 uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
111 uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
112
113 _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
114 &start_prop, sizeof(start_prop))));
115 _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
116 &end_prop, sizeof(end_prop))));
117 }
118
119 /* TODO: put all the memory in one node on chip 0 until we find a
120 * way to specify different ranges for each chip
121 */
122 powernv_populate_memory_node(fdt, 0, 0, machine->ram_size);
123
124 return fdt;
125}
126
127static void ppc_powernv_reset(void)
128{
129 MachineState *machine = MACHINE(qdev_get_machine());
130 void *fdt;
131
132 qemu_devices_reset();
133
134 fdt = powernv_create_fdt(machine);
135
136 /* Pack resulting tree */
137 _FDT((fdt_pack(fdt)));
138
139 cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
140}
141
142static void ppc_powernv_init(MachineState *machine)
143{
144 PnvMachineState *pnv = POWERNV_MACHINE(machine);
145 MemoryRegion *ram;
146 char *fw_filename;
147 long fw_size;
148
149 /* allocate RAM */
150 if (machine->ram_size < (1 * G_BYTE)) {
151 error_report("Warning: skiboot may not work with < 1GB of RAM");
152 }
153
154 ram = g_new(MemoryRegion, 1);
155 memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
156 machine->ram_size);
157 memory_region_add_subregion(get_system_memory(), 0, ram);
158
159 /* load skiboot firmware */
160 if (bios_name == NULL) {
161 bios_name = FW_FILE_NAME;
162 }
163
164 fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
165
166 fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
167 if (fw_size < 0) {
168 hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
169 exit(1);
170 }
171 g_free(fw_filename);
172
173 /* load kernel */
174 if (machine->kernel_filename) {
175 long kernel_size;
176
177 kernel_size = load_image_targphys(machine->kernel_filename,
178 KERNEL_LOAD_ADDR, 0x2000000);
179 if (kernel_size < 0) {
180 hw_error("qemu: could not load kernel'%s'\n",
181 machine->kernel_filename);
182 exit(1);
183 }
184 }
185
186 /* load initrd */
187 if (machine->initrd_filename) {
188 pnv->initrd_base = INITRD_LOAD_ADDR;
189 pnv->initrd_size = load_image_targphys(machine->initrd_filename,
190 pnv->initrd_base, 0x10000000); /* 128MB max */
191 if (pnv->initrd_size < 0) {
192 error_report("qemu: could not load initial ram disk '%s'",
193 machine->initrd_filename);
194 exit(1);
195 }
196 }
197}
198
199static void powernv_machine_class_init(ObjectClass *oc, void *data)
200{
201 MachineClass *mc = MACHINE_CLASS(oc);
202
203 mc->desc = "IBM PowerNV (Non-Virtualized)";
204 mc->init = ppc_powernv_init;
205 mc->reset = ppc_powernv_reset;
206 mc->max_cpus = MAX_CPUS;
207 mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
208 * storage */
209 mc->no_parallel = 1;
210 mc->default_boot_order = NULL;
211 mc->default_ram_size = 1 * G_BYTE;
212}
213
214static const TypeInfo powernv_machine_info = {
215 .name = TYPE_POWERNV_MACHINE,
216 .parent = TYPE_MACHINE,
217 .instance_size = sizeof(PnvMachineState),
218 .class_init = powernv_machine_class_init,
219};
220
221static void powernv_machine_register_types(void)
222{
223 type_register_static(&powernv_machine_info);
224}
225
226type_init(powernv_machine_register_types)