]> git.proxmox.com Git - qemu.git/blame - hw/mips_malta.c
Improved initrd support for mips.
[qemu.git] / hw / mips_malta.c
CommitLineData
5856de80
TS
1/*
2 * QEMU Malta board support
3 *
4 * Copyright (c) 2006 Aurelien Jarno
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "vl.h"
26
44cbbf18
TS
27#ifdef TARGET_WORDS_BIGENDIAN
28#define BIOS_FILENAME "mips_bios.bin"
29#else
30#define BIOS_FILENAME "mipsel_bios.bin"
31#endif
32
60aa19ab 33#ifdef TARGET_MIPS64
74287114 34#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
5856de80 35#else
74287114 36#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
5856de80
TS
37#endif
38
74287114
TS
39#define ENVP_ADDR (int32_t)0x80002000
40#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
5856de80
TS
41
42#define ENVP_NB_ENTRIES 16
43#define ENVP_ENTRY_SIZE 256
44
45
46extern FILE *logfile;
47
48typedef struct {
49 uint32_t leds;
50 uint32_t brk;
51 uint32_t gpout;
130751ee 52 uint32_t i2cin;
5856de80
TS
53 uint32_t i2coe;
54 uint32_t i2cout;
55 uint32_t i2csel;
56 CharDriverState *display;
57 char display_text[9];
a4bc3afc 58 SerialState *uart;
5856de80
TS
59} MaltaFPGAState;
60
61static PITState *pit;
62
4de9b249 63/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
5856de80
TS
64static void pic_irq_request(void *opaque, int level)
65{
4de9b249 66 cpu_mips_irq_request(opaque, 2, level);
5856de80
TS
67}
68
69/* Malta FPGA */
70static void malta_fpga_update_display(void *opaque)
71{
72 char leds_text[9];
73 int i;
74 MaltaFPGAState *s = opaque;
75
76 for (i = 7 ; i >= 0 ; i--) {
77 if (s->leds & (1 << i))
78 leds_text[i] = '#';
79 else
80 leds_text[i] = ' ';
81 }
82 leds_text[8] = '\0';
83
472c5273
TS
84 qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
85 qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
5856de80
TS
86}
87
130751ee
TS
88/*
89 * EEPROM 24C01 / 24C02 emulation.
90 *
91 * Emulation for serial EEPROMs:
92 * 24C01 - 1024 bit (128 x 8)
93 * 24C02 - 2048 bit (256 x 8)
94 *
95 * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
96 */
97
98//~ #define DEBUG
99
100#if defined(DEBUG)
101# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args)
102#else
103# define logout(fmt, args...) ((void)0)
104#endif
105
106struct _eeprom24c0x_t {
107 uint8_t tick;
108 uint8_t address;
109 uint8_t command;
110 uint8_t ack;
111 uint8_t scl;
112 uint8_t sda;
113 uint8_t data;
114 //~ uint16_t size;
115 uint8_t contents[256];
116};
117
118typedef struct _eeprom24c0x_t eeprom24c0x_t;
119
120static eeprom24c0x_t eeprom = {
121 contents: {
122 /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
123 /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
124 /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
125 /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
126 /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
127 /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
129 /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
130 /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
131 /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
132 /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134 /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
135 /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
136 /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
137 /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
138 },
139};
140
141static uint8_t eeprom24c0x_read()
142{
143 logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
144 eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
145 return eeprom.sda;
146}
147
148static void eeprom24c0x_write(int scl, int sda)
149{
150 if (eeprom.scl && scl && (eeprom.sda != sda)) {
151 logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
152 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
153 if (!sda) {
154 eeprom.tick = 1;
155 eeprom.command = 0;
156 }
157 } else if (eeprom.tick == 0 && !eeprom.ack) {
158 /* Waiting for start. */
159 logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
160 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
161 } else if (!eeprom.scl && scl) {
162 logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
163 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
164 if (eeprom.ack) {
165 logout("\ti2c ack bit = 0\n");
166 sda = 0;
167 eeprom.ack = 0;
168 } else if (eeprom.sda == sda) {
169 uint8_t bit = (sda != 0);
170 logout("\ti2c bit = %d\n", bit);
171 if (eeprom.tick < 9) {
172 eeprom.command <<= 1;
173 eeprom.command += bit;
174 eeprom.tick++;
175 if (eeprom.tick == 9) {
176 logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
177 eeprom.ack = 1;
178 }
179 } else if (eeprom.tick < 17) {
180 if (eeprom.command & 1) {
181 sda = ((eeprom.data & 0x80) != 0);
182 }
183 eeprom.address <<= 1;
184 eeprom.address += bit;
185 eeprom.tick++;
186 eeprom.data <<= 1;
187 if (eeprom.tick == 17) {
188 eeprom.data = eeprom.contents[eeprom.address];
189 logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
190 eeprom.ack = 1;
191 eeprom.tick = 0;
192 }
193 } else if (eeprom.tick >= 17) {
194 sda = 0;
195 }
196 } else {
197 logout("\tsda changed with raising scl\n");
198 }
199 } else {
200 logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
201 }
202 eeprom.scl = scl;
203 eeprom.sda = sda;
204}
205
5856de80
TS
206static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
207{
208 MaltaFPGAState *s = opaque;
209 uint32_t val = 0;
210 uint32_t saddr;
211
212 saddr = (addr & 0xfffff);
213
214 switch (saddr) {
215
216 /* SWITCH Register */
217 case 0x00200:
218 val = 0x00000000; /* All switches closed */
219 break;
220
221 /* STATUS Register */
222 case 0x00208:
223#ifdef TARGET_WORDS_BIGENDIAN
224 val = 0x00000012;
225#else
226 val = 0x00000010;
227#endif
228 break;
229
230 /* JMPRS Register */
231 case 0x00210:
232 val = 0x00;
233 break;
234
235 /* LEDBAR Register */
236 case 0x00408:
237 val = s->leds;
238 break;
239
240 /* BRKRES Register */
241 case 0x00508:
242 val = s->brk;
243 break;
244
a4bc3afc
TS
245 /* UART Registers */
246 case 0x00900:
247 case 0x00904:
248 case 0x00908:
249 case 0x0090c:
250 case 0x00910:
251 case 0x00914:
252 case 0x00918:
253 case 0x0091c:
254 val = serial_mm_readl(s->uart, addr);
255 break;
256
5856de80
TS
257 /* GPOUT Register */
258 case 0x00a00:
259 val = s->gpout;
260 break;
261
262 /* XXX: implement a real I2C controller */
263
264 /* GPINP Register */
265 case 0x00a08:
266 /* IN = OUT until a real I2C control is implemented */
267 if (s->i2csel)
268 val = s->i2cout;
269 else
270 val = 0x00;
271 break;
272
273 /* I2CINP Register */
274 case 0x00b00:
130751ee 275 val = ((s->i2cin & ~1) | eeprom24c0x_read());
5856de80
TS
276 break;
277
278 /* I2COE Register */
279 case 0x00b08:
280 val = s->i2coe;
281 break;
282
283 /* I2COUT Register */
284 case 0x00b10:
285 val = s->i2cout;
286 break;
287
288 /* I2CSEL Register */
289 case 0x00b18:
130751ee 290 val = s->i2csel;
5856de80
TS
291 break;
292
293 default:
294#if 0
3594c774 295 printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 296 addr);
5856de80
TS
297#endif
298 break;
299 }
300 return val;
301}
302
303static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
304 uint32_t val)
305{
306 MaltaFPGAState *s = opaque;
307 uint32_t saddr;
308
309 saddr = (addr & 0xfffff);
310
311 switch (saddr) {
312
313 /* SWITCH Register */
314 case 0x00200:
315 break;
316
317 /* JMPRS Register */
318 case 0x00210:
319 break;
320
321 /* LEDBAR Register */
322 /* XXX: implement a 8-LED array */
323 case 0x00408:
324 s->leds = val & 0xff;
325 break;
326
327 /* ASCIIWORD Register */
328 case 0x00410:
329 snprintf(s->display_text, 9, "%08X", val);
330 malta_fpga_update_display(s);
331 break;
332
333 /* ASCIIPOS0 to ASCIIPOS7 Registers */
334 case 0x00418:
335 case 0x00420:
336 case 0x00428:
337 case 0x00430:
338 case 0x00438:
339 case 0x00440:
340 case 0x00448:
341 case 0x00450:
342 s->display_text[(saddr - 0x00418) >> 3] = (char) val;
343 malta_fpga_update_display(s);
344 break;
345
346 /* SOFTRES Register */
347 case 0x00500:
348 if (val == 0x42)
349 qemu_system_reset_request ();
350 break;
351
352 /* BRKRES Register */
353 case 0x00508:
354 s->brk = val & 0xff;
355 break;
356
a4bc3afc
TS
357 /* UART Registers */
358 case 0x00900:
359 case 0x00904:
360 case 0x00908:
361 case 0x0090c:
362 case 0x00910:
363 case 0x00914:
364 case 0x00918:
365 case 0x0091c:
366 serial_mm_writel(s->uart, addr, val);
367 break;
368
5856de80
TS
369 /* GPOUT Register */
370 case 0x00a00:
371 s->gpout = val & 0xff;
372 break;
373
374 /* I2COE Register */
375 case 0x00b08:
376 s->i2coe = val & 0x03;
377 break;
378
379 /* I2COUT Register */
380 case 0x00b10:
130751ee
TS
381 eeprom24c0x_write(val & 0x02, val & 0x01);
382 s->i2cout = val;
5856de80
TS
383 break;
384
385 /* I2CSEL Register */
386 case 0x00b18:
130751ee 387 s->i2csel = val & 0x01;
5856de80
TS
388 break;
389
390 default:
391#if 0
3594c774 392 printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 393 addr);
5856de80
TS
394#endif
395 break;
396 }
397}
398
399static CPUReadMemoryFunc *malta_fpga_read[] = {
400 malta_fpga_readl,
401 malta_fpga_readl,
402 malta_fpga_readl
403};
404
405static CPUWriteMemoryFunc *malta_fpga_write[] = {
406 malta_fpga_writel,
407 malta_fpga_writel,
408 malta_fpga_writel
409};
410
411void malta_fpga_reset(void *opaque)
412{
413 MaltaFPGAState *s = opaque;
414
415 s->leds = 0x00;
416 s->brk = 0x0a;
417 s->gpout = 0x00;
130751ee 418 s->i2cin = 0x3;
5856de80
TS
419 s->i2coe = 0x0;
420 s->i2cout = 0x3;
421 s->i2csel = 0x1;
422
423 s->display_text[8] = '\0';
424 snprintf(s->display_text, 9, " ");
425 malta_fpga_update_display(s);
426}
427
a4bc3afc 428MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env)
5856de80
TS
429{
430 MaltaFPGAState *s;
a4bc3afc 431 CharDriverState *uart_chr;
5856de80
TS
432 int malta;
433
434 s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
435
436 malta = cpu_register_io_memory(0, malta_fpga_read,
437 malta_fpga_write, s);
a4bc3afc 438
5856de80
TS
439 cpu_register_physical_memory(base, 0x100000, malta);
440
441 s->display = qemu_chr_open("vc");
af23902b 442 qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
5856de80
TS
443 qemu_chr_printf(s->display, "+--------+\r\n");
444 qemu_chr_printf(s->display, "+ +\r\n");
445 qemu_chr_printf(s->display, "+--------+\r\n");
446 qemu_chr_printf(s->display, "\n");
447 qemu_chr_printf(s->display, "Malta ASCII\r\n");
448 qemu_chr_printf(s->display, "+--------+\r\n");
449 qemu_chr_printf(s->display, "+ +\r\n");
450 qemu_chr_printf(s->display, "+--------+\r\n");
451
a4bc3afc
TS
452 uart_chr = qemu_chr_open("vc");
453 qemu_chr_printf(uart_chr, "CBUS UART\r\n");
454 s->uart = serial_mm_init(&cpu_mips_irq_request, env, base, 3, 2,
455 uart_chr, 0);
456
5856de80
TS
457 malta_fpga_reset(s);
458 qemu_register_reset(malta_fpga_reset, s);
459
460 return s;
461}
462
463/* Audio support */
464#ifdef HAS_AUDIO
465static void audio_init (PCIBus *pci_bus)
466{
467 struct soundhw *c;
468 int audio_enabled = 0;
469
470 for (c = soundhw; !audio_enabled && c->name; ++c) {
471 audio_enabled = c->enabled;
472 }
473
474 if (audio_enabled) {
475 AudioState *s;
476
477 s = AUD_init ();
478 if (s) {
479 for (c = soundhw; c->name; ++c) {
480 if (c->enabled) {
481 if (c->isa) {
482 fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
483 exit(1);
484 }
485 else {
486 if (pci_bus) {
487 c->init.init_pci (pci_bus, s);
488 }
489 }
490 }
491 }
492 }
493 }
494}
495#endif
496
497/* Network support */
498static void network_init (PCIBus *pci_bus)
499{
500 int i;
501 NICInfo *nd;
502
503 for(i = 0; i < nb_nics; i++) {
504 nd = &nd_table[i];
505 if (!nd->model) {
506 nd->model = "pcnet";
507 }
508 if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
509 /* The malta board has a PCNet card using PCI SLOT 11 */
510 pci_nic_init(pci_bus, nd, 88);
511 } else {
512 pci_nic_init(pci_bus, nd, -1);
513 }
514 }
515}
516
517/* ROM and pseudo bootloader
518
519 The following code implements a very very simple bootloader. It first
520 loads the registers a0 to a3 to the values expected by the OS, and
521 then jump at the kernel address.
522
523 The bootloader should pass the locations of the kernel arguments and
524 environment variables tables. Those tables contain the 32-bit address
525 of NULL terminated strings. The environment variables table should be
526 terminated by a NULL address.
527
528 For a simpler implementation, the number of kernel arguments is fixed
529 to two (the name of the kernel and the command line), and the two
530 tables are actually the same one.
531
532 The registers a0 to a3 should contain the following values:
533 a0 - number of kernel arguments
534 a1 - 32-bit address of the kernel arguments table
535 a2 - 32-bit address of the environment variables table
536 a3 - RAM size in bytes
537*/
538
74287114 539static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
5856de80
TS
540{
541 uint32_t *p;
542
543 /* Small bootloader */
544 p = (uint32_t *) (phys_ram_base + bios_offset);
3ddd0065
TS
545 stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */
546 stl_raw(p++, 0x00000000); /* nop */
5856de80
TS
547
548 /* Second part of the bootloader */
549 p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
3ddd0065
TS
550 stl_raw(p++, 0x3c040000); /* lui a0, 0 */
551 stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */
552 stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
553 stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
554 stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
555 stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
556 stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
557 stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
74287114
TS
558 stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
559 stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
3ddd0065
TS
560 stl_raw(p++, 0x03e00008); /* jr ra */
561 stl_raw(p++, 0x00000000); /* nop */
5856de80
TS
562}
563
564static void prom_set(int index, const char *string, ...)
565{
566 va_list ap;
3ddd0065
TS
567 int32_t *p;
568 int32_t table_addr;
5856de80
TS
569 char *s;
570
571 if (index >= ENVP_NB_ENTRIES)
572 return;
573
3ddd0065 574 p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
5856de80
TS
575 p += index;
576
577 if (string == NULL) {
578 stl_raw(p, 0);
579 return;
580 }
581
3ddd0065 582 table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
5856de80
TS
583 s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
584
585 stl_raw(p, table_addr);
586
587 va_start(ap, string);
588 vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
589 va_end(ap);
590}
591
592/* Kernel */
593static int64_t load_kernel (CPUState *env)
594{
74287114 595 int64_t kernel_entry, kernel_low, kernel_high;
5856de80
TS
596 int index = 0;
597 long initrd_size;
74287114 598 ram_addr_t initrd_offset;
5856de80 599
74287114
TS
600 if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
601 &kernel_entry, &kernel_low, &kernel_high) < 0) {
5856de80
TS
602 fprintf(stderr, "qemu: could not load kernel '%s'\n",
603 env->kernel_filename);
604 exit(1);
605 }
606
607 /* load initrd */
608 initrd_size = 0;
74287114 609 initrd_offset = 0;
5856de80 610 if (env->initrd_filename) {
74287114
TS
611 initrd_size = get_image_size (env->initrd_filename);
612 if (initrd_size > 0) {
613 initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
614 if (initrd_offset + initrd_size > env->ram_size) {
615 fprintf(stderr,
616 "qemu: memory too small for initial ram disk '%s'\n",
617 env->initrd_filename);
618 exit(1);
619 }
620 initrd_size = load_image(env->initrd_filename,
621 phys_ram_base + initrd_offset);
622 }
5856de80
TS
623 if (initrd_size == (target_ulong) -1) {
624 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
625 env->initrd_filename);
626 exit(1);
627 }
628 }
629
630 /* Store command line. */
631 prom_set(index++, env->kernel_filename);
632 if (initrd_size > 0)
74287114
TS
633 prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
634 PHYS_TO_VIRT(initrd_offset), initrd_size,
635 env->kernel_cmdline);
5856de80
TS
636 else
637 prom_set(index++, env->kernel_cmdline);
638
639 /* Setup minimum environment variables */
640 prom_set(index++, "memsize");
641 prom_set(index++, "%i", env->ram_size);
642 prom_set(index++, "modetty0");
643 prom_set(index++, "38400n8r");
644 prom_set(index++, NULL);
645
74287114 646 return kernel_entry;
5856de80
TS
647}
648
649static void main_cpu_reset(void *opaque)
650{
651 CPUState *env = opaque;
652 cpu_reset(env);
653
654 /* The bootload does not need to be rewritten as it is located in a
655 read only location. The kernel location and the arguments table
656 location does not change. */
657 if (env->kernel_filename)
658 load_kernel (env);
659}
660
70705261 661static
5856de80
TS
662void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
663 DisplayState *ds, const char **fd_filename, int snapshot,
664 const char *kernel_filename, const char *kernel_cmdline,
94fc95cd 665 const char *initrd_filename, const char *cpu_model)
5856de80
TS
666{
667 char buf[1024];
668 unsigned long bios_offset;
74287114 669 int64_t kernel_entry;
5856de80
TS
670 PCIBus *pci_bus;
671 CPUState *env;
672 RTCState *rtc_state;
f1770b3e 673 /* fdctrl_t *floppy_controller; */
5856de80
TS
674 MaltaFPGAState *malta_fpga;
675 int ret;
33d68b5f 676 mips_def_t *def;
5856de80 677
33d68b5f
TS
678 /* init CPUs */
679 if (cpu_model == NULL) {
60aa19ab 680#ifdef TARGET_MIPS64
33d68b5f
TS
681 cpu_model = "R4000";
682#else
683 cpu_model = "4KEc";
684#endif
685 }
686 if (mips_find_by_name(cpu_model, &def) != 0)
687 def = NULL;
5856de80 688 env = cpu_init();
33d68b5f 689 cpu_mips_register(env, def);
5856de80
TS
690 register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
691 qemu_register_reset(main_cpu_reset, env);
692
693 /* allocate RAM */
694 cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
695
696 /* Map the bios at two physical locations, as on the real board */
697 bios_offset = ram_size + vga_ram_size;
698 cpu_register_physical_memory(0x1e000000LL,
699 BIOS_SIZE, bios_offset | IO_MEM_ROM);
700 cpu_register_physical_memory(0x1fc00000LL,
701 BIOS_SIZE, bios_offset | IO_MEM_ROM);
702
703 /* Load a BIOS image except if a kernel image has been specified. In
704 the later case, just write a small bootloader to the flash
705 location. */
706 if (kernel_filename) {
707 env->ram_size = ram_size;
708 env->kernel_filename = kernel_filename;
709 env->kernel_cmdline = kernel_cmdline;
710 env->initrd_filename = initrd_filename;
74287114
TS
711 kernel_entry = load_kernel(env);
712 write_bootloader(env, bios_offset, kernel_entry);
5856de80
TS
713 } else {
714 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
715 ret = load_image(buf, phys_ram_base + bios_offset);
331ad6f4 716 if (ret < 0 || ret > BIOS_SIZE) {
5856de80
TS
717 fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
718 buf);
719 exit(1);
720 }
721 }
722
723 /* Board ID = 0x420 (Malta Board with CoreLV)
724 XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
725 map to the board ID. */
726 stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
727
728 /* Init internal devices */
729 cpu_mips_clock_init(env);
730 cpu_mips_irqctrl_init();
731
732 /* FPGA */
a4bc3afc 733 malta_fpga = malta_fpga_init(0x1f000000LL, env);
5856de80
TS
734
735 /* Interrupt controller */
736 isa_pic = pic_init(pic_irq_request, env);
737
738 /* Northbridge */
739 pci_bus = pci_gt64120_init(isa_pic);
740
741 /* Southbridge */
742 piix4_init(pci_bus, 80);
743 pci_piix3_ide_init(pci_bus, bs_table, 81);
744 usb_uhci_init(pci_bus, 82);
745 piix4_pm_init(pci_bus, 83);
746 pit = pit_init(0x40, 0);
747 DMA_init(0);
748
749 /* Super I/O */
750 kbd_init();
751 rtc_state = rtc_init(0x70, 8);
7bcc17dc
TS
752 if (serial_hds[0])
753 serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
754 if (serial_hds[1])
c05ac0cd 755 serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 3, serial_hds[1]);
7bcc17dc
TS
756 if (parallel_hds[0])
757 parallel_init(0x378, 7, parallel_hds[0]);
5856de80 758 /* XXX: The floppy controller does not work correctly, something is
f1770b3e
TS
759 probably wrong.
760 floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
5856de80
TS
761
762 /* Sound card */
763#ifdef HAS_AUDIO
764 audio_init(pci_bus);
765#endif
766
767 /* Network card */
768 network_init(pci_bus);
11f29511
TS
769
770 /* Optional PCI video card */
771 pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
772 ram_size, vga_ram_size);
5856de80
TS
773}
774
775QEMUMachine mips_malta_machine = {
776 "malta",
777 "MIPS Malta Core LV",
778 mips_malta_init,
779};