]> git.proxmox.com Git - mirror_qemu.git/blame - hw/mips_malta.c
Fix segfault in -nographic mode, by Stefen Weil.
[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
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
87ee1669 45extern int nographic;
5856de80
TS
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
5856de80
TS
63/* Malta FPGA */
64static void malta_fpga_update_display(void *opaque)
65{
66 char leds_text[9];
67 int i;
68 MaltaFPGAState *s = opaque;
69
87ee1669
TS
70 if (!nographic) {
71 for (i = 7 ; i >= 0 ; i--) {
72 if (s->leds & (1 << i))
73 leds_text[i] = '#';
74 else
75 leds_text[i] = ' ';
76 }
77 leds_text[8] = '\0';
5856de80 78
87ee1669
TS
79 qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
80 qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
81 }
5856de80
TS
82}
83
130751ee
TS
84/*
85 * EEPROM 24C01 / 24C02 emulation.
86 *
87 * Emulation for serial EEPROMs:
88 * 24C01 - 1024 bit (128 x 8)
89 * 24C02 - 2048 bit (256 x 8)
90 *
91 * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
92 */
93
94//~ #define DEBUG
95
96#if defined(DEBUG)
97# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args)
98#else
99# define logout(fmt, args...) ((void)0)
100#endif
101
102struct _eeprom24c0x_t {
103 uint8_t tick;
104 uint8_t address;
105 uint8_t command;
106 uint8_t ack;
107 uint8_t scl;
108 uint8_t sda;
109 uint8_t data;
110 //~ uint16_t size;
111 uint8_t contents[256];
112};
113
114typedef struct _eeprom24c0x_t eeprom24c0x_t;
115
116static eeprom24c0x_t eeprom = {
117 contents: {
118 /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
119 /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
120 /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
121 /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
122 /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
123 /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
124 /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
125 /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
126 /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
127 /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
129 /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130 /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
131 /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
132 /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
134 },
135};
136
137static uint8_t eeprom24c0x_read()
138{
139 logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
140 eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
141 return eeprom.sda;
142}
143
144static void eeprom24c0x_write(int scl, int sda)
145{
146 if (eeprom.scl && scl && (eeprom.sda != sda)) {
147 logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
148 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
149 if (!sda) {
150 eeprom.tick = 1;
151 eeprom.command = 0;
152 }
153 } else if (eeprom.tick == 0 && !eeprom.ack) {
154 /* Waiting for start. */
155 logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
156 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
157 } else if (!eeprom.scl && scl) {
158 logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
159 eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
160 if (eeprom.ack) {
161 logout("\ti2c ack bit = 0\n");
162 sda = 0;
163 eeprom.ack = 0;
164 } else if (eeprom.sda == sda) {
165 uint8_t bit = (sda != 0);
166 logout("\ti2c bit = %d\n", bit);
167 if (eeprom.tick < 9) {
168 eeprom.command <<= 1;
169 eeprom.command += bit;
170 eeprom.tick++;
171 if (eeprom.tick == 9) {
172 logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
173 eeprom.ack = 1;
174 }
175 } else if (eeprom.tick < 17) {
176 if (eeprom.command & 1) {
177 sda = ((eeprom.data & 0x80) != 0);
178 }
179 eeprom.address <<= 1;
180 eeprom.address += bit;
181 eeprom.tick++;
182 eeprom.data <<= 1;
183 if (eeprom.tick == 17) {
184 eeprom.data = eeprom.contents[eeprom.address];
185 logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
186 eeprom.ack = 1;
187 eeprom.tick = 0;
188 }
189 } else if (eeprom.tick >= 17) {
190 sda = 0;
191 }
192 } else {
193 logout("\tsda changed with raising scl\n");
194 }
195 } else {
196 logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
197 }
198 eeprom.scl = scl;
199 eeprom.sda = sda;
200}
201
5856de80
TS
202static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
203{
204 MaltaFPGAState *s = opaque;
205 uint32_t val = 0;
206 uint32_t saddr;
207
208 saddr = (addr & 0xfffff);
209
210 switch (saddr) {
211
212 /* SWITCH Register */
213 case 0x00200:
214 val = 0x00000000; /* All switches closed */
215 break;
216
217 /* STATUS Register */
218 case 0x00208:
219#ifdef TARGET_WORDS_BIGENDIAN
220 val = 0x00000012;
221#else
222 val = 0x00000010;
223#endif
224 break;
225
226 /* JMPRS Register */
227 case 0x00210:
228 val = 0x00;
229 break;
230
231 /* LEDBAR Register */
232 case 0x00408:
233 val = s->leds;
234 break;
235
236 /* BRKRES Register */
237 case 0x00508:
238 val = s->brk;
239 break;
240
b6dc7ebb 241 /* UART Registers are handled directly by the serial device */
a4bc3afc 242
5856de80
TS
243 /* GPOUT Register */
244 case 0x00a00:
245 val = s->gpout;
246 break;
247
248 /* XXX: implement a real I2C controller */
249
250 /* GPINP Register */
251 case 0x00a08:
252 /* IN = OUT until a real I2C control is implemented */
253 if (s->i2csel)
254 val = s->i2cout;
255 else
256 val = 0x00;
257 break;
258
259 /* I2CINP Register */
260 case 0x00b00:
130751ee 261 val = ((s->i2cin & ~1) | eeprom24c0x_read());
5856de80
TS
262 break;
263
264 /* I2COE Register */
265 case 0x00b08:
266 val = s->i2coe;
267 break;
268
269 /* I2COUT Register */
270 case 0x00b10:
271 val = s->i2cout;
272 break;
273
274 /* I2CSEL Register */
275 case 0x00b18:
130751ee 276 val = s->i2csel;
5856de80
TS
277 break;
278
279 default:
280#if 0
3594c774 281 printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 282 addr);
5856de80
TS
283#endif
284 break;
285 }
286 return val;
287}
288
289static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
290 uint32_t val)
291{
292 MaltaFPGAState *s = opaque;
293 uint32_t saddr;
294
295 saddr = (addr & 0xfffff);
296
297 switch (saddr) {
298
299 /* SWITCH Register */
300 case 0x00200:
301 break;
302
303 /* JMPRS Register */
304 case 0x00210:
305 break;
306
307 /* LEDBAR Register */
308 /* XXX: implement a 8-LED array */
309 case 0x00408:
310 s->leds = val & 0xff;
311 break;
312
313 /* ASCIIWORD Register */
314 case 0x00410:
315 snprintf(s->display_text, 9, "%08X", val);
316 malta_fpga_update_display(s);
317 break;
318
319 /* ASCIIPOS0 to ASCIIPOS7 Registers */
320 case 0x00418:
321 case 0x00420:
322 case 0x00428:
323 case 0x00430:
324 case 0x00438:
325 case 0x00440:
326 case 0x00448:
327 case 0x00450:
328 s->display_text[(saddr - 0x00418) >> 3] = (char) val;
329 malta_fpga_update_display(s);
330 break;
331
332 /* SOFTRES Register */
333 case 0x00500:
334 if (val == 0x42)
335 qemu_system_reset_request ();
336 break;
337
338 /* BRKRES Register */
339 case 0x00508:
340 s->brk = val & 0xff;
341 break;
342
b6dc7ebb 343 /* UART Registers are handled directly by the serial device */
a4bc3afc 344
5856de80
TS
345 /* GPOUT Register */
346 case 0x00a00:
347 s->gpout = val & 0xff;
348 break;
349
350 /* I2COE Register */
351 case 0x00b08:
352 s->i2coe = val & 0x03;
353 break;
354
355 /* I2COUT Register */
356 case 0x00b10:
130751ee
TS
357 eeprom24c0x_write(val & 0x02, val & 0x01);
358 s->i2cout = val;
5856de80
TS
359 break;
360
361 /* I2CSEL Register */
362 case 0x00b18:
130751ee 363 s->i2csel = val & 0x01;
5856de80
TS
364 break;
365
366 default:
367#if 0
3594c774 368 printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
44cbbf18 369 addr);
5856de80
TS
370#endif
371 break;
372 }
373}
374
375static CPUReadMemoryFunc *malta_fpga_read[] = {
376 malta_fpga_readl,
377 malta_fpga_readl,
378 malta_fpga_readl
379};
380
381static CPUWriteMemoryFunc *malta_fpga_write[] = {
382 malta_fpga_writel,
383 malta_fpga_writel,
384 malta_fpga_writel
385};
386
387void malta_fpga_reset(void *opaque)
388{
389 MaltaFPGAState *s = opaque;
390
391 s->leds = 0x00;
392 s->brk = 0x0a;
393 s->gpout = 0x00;
130751ee 394 s->i2cin = 0x3;
5856de80
TS
395 s->i2coe = 0x0;
396 s->i2cout = 0x3;
397 s->i2csel = 0x1;
398
399 s->display_text[8] = '\0';
400 snprintf(s->display_text, 9, " ");
401 malta_fpga_update_display(s);
402}
403
a4bc3afc 404MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env)
5856de80
TS
405{
406 MaltaFPGAState *s;
a4bc3afc 407 CharDriverState *uart_chr;
5856de80
TS
408 int malta;
409
410 s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
411
412 malta = cpu_register_io_memory(0, malta_fpga_read,
413 malta_fpga_write, s);
a4bc3afc 414
b6dc7ebb
TS
415 cpu_register_physical_memory(base, 0x900, malta);
416 cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
5856de80 417
87ee1669
TS
418 if (!nographic) {
419 s->display = qemu_chr_open("vc");
420 qemu_chr_printf(s->display, "\e[HMalta LEDBAR\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 qemu_chr_printf(s->display, "\n");
425 qemu_chr_printf(s->display, "Malta ASCII\r\n");
426 qemu_chr_printf(s->display, "+--------+\r\n");
427 qemu_chr_printf(s->display, "+ +\r\n");
428 qemu_chr_printf(s->display, "+--------+\r\n");
429
430 uart_chr = qemu_chr_open("vc");
431 qemu_chr_printf(uart_chr, "CBUS UART\r\n");
432 s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1);
433 }
a4bc3afc 434
5856de80
TS
435 malta_fpga_reset(s);
436 qemu_register_reset(malta_fpga_reset, s);
437
438 return s;
439}
440
441/* Audio support */
442#ifdef HAS_AUDIO
443static void audio_init (PCIBus *pci_bus)
444{
445 struct soundhw *c;
446 int audio_enabled = 0;
447
448 for (c = soundhw; !audio_enabled && c->name; ++c) {
449 audio_enabled = c->enabled;
450 }
451
452 if (audio_enabled) {
453 AudioState *s;
454
455 s = AUD_init ();
456 if (s) {
457 for (c = soundhw; c->name; ++c) {
5066b9f1
TS
458 if (c->enabled)
459 c->init.init_pci (pci_bus, s);
5856de80
TS
460 }
461 }
462 }
463}
464#endif
465
466/* Network support */
467static void network_init (PCIBus *pci_bus)
468{
469 int i;
470 NICInfo *nd;
471
472 for(i = 0; i < nb_nics; i++) {
473 nd = &nd_table[i];
474 if (!nd->model) {
475 nd->model = "pcnet";
476 }
477 if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
478 /* The malta board has a PCNet card using PCI SLOT 11 */
479 pci_nic_init(pci_bus, nd, 88);
480 } else {
481 pci_nic_init(pci_bus, nd, -1);
482 }
483 }
484}
485
486/* ROM and pseudo bootloader
487
488 The following code implements a very very simple bootloader. It first
489 loads the registers a0 to a3 to the values expected by the OS, and
490 then jump at the kernel address.
491
492 The bootloader should pass the locations of the kernel arguments and
493 environment variables tables. Those tables contain the 32-bit address
494 of NULL terminated strings. The environment variables table should be
495 terminated by a NULL address.
496
497 For a simpler implementation, the number of kernel arguments is fixed
498 to two (the name of the kernel and the command line), and the two
499 tables are actually the same one.
500
501 The registers a0 to a3 should contain the following values:
502 a0 - number of kernel arguments
503 a1 - 32-bit address of the kernel arguments table
504 a2 - 32-bit address of the environment variables table
505 a3 - RAM size in bytes
506*/
507
74287114 508static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
5856de80
TS
509{
510 uint32_t *p;
511
512 /* Small bootloader */
513 p = (uint32_t *) (phys_ram_base + bios_offset);
26ea0918 514 stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */
3ddd0065 515 stl_raw(p++, 0x00000000); /* nop */
5856de80 516
26ea0918
TS
517 /* YAMON service vector */
518 stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */
519 stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */
520 stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */
521 stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */
522 stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */
523 stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */
524 stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
525 stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */
526 stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */
527 stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */
528 stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */
529 stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */
530 stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */
531
532
5856de80 533 /* Second part of the bootloader */
26ea0918 534 p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
d52fff71
TS
535 stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */
536 stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
471ea271 537 stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
3ddd0065 538 stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
471ea271 539 stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
3ddd0065
TS
540 stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
541 stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
542 stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
543 stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
2802bfe3
TS
544
545 /* Load BAR registers as done by YAMON */
546 stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */
547
548#ifdef TARGET_WORDS_BIGENDIAN
549 stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */
550#else
551 stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */
552#endif
553 stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */
554#ifdef TARGET_WORDS_BIGENDIAN
555 stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */
556#else
557 stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */
558#endif
559 stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */
560
561#ifdef TARGET_WORDS_BIGENDIAN
562 stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */
563#else
564 stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */
565#endif
566 stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */
567#ifdef TARGET_WORDS_BIGENDIAN
568 stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */
569#else
570 stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */
571#endif
572 stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */
573
574#ifdef TARGET_WORDS_BIGENDIAN
575 stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */
576#else
577 stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */
578#endif
579 stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */
580#ifdef TARGET_WORDS_BIGENDIAN
581 stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */
582#else
583 stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */
584#endif
585 stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */
586
587 /* Jump to kernel code */
74287114
TS
588 stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
589 stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
3ddd0065
TS
590 stl_raw(p++, 0x03e00008); /* jr ra */
591 stl_raw(p++, 0x00000000); /* nop */
26ea0918
TS
592
593 /* YAMON subroutines */
594 p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
595 stl_raw(p++, 0x03e00008); /* jr ra */
596 stl_raw(p++, 0x24020000); /* li v0,0 */
597 /* 808 YAMON print */
598 stl_raw(p++, 0x03e06821); /* move t5,ra */
599 stl_raw(p++, 0x00805821); /* move t3,a0 */
600 stl_raw(p++, 0x00a05021); /* move t2,a1 */
601 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
602 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
603 stl_raw(p++, 0x10800005); /* beqz a0,834 */
604 stl_raw(p++, 0x00000000); /* nop */
605 stl_raw(p++, 0x0ff0021c); /* jal 870 */
606 stl_raw(p++, 0x00000000); /* nop */
607 stl_raw(p++, 0x08000205); /* j 814 */
608 stl_raw(p++, 0x00000000); /* nop */
609 stl_raw(p++, 0x01a00008); /* jr t5 */
610 stl_raw(p++, 0x01602021); /* move a0,t3 */
611 /* 0x83c YAMON print_count */
612 stl_raw(p++, 0x03e06821); /* move t5,ra */
613 stl_raw(p++, 0x00805821); /* move t3,a0 */
614 stl_raw(p++, 0x00a05021); /* move t2,a1 */
615 stl_raw(p++, 0x00c06021); /* move t4,a2 */
616 stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
617 stl_raw(p++, 0x0ff0021c); /* jal 870 */
618 stl_raw(p++, 0x00000000); /* nop */
619 stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
620 stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */
621 stl_raw(p++, 0x1580fffa); /* bnez t4,84c */
622 stl_raw(p++, 0x00000000); /* nop */
623 stl_raw(p++, 0x01a00008); /* jr t5 */
624 stl_raw(p++, 0x01602021); /* move a0,t3 */
625 /* 0x870 */
626 stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */
627 stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */
628 stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */
629 stl_raw(p++, 0x00000000); /* nop */
630 stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */
631 stl_raw(p++, 0x1120fffc); /* beqz t1,878 <outch+0x8> */
632 stl_raw(p++, 0x00000000); /* nop */
633 stl_raw(p++, 0x03e00008); /* jr ra */
634 stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */
635
5856de80
TS
636}
637
638static void prom_set(int index, const char *string, ...)
639{
640 va_list ap;
3ddd0065
TS
641 int32_t *p;
642 int32_t table_addr;
5856de80
TS
643 char *s;
644
645 if (index >= ENVP_NB_ENTRIES)
646 return;
647
3ddd0065 648 p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
5856de80
TS
649 p += index;
650
651 if (string == NULL) {
652 stl_raw(p, 0);
653 return;
654 }
655
3ddd0065 656 table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
5856de80
TS
657 s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
658
659 stl_raw(p, table_addr);
660
661 va_start(ap, string);
662 vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
663 va_end(ap);
664}
665
666/* Kernel */
667static int64_t load_kernel (CPUState *env)
668{
74287114 669 int64_t kernel_entry, kernel_low, kernel_high;
5856de80
TS
670 int index = 0;
671 long initrd_size;
74287114 672 ram_addr_t initrd_offset;
5856de80 673
74287114
TS
674 if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
675 &kernel_entry, &kernel_low, &kernel_high) < 0) {
5856de80
TS
676 fprintf(stderr, "qemu: could not load kernel '%s'\n",
677 env->kernel_filename);
acdf72bb 678 exit(1);
5856de80
TS
679 }
680
681 /* load initrd */
682 initrd_size = 0;
74287114 683 initrd_offset = 0;
5856de80 684 if (env->initrd_filename) {
74287114
TS
685 initrd_size = get_image_size (env->initrd_filename);
686 if (initrd_size > 0) {
687 initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
688 if (initrd_offset + initrd_size > env->ram_size) {
689 fprintf(stderr,
690 "qemu: memory too small for initial ram disk '%s'\n",
691 env->initrd_filename);
692 exit(1);
693 }
694 initrd_size = load_image(env->initrd_filename,
695 phys_ram_base + initrd_offset);
696 }
5856de80
TS
697 if (initrd_size == (target_ulong) -1) {
698 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
699 env->initrd_filename);
700 exit(1);
701 }
702 }
703
704 /* Store command line. */
705 prom_set(index++, env->kernel_filename);
706 if (initrd_size > 0)
74287114
TS
707 prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
708 PHYS_TO_VIRT(initrd_offset), initrd_size,
709 env->kernel_cmdline);
5856de80
TS
710 else
711 prom_set(index++, env->kernel_cmdline);
712
713 /* Setup minimum environment variables */
714 prom_set(index++, "memsize");
715 prom_set(index++, "%i", env->ram_size);
716 prom_set(index++, "modetty0");
717 prom_set(index++, "38400n8r");
718 prom_set(index++, NULL);
719
74287114 720 return kernel_entry;
5856de80
TS
721}
722
723static void main_cpu_reset(void *opaque)
724{
725 CPUState *env = opaque;
726 cpu_reset(env);
51b2772f 727 cpu_mips_register(env, NULL);
5856de80
TS
728
729 /* The bootload does not need to be rewritten as it is located in a
730 read only location. The kernel location and the arguments table
731 location does not change. */
fb82fea0
TS
732 if (env->kernel_filename) {
733 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
5856de80 734 load_kernel (env);
fb82fea0 735 }
5856de80
TS
736}
737
70705261 738static
5856de80
TS
739void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
740 DisplayState *ds, const char **fd_filename, int snapshot,
741 const char *kernel_filename, const char *kernel_cmdline,
94fc95cd 742 const char *initrd_filename, const char *cpu_model)
5856de80
TS
743{
744 char buf[1024];
745 unsigned long bios_offset;
74287114 746 int64_t kernel_entry;
5856de80
TS
747 PCIBus *pci_bus;
748 CPUState *env;
749 RTCState *rtc_state;
f1770b3e 750 /* fdctrl_t *floppy_controller; */
5856de80
TS
751 MaltaFPGAState *malta_fpga;
752 int ret;
33d68b5f 753 mips_def_t *def;
d537cf6c 754 qemu_irq *i8259;
7b717336
TS
755 int piix4_devfn;
756 uint8_t *eeprom_buf;
757 i2c_bus *smbus;
758 int i;
5856de80 759
33d68b5f
TS
760 /* init CPUs */
761 if (cpu_model == NULL) {
60aa19ab 762#ifdef TARGET_MIPS64
c9c1a064 763 cpu_model = "20Kc";
33d68b5f 764#else
1c32f43e 765 cpu_model = "24Kf";
33d68b5f
TS
766#endif
767 }
768 if (mips_find_by_name(cpu_model, &def) != 0)
769 def = NULL;
5856de80 770 env = cpu_init();
33d68b5f 771 cpu_mips_register(env, def);
5856de80
TS
772 register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
773 qemu_register_reset(main_cpu_reset, env);
774
775 /* allocate RAM */
776 cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
777
778 /* Map the bios at two physical locations, as on the real board */
779 bios_offset = ram_size + vga_ram_size;
780 cpu_register_physical_memory(0x1e000000LL,
781 BIOS_SIZE, bios_offset | IO_MEM_ROM);
782 cpu_register_physical_memory(0x1fc00000LL,
783 BIOS_SIZE, bios_offset | IO_MEM_ROM);
784
070ce5ed
TS
785 /* FPGA */
786 malta_fpga = malta_fpga_init(0x1f000000LL, env);
787
788 /* Load a BIOS image unless a kernel image has been specified. */
789 if (!kernel_filename) {
790 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
791 ret = load_image(buf, phys_ram_base + bios_offset);
792 if (ret < 0 || ret > BIOS_SIZE) {
793 fprintf(stderr,
794 "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
795 buf);
796 exit(1);
797 }
3187ef03
TS
798 /* In little endian mode the 32bit words in the bios are swapped,
799 a neat trick which allows bi-endian firmware. */
800#ifndef TARGET_WORDS_BIGENDIAN
801 {
802 uint32_t *addr;
803 for (addr = (uint32_t *)(phys_ram_base + bios_offset);
804 addr < (uint32_t *)(phys_ram_base + bios_offset + ret);
805 addr++) {
806 *addr = bswap32(*addr);
807 }
808 }
809#endif
070ce5ed
TS
810 }
811
812 /* If a kernel image has been specified, write a small bootloader
813 to the flash location. */
5856de80
TS
814 if (kernel_filename) {
815 env->ram_size = ram_size;
816 env->kernel_filename = kernel_filename;
817 env->kernel_cmdline = kernel_cmdline;
818 env->initrd_filename = initrd_filename;
74287114 819 kernel_entry = load_kernel(env);
fb82fea0 820 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
74287114 821 write_bootloader(env, bios_offset, kernel_entry);
5856de80
TS
822 }
823
824 /* Board ID = 0x420 (Malta Board with CoreLV)
825 XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
826 map to the board ID. */
827 stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
828
829 /* Init internal devices */
d537cf6c 830 cpu_mips_irq_init_cpu(env);
5856de80
TS
831 cpu_mips_clock_init(env);
832 cpu_mips_irqctrl_init();
833
5856de80 834 /* Interrupt controller */
d537cf6c
PB
835 /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
836 i8259 = i8259_init(env->irq[2]);
5856de80
TS
837
838 /* Northbridge */
d537cf6c 839 pci_bus = pci_gt64120_init(i8259);
5856de80
TS
840
841 /* Southbridge */
7b717336 842 piix4_devfn = piix4_init(pci_bus, 80);
afcc3cdf
TS
843 pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259);
844 usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
7b717336
TS
845 smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100);
846 eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
847 for (i = 0; i < 8; i++) {
848 /* TODO: Populate SPD eeprom data. */
849 smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
850 }
d537cf6c 851 pit = pit_init(0x40, i8259[0]);
5856de80
TS
852 DMA_init(0);
853
854 /* Super I/O */
d537cf6c
PB
855 i8042_init(i8259[1], i8259[12], 0x60);
856 rtc_state = rtc_init(0x70, i8259[8]);
7bcc17dc 857 if (serial_hds[0])
d537cf6c 858 serial_init(0x3f8, i8259[4], serial_hds[0]);
7bcc17dc 859 if (serial_hds[1])
d537cf6c 860 serial_init(0x2f8, i8259[3], serial_hds[1]);
7bcc17dc 861 if (parallel_hds[0])
d537cf6c 862 parallel_init(0x378, i8259[7], parallel_hds[0]);
5856de80 863 /* XXX: The floppy controller does not work correctly, something is
f1770b3e 864 probably wrong.
d537cf6c 865 floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
5856de80
TS
866
867 /* Sound card */
868#ifdef HAS_AUDIO
869 audio_init(pci_bus);
870#endif
871
872 /* Network card */
873 network_init(pci_bus);
11f29511
TS
874
875 /* Optional PCI video card */
876 pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
877 ram_size, vga_ram_size);
5856de80
TS
878}
879
880QEMUMachine mips_malta_machine = {
881 "malta",
882 "MIPS Malta Core LV",
883 mips_malta_init,
884};