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