|
|
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 "virtio-blk.h" ! 26: #include "boards.h" ! 27: #include "sysemu.h" ! 28: #include "kvm.h" ! 29: #include "kvm_ppc.h" ! 30: #include "device_tree.h" ! 31: #include "openpic.h" ! 32: #include "ppce500.h" ! 33: ! 34: #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" ! 35: #define UIMAGE_LOAD_BASE 0 ! 36: #define DTB_LOAD_BASE 0x600000 ! 37: #define INITRD_LOAD_BASE 0x2000000 ! 38: ! 39: #define RAM_SIZES_ALIGN (64UL << 20) ! 40: ! 41: #define MPC8544_CCSRBAR_BASE 0xE0000000 ! 42: #define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000) ! 43: #define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500) ! 44: #define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600) ! 45: #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000) ! 46: #define MPC8544_PCI_REGS_SIZE 0x1000 ! 47: #define MPC8544_PCI_IO 0xE1000000 ! 48: #define MPC8544_PCI_IOLEN 0x10000 ! 49: ! 50: static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop) ! 51: { ! 52: uint32_t cell; ! 53: int ret; ! 54: ! 55: ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell)); ! 56: if (ret < 0) { ! 57: fprintf(stderr, "couldn't read host %s/%s\n", node, prop); ! 58: goto out; ! 59: } ! 60: ! 61: ret = qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0", ! 62: prop, cell); ! 63: if (ret < 0) { ! 64: fprintf(stderr, "couldn't set guest /cpus/PowerPC,8544@0/%s\n", prop); ! 65: goto out; ! 66: } ! 67: ! 68: out: ! 69: return ret; ! 70: } ! 71: ! 72: static void *mpc8544_load_device_tree(void *addr, ! 73: uint32_t ramsize, ! 74: target_phys_addr_t initrd_base, ! 75: target_phys_addr_t initrd_size, ! 76: const char *kernel_cmdline) ! 77: { ! 78: void *fdt = NULL; ! 79: #ifdef HAVE_FDT ! 80: uint32_t mem_reg_property[] = {0, ramsize}; ! 81: char *path; ! 82: int pathlen; ! 83: int ret; ! 84: ! 85: pathlen = snprintf(NULL, 0, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE) + 1; ! 86: path = qemu_malloc(pathlen); ! 87: ! 88: snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE); ! 89: ! 90: fdt = load_device_tree(path, addr); ! 91: qemu_free(path); ! 92: if (fdt == NULL) ! 93: goto out; ! 94: ! 95: /* Manipulate device tree in memory. */ ! 96: ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, ! 97: sizeof(mem_reg_property)); ! 98: if (ret < 0) ! 99: fprintf(stderr, "couldn't set /memory/reg\n"); ! 100: ! 101: ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", ! 102: initrd_base); ! 103: if (ret < 0) ! 104: fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); ! 105: ! 106: ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", ! 107: (initrd_base + initrd_size)); ! 108: if (ret < 0) ! 109: fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); ! 110: ! 111: ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", ! 112: kernel_cmdline); ! 113: if (ret < 0) ! 114: fprintf(stderr, "couldn't set /chosen/bootargs\n"); ! 115: ! 116: if (kvm_enabled()) { ! 117: struct dirent *dirp; ! 118: DIR *dp; ! 119: char buf[128]; ! 120: ! 121: if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) { ! 122: printf("Can't open directory /proc/device-tree/cpus/\n"); ! 123: goto out; ! 124: } ! 125: ! 126: buf[0] = '\0'; ! 127: while ((dirp = readdir(dp)) != NULL) { ! 128: if (strncmp(dirp->d_name, "PowerPC", 7) == 0) { ! 129: snprintf(buf, 128, "/cpus/%s", dirp->d_name); ! 130: break; ! 131: } ! 132: } ! 133: closedir(dp); ! 134: if (buf[0] == '\0') { ! 135: printf("Unknow host!\n"); ! 136: goto out; ! 137: } ! 138: ! 139: mpc8544_copy_soc_cell(fdt, buf, "clock-frequency"); ! 140: mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); ! 141: } ! 142: ! 143: out: ! 144: #endif ! 145: ! 146: return fdt; ! 147: } ! 148: ! 149: static void mpc8544ds_init(ram_addr_t ram_size, int vga_ram_size, ! 150: const char *boot_device, ! 151: const char *kernel_filename, ! 152: const char *kernel_cmdline, ! 153: const char *initrd_filename, ! 154: const char *cpu_model) ! 155: { ! 156: PCIBus *pci_bus; ! 157: CPUState *env; ! 158: uint64_t elf_entry; ! 159: uint64_t elf_lowaddr; ! 160: target_ulong entry=0; ! 161: target_ulong loadaddr=UIMAGE_LOAD_BASE; ! 162: target_long kernel_size=0; ! 163: target_ulong dt_base=DTB_LOAD_BASE; ! 164: target_ulong initrd_base=INITRD_LOAD_BASE; ! 165: target_long initrd_size=0; ! 166: void *fdt; ! 167: int i=0; ! 168: unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; ! 169: qemu_irq *irqs, *mpic, *pci_irqs; ! 170: SerialState * serial[2]; ! 171: ! 172: /* Setup CPU */ ! 173: env = cpu_ppc_init("e500v2_v30"); ! 174: if (!env) { ! 175: fprintf(stderr, "Unable to initialize CPU!\n"); ! 176: exit(1); ! 177: } ! 178: ! 179: /* Fixup Memory size on a alignment boundary */ ! 180: ram_size &= ~(RAM_SIZES_ALIGN - 1); ! 181: ! 182: /* Register Memory */ ! 183: cpu_register_physical_memory(0, ram_size, 0); ! 184: ! 185: /* MPIC */ ! 186: irqs = qemu_mallocz(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); ! 187: irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT]; ! 188: irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT]; ! 189: mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL); ! 190: ! 191: /* Serial */ ! 192: if (serial_hds[0]) ! 193: serial[0] = serial_mm_init(MPC8544_SERIAL0_REGS_BASE, ! 194: 0, mpic[12+26], 399193, ! 195: serial_hds[0], 1); ! 196: ! 197: if (serial_hds[1]) ! 198: serial[0] = serial_mm_init(MPC8544_SERIAL1_REGS_BASE, ! 199: 0, mpic[12+26], 399193, ! 200: serial_hds[0], 1); ! 201: ! 202: /* PCI */ ! 203: pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4); ! 204: pci_irqs[0] = mpic[pci_irq_nrs[0]]; ! 205: pci_irqs[1] = mpic[pci_irq_nrs[1]]; ! 206: pci_irqs[2] = mpic[pci_irq_nrs[2]]; ! 207: pci_irqs[3] = mpic[pci_irq_nrs[3]]; ! 208: pci_bus = ppce500_pci_init(pci_irqs, MPC8544_PCI_REGS_BASE); ! 209: if (!pci_bus) ! 210: printf("couldn't create PCI controller!\n"); ! 211: ! 212: isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); ! 213: ! 214: if (pci_bus) { ! 215: int unit_id = 0; ! 216: ! 217: /* Add virtio block devices. */ ! 218: while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { ! 219: virtio_blk_init(pci_bus, drives_table[i].bdrv); ! 220: unit_id++; ! 221: } ! 222: ! 223: /* Register network interfaces. */ ! 224: for (i = 0; i < nb_nics; i++) { ! 225: pci_nic_init(pci_bus, &nd_table[i], -1, "virtio"); ! 226: } ! 227: } ! 228: ! 229: /* Load kernel. */ ! 230: if (kernel_filename) { ! 231: kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); ! 232: if (kernel_size < 0) { ! 233: kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_lowaddr, ! 234: NULL); ! 235: entry = elf_entry; ! 236: loadaddr = elf_lowaddr; ! 237: } ! 238: /* XXX try again as binary */ ! 239: if (kernel_size < 0) { ! 240: fprintf(stderr, "qemu: could not load kernel '%s'\n", ! 241: kernel_filename); ! 242: exit(1); ! 243: } ! 244: } ! 245: ! 246: /* Load initrd. */ ! 247: if (initrd_filename) { ! 248: initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); ! 249: ! 250: if (initrd_size < 0) { ! 251: fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", ! 252: initrd_filename); ! 253: exit(1); ! 254: } ! 255: } ! 256: ! 257: /* If we're loading a kernel directly, we must load the device tree too. */ ! 258: if (kernel_filename) { ! 259: fdt = mpc8544_load_device_tree(phys_ram_base + dt_base, ram_size, ! 260: initrd_base, initrd_size, kernel_cmdline); ! 261: if (fdt == NULL) { ! 262: fprintf(stderr, "couldn't load device tree\n"); ! 263: exit(1); ! 264: } ! 265: ! 266: /* Set initial guest state. */ ! 267: env->gpr[1] = (16<<20) - 8; ! 268: env->gpr[3] = dt_base; ! 269: env->nip = entry; ! 270: /* XXX we currently depend on KVM to create some initial TLB entries. */ ! 271: } ! 272: ! 273: if (kvm_enabled()) ! 274: kvmppc_init(); ! 275: ! 276: return; ! 277: } ! 278: ! 279: QEMUMachine mpc8544ds_machine = { ! 280: .name = "mpc8544ds", ! 281: .desc = "mpc8544ds", ! 282: .init = mpc8544ds_init, ! 283: .ram_require = RAM_SIZES_ALIGN | RAMSIZE_FIXED, ! 284: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.