qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ppc440_bamboo.c (9951B)


      1 /*
      2  * QEMU PowerPC 440 Bamboo board emulation
      3  *
      4  * Copyright 2007 IBM Corporation.
      5  * Authors:
      6  *  Jerone Young <jyoung5@us.ibm.com>
      7  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
      8  *  Hollis Blanchard <hollisb@us.ibm.com>
      9  *
     10  * This work is licensed under the GNU GPL license version 2 or later.
     11  *
     12  */
     13 
     14 #include "qemu/osdep.h"
     15 #include "qemu/units.h"
     16 #include "qemu/error-report.h"
     17 #include "qemu/datadir.h"
     18 #include "qemu/error-report.h"
     19 #include "net/net.h"
     20 #include "hw/pci/pci.h"
     21 #include "hw/boards.h"
     22 #include "sysemu/kvm.h"
     23 #include "kvm_ppc.h"
     24 #include "sysemu/device_tree.h"
     25 #include "hw/loader.h"
     26 #include "elf.h"
     27 #include "hw/char/serial.h"
     28 #include "hw/ppc/ppc.h"
     29 #include "ppc405.h"
     30 #include "sysemu/sysemu.h"
     31 #include "sysemu/reset.h"
     32 #include "hw/sysbus.h"
     33 #include "hw/intc/ppc-uic.h"
     34 #include "hw/qdev-properties.h"
     35 #include "qapi/error.h"
     36 
     37 #include <libfdt.h>
     38 
     39 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
     40 
     41 /* from u-boot */
     42 #define KERNEL_ADDR  0x1000000
     43 #define FDT_ADDR     0x1800000
     44 #define RAMDISK_ADDR 0x1900000
     45 
     46 #define PPC440EP_PCI_CONFIG     0xeec00000
     47 #define PPC440EP_PCI_INTACK     0xeed00000
     48 #define PPC440EP_PCI_SPECIAL    0xeed00000
     49 #define PPC440EP_PCI_REGS       0xef400000
     50 #define PPC440EP_PCI_IO         0xe8000000
     51 #define PPC440EP_PCI_IOLEN      0x00010000
     52 
     53 static hwaddr entry;
     54 
     55 static int bamboo_load_device_tree(MachineState *machine,
     56                                    hwaddr addr,
     57                                    hwaddr initrd_base,
     58                                    hwaddr initrd_size)
     59 {
     60     int ret = -1;
     61     uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
     62     char *filename;
     63     int fdt_size;
     64     void *fdt;
     65     uint32_t tb_freq = 400000000;
     66     uint32_t clock_freq = 400000000;
     67 
     68     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     69     if (!filename) {
     70         return -1;
     71     }
     72     fdt = load_device_tree(filename, &fdt_size);
     73     g_free(filename);
     74     if (fdt == NULL) {
     75         return -1;
     76     }
     77 
     78     /* Manipulate device tree in memory. */
     79 
     80     ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
     81                            sizeof(mem_reg_property));
     82     if (ret < 0) {
     83         fprintf(stderr, "couldn't set /memory/reg\n");
     84     }
     85     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
     86                                 initrd_base);
     87     if (ret < 0) {
     88         fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
     89     }
     90     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
     91                                 (initrd_base + initrd_size));
     92     if (ret < 0) {
     93         fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
     94     }
     95     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
     96                                   machine->kernel_cmdline);
     97     if (ret < 0) {
     98         fprintf(stderr, "couldn't set /chosen/bootargs\n");
     99     }
    100 
    101     /*
    102      * Copy data from the host device tree into the guest. Since the guest can
    103      * directly access the timebase without host involvement, we must expose
    104      * the correct frequencies.
    105      */
    106     if (kvm_enabled()) {
    107         tb_freq = kvmppc_get_tbfreq();
    108         clock_freq = kvmppc_get_clockfreq();
    109     }
    110 
    111     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
    112                           clock_freq);
    113     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
    114                           tb_freq);
    115 
    116     rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    117 
    118     /* Set ms->fdt for 'dumpdtb' QMP/HMP command */
    119     machine->fdt = fdt;
    120 
    121     return 0;
    122 }
    123 
    124 /* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
    125 static void mmubooke_create_initial_mapping(CPUPPCState *env,
    126                                      target_ulong va,
    127                                      hwaddr pa)
    128 {
    129     ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
    130 
    131     tlb->attr = 0;
    132     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
    133     tlb->size = 1U << 31; /* up to 0x80000000  */
    134     tlb->EPN = va & TARGET_PAGE_MASK;
    135     tlb->RPN = pa & TARGET_PAGE_MASK;
    136     tlb->PID = 0;
    137 
    138     tlb = &env->tlb.tlbe[1];
    139     tlb->attr = 0;
    140     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
    141     tlb->size = 1U << 31; /* up to 0xffffffff  */
    142     tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
    143     tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
    144     tlb->PID = 0;
    145 }
    146 
    147 static void main_cpu_reset(void *opaque)
    148 {
    149     PowerPCCPU *cpu = opaque;
    150     CPUPPCState *env = &cpu->env;
    151 
    152     cpu_reset(CPU(cpu));
    153     env->gpr[1] = (16 * MiB) - 8;
    154     env->gpr[3] = FDT_ADDR;
    155     env->nip = entry;
    156 
    157     /* Create a mapping for the kernel.  */
    158     mmubooke_create_initial_mapping(env, 0, 0);
    159 }
    160 
    161 static void bamboo_init(MachineState *machine)
    162 {
    163     const char *kernel_filename = machine->kernel_filename;
    164     const char *initrd_filename = machine->initrd_filename;
    165     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
    166     MemoryRegion *address_space_mem = get_system_memory();
    167     MemoryRegion *isa = g_new(MemoryRegion, 1);
    168     PCIBus *pcibus;
    169     PowerPCCPU *cpu;
    170     CPUPPCState *env;
    171     target_long initrd_size = 0;
    172     DeviceState *dev;
    173     DeviceState *uicdev;
    174     SysBusDevice *uicsbd;
    175     int success;
    176     int i;
    177 
    178     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
    179     env = &cpu->env;
    180 
    181     if (env->mmu_model != POWERPC_MMU_BOOKE) {
    182         error_report("MMU model %i not supported by this machine",
    183                      env->mmu_model);
    184         exit(1);
    185     }
    186 
    187     qemu_register_reset(main_cpu_reset, cpu);
    188     ppc_booke_timers_init(cpu, 400000000, 0);
    189     ppc_dcr_init(env, NULL, NULL);
    190 
    191     /* interrupt controller */
    192     uicdev = qdev_new(TYPE_PPC_UIC);
    193     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
    194     object_unref(OBJECT(uicdev));
    195     uicsbd = SYS_BUS_DEVICE(uicdev);
    196     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
    197                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
    198     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
    199                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
    200 
    201     /* SDRAM controller */
    202     dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR);
    203     object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
    204                              &error_abort);
    205     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
    206     object_unref(OBJECT(dev));
    207     /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
    208     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14));
    209     /* Enable SDRAM memory regions, this should be done by the firmware */
    210     ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
    211 
    212     /* PCI */
    213     dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
    214                                 PPC440EP_PCI_CONFIG,
    215                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
    216                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
    217                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
    218                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
    219                                 NULL);
    220     pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
    221     if (!pcibus) {
    222         error_report("couldn't create PCI controller");
    223         exit(1);
    224     }
    225 
    226     memory_region_init_alias(isa, NULL, "isa_mmio",
    227                              get_system_io(), 0, PPC440EP_PCI_IOLEN);
    228     memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
    229 
    230     if (serial_hd(0) != NULL) {
    231         serial_mm_init(address_space_mem, 0xef600300, 0,
    232                        qdev_get_gpio_in(uicdev, 0),
    233                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
    234                        DEVICE_BIG_ENDIAN);
    235     }
    236     if (serial_hd(1) != NULL) {
    237         serial_mm_init(address_space_mem, 0xef600400, 0,
    238                        qdev_get_gpio_in(uicdev, 1),
    239                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
    240                        DEVICE_BIG_ENDIAN);
    241     }
    242 
    243     if (pcibus) {
    244         /* Register network interfaces. */
    245         for (i = 0; i < nb_nics; i++) {
    246             /*
    247              * There are no PCI NICs on the Bamboo board, but there are
    248              * PCI slots, so we can pick whatever default model we want.
    249              */
    250             pci_nic_init_nofail(&nd_table[i], pcibus, "e1000", NULL);
    251         }
    252     }
    253 
    254     /* Load kernel. */
    255     if (kernel_filename) {
    256         hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
    257         success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
    258                               NULL, NULL);
    259         if (success < 0) {
    260             uint64_t elf_entry;
    261             success = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
    262                                NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
    263             entry = elf_entry;
    264         }
    265         /* XXX try again as binary */
    266         if (success < 0) {
    267             error_report("could not load kernel '%s'", kernel_filename);
    268             exit(1);
    269         }
    270     }
    271 
    272     /* Load initrd. */
    273     if (initrd_filename) {
    274         initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
    275                                           machine->ram_size - RAMDISK_ADDR);
    276 
    277         if (initrd_size < 0) {
    278             error_report("could not load ram disk '%s' at %x",
    279                          initrd_filename, RAMDISK_ADDR);
    280             exit(1);
    281         }
    282     }
    283 
    284     /* If we're loading a kernel directly, we must load the device tree too. */
    285     if (kernel_filename) {
    286         if (bamboo_load_device_tree(machine, FDT_ADDR,
    287                                     RAMDISK_ADDR, initrd_size) < 0) {
    288             error_report("couldn't load device tree");
    289             exit(1);
    290         }
    291     }
    292 }
    293 
    294 static void bamboo_machine_init(MachineClass *mc)
    295 {
    296     mc->desc = "bamboo";
    297     mc->init = bamboo_init;
    298     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("440epb");
    299     mc->default_ram_id = "ppc4xx.sdram";
    300 }
    301 
    302 DEFINE_MACHINE("bamboo", bamboo_machine_init)