File: | hw/ppc/e500.c |
Location: | line 792, column 21 |
Description: | Access to field 'load_info' results in a dereference of a null pointer (loaded from variable 'env') |
1 | /* | |||
2 | * QEMU PowerPC e500-based platforms | |||
3 | * | |||
4 | * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. | |||
5 | * | |||
6 | * Author: Yu Liu, <yu.liu@freescale.com> | |||
7 | * | |||
8 | * This file is derived from hw/ppc440_bamboo.c, | |||
9 | * the copyright for that material belongs to the original owners. | |||
10 | * | |||
11 | * This is free software; you can redistribute it and/or modify | |||
12 | * it under the terms of the GNU General Public License as published by | |||
13 | * the Free Software Foundation; either version 2 of the License, or | |||
14 | * (at your option) any later version. | |||
15 | */ | |||
16 | ||||
17 | #include "config.h" | |||
18 | #include "qemu-common.h" | |||
19 | #include "e500.h" | |||
20 | #include "e500-ccsr.h" | |||
21 | #include "net/net.h" | |||
22 | #include "qemu/config-file.h" | |||
23 | #include "hw/hw.h" | |||
24 | #include "hw/char/serial.h" | |||
25 | #include "hw/pci/pci.h" | |||
26 | #include "hw/boards.h" | |||
27 | #include "sysemu/sysemu.h" | |||
28 | #include "sysemu/kvm.h" | |||
29 | #include "kvm_ppc.h" | |||
30 | #include "sysemu/device_tree.h" | |||
31 | #include "hw/ppc/openpic.h" | |||
32 | #include "hw/ppc/ppc.h" | |||
33 | #include "hw/loader.h" | |||
34 | #include "elf.h" | |||
35 | #include "hw/sysbus.h" | |||
36 | #include "exec/address-spaces.h" | |||
37 | #include "qemu/host-utils.h" | |||
38 | #include "hw/pci-host/ppce500.h" | |||
39 | ||||
40 | #define EPAPR_MAGIC(0x45504150) (0x45504150) | |||
41 | #define BINARY_DEVICE_TREE_FILE"mpc8544ds.dtb" "mpc8544ds.dtb" | |||
42 | #define UIMAGE_LOAD_BASE0 0 | |||
43 | #define DTC_LOAD_PAD0x1800000 0x1800000 | |||
44 | #define DTC_PAD_MASK0xFFFFF 0xFFFFF | |||
45 | #define DTB_MAX_SIZE(8 * 1024 * 1024) (8 * 1024 * 1024) | |||
46 | #define INITRD_LOAD_PAD0x2000000 0x2000000 | |||
47 | #define INITRD_PAD_MASK0xFFFFFF 0xFFFFFF | |||
48 | ||||
49 | #define RAM_SIZES_ALIGN(64UL << 20) (64UL << 20) | |||
50 | ||||
51 | /* TODO: parameterize */ | |||
52 | #define MPC8544_CCSRBAR_BASE0xE0000000ULL 0xE0000000ULL | |||
53 | #define MPC8544_CCSRBAR_SIZE0x00100000ULL 0x00100000ULL | |||
54 | #define MPC8544_MPIC_REGS_OFFSET0x40000ULL 0x40000ULL | |||
55 | #define MPC8544_MSI_REGS_OFFSET0x41600ULL 0x41600ULL | |||
56 | #define MPC8544_SERIAL0_REGS_OFFSET0x4500ULL 0x4500ULL | |||
57 | #define MPC8544_SERIAL1_REGS_OFFSET0x4600ULL 0x4600ULL | |||
58 | #define MPC8544_PCI_REGS_OFFSET0x8000ULL 0x8000ULL | |||
59 | #define MPC8544_PCI_REGS_BASE(0xE0000000ULL + 0x8000ULL) (MPC8544_CCSRBAR_BASE0xE0000000ULL + \ | |||
60 | MPC8544_PCI_REGS_OFFSET0x8000ULL) | |||
61 | #define MPC8544_PCI_REGS_SIZE0x1000ULL 0x1000ULL | |||
62 | #define MPC8544_PCI_IO0xE1000000ULL 0xE1000000ULL | |||
63 | #define MPC8544_UTIL_OFFSET0xe0000ULL 0xe0000ULL | |||
64 | #define MPC8544_SPIN_BASE0xEF000000ULL 0xEF000000ULL | |||
65 | ||||
66 | struct boot_info | |||
67 | { | |||
68 | uint32_t dt_base; | |||
69 | uint32_t dt_size; | |||
70 | uint32_t entry; | |||
71 | }; | |||
72 | ||||
73 | static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, | |||
74 | int nr_slots, int *len) | |||
75 | { | |||
76 | int i = 0; | |||
77 | int slot; | |||
78 | int pci_irq; | |||
79 | int host_irq; | |||
80 | int last_slot = first_slot + nr_slots; | |||
81 | uint32_t *pci_map; | |||
82 | ||||
83 | *len = nr_slots * 4 * 7 * sizeof(uint32_t); | |||
84 | pci_map = g_malloc(*len); | |||
85 | ||||
86 | for (slot = first_slot; slot < last_slot; slot++) { | |||
87 | for (pci_irq = 0; pci_irq < 4; pci_irq++) { | |||
88 | pci_map[i++] = cpu_to_be32(slot << 11); | |||
89 | pci_map[i++] = cpu_to_be32(0x0); | |||
90 | pci_map[i++] = cpu_to_be32(0x0); | |||
91 | pci_map[i++] = cpu_to_be32(pci_irq + 1); | |||
92 | pci_map[i++] = cpu_to_be32(mpic); | |||
93 | host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); | |||
94 | pci_map[i++] = cpu_to_be32(host_irq + 1); | |||
95 | pci_map[i++] = cpu_to_be32(0x1); | |||
96 | } | |||
97 | } | |||
98 | ||||
99 | assert((i * sizeof(uint32_t)) == *len)(((i * sizeof(uint32_t)) == *len) ? (void) (0) : __assert_fail ("(i * sizeof(uint32_t)) == *len", "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 99, __PRETTY_FUNCTION__)); | |||
100 | ||||
101 | return pci_map; | |||
102 | } | |||
103 | ||||
104 | static void dt_serial_create(void *fdt, unsigned long long offset, | |||
105 | const char *soc, const char *mpic, | |||
106 | const char *alias, int idx, bool_Bool defcon) | |||
107 | { | |||
108 | char ser[128]; | |||
109 | ||||
110 | snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); | |||
111 | qemu_fdt_add_subnode(fdt, ser); | |||
112 | qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); | |||
113 | qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); | |||
114 | qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100)do { uint32_t qdt_tmp[] = { offset, 0x100 }; int i; for (i = 0 ; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp [i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, ser, "reg" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
115 | qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); | |||
116 | qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); | |||
117 | qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2)do { uint32_t qdt_tmp[] = { 42, 2 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, ser, "interrupts" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
118 | qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); | |||
119 | qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); | |||
120 | ||||
121 | if (defcon) { | |||
122 | qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); | |||
123 | } | |||
124 | } | |||
125 | ||||
126 | static int ppce500_load_device_tree(QEMUMachineInitArgs *args, | |||
127 | PPCE500Params *params, | |||
128 | hwaddr addr, | |||
129 | hwaddr initrd_base, | |||
130 | hwaddr initrd_size, | |||
131 | bool_Bool dry_run) | |||
132 | { | |||
133 | CPUPPCState *env = first_cpu((&cpus)->tqh_first)->env_ptr; | |||
134 | int ret = -1; | |||
135 | uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) }; | |||
136 | int fdt_size; | |||
137 | void *fdt; | |||
138 | uint8_t hypercall[16]; | |||
139 | uint32_t clock_freq = 400000000; | |||
140 | uint32_t tb_freq = 400000000; | |||
141 | int i; | |||
142 | char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; | |||
143 | char soc[128]; | |||
144 | char mpic[128]; | |||
145 | uint32_t mpic_ph; | |||
146 | uint32_t msi_ph; | |||
147 | char gutil[128]; | |||
148 | char pci[128]; | |||
149 | char msi[128]; | |||
150 | uint32_t *pci_map = NULL((void*)0); | |||
151 | int len; | |||
152 | uint32_t pci_ranges[14] = | |||
153 | { | |||
154 | 0x2000000, 0x0, 0xc0000000, | |||
155 | 0x0, 0xc0000000, | |||
156 | 0x0, 0x20000000, | |||
157 | ||||
158 | 0x1000000, 0x0, 0x0, | |||
159 | 0x0, 0xe1000000, | |||
160 | 0x0, 0x10000, | |||
161 | }; | |||
162 | QemuOpts *machine_opts = qemu_get_machine_opts(); | |||
163 | const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); | |||
164 | const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); | |||
165 | ||||
166 | if (dtb_file) { | |||
167 | char *filename; | |||
168 | filename = qemu_find_file(QEMU_FILE_TYPE_BIOS0, dtb_file); | |||
169 | if (!filename) { | |||
170 | goto out; | |||
171 | } | |||
172 | ||||
173 | fdt = load_device_tree(filename, &fdt_size); | |||
174 | if (!fdt) { | |||
175 | goto out; | |||
176 | } | |||
177 | goto done; | |||
178 | } | |||
179 | ||||
180 | fdt = create_device_tree(&fdt_size); | |||
181 | if (fdt == NULL((void*)0)) { | |||
182 | goto out; | |||
183 | } | |||
184 | ||||
185 | /* Manipulate device tree in memory. */ | |||
186 | qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); | |||
187 | qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); | |||
188 | ||||
189 | qemu_fdt_add_subnode(fdt, "/memory"); | |||
190 | qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); | |||
191 | qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, | |||
192 | sizeof(mem_reg_property)); | |||
193 | ||||
194 | qemu_fdt_add_subnode(fdt, "/chosen"); | |||
195 | if (initrd_size) { | |||
196 | ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", | |||
197 | initrd_base); | |||
198 | if (ret < 0) { | |||
199 | fprintf(stderrstderr, "couldn't set /chosen/linux,initrd-start\n"); | |||
200 | } | |||
201 | ||||
202 | ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", | |||
203 | (initrd_base + initrd_size)); | |||
204 | if (ret < 0) { | |||
205 | fprintf(stderrstderr, "couldn't set /chosen/linux,initrd-end\n"); | |||
206 | } | |||
207 | } | |||
208 | ||||
209 | ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", | |||
210 | args->kernel_cmdline); | |||
211 | if (ret < 0) | |||
212 | fprintf(stderrstderr, "couldn't set /chosen/bootargs\n"); | |||
213 | ||||
214 | if (kvm_enabled()(0)) { | |||
215 | /* Read out host's frequencies */ | |||
216 | clock_freq = kvmppc_get_clockfreq(); | |||
217 | tb_freq = kvmppc_get_tbfreq(); | |||
218 | ||||
219 | /* indicate KVM hypercall interface */ | |||
220 | qemu_fdt_add_subnode(fdt, "/hypervisor"); | |||
221 | qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", | |||
222 | "linux,kvm"); | |||
223 | kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); | |||
224 | qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", | |||
225 | hypercall, sizeof(hypercall)); | |||
226 | /* if KVM supports the idle hcall, set property indicating this */ | |||
227 | if (kvmppc_get_hasidle(env)) { | |||
228 | qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL((void*)0), 0); | |||
229 | } | |||
230 | } | |||
231 | ||||
232 | /* Create CPU nodes */ | |||
233 | qemu_fdt_add_subnode(fdt, "/cpus"); | |||
234 | qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); | |||
235 | qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); | |||
236 | ||||
237 | /* We need to generate the cpu nodes in reverse order, so Linux can pick | |||
238 | the first node as boot node and be happy */ | |||
239 | for (i = smp_cpus - 1; i >= 0; i--) { | |||
240 | CPUState *cpu; | |||
241 | char cpu_name[128]; | |||
242 | uint64_t cpu_release_addr = MPC8544_SPIN_BASE0xEF000000ULL + (i * 0x20); | |||
243 | ||||
244 | cpu = qemu_get_cpu(i); | |||
245 | if (cpu == NULL((void*)0)) { | |||
246 | continue; | |||
247 | } | |||
248 | env = cpu->env_ptr; | |||
249 | ||||
250 | snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", | |||
251 | cpu->cpu_index); | |||
252 | qemu_fdt_add_subnode(fdt, cpu_name); | |||
253 | qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); | |||
254 | qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); | |||
255 | qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); | |||
256 | qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); | |||
257 | qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", | |||
258 | env->dcache_line_size); | |||
259 | qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", | |||
260 | env->icache_line_size); | |||
261 | qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); | |||
262 | qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); | |||
263 | qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); | |||
264 | if (cpu->cpu_index) { | |||
265 | qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); | |||
266 | qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", | |||
267 | "spin-table"); | |||
268 | qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", | |||
269 | cpu_release_addr); | |||
270 | } else { | |||
271 | qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); | |||
272 | } | |||
273 | } | |||
274 | ||||
275 | qemu_fdt_add_subnode(fdt, "/aliases"); | |||
276 | /* XXX These should go into their respective devices' code */ | |||
277 | snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE0xE0000000ULL); | |||
278 | qemu_fdt_add_subnode(fdt, soc); | |||
279 | qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); | |||
280 | qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, | |||
281 | sizeof(compatible_sb)); | |||
282 | qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); | |||
283 | qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); | |||
284 | qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,do { uint32_t qdt_tmp[] = { 0x0, 0xE0000000ULL >> 32, 0xE0000000ULL , 0x00100000ULL }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp [i]); } qemu_fdt_setprop(fdt, soc, "ranges", qdt_tmp, sizeof( qdt_tmp)); } while (0) | |||
285 | MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,do { uint32_t qdt_tmp[] = { 0x0, 0xE0000000ULL >> 32, 0xE0000000ULL , 0x00100000ULL }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp [i]); } qemu_fdt_setprop(fdt, soc, "ranges", qdt_tmp, sizeof( qdt_tmp)); } while (0) | |||
286 | MPC8544_CCSRBAR_SIZE)do { uint32_t qdt_tmp[] = { 0x0, 0xE0000000ULL >> 32, 0xE0000000ULL , 0x00100000ULL }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp [i]); } qemu_fdt_setprop(fdt, soc, "ranges", qdt_tmp, sizeof( qdt_tmp)); } while (0); | |||
287 | /* XXX should contain a reasonable value */ | |||
288 | qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); | |||
289 | ||||
290 | snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET0x40000ULL); | |||
291 | qemu_fdt_add_subnode(fdt, mpic); | |||
292 | qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); | |||
293 | qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); | |||
294 | qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,do { uint32_t qdt_tmp[] = { 0x40000ULL, 0x40000 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, mpic, "reg", qdt_tmp, sizeof(qdt_tmp)); } while (0) | |||
295 | 0x40000)do { uint32_t qdt_tmp[] = { 0x40000ULL, 0x40000 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, mpic, "reg", qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
296 | qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); | |||
297 | qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); | |||
298 | mpic_ph = qemu_fdt_alloc_phandle(fdt); | |||
299 | qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); | |||
300 | qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); | |||
301 | qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL((void*)0), 0); | |||
302 | ||||
303 | /* | |||
304 | * We have to generate ser1 first, because Linux takes the first | |||
305 | * device it finds in the dt as serial output device. And we generate | |||
306 | * devices in reverse order to the dt. | |||
307 | */ | |||
308 | dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET0x4600ULL, | |||
309 | soc, mpic, "serial1", 1, false0); | |||
310 | dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET0x4500ULL, | |||
311 | soc, mpic, "serial0", 0, true1); | |||
312 | ||||
313 | snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, | |||
314 | MPC8544_UTIL_OFFSET0xe0000ULL); | |||
315 | qemu_fdt_add_subnode(fdt, gutil); | |||
316 | qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); | |||
317 | qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000)do { uint32_t qdt_tmp[] = { 0xe0000ULL, 0x1000 }; int i; for ( i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt , gutil, "reg", qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
318 | qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL((void*)0), 0); | |||
319 | ||||
320 | snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET0x41600ULL); | |||
321 | qemu_fdt_add_subnode(fdt, msi); | |||
322 | qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); | |||
323 | qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200)do { uint32_t qdt_tmp[] = { 0x41600ULL, 0x200 }; int i; for ( i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt , msi, "reg", qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
324 | msi_ph = qemu_fdt_alloc_phandle(fdt); | |||
325 | qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100)do { uint32_t qdt_tmp[] = { 0x0, 0x100 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp [i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, msi, "msi-available-ranges" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
326 | qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); | |||
327 | qemu_fdt_setprop_cells(fdt, msi, "interrupts",do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
328 | 0xe0, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
329 | 0xe1, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
330 | 0xe2, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
331 | 0xe3, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
332 | 0xe4, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
333 | 0xe5, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
334 | 0xe6, 0x0,do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ) | |||
335 | 0xe7, 0x0)do { uint32_t qdt_tmp[] = { 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3 , 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, msi, "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0 ); | |||
336 | qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); | |||
337 | qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); | |||
338 | ||||
339 | snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE(0xE0000000ULL + 0x8000ULL)); | |||
340 | qemu_fdt_add_subnode(fdt, pci); | |||
341 | qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); | |||
342 | qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); | |||
343 | qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); | |||
344 | qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,do { uint32_t qdt_tmp[] = { 0xf800, 0x0, 0x0, 0x7 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, pci, "interrupt-map-mask", qdt_tmp, sizeof(qdt_tmp)); } while (0) | |||
345 | 0x0, 0x7)do { uint32_t qdt_tmp[] = { 0xf800, 0x0, 0x0, 0x7 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++ ) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop( fdt, pci, "interrupt-map-mask", qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
346 | pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), | |||
347 | params->pci_first_slot, params->pci_nr_slots, | |||
348 | &len); | |||
349 | qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); | |||
350 | qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); | |||
351 | qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2)do { uint32_t qdt_tmp[] = { 24, 2 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, pci, "interrupts" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
352 | qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255)do { uint32_t qdt_tmp[] = { 0, 255 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, pci, "bus-range" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
353 | for (i = 0; i < 14; i++) { | |||
354 | pci_ranges[i] = cpu_to_be32(pci_ranges[i]); | |||
355 | } | |||
356 | qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); | |||
357 | qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); | |||
358 | qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,do { uint32_t qdt_tmp[] = { (0xE0000000ULL + 0x8000ULL) >> 32, (0xE0000000ULL + 0x8000ULL), 0, 0x1000 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp [i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, pci, "reg" , qdt_tmp, sizeof(qdt_tmp)); } while (0) | |||
359 | MPC8544_PCI_REGS_BASE, 0, 0x1000)do { uint32_t qdt_tmp[] = { (0xE0000000ULL + 0x8000ULL) >> 32, (0xE0000000ULL + 0x8000ULL), 0, 0x1000 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp [i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, pci, "reg" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
360 | qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); | |||
361 | qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); | |||
362 | qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); | |||
363 | qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); | |||
364 | qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); | |||
365 | ||||
366 | params->fixup_devtree(params, fdt); | |||
367 | ||||
368 | if (toplevel_compat) { | |||
369 | qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, | |||
370 | strlen(toplevel_compat) + 1); | |||
371 | } | |||
372 | ||||
373 | done: | |||
374 | if (!dry_run) { | |||
375 | qemu_fdt_dumpdtb(fdt, fdt_size); | |||
376 | cpu_physical_memory_write(addr, fdt, fdt_size); | |||
377 | } | |||
378 | ret = fdt_size; | |||
379 | ||||
380 | out: | |||
381 | g_free(pci_map); | |||
382 | ||||
383 | return ret; | |||
384 | } | |||
385 | ||||
386 | typedef struct DeviceTreeParams { | |||
387 | QEMUMachineInitArgs args; | |||
388 | PPCE500Params params; | |||
389 | hwaddr addr; | |||
390 | hwaddr initrd_base; | |||
391 | hwaddr initrd_size; | |||
392 | } DeviceTreeParams; | |||
393 | ||||
394 | static void ppce500_reset_device_tree(void *opaque) | |||
395 | { | |||
396 | DeviceTreeParams *p = opaque; | |||
397 | ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base, | |||
398 | p->initrd_size, false0); | |||
399 | } | |||
400 | ||||
401 | static int ppce500_prep_device_tree(QEMUMachineInitArgs *args, | |||
402 | PPCE500Params *params, | |||
403 | hwaddr addr, | |||
404 | hwaddr initrd_base, | |||
405 | hwaddr initrd_size) | |||
406 | { | |||
407 | DeviceTreeParams *p = g_new(DeviceTreeParams, 1)((DeviceTreeParams *) g_malloc_n ((1), sizeof (DeviceTreeParams ))); | |||
408 | p->args = *args; | |||
409 | p->params = *params; | |||
410 | p->addr = addr; | |||
411 | p->initrd_base = initrd_base; | |||
412 | p->initrd_size = initrd_size; | |||
413 | ||||
414 | qemu_register_reset(ppce500_reset_device_tree, p); | |||
415 | ||||
416 | /* Issue the device tree loader once, so that we get the size of the blob */ | |||
417 | return ppce500_load_device_tree(args, params, addr, initrd_base, | |||
418 | initrd_size, true1); | |||
419 | } | |||
420 | ||||
421 | /* Create -kernel TLB entries for BookE. */ | |||
422 | static inline hwaddr booke206_page_size_to_tlb(uint64_t size) | |||
423 | { | |||
424 | return 63 - clz64(size >> 10); | |||
425 | } | |||
426 | ||||
427 | static int booke206_initial_map_tsize(CPUPPCState *env) | |||
428 | { | |||
429 | struct boot_info *bi = env->load_info; | |||
430 | hwaddr dt_end; | |||
431 | int ps; | |||
432 | ||||
433 | /* Our initial TLB entry needs to cover everything from 0 to | |||
434 | the device tree top */ | |||
435 | dt_end = bi->dt_base + bi->dt_size; | |||
436 | ps = booke206_page_size_to_tlb(dt_end) + 1; | |||
437 | if (ps & 1) { | |||
438 | /* e500v2 can only do even TLB size bits */ | |||
439 | ps++; | |||
440 | } | |||
441 | return ps; | |||
442 | } | |||
443 | ||||
444 | static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) | |||
445 | { | |||
446 | int tsize; | |||
447 | ||||
448 | tsize = booke206_initial_map_tsize(env); | |||
449 | return (1ULL << 10 << tsize); | |||
450 | } | |||
451 | ||||
452 | static void mmubooke_create_initial_mapping(CPUPPCState *env) | |||
453 | { | |||
454 | ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); | |||
455 | hwaddr size; | |||
456 | int ps; | |||
457 | ||||
458 | ps = booke206_initial_map_tsize(env); | |||
459 | size = (ps << MAS1_TSIZE_SHIFT7); | |||
460 | tlb->mas1 = MAS1_VALID0x80000000 | size; | |||
461 | tlb->mas2 = 0; | |||
462 | tlb->mas7_3 = 0; | |||
463 | tlb->mas7_3 |= MAS3_UR0x00000002 | MAS3_UW0x00000008 | MAS3_UX0x00000020 | MAS3_SR0x00000001 | MAS3_SW0x00000004 | MAS3_SX0x00000010; | |||
464 | ||||
465 | env->tlb_dirty = true1; | |||
466 | } | |||
467 | ||||
468 | static void ppce500_cpu_reset_sec(void *opaque) | |||
469 | { | |||
470 | PowerPCCPU *cpu = opaque; | |||
471 | CPUState *cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c", 471 , __func__)); | |||
472 | CPUPPCState *env = &cpu->env; | |||
473 | ||||
474 | cpu_reset(cs); | |||
475 | ||||
476 | /* Secondary CPU starts in halted state for now. Needs to change when | |||
477 | implementing non-kernel boot. */ | |||
478 | cs->halted = 1; | |||
479 | env->exception_index = EXCP_HLT0x10001; | |||
480 | } | |||
481 | ||||
482 | static void ppce500_cpu_reset(void *opaque) | |||
483 | { | |||
484 | PowerPCCPU *cpu = opaque; | |||
485 | CPUState *cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c", 485 , __func__)); | |||
486 | CPUPPCState *env = &cpu->env; | |||
487 | struct boot_info *bi = env->load_info; | |||
488 | ||||
489 | cpu_reset(cs); | |||
490 | ||||
491 | /* Set initial guest state. */ | |||
492 | cs->halted = 0; | |||
493 | env->gpr[1] = (16<<20) - 8; | |||
494 | env->gpr[3] = bi->dt_base; | |||
495 | env->gpr[4] = 0; | |||
496 | env->gpr[5] = 0; | |||
497 | env->gpr[6] = EPAPR_MAGIC(0x45504150); | |||
498 | env->gpr[7] = mmubooke_initial_mapsize(env); | |||
499 | env->gpr[8] = 0; | |||
500 | env->gpr[9] = 0; | |||
501 | env->nip = bi->entry; | |||
502 | mmubooke_create_initial_mapping(env); | |||
503 | } | |||
504 | ||||
505 | static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, | |||
506 | qemu_irq **irqs) | |||
507 | { | |||
508 | DeviceState *dev; | |||
509 | SysBusDevice *s; | |||
510 | int i, j, k; | |||
511 | ||||
512 | dev = qdev_create(NULL((void*)0), TYPE_OPENPIC"openpic"); | |||
513 | qdev_prop_set_uint32(dev, "model", params->mpic_version); | |||
514 | qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); | |||
515 | ||||
516 | qdev_init_nofail(dev); | |||
517 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 517, __func__)); | |||
518 | ||||
519 | k = 0; | |||
520 | for (i = 0; i < smp_cpus; i++) { | |||
521 | for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { | |||
522 | sysbus_connect_irq(s, k++, irqs[i][j]); | |||
523 | } | |||
524 | } | |||
525 | ||||
526 | return dev; | |||
527 | } | |||
528 | ||||
529 | static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, | |||
530 | qemu_irq **irqs) | |||
531 | { | |||
532 | DeviceState *dev; | |||
533 | CPUState *cs; | |||
534 | int r; | |||
535 | ||||
536 | dev = qdev_create(NULL((void*)0), TYPE_KVM_OPENPIC"kvm-openpic"); | |||
537 | qdev_prop_set_uint32(dev, "model", params->mpic_version); | |||
538 | ||||
539 | r = qdev_init(dev); | |||
540 | if (r) { | |||
541 | return NULL((void*)0); | |||
542 | } | |||
543 | ||||
544 | CPU_FOREACH(cs)for ((cs) = ((&cpus)->tqh_first); (cs); (cs) = ((cs)-> node.tqe_next)) { | |||
545 | if (kvm_openpic_connect_vcpu(dev, cs)) { | |||
546 | fprintf(stderrstderr, "%s: failed to connect vcpu to irqchip\n", | |||
547 | __func__); | |||
548 | abort(); | |||
549 | } | |||
550 | } | |||
551 | ||||
552 | return dev; | |||
553 | } | |||
554 | ||||
555 | static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, | |||
556 | qemu_irq **irqs) | |||
557 | { | |||
558 | qemu_irq *mpic; | |||
559 | DeviceState *dev = NULL((void*)0); | |||
560 | SysBusDevice *s; | |||
561 | int i; | |||
562 | ||||
563 | mpic = g_new(qemu_irq, 256)((qemu_irq *) g_malloc_n ((256), sizeof (qemu_irq))); | |||
564 | ||||
565 | if (kvm_enabled()(0)) { | |||
566 | QemuOpts *machine_opts = qemu_get_machine_opts(); | |||
567 | bool_Bool irqchip_allowed = qemu_opt_get_bool(machine_opts, | |||
568 | "kernel_irqchip", true1); | |||
569 | bool_Bool irqchip_required = qemu_opt_get_bool(machine_opts, | |||
570 | "kernel_irqchip", false0); | |||
571 | ||||
572 | if (irqchip_allowed) { | |||
573 | dev = ppce500_init_mpic_kvm(params, irqs); | |||
574 | } | |||
575 | ||||
576 | if (irqchip_required && !dev) { | |||
577 | fprintf(stderrstderr, "%s: irqchip requested but unavailable\n", | |||
578 | __func__); | |||
579 | abort(); | |||
580 | } | |||
581 | } | |||
582 | ||||
583 | if (!dev) { | |||
584 | dev = ppce500_init_mpic_qemu(params, irqs); | |||
585 | } | |||
586 | ||||
587 | for (i = 0; i < 256; i++) { | |||
588 | mpic[i] = qdev_get_gpio_in(dev, i); | |||
589 | } | |||
590 | ||||
591 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 591, __func__)); | |||
592 | memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET0x40000ULL, | |||
593 | s->mmio[0].memory); | |||
594 | ||||
595 | return mpic; | |||
596 | } | |||
597 | ||||
598 | void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) | |||
599 | { | |||
600 | MemoryRegion *address_space_mem = get_system_memory(); | |||
601 | MemoryRegion *ram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
602 | PCIBus *pci_bus; | |||
603 | CPUPPCState *env = NULL((void*)0); | |||
604 | uint64_t elf_entry; | |||
605 | uint64_t elf_lowaddr; | |||
606 | hwaddr entry=0; | |||
607 | hwaddr loadaddr=UIMAGE_LOAD_BASE0; | |||
608 | target_long kernel_size=0; | |||
609 | target_ulong dt_base = 0; | |||
610 | target_ulong initrd_base = 0; | |||
611 | target_long initrd_size = 0; | |||
612 | target_ulong cur_base = 0; | |||
613 | int i; | |||
614 | unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; | |||
615 | qemu_irq **irqs, *mpic; | |||
616 | DeviceState *dev; | |||
617 | CPUPPCState *firstenv = NULL((void*)0); | |||
| ||||
618 | MemoryRegion *ccsr_addr_space; | |||
619 | SysBusDevice *s; | |||
620 | PPCE500CCSRState *ccsr; | |||
621 | ||||
622 | /* Setup CPUs */ | |||
623 | if (args->cpu_model == NULL((void*)0)) { | |||
624 | args->cpu_model = "e500v2_v30"; | |||
625 | } | |||
626 | ||||
627 | irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); | |||
628 | irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); | |||
629 | for (i = 0; i < smp_cpus; i++) { | |||
630 | PowerPCCPU *cpu; | |||
631 | CPUState *cs; | |||
632 | qemu_irq *input; | |||
633 | ||||
634 | cpu = cpu_ppc_init(args->cpu_model); | |||
635 | if (cpu == NULL((void*)0)) { | |||
636 | fprintf(stderrstderr, "Unable to initialize CPU!\n"); | |||
637 | exit(1); | |||
638 | } | |||
639 | env = &cpu->env; | |||
640 | cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c", 640 , __func__)); | |||
641 | ||||
642 | if (!firstenv) { | |||
643 | firstenv = env; | |||
644 | } | |||
645 | ||||
646 | irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); | |||
647 | input = (qemu_irq *)env->irq_inputs; | |||
648 | irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; | |||
649 | irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; | |||
650 | env->spr[SPR_BOOKE_PIR(0x11E)] = cs->cpu_index = i; | |||
651 | env->mpic_iack = MPC8544_CCSRBAR_BASE0xE0000000ULL + | |||
652 | MPC8544_MPIC_REGS_OFFSET0x40000ULL + 0xa0; | |||
653 | ||||
654 | ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500(1 << 1)); | |||
655 | ||||
656 | /* Register reset handler */ | |||
657 | if (!i) { | |||
658 | /* Primary CPU */ | |||
659 | struct boot_info *boot_info; | |||
660 | boot_info = g_malloc0(sizeof(struct boot_info)); | |||
661 | qemu_register_reset(ppce500_cpu_reset, cpu); | |||
662 | env->load_info = boot_info; | |||
663 | } else { | |||
664 | /* Secondary CPUs */ | |||
665 | qemu_register_reset(ppce500_cpu_reset_sec, cpu); | |||
666 | } | |||
667 | } | |||
668 | ||||
669 | env = firstenv; | |||
670 | ||||
671 | /* Fixup Memory size on a alignment boundary */ | |||
672 | ram_size &= ~(RAM_SIZES_ALIGN(64UL << 20) - 1); | |||
673 | args->ram_size = ram_size; | |||
674 | ||||
675 | /* Register Memory */ | |||
676 | memory_region_init_ram(ram, NULL((void*)0), "mpc8544ds.ram", ram_size); | |||
677 | vmstate_register_ram_global(ram); | |||
678 | memory_region_add_subregion(address_space_mem, 0, ram); | |||
679 | ||||
680 | dev = qdev_create(NULL((void*)0), "e500-ccsr"); | |||
681 | object_property_add_child(qdev_get_machine(), "e500-ccsr", | |||
682 | OBJECT(dev)((Object *)(dev)), NULL((void*)0)); | |||
683 | qdev_init_nofail(dev); | |||
684 | ccsr = CCSR(dev)((PPCE500CCSRState *)object_dynamic_cast_assert(((Object *)(( dev))), ("e500-ccsr"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 684, __func__)); | |||
685 | ccsr_addr_space = &ccsr->ccsr_space; | |||
686 | memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE0xE0000000ULL, | |||
687 | ccsr_addr_space); | |||
688 | ||||
689 | mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); | |||
690 | ||||
691 | /* Serial */ | |||
692 | if (serial_hds[0]) { | |||
693 | serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET0x4500ULL, | |||
694 | 0, mpic[42], 399193, | |||
695 | serial_hds[0], DEVICE_BIG_ENDIAN); | |||
696 | } | |||
697 | ||||
698 | if (serial_hds[1]) { | |||
699 | serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET0x4600ULL, | |||
700 | 0, mpic[42], 399193, | |||
701 | serial_hds[1], DEVICE_BIG_ENDIAN); | |||
702 | } | |||
703 | ||||
704 | /* General Utility device */ | |||
705 | dev = qdev_create(NULL((void*)0), "mpc8544-guts"); | |||
706 | qdev_init_nofail(dev); | |||
707 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 707, __func__)); | |||
708 | memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET0xe0000ULL, | |||
709 | sysbus_mmio_get_region(s, 0)); | |||
710 | ||||
711 | /* PCI */ | |||
712 | dev = qdev_create(NULL((void*)0), "e500-pcihost"); | |||
713 | qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); | |||
714 | qdev_init_nofail(dev); | |||
715 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 715, __func__)); | |||
716 | sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]); | |||
717 | sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]); | |||
718 | sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]); | |||
719 | sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]); | |||
720 | memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET0x8000ULL, | |||
721 | sysbus_mmio_get_region(s, 0)); | |||
722 | ||||
723 | pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); | |||
724 | if (!pci_bus) | |||
725 | printf("couldn't create PCI controller!\n"); | |||
726 | ||||
727 | sysbus_mmio_map(SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 727, __func__)), 1, MPC8544_PCI_IO0xE1000000ULL); | |||
728 | ||||
729 | if (pci_bus) { | |||
730 | /* Register network interfaces. */ | |||
731 | for (i = 0; i < nb_nics; i++) { | |||
732 | pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL((void*)0)); | |||
733 | } | |||
734 | } | |||
735 | ||||
736 | /* Register spinning region */ | |||
737 | sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE0xEF000000ULL, NULL((void*)0)); | |||
738 | ||||
739 | /* Load kernel. */ | |||
740 | if (args->kernel_filename) { | |||
741 | kernel_size = load_uimage(args->kernel_filename, &entry, | |||
742 | &loadaddr, NULL((void*)0)); | |||
743 | if (kernel_size < 0) { | |||
744 | kernel_size = load_elf(args->kernel_filename, NULL((void*)0), NULL((void*)0), | |||
745 | &elf_entry, &elf_lowaddr, NULL((void*)0), 1, | |||
746 | ELF_MACHINE20, 0); | |||
747 | entry = elf_entry; | |||
748 | loadaddr = elf_lowaddr; | |||
749 | } | |||
750 | /* XXX try again as binary */ | |||
751 | if (kernel_size < 0) { | |||
752 | fprintf(stderrstderr, "qemu: could not load kernel '%s'\n", | |||
753 | args->kernel_filename); | |||
754 | exit(1); | |||
755 | } | |||
756 | ||||
757 | cur_base = loadaddr + kernel_size; | |||
758 | ||||
759 | /* Reserve space for dtb */ | |||
760 | dt_base = (cur_base + DTC_LOAD_PAD0x1800000) & ~DTC_PAD_MASK0xFFFFF; | |||
761 | cur_base += DTB_MAX_SIZE(8 * 1024 * 1024); | |||
762 | } | |||
763 | ||||
764 | /* Load initrd. */ | |||
765 | if (args->initrd_filename) { | |||
766 | initrd_base = (cur_base + INITRD_LOAD_PAD0x2000000) & ~INITRD_PAD_MASK0xFFFFFF; | |||
767 | initrd_size = load_image_targphys(args->initrd_filename, initrd_base, | |||
768 | ram_size - initrd_base); | |||
769 | ||||
770 | if (initrd_size < 0) { | |||
771 | fprintf(stderrstderr, "qemu: could not load initial ram disk '%s'\n", | |||
772 | args->initrd_filename); | |||
773 | exit(1); | |||
774 | } | |||
775 | ||||
776 | cur_base = initrd_base + initrd_size; | |||
777 | } | |||
778 | ||||
779 | /* If we're loading a kernel directly, we must load the device tree too. */ | |||
780 | if (args->kernel_filename) { | |||
781 | struct boot_info *boot_info; | |||
782 | int dt_size; | |||
783 | ||||
784 | dt_size = ppce500_prep_device_tree(args, params, dt_base, | |||
785 | initrd_base, initrd_size); | |||
786 | if (dt_size < 0) { | |||
787 | fprintf(stderrstderr, "couldn't load device tree\n"); | |||
788 | exit(1); | |||
789 | } | |||
790 | assert(dt_size < DTB_MAX_SIZE)((dt_size < (8 * 1024 * 1024)) ? (void) (0) : __assert_fail ("dt_size < (8 * 1024 * 1024)", "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 790, __PRETTY_FUNCTION__)); | |||
791 | ||||
792 | boot_info = env->load_info; | |||
| ||||
793 | boot_info->entry = entry; | |||
794 | boot_info->dt_base = dt_base; | |||
795 | boot_info->dt_size = dt_size; | |||
796 | } | |||
797 | ||||
798 | if (kvm_enabled()(0)) { | |||
799 | kvmppc_init(); | |||
800 | } | |||
801 | } | |||
802 | ||||
803 | static int e500_ccsr_initfn(SysBusDevice *dev) | |||
804 | { | |||
805 | PPCE500CCSRState *ccsr; | |||
806 | ||||
807 | ccsr = CCSR(dev)((PPCE500CCSRState *)object_dynamic_cast_assert(((Object *)(( dev))), ("e500-ccsr"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 807, __func__)); | |||
808 | memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr)((Object *)(ccsr)), "e500-ccsr", | |||
809 | MPC8544_CCSRBAR_SIZE0x00100000ULL); | |||
810 | return 0; | |||
811 | } | |||
812 | ||||
813 | static void e500_ccsr_class_init(ObjectClass *klass, void *data) | |||
814 | { | |||
815 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass)((SysBusDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ppc/e500.c" , 815, __func__)); | |||
816 | k->init = e500_ccsr_initfn; | |||
817 | } | |||
818 | ||||
819 | static const TypeInfo e500_ccsr_info = { | |||
820 | .name = TYPE_CCSR"e500-ccsr", | |||
821 | .parent = TYPE_SYS_BUS_DEVICE"sys-bus-device", | |||
822 | .instance_size = sizeof(PPCE500CCSRState), | |||
823 | .class_init = e500_ccsr_class_init, | |||
824 | }; | |||
825 | ||||
826 | static void e500_register_types(void) | |||
827 | { | |||
828 | type_register_static(&e500_ccsr_info); | |||
829 | } | |||
830 | ||||
831 | type_init(e500_register_types)static void __attribute__((constructor)) do_qemu_init_e500_register_types (void) { register_module_init(e500_register_types, MODULE_INIT_QOM ); } |