qemu/hw/mips_mipssim.c
<<
>>
Prefs
   1/*
   2 * QEMU/mipssim emulation
   3 *
   4 * Emulates a very simple machine model similiar to the one use by the
   5 * proprietary MIPS emulator.
   6 * 
   7 * Copyright (c) 2007 Thiemo Seufer
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27#include "hw.h"
  28#include "mips.h"
  29#include "pc.h"
  30#include "isa.h"
  31#include "net.h"
  32#include "sysemu.h"
  33#include "boards.h"
  34
  35#ifdef TARGET_WORDS_BIGENDIAN
  36#define BIOS_FILENAME "mips_bios.bin"
  37#else
  38#define BIOS_FILENAME "mipsel_bios.bin"
  39#endif
  40
  41#ifdef TARGET_MIPS64
  42#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
  43#else
  44#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
  45#endif
  46
  47#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
  48
  49static struct _loaderparams {
  50    int ram_size;
  51    const char *kernel_filename;
  52    const char *kernel_cmdline;
  53    const char *initrd_filename;
  54} loaderparams;
  55
  56static void load_kernel (CPUState *env)
  57{
  58    int64_t entry, kernel_low, kernel_high;
  59    long kernel_size;
  60    long initrd_size;
  61    ram_addr_t initrd_offset;
  62
  63    kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
  64                           (uint64_t *)&entry, (uint64_t *)&kernel_low,
  65                           (uint64_t *)&kernel_high);
  66    if (kernel_size >= 0) {
  67        if ((entry & ~0x7fffffffULL) == 0x80000000)
  68            entry = (int32_t)entry;
  69        env->active_tc.PC = entry;
  70    } else {
  71        fprintf(stderr, "qemu: could not load kernel '%s'\n",
  72                loaderparams.kernel_filename);
  73        exit(1);
  74    }
  75
  76    /* load initrd */
  77    initrd_size = 0;
  78    initrd_offset = 0;
  79    if (loaderparams.initrd_filename) {
  80        initrd_size = get_image_size (loaderparams.initrd_filename);
  81        if (initrd_size > 0) {
  82            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
  83            if (initrd_offset + initrd_size > loaderparams.ram_size) {
  84                fprintf(stderr,
  85                        "qemu: memory too small for initial ram disk '%s'\n",
  86                        loaderparams.initrd_filename);
  87                exit(1);
  88            }
  89            initrd_size = load_image(loaderparams.initrd_filename,
  90                                     phys_ram_base + initrd_offset);
  91        }
  92        if (initrd_size == (target_ulong) -1) {
  93            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
  94                    loaderparams.initrd_filename);
  95            exit(1);
  96        }
  97    }
  98}
  99
 100static void main_cpu_reset(void *opaque)
 101{
 102    CPUState *env = opaque;
 103    cpu_reset(env);
 104
 105    if (loaderparams.kernel_filename)
 106        load_kernel (env);
 107}
 108
 109static void
 110mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
 111                   const char *boot_device,
 112                   const char *kernel_filename, const char *kernel_cmdline,
 113                   const char *initrd_filename, const char *cpu_model)
 114{
 115    char buf[1024];
 116    unsigned long bios_offset;
 117    CPUState *env;
 118    int bios_size;
 119
 120    /* Init CPUs. */
 121    if (cpu_model == NULL) {
 122#ifdef TARGET_MIPS64
 123        cpu_model = "5Kf";
 124#else
 125        cpu_model = "24Kf";
 126#endif
 127    }
 128    env = cpu_init(cpu_model);
 129    if (!env) {
 130        fprintf(stderr, "Unable to find CPU definition\n");
 131        exit(1);
 132    }
 133    qemu_register_reset(main_cpu_reset, env);
 134
 135    /* Allocate RAM. */
 136    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 137
 138    /* Load a BIOS / boot exception handler image. */
 139    bios_offset = ram_size + vga_ram_size;
 140    if (bios_name == NULL)
 141        bios_name = BIOS_FILENAME;
 142    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
 143    bios_size = load_image(buf, phys_ram_base + bios_offset);
 144    if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
 145        /* Bail out if we have neither a kernel image nor boot vector code. */
 146        fprintf(stderr,
 147                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
 148                buf);
 149        exit(1);
 150    } else {
 151        /* Map the BIOS / boot exception handler. */
 152        cpu_register_physical_memory(0x1fc00000LL,
 153                                     bios_size, bios_offset | IO_MEM_ROM);
 154        /* We have a boot vector start address. */
 155        env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
 156    }
 157
 158    if (kernel_filename) {
 159        loaderparams.ram_size = ram_size;
 160        loaderparams.kernel_filename = kernel_filename;
 161        loaderparams.kernel_cmdline = kernel_cmdline;
 162        loaderparams.initrd_filename = initrd_filename;
 163        load_kernel(env);
 164    }
 165
 166    /* Init CPU internal devices. */
 167    cpu_mips_irq_init_cpu(env);
 168    cpu_mips_clock_init(env);
 169
 170    /* Register 64 KB of ISA IO space at 0x1fd00000. */
 171    isa_mmio_init(0x1fd00000, 0x00010000);
 172
 173    /* A single 16450 sits at offset 0x3f8. It is attached to
 174       MIPS CPU INT2, which is interrupt 4. */
 175    if (serial_hds[0])
 176        serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]);
 177
 178    if (nd_table[0].vlan)
 179        /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
 180        mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
 181}
 182
 183QEMUMachine mips_mipssim_machine = {
 184    .name = "mipssim",
 185    .desc = "MIPS MIPSsim platform",
 186    .init = mips_mipssim_init,
 187    .ram_require = BIOS_SIZE + VGA_RAM_SIZE /* unused */,
 188    .nodisk_ok = 1,
 189};
 190