mips_r4k.c 7.62 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
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;

ths's avatar
ths committed
67
68
69
70
static void load_kernel (CPUState *env, int ram_size,
                         const char *kernel_filename,
                         const char *kernel_cmdline,
                         const char *initrd_filename)
71
{
ths's avatar
ths committed
72
    int64_t entry, kernel_low, kernel_high;
73
    long kernel_size, initrd_size;
ths's avatar
ths committed
74
    ram_addr_t initrd_offset;
75

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

    /* load initrd */
    initrd_size = 0;
ths's avatar
ths committed
90
    initrd_offset = 0;
91
    if (initrd_filename) {
ths's avatar
ths committed
92
93
94
95
96
97
98
99
100
101
102
103
        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);
        }
104
105
106
107
108
109
110
111
112
113
114
        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
115
                      "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
ths's avatar
ths committed
116
                      PHYS_TO_VIRT((uint32_t)initrd_offset),
117
118
119
120
121
122
123
                      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
124
125
    *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
    *(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
126
127
128
129
130
131
}

static void main_cpu_reset(void *opaque)
{
    CPUState *env = opaque;
    cpu_reset(env);
ths's avatar
ths committed
132
    cpu_mips_register(env, NULL);
133
134
135
136
137

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

139
static
140
void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device,
bellard's avatar
bellard committed
141
142
                    DisplayState *ds, const char **fd_filename, int snapshot,
                    const char *kernel_filename, const char *kernel_cmdline,
143
                    const char *initrd_filename, const char *cpu_model)
bellard's avatar
bellard committed
144
145
146
{
    char buf[1024];
    unsigned long bios_offset;
147
    int bios_size;
bellard's avatar
bellard committed
148
    CPUState *env;
ths's avatar
ths committed
149
    RTCState *rtc_state;
pbrook's avatar
pbrook committed
150
    int i;
151
    mips_def_t *def;
pbrook's avatar
pbrook committed
152
    qemu_irq *i8259;
bellard's avatar
bellard committed
153

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

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

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

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

    if (kernel_filename) {
197
198
199
200
201
202
        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
203
204
    }

205
    /* Init CPU internal devices */
pbrook's avatar
pbrook committed
206
    cpu_mips_irq_init_cpu(env);
bellard's avatar
bellard committed
207
    cpu_mips_clock_init(env);
bellard's avatar
bellard committed
208
209
    cpu_mips_irqctrl_init();

pbrook's avatar
pbrook committed
210
211
212
213
    /* 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
214

bellard's avatar
bellard committed
215
    /* Register 64 KB of ISA IO space at 0x14000000 */
pbrook's avatar
pbrook committed
216
    isa_mmio_init(0x14000000, 0x00010000);
bellard's avatar
bellard committed
217
218
    isa_mem_base = 0x10000000;

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

ths's avatar
ths committed
221
222
    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
        if (serial_hds[i]) {
pbrook's avatar
pbrook committed
223
            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
ths's avatar
ths committed
224
225
226
        }
    }

227
    isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
bellard's avatar
bellard committed
228
                 vga_ram_size);
bellard's avatar
bellard committed
229

230
231
232
    if (nd_table[0].vlan) {
        if (nd_table[0].model == NULL
            || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
pbrook's avatar
pbrook committed
233
            isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
234
235
236
        } else if (strcmp(nd_table[0].model, "?") == 0) {
            fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n");
            exit (1);
237
238
239
240
241
        } else {
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
            exit (1);
        }
    }
pbrook's avatar
pbrook committed
242
243

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

pbrook's avatar
pbrook committed
247
    i8042_init(i8259[1], i8259[12], 0x60);
248
    ds1225y_init(0x9000, "nvram");
bellard's avatar
bellard committed
249
250
251
252
253
254
255
}

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