qemu/hw/openrisc/openrisc_sim.c
<<
>>
Prefs
   1/*
   2 * OpenRISC simulator for use as an IIS.
   3 *
   4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
   5 *                         Feng Gao <gf91597@gmail.com>
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qemu/error-report.h"
  23#include "qapi/error.h"
  24#include "cpu.h"
  25#include "hw/irq.h"
  26#include "hw/boards.h"
  27#include "elf.h"
  28#include "hw/char/serial.h"
  29#include "net/net.h"
  30#include "hw/loader.h"
  31#include "hw/qdev-properties.h"
  32#include "sysemu/sysemu.h"
  33#include "hw/sysbus.h"
  34#include "sysemu/qtest.h"
  35#include "sysemu/reset.h"
  36#include "hw/core/split-irq.h"
  37
  38#define KERNEL_LOAD_ADDR 0x100
  39
  40static struct openrisc_boot_info {
  41    uint32_t bootstrap_pc;
  42} boot_info;
  43
  44static void main_cpu_reset(void *opaque)
  45{
  46    OpenRISCCPU *cpu = opaque;
  47    CPUState *cs = CPU(cpu);
  48
  49    cpu_reset(CPU(cpu));
  50
  51    cpu_set_pc(cs, boot_info.bootstrap_pc);
  52}
  53
  54static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin)
  55{
  56    return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin);
  57}
  58
  59static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors,
  60                                  int num_cpus, OpenRISCCPU *cpus[],
  61                                  int irq_pin, NICInfo *nd)
  62{
  63    DeviceState *dev;
  64    SysBusDevice *s;
  65    int i;
  66
  67    dev = qdev_new("open_eth");
  68    qdev_set_nic_properties(dev, nd);
  69
  70    s = SYS_BUS_DEVICE(dev);
  71    sysbus_realize_and_unref(s, &error_fatal);
  72    if (num_cpus > 1) {
  73        DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ);
  74        qdev_prop_set_uint32(splitter, "num-lines", num_cpus);
  75        qdev_realize_and_unref(splitter, NULL, &error_fatal);
  76        for (i = 0; i < num_cpus; i++) {
  77            qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin));
  78        }
  79        sysbus_connect_irq(s, 0, qdev_get_gpio_in(splitter, 0));
  80    } else {
  81        sysbus_connect_irq(s, 0, get_cpu_irq(cpus, 0, irq_pin));
  82    }
  83    sysbus_mmio_map(s, 0, base);
  84    sysbus_mmio_map(s, 1, descriptors);
  85}
  86
  87static void openrisc_sim_ompic_init(hwaddr base, int num_cpus,
  88                                    OpenRISCCPU *cpus[], int irq_pin)
  89{
  90    DeviceState *dev;
  91    SysBusDevice *s;
  92    int i;
  93
  94    dev = qdev_new("or1k-ompic");
  95    qdev_prop_set_uint32(dev, "num-cpus", num_cpus);
  96
  97    s = SYS_BUS_DEVICE(dev);
  98    sysbus_realize_and_unref(s, &error_fatal);
  99    for (i = 0; i < num_cpus; i++) {
 100        sysbus_connect_irq(s, i, get_cpu_irq(cpus, i, irq_pin));
 101    }
 102    sysbus_mmio_map(s, 0, base);
 103}
 104
 105static void openrisc_load_kernel(ram_addr_t ram_size,
 106                                 const char *kernel_filename)
 107{
 108    long kernel_size;
 109    uint64_t elf_entry;
 110    hwaddr entry;
 111
 112    if (kernel_filename && !qtest_enabled()) {
 113        kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
 114                               &elf_entry, NULL, NULL, NULL, 1, EM_OPENRISC,
 115                               1, 0);
 116        entry = elf_entry;
 117        if (kernel_size < 0) {
 118            kernel_size = load_uimage(kernel_filename,
 119                                      &entry, NULL, NULL, NULL, NULL);
 120        }
 121        if (kernel_size < 0) {
 122            kernel_size = load_image_targphys(kernel_filename,
 123                                              KERNEL_LOAD_ADDR,
 124                                              ram_size - KERNEL_LOAD_ADDR);
 125        }
 126
 127        if (entry <= 0) {
 128            entry = KERNEL_LOAD_ADDR;
 129        }
 130
 131        if (kernel_size < 0) {
 132            error_report("couldn't load the kernel '%s'", kernel_filename);
 133            exit(1);
 134        }
 135        boot_info.bootstrap_pc = entry;
 136    }
 137}
 138
 139static void openrisc_sim_init(MachineState *machine)
 140{
 141    ram_addr_t ram_size = machine->ram_size;
 142    const char *kernel_filename = machine->kernel_filename;
 143    OpenRISCCPU *cpus[2] = {};
 144    MemoryRegion *ram;
 145    qemu_irq serial_irq;
 146    int n;
 147    unsigned int smp_cpus = machine->smp.cpus;
 148
 149    assert(smp_cpus >= 1 && smp_cpus <= 2);
 150    for (n = 0; n < smp_cpus; n++) {
 151        cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type));
 152        if (cpus[n] == NULL) {
 153            fprintf(stderr, "Unable to find CPU definition!\n");
 154            exit(1);
 155        }
 156
 157        cpu_openrisc_clock_init(cpus[n]);
 158
 159        qemu_register_reset(main_cpu_reset, cpus[n]);
 160    }
 161
 162    ram = g_malloc(sizeof(*ram));
 163    memory_region_init_ram(ram, NULL, "openrisc.ram", ram_size, &error_fatal);
 164    memory_region_add_subregion(get_system_memory(), 0, ram);
 165
 166    if (nd_table[0].used) {
 167        openrisc_sim_net_init(0x92000000, 0x92000400, smp_cpus,
 168                              cpus, 4, nd_table);
 169    }
 170
 171    if (smp_cpus > 1) {
 172        openrisc_sim_ompic_init(0x98000000, smp_cpus, cpus, 1);
 173
 174        serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2),
 175                                    get_cpu_irq(cpus, 1, 2));
 176    } else {
 177        serial_irq = get_cpu_irq(cpus, 0, 2);
 178    }
 179
 180    serial_mm_init(get_system_memory(), 0x90000000, 0, serial_irq,
 181                   115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
 182
 183    openrisc_load_kernel(ram_size, kernel_filename);
 184}
 185
 186static void openrisc_sim_machine_init(MachineClass *mc)
 187{
 188    mc->desc = "or1k simulation";
 189    mc->init = openrisc_sim_init;
 190    mc->max_cpus = 2;
 191    mc->is_default = true;
 192    mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200");
 193}
 194
 195DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init)
 196