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

#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
ths's avatar
ths committed
14
15
16
17
18
19
#define KERNEL_LOAD_ADDR (int32_t)0x80010000
#ifdef MIPS_HAS_MIPS64
#define INITRD_LOAD_ADDR (int64_t)0x80800000
#else
#define INITRD_LOAD_ADDR (int32_t)0x80800000
#endif
bellard's avatar
bellard committed
20

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

pbrook's avatar
pbrook committed
23
24
25
26
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
27
28
extern FILE *logfile;

29
static PITState *pit; /* PIT i8254 */
bellard's avatar
bellard committed
30

31
32
/*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
33
static void pic_irq_request(void *opaque, int level)
bellard's avatar
bellard committed
34
{
bellard's avatar
bellard committed
35
    CPUState *env = first_cpu;
bellard's avatar
bellard committed
36
    if (level) {
bellard's avatar
bellard committed
37
38
        env->CP0_Cause |= 0x00000400;
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
bellard's avatar
bellard committed
39
    } else {
bellard's avatar
bellard committed
40
41
	env->CP0_Cause &= ~0x00000400;
        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
bellard's avatar
bellard committed
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
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);
81
82
    if (kernel_size >= 0) {
        if ((entry & ~0x7fffffffULL) == 0x80000000)
ths's avatar
ths committed
83
            entry = (int32_t)entry;
84
        env->PC = entry;
85
    } else {
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
        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,
112
                      "rd_start=0x" TLSZ " rd_size=%li ",
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
                      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
134

bellard's avatar
bellard committed
135
136
137
138
139
140
141
142
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
143
    CPUState *env;
ths's avatar
ths committed
144
    static RTCState *rtc_state;
pbrook's avatar
pbrook committed
145
    int i;
bellard's avatar
bellard committed
146
147
148

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

bellard's avatar
bellard committed
151
152
    /* allocate RAM */
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bellard's avatar
bellard committed
153

154
155
156
157
158
159
    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
160
161
162
163
    /* 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
164
165
166
    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
167
168
169
170
171
172
173
    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
174
    }
bellard's avatar
bellard committed
175
176

    if (kernel_filename) {
177
178
179
180
181
182
        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
183
184
    }

185
    /* Init CPU internal devices */
bellard's avatar
bellard committed
186
    cpu_mips_clock_init(env);
bellard's avatar
bellard committed
187
188
    cpu_mips_irqctrl_init();

ths's avatar
ths committed
189
190
    rtc_state = rtc_init(0x70, 8);

bellard's avatar
bellard committed
191
    /* Register 64 KB of ISA IO space at 0x14000000 */
pbrook's avatar
pbrook committed
192
    isa_mmio_init(0x14000000, 0x00010000);
bellard's avatar
bellard committed
193
194
    isa_mem_base = 0x10000000;

bellard's avatar
bellard committed
195
    isa_pic = pic_init(pic_irq_request, env);
bellard's avatar
bellard committed
196
    pit = pit_init(0x40, 0);
ths's avatar
ths committed
197

198
    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
bellard's avatar
bellard committed
199
200
    isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
                 vga_ram_size);
bellard's avatar
bellard committed
201

202
203
204
205
206
207
208
209
210
    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
211
212
213
214

    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
215
216
217
218
219
220
221
}

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