mips_r4k.c 7.29 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
#include "vl.h"

ths's avatar
ths committed
12
#ifdef TARGET_WORDS_BIGENDIAN
bellard's avatar
bellard committed
13
#define BIOS_FILENAME "mips_bios.bin"
14 15 16
#else
#define BIOS_FILENAME "mipsel_bios.bin"
#endif
ths's avatar
ths committed
17

ths's avatar
ths committed
18
#ifdef TARGET_MIPS64
ths's avatar
ths committed
19
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
ths's avatar
ths committed
20
#else
ths's avatar
ths committed
21
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
ths's avatar
ths committed
22
#endif
bellard's avatar
bellard committed
23

ths's avatar
ths committed
24
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
bellard's avatar
bellard committed
25

pbrook's avatar
pbrook committed
26 27 28 29
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };

ths's avatar
ths committed
30 31 32
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };

bellard's avatar
bellard committed
33 34
extern FILE *logfile;

35
static PITState *pit; /* PIT i8254 */
bellard's avatar
bellard committed
36

37
/*i8254 PIT is attached to the IRQ0 at PIC i8259 */
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
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)
{
ths's avatar
ths committed
71
    int64_t entry, kernel_low, kernel_high;
72
    long kernel_size, initrd_size;
ths's avatar
ths committed
73
    ram_addr_t initrd_offset;
74

ths's avatar
ths committed
75 76
    kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND,
                           &entry, &kernel_low, &kernel_high);
77 78
    if (kernel_size >= 0) {
        if ((entry & ~0x7fffffffULL) == 0x80000000)
ths's avatar
ths committed
79
            entry = (int32_t)entry;
80
        env->PC = entry;
81
    } else {
82 83 84
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
                kernel_filename);
        exit(1);
85 86 87 88
    }

    /* load initrd */
    initrd_size = 0;
ths's avatar
ths committed
89
    initrd_offset = 0;
90
    if (initrd_filename) {
ths's avatar
ths committed
91 92 93 94 95 96 97 98 99 100 101 102
        initrd_size = get_image_size (initrd_filename);
        if (initrd_size > 0) {
            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
            if (initrd_offset + initrd_size > ram_size) {
                fprintf(stderr,
                        "qemu: memory too small for initial ram disk '%s'\n",
                        initrd_filename);
                exit(1);
            }
            initrd_size = load_image(initrd_filename,
                                     phys_ram_base + initrd_offset);
        }
103 104 105 106 107 108 109 110 111 112 113
        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,
ths's avatar
ths committed
114
                      "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
ths's avatar
ths committed
115
                      PHYS_TO_VIRT((uint32_t)initrd_offset),
116 117 118 119 120 121 122
                      initrd_size);
        strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
    }
    else {
        strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
    }

ths's avatar
ths committed
123 124
    *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
    *(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
125 126 127 128 129 130 131 132 133 134 135
}

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
136

137
static
bellard's avatar
bellard committed
138 139 140
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,
141
                    const char *initrd_filename, const char *cpu_model)
bellard's avatar
bellard committed
142 143 144
{
    char buf[1024];
    unsigned long bios_offset;
145
    int bios_size;
bellard's avatar
bellard committed
146
    CPUState *env;
ths's avatar
ths committed
147
    RTCState *rtc_state;
pbrook's avatar
pbrook committed
148
    int i;
149
    mips_def_t *def;
pbrook's avatar
pbrook committed
150
    qemu_irq *i8259;
bellard's avatar
bellard committed
151

152 153
    /* init CPUs */
    if (cpu_model == NULL) {
ths's avatar
ths committed
154
#ifdef TARGET_MIPS64
155 156 157 158 159 160 161
        cpu_model = "R4000";
#else
        cpu_model = "4KEc";
#endif
    }
    if (mips_find_by_name(cpu_model, &def) != 0)
        def = NULL;
bellard's avatar
bellard committed
162
    env = cpu_init();
163
    cpu_mips_register(env, def);
bellard's avatar
bellard committed
164
    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
165
    qemu_register_reset(main_cpu_reset, env);
bellard's avatar
bellard committed
166

bellard's avatar
bellard committed
167 168
    /* allocate RAM */
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bellard's avatar
bellard committed
169

170 171
    if (!mips_qemu_iomemtype) {
        mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
172
                                                     mips_qemu_write, NULL);
173 174 175
    }
    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);

bellard's avatar
bellard committed
176 177 178 179
    /* 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
180 181
    bios_offset = ram_size + vga_ram_size;
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
182
    bios_size = load_image(buf, phys_ram_base + bios_offset);
ths's avatar
ths committed
183
    if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
ths's avatar
ths committed
184
	cpu_register_physical_memory(0x1fc00000,
bellard's avatar
bellard committed
185 186 187 188 189
				     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
190
    }
bellard's avatar
bellard committed
191 192

    if (kernel_filename) {
193 194 195 196 197 198
        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
199 200
    }

201
    /* Init CPU internal devices */
pbrook's avatar
pbrook committed
202
    cpu_mips_irq_init_cpu(env);
bellard's avatar
bellard committed
203
    cpu_mips_clock_init(env);
bellard's avatar
bellard committed
204 205
    cpu_mips_irqctrl_init();

pbrook's avatar
pbrook committed
206 207 208 209
    /* The PIC is attached to the MIPS CPU INT0 pin */
    i8259 = i8259_init(env->irq[2]);

    rtc_state = rtc_init(0x70, i8259[8]);
ths's avatar
ths committed
210

bellard's avatar
bellard committed
211
    /* Register 64 KB of ISA IO space at 0x14000000 */
pbrook's avatar
pbrook committed
212
    isa_mmio_init(0x14000000, 0x00010000);
bellard's avatar
bellard committed
213 214
    isa_mem_base = 0x10000000;

pbrook's avatar
pbrook committed
215
    pit = pit_init(0x40, i8259[0]);
ths's avatar
ths committed
216

ths's avatar
ths committed
217 218
    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
        if (serial_hds[i]) {
pbrook's avatar
pbrook committed
219
            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
ths's avatar
ths committed
220 221 222
        }
    }

bellard's avatar
bellard committed
223 224
    isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
                 vga_ram_size);
bellard's avatar
bellard committed
225

226 227 228
    if (nd_table[0].vlan) {
        if (nd_table[0].model == NULL
            || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
pbrook's avatar
pbrook committed
229
            isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
230 231 232 233 234
        } else {
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
            exit (1);
        }
    }
pbrook's avatar
pbrook committed
235 236

    for(i = 0; i < 2; i++)
pbrook's avatar
pbrook committed
237
        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
pbrook's avatar
pbrook committed
238
                     bs_table[2 * i], bs_table[2 * i + 1]);
239

pbrook's avatar
pbrook committed
240
    i8042_init(i8259[1], i8259[12], 0x60);
241
    ds1225y_init(0x9000, "nvram");
bellard's avatar
bellard committed
242 243 244 245 246 247 248
}

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