mips_r4k.c 6.3 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;
ths's avatar
ths committed
138
    static RTCState *rtc_state;
pbrook's avatar
pbrook committed
139
    int i;
bellard's avatar
bellard committed
140 141 142

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

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

148 149 150 151 152 153
    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
154 155 156 157
    /* 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
158 159 160
    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
161 162 163 164 165 166 167
    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
168
    }
bellard's avatar
bellard committed
169 170

    if (kernel_filename) {
171 172 173 174 175 176
        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
177 178
    }

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

ths's avatar
ths committed
183 184
    rtc_state = rtc_init(0x70, 8);

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

bellard's avatar
bellard committed
189
    isa_pic = pic_init(pic_irq_request, env);
bellard's avatar
bellard committed
190
    pit = pit_init(0x40, 0);
ths's avatar
ths committed
191

192
    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
bellard's avatar
bellard committed
193 194
    isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
                 vga_ram_size);
bellard's avatar
bellard committed
195

196 197 198 199 200 201 202 203 204
    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
205 206 207 208

    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
209 210 211 212 213 214 215
}

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