mips_r4k.c 6.24 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * QEMU/MIPS pseudo-board
 *
 * emulates a simple machine with ISA-like bus.
 * ISA IO space mapped to the 0x14000000 (PHYS) and
 * ISA memory at the 0x10000000 (PHYS, 16Mb in size).
 * All peripherial devices are attached to this "bus" with
 * the standard PC ISA addresses.
*/
bellard's avatar
bellard committed
10 11 12 13 14 15 16
#include "vl.h"

#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000

bellard's avatar
bellard committed
17 18
#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)

pbrook's avatar
pbrook committed
19 20 21 22
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };

bellard's avatar
bellard committed
23 24
extern FILE *logfile;

25
static PITState *pit; /* PIT i8254 */
bellard's avatar
bellard committed
26

27 28
/*i8254 PIT is attached to the IRQ0 at PIC i8259 */
/*The PIC is attached to the MIPS CPU INT0 pin */
bellard's avatar
bellard committed
29
static void pic_irq_request(void *opaque, int level)
bellard's avatar
bellard committed
30
{
bellard's avatar
bellard committed
31
    CPUState *env = first_cpu;
bellard's avatar
bellard committed
32
    if (level) {
bellard's avatar
bellard committed
33 34
        env->CP0_Cause |= 0x00000400;
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
bellard's avatar
bellard committed
35
    } else {
bellard's avatar
bellard committed
36 37
	env->CP0_Cause &= ~0x00000400;
        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
bellard's avatar
bellard committed
38 39 40
    }
}

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
			      uint32_t val)
{
    if ((addr & 0xffff) == 0 && val == 42)
        qemu_system_reset_request ();
    else if ((addr & 0xffff) == 4 && val == 42)
        qemu_system_shutdown_request ();
}

static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
{
    return 0;
}

static CPUWriteMemoryFunc *mips_qemu_write[] = {
    &mips_qemu_writel,
    &mips_qemu_writel,
    &mips_qemu_writel,
};

static CPUReadMemoryFunc *mips_qemu_read[] = {
    &mips_qemu_readl,
    &mips_qemu_readl,
    &mips_qemu_readl,
};

static int mips_qemu_iomemtype = 0;

void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
		  const char *kernel_cmdline,
		  const char *initrd_filename)
{
    int64_t entry = 0;
    long kernel_size, initrd_size;

    kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
    if (kernel_size >= 0)
        env->PC = entry;
    else {
        kernel_size = load_image(kernel_filename,
                                 phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
        if (kernel_size < 0) {
            fprintf(stderr, "qemu: could not load kernel '%s'\n",
                    kernel_filename);
            exit(1);
        }
        env->PC = KERNEL_LOAD_ADDR;
    }

    /* load initrd */
    initrd_size = 0;
    if (initrd_filename) {
        initrd_size = load_image(initrd_filename,
                                 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
        if (initrd_size == (target_ulong) -1) {
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                    initrd_filename);
            exit(1);
        }
    }

    /* Store command line.  */
    if (initrd_size > 0) {
        int ret;
        ret = sprintf(phys_ram_base + (16 << 20) - 256,
                      "rd_start=0x%08x rd_size=%li ",
                      INITRD_LOAD_ADDR,
                      initrd_size);
        strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
    }
    else {
        strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
    }

    *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
    *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
}

static void main_cpu_reset(void *opaque)
{
    CPUState *env = opaque;
    cpu_reset(env);

    if (env->kernel_filename)
        load_kernel (env, env->ram_size, env->kernel_filename,
                     env->kernel_cmdline, env->initrd_filename);
}
bellard's avatar
bellard committed
128

bellard's avatar
bellard committed
129 130 131 132 133 134 135 136
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
                    DisplayState *ds, const char **fd_filename, int snapshot,
                    const char *kernel_filename, const char *kernel_cmdline,
                    const char *initrd_filename)
{
    char buf[1024];
    unsigned long bios_offset;
    int ret;
bellard's avatar
bellard committed
137
    CPUState *env;
pbrook's avatar
pbrook committed
138
    int i;
bellard's avatar
bellard committed
139 140 141

    env = cpu_init();
    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
142
    qemu_register_reset(main_cpu_reset, env);
bellard's avatar
bellard committed
143

bellard's avatar
bellard committed
144 145
    /* allocate RAM */
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bellard's avatar
bellard committed
146

147 148 149 150 151 152
    if (!mips_qemu_iomemtype) {
        mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
						     mips_qemu_write, NULL);
    }
    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);

bellard's avatar
bellard committed
153 154 155 156
    /* Try to load a BIOS image. If this fails, we continue regardless,
       but initialize the hardware ourselves. When a kernel gets
       preloaded we also initialize the hardware, since the BIOS wasn't
       run. */
bellard's avatar
bellard committed
157 158 159
    bios_offset = ram_size + vga_ram_size;
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
    ret = load_image(buf, phys_ram_base + bios_offset);
bellard's avatar
bellard committed
160 161 162 163 164 165 166
    if (ret == BIOS_SIZE) {
	cpu_register_physical_memory((uint32_t)(0x1fc00000),
				     BIOS_SIZE, bios_offset | IO_MEM_ROM);
    } else {
	/* not fatal */
        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
		buf);
bellard's avatar
bellard committed
167
    }
bellard's avatar
bellard committed
168 169

    if (kernel_filename) {
170 171 172 173 174 175
        load_kernel (env, ram_size, kernel_filename, kernel_cmdline,
		     initrd_filename);
	env->ram_size = ram_size;
	env->kernel_filename = kernel_filename;
	env->kernel_cmdline = kernel_cmdline;
	env->initrd_filename = initrd_filename;
bellard's avatar
bellard committed
176 177
    }

178
    /* Init CPU internal devices */
bellard's avatar
bellard committed
179
    cpu_mips_clock_init(env);
bellard's avatar
bellard committed
180 181
    cpu_mips_irqctrl_init();

bellard's avatar
bellard committed
182
    /* Register 64 KB of ISA IO space at 0x14000000 */
pbrook's avatar
pbrook committed
183
    isa_mmio_init(0x14000000, 0x00010000);
bellard's avatar
bellard committed
184 185
    isa_mem_base = 0x10000000;

bellard's avatar
bellard committed
186
    isa_pic = pic_init(pic_irq_request, env);
bellard's avatar
bellard committed
187
    pit = pit_init(0x40, 0);
188
    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
bellard's avatar
bellard committed
189 190
    isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
                 vga_ram_size);
bellard's avatar
bellard committed
191

192 193 194 195 196 197 198 199 200
    if (nd_table[0].vlan) {
        if (nd_table[0].model == NULL
            || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
            isa_ne2000_init(0x300, 9, &nd_table[0]);
        } else {
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
            exit (1);
        }
    }
pbrook's avatar
pbrook committed
201 202 203 204

    for(i = 0; i < 2; i++)
        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
                     bs_table[2 * i], bs_table[2 * i + 1]);
bellard's avatar
bellard committed
205 206 207 208 209 210 211
}

QEMUMachine mips_machine = {
    "mips",
    "mips r4k platform",
    mips_r4k_init,
};