/*
* QEMU/mipssim emulation
*
- * Emulates a very simple machine model similiar to the one use by the
+ * Emulates a very simple machine model similar to the one used by the
* proprietary MIPS emulator.
*
* Copyright (c) 2007 Thiemo Seufer
*/
#include "hw.h"
#include "mips.h"
+#include "mips_cpudevs.h"
#include "pc.h"
#include "isa.h"
#include "net.h"
#include "mips-bios.h"
#include "loader.h"
#include "elf.h"
-
-#ifdef TARGET_MIPS64
-#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
-#else
-#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
-#endif
-
-#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
+#include "sysbus.h"
+#include "exec-memory.h"
static struct _loaderparams {
int ram_size;
const char *initrd_filename;
} loaderparams;
-static void load_kernel (CPUState *env)
+typedef struct ResetData {
+ MIPSCPU *cpu;
+ uint64_t vector;
+} ResetData;
+
+static int64_t load_kernel(void)
{
- int64_t entry, kernel_low, kernel_high;
+ int64_t entry, kernel_high;
long kernel_size;
long initrd_size;
ram_addr_t initrd_offset;
big_endian = 0;
#endif
- kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
- (uint64_t *)&entry, (uint64_t *)&kernel_low,
- (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1);
+ kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
+ NULL, (uint64_t *)&entry, NULL,
+ (uint64_t *)&kernel_high, big_endian,
+ ELF_MACHINE, 1);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
- env->active_tc.PC = entry;
} else {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
exit(1);
}
}
+ return entry;
}
static void main_cpu_reset(void *opaque)
{
- CPUState *env = opaque;
- cpu_reset(env);
+ ResetData *s = (ResetData *)opaque;
+ CPUMIPSState *env = &s->cpu->env;
- if (loaderparams.kernel_filename)
- load_kernel (env);
+ cpu_reset(CPU(s->cpu));
+ env->active_tc.PC = s->vector & ~(target_ulong)1;
+ if (s->vector & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ }
+}
+
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "mipsnet");
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+
+ s = sysbus_from_qdev(dev);
+ sysbus_connect_irq(s, 0, irq);
+ memory_region_add_subregion(get_system_io(),
+ base,
+ sysbus_mmio_get_region(s, 0));
}
static void
-mips_mipssim_init (ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename, const char *cpu_model)
+mips_mipssim_init(QEMUMachineInitArgs *args)
{
+ ram_addr_t ram_size = args->ram_size;
+ const char *cpu_model = args->cpu_model;
+ const char *kernel_filename = args->kernel_filename;
+ const char *kernel_cmdline = args->kernel_cmdline;
+ const char *initrd_filename = args->initrd_filename;
char *filename;
- ram_addr_t ram_offset;
- ram_addr_t bios_offset;
- CPUState *env;
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ MemoryRegion *bios = g_new(MemoryRegion, 1);
+ MIPSCPU *cpu;
+ CPUMIPSState *env;
+ ResetData *reset_info;
int bios_size;
/* Init CPUs. */
cpu_model = "24Kf";
#endif
}
- env = cpu_init(cpu_model);
- if (!env) {
+ cpu = cpu_mips_init(cpu_model);
+ if (cpu == NULL) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- qemu_register_reset(main_cpu_reset, env);
+ env = &cpu->env;
+
+ reset_info = g_malloc0(sizeof(ResetData));
+ reset_info->cpu = cpu;
+ reset_info->vector = env->active_tc.PC;
+ qemu_register_reset(main_cpu_reset, reset_info);
/* Allocate RAM. */
- ram_offset = qemu_ram_alloc(ram_size);
- bios_offset = qemu_ram_alloc(BIOS_SIZE);
+ memory_region_init_ram(ram, "mips_mipssim.ram", ram_size);
+ vmstate_register_ram_global(ram);
+ memory_region_init_ram(bios, "mips_mipssim.bios", BIOS_SIZE);
+ vmstate_register_ram_global(bios);
+ memory_region_set_readonly(bios, true);
- cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+ memory_region_add_subregion(address_space_mem, 0, ram);
/* Map the BIOS / boot exception handler. */
- cpu_register_physical_memory(0x1fc00000LL,
- BIOS_SIZE, bios_offset | IO_MEM_ROM);
+ memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
/* Load a BIOS / boot exception handler image. */
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
- qemu_free(filename);
+ g_free(filename);
} else {
bios_size = -1;
}
loaderparams.kernel_filename = kernel_filename;
loaderparams.kernel_cmdline = kernel_cmdline;
loaderparams.initrd_filename = initrd_filename;
- load_kernel(env);
+ reset_info->vector = load_kernel();
}
/* Init CPU internal devices. */
if (serial_hds[0])
serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]);
- if (nd_table[0].vlan)
+ if (nd_table[0].used)
/* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
}