|
|
1.1 root 1: /*
2: * Qemu PowerPC MPC8544DS board emualtion
3: *
4: * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
5: *
6: * Author: Yu Liu, <[email protected]>
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 <dirent.h>
18:
19: #include "config.h"
20: #include "qemu-common.h"
21: #include "net.h"
22: #include "hw.h"
23: #include "pc.h"
24: #include "pci.h"
25: #include "boards.h"
26: #include "sysemu.h"
27: #include "kvm.h"
28: #include "kvm_ppc.h"
29: #include "device_tree.h"
30: #include "openpic.h"
1.1.1.6 ! root 31: #include "ppc.h"
1.1.1.3 root 32: #include "loader.h"
33: #include "elf.h"
1.1.1.6 ! root 34: #include "sysbus.h"
1.1 root 35:
36: #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
37: #define UIMAGE_LOAD_BASE 0
1.1.1.4 root 38: #define DTC_LOAD_PAD 0x500000
39: #define DTC_PAD_MASK 0xFFFFF
40: #define INITRD_LOAD_PAD 0x2000000
41: #define INITRD_PAD_MASK 0xFFFFFF
1.1 root 42:
43: #define RAM_SIZES_ALIGN (64UL << 20)
44:
45: #define MPC8544_CCSRBAR_BASE 0xE0000000
46: #define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
47: #define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
48: #define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600)
49: #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000)
50: #define MPC8544_PCI_REGS_SIZE 0x1000
51: #define MPC8544_PCI_IO 0xE1000000
52: #define MPC8544_PCI_IOLEN 0x10000
1.1.1.6 ! root 53: #define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
! 54:
! 55: struct boot_info
! 56: {
! 57: uint32_t dt_base;
! 58: uint32_t entry;
! 59: };
1.1 root 60:
1.1.1.3 root 61: #ifdef CONFIG_FDT
1.1 root 62: static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
63: {
64: uint32_t cell;
65: int ret;
66:
67: ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
68: if (ret < 0) {
69: fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
70: goto out;
71: }
72:
73: ret = qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
74: prop, cell);
75: if (ret < 0) {
76: fprintf(stderr, "couldn't set guest /cpus/PowerPC,8544@0/%s\n", prop);
77: goto out;
78: }
79:
80: out:
81: return ret;
82: }
1.1.1.2 root 83: #endif
1.1 root 84:
1.1.1.6 ! root 85: static int mpc8544_load_device_tree(CPUState *env,
! 86: target_phys_addr_t addr,
! 87: uint32_t ramsize,
! 88: target_phys_addr_t initrd_base,
! 89: target_phys_addr_t initrd_size,
! 90: const char *kernel_cmdline)
1.1 root 91: {
1.1.1.4 root 92: int ret = -1;
1.1.1.3 root 93: #ifdef CONFIG_FDT
1.1.1.6 ! root 94: uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
1.1.1.2 root 95: char *filename;
96: int fdt_size;
1.1.1.4 root 97: void *fdt;
1.1.1.6 ! root 98: uint8_t hypercall[16];
1.1 root 99:
1.1.1.2 root 100: filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
101: if (!filename) {
102: goto out;
103: }
104: fdt = load_device_tree(filename, &fdt_size);
105: qemu_free(filename);
106: if (fdt == NULL) {
1.1 root 107: goto out;
1.1.1.2 root 108: }
1.1 root 109:
110: /* Manipulate device tree in memory. */
111: ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
112: sizeof(mem_reg_property));
113: if (ret < 0)
114: fprintf(stderr, "couldn't set /memory/reg\n");
115:
1.1.1.6 ! root 116: if (initrd_size) {
! 117: ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
! 118: initrd_base);
! 119: if (ret < 0) {
! 120: fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
! 121: }
1.1 root 122:
1.1.1.6 ! root 123: ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
! 124: (initrd_base + initrd_size));
! 125: if (ret < 0) {
! 126: fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
! 127: }
! 128: }
1.1 root 129:
130: ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
131: kernel_cmdline);
132: if (ret < 0)
133: fprintf(stderr, "couldn't set /chosen/bootargs\n");
134:
135: if (kvm_enabled()) {
136: struct dirent *dirp;
137: DIR *dp;
138: char buf[128];
139:
140: if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) {
141: printf("Can't open directory /proc/device-tree/cpus/\n");
1.1.1.4 root 142: ret = -1;
1.1 root 143: goto out;
144: }
145:
146: buf[0] = '\0';
147: while ((dirp = readdir(dp)) != NULL) {
148: if (strncmp(dirp->d_name, "PowerPC", 7) == 0) {
149: snprintf(buf, 128, "/cpus/%s", dirp->d_name);
150: break;
151: }
152: }
153: closedir(dp);
154: if (buf[0] == '\0') {
155: printf("Unknow host!\n");
1.1.1.4 root 156: ret = -1;
1.1 root 157: goto out;
158: }
159:
160: mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
161: mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
1.1.1.6 ! root 162:
! 163: /* indicate KVM hypercall interface */
! 164: qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
! 165: "linux,kvm");
! 166: kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
! 167: qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
! 168: hypercall, sizeof(hypercall));
! 169: } else {
! 170: const uint32_t freq = 400000000;
! 171:
! 172: qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
! 173: "clock-frequency", freq);
! 174: qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
! 175: "timebase-frequency", freq);
1.1 root 176: }
177:
1.1.1.4 root 178: ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
179: qemu_free(fdt);
1.1.1.2 root 180:
1.1 root 181: out:
182: #endif
183:
1.1.1.4 root 184: return ret;
1.1 root 185: }
186:
1.1.1.6 ! root 187: /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
! 188: static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
! 189: {
! 190: return (ffs(size >> 10) - 1) >> 1;
! 191: }
! 192:
! 193: static void mmubooke_create_initial_mapping(CPUState *env,
! 194: target_ulong va,
! 195: target_phys_addr_t pa)
! 196: {
! 197: ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
! 198: target_phys_addr_t size;
! 199:
! 200: size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
! 201: tlb->mas1 = MAS1_VALID | size;
! 202: tlb->mas2 = va & TARGET_PAGE_MASK;
! 203: tlb->mas7_3 = pa & TARGET_PAGE_MASK;
! 204: tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
! 205: }
! 206:
! 207: static void mpc8544ds_cpu_reset(void *opaque)
! 208: {
! 209: CPUState *env = opaque;
! 210: struct boot_info *bi = env->load_info;
! 211:
! 212: cpu_reset(env);
! 213:
! 214: /* Set initial guest state. */
! 215: env->gpr[1] = (16<<20) - 8;
! 216: env->gpr[3] = bi->dt_base;
! 217: env->nip = bi->entry;
! 218: mmubooke_create_initial_mapping(env, 0, 0);
! 219: }
! 220:
1.1.1.2 root 221: static void mpc8544ds_init(ram_addr_t ram_size,
1.1 root 222: const char *boot_device,
223: const char *kernel_filename,
224: const char *kernel_cmdline,
225: const char *initrd_filename,
226: const char *cpu_model)
227: {
228: PCIBus *pci_bus;
229: CPUState *env;
230: uint64_t elf_entry;
231: uint64_t elf_lowaddr;
1.1.1.3 root 232: target_phys_addr_t entry=0;
233: target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
1.1 root 234: target_long kernel_size=0;
1.1.1.4 root 235: target_ulong dt_base = 0;
236: target_ulong initrd_base = 0;
1.1 root 237: target_long initrd_size=0;
238: int i=0;
239: unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
1.1.1.6 ! root 240: qemu_irq *irqs, *mpic;
! 241: DeviceState *dev;
! 242: struct boot_info *boot_info;
1.1 root 243:
244: /* Setup CPU */
1.1.1.6 ! root 245: if (cpu_model == NULL) {
! 246: cpu_model = "e500v2_v30";
! 247: }
! 248:
! 249: env = cpu_ppc_init(cpu_model);
1.1 root 250: if (!env) {
251: fprintf(stderr, "Unable to initialize CPU!\n");
252: exit(1);
253: }
254:
1.1.1.6 ! root 255: /* XXX register timer? */
! 256: ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
! 257: ppc_dcr_init(env, NULL, NULL);
! 258:
! 259: /* Register reset handler */
! 260: qemu_register_reset(mpc8544ds_cpu_reset, env);
! 261:
1.1 root 262: /* Fixup Memory size on a alignment boundary */
263: ram_size &= ~(RAM_SIZES_ALIGN - 1);
264:
265: /* Register Memory */
1.1.1.4 root 266: cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL,
267: "mpc8544ds.ram", ram_size));
1.1 root 268:
269: /* MPIC */
270: irqs = qemu_mallocz(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
271: irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
272: irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
273: mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
274:
275: /* Serial */
1.1.1.4 root 276: if (serial_hds[0]) {
1.1.1.5 root 277: serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
278: 0, mpic[12+26], 399193,
279: serial_hds[0], 1, 1);
1.1.1.4 root 280: }
1.1 root 281:
1.1.1.4 root 282: if (serial_hds[1]) {
1.1.1.5 root 283: serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
284: 0, mpic[12+26], 399193,
285: serial_hds[0], 1, 1);
1.1.1.4 root 286: }
1.1 root 287:
1.1.1.6 ! root 288: /* General Utility device */
! 289: sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
! 290:
1.1 root 291: /* PCI */
1.1.1.6 ! root 292: dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
! 293: mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
! 294: mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
! 295: NULL);
! 296: pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
1.1 root 297: if (!pci_bus)
298: printf("couldn't create PCI controller!\n");
299:
1.1.1.5 root 300: isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
1.1 root 301:
302: if (pci_bus) {
303: /* Register network interfaces. */
304: for (i = 0; i < nb_nics; i++) {
1.1.1.3 root 305: pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
1.1 root 306: }
307: }
308:
309: /* Load kernel. */
310: if (kernel_filename) {
311: kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
312: if (kernel_size < 0) {
1.1.1.4 root 313: kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
314: &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
1.1 root 315: entry = elf_entry;
316: loadaddr = elf_lowaddr;
317: }
318: /* XXX try again as binary */
319: if (kernel_size < 0) {
320: fprintf(stderr, "qemu: could not load kernel '%s'\n",
321: kernel_filename);
322: exit(1);
323: }
324: }
325:
326: /* Load initrd. */
327: if (initrd_filename) {
1.1.1.4 root 328: initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
1.1.1.2 root 329: initrd_size = load_image_targphys(initrd_filename, initrd_base,
330: ram_size - initrd_base);
1.1 root 331:
332: if (initrd_size < 0) {
333: fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
334: initrd_filename);
335: exit(1);
336: }
337: }
338:
1.1.1.6 ! root 339: boot_info = qemu_mallocz(sizeof(struct boot_info));
! 340:
1.1 root 341: /* If we're loading a kernel directly, we must load the device tree too. */
342: if (kernel_filename) {
1.1.1.6 ! root 343: #ifndef CONFIG_FDT
! 344: cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
! 345: #endif
1.1.1.4 root 346: dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
1.1.1.6 ! root 347: if (mpc8544_load_device_tree(env, dt_base, ram_size,
1.1.1.4 root 348: initrd_base, initrd_size, kernel_cmdline) < 0) {
1.1 root 349: fprintf(stderr, "couldn't load device tree\n");
350: exit(1);
351: }
352:
1.1.1.6 ! root 353: boot_info->entry = entry;
! 354: boot_info->dt_base = dt_base;
1.1 root 355: }
1.1.1.6 ! root 356: env->load_info = boot_info;
1.1 root 357:
1.1.1.6 ! root 358: if (kvm_enabled()) {
1.1 root 359: kvmppc_init();
1.1.1.6 ! root 360: }
1.1 root 361: }
362:
1.1.1.2 root 363: static QEMUMachine mpc8544ds_machine = {
1.1 root 364: .name = "mpc8544ds",
365: .desc = "mpc8544ds",
366: .init = mpc8544ds_init,
367: };
1.1.1.2 root 368:
369: static void mpc8544ds_machine_init(void)
370: {
371: qemu_register_machine(&mpc8544ds_machine);
372: }
373:
374: machine_init(mpc8544ds_machine_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.