Reworking MIPS interrupt handling, by Aurelien Jarno.
[qemu] / hw / mips_malta.c
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
27 #define BIOS_FILENAME           "mips_bios.bin"
28 #ifdef MIPS_HAS_MIPS64
29 #define INITRD_LOAD_ADDR        (uint64_t)0x80800000
30 #define ENVP_ADDR               (uint64_t)0x80002000
31 #else
32 #define INITRD_LOAD_ADDR        (uint32_t)0x80800000
33 #define ENVP_ADDR               (uint32_t)0x80002000
34 #endif
35
36 #define VIRT_TO_PHYS_ADDEND     (-((uint64_t)(uint32_t)0x80000000))
37
38 #define ENVP_NB_ENTRIES         16
39 #define ENVP_ENTRY_SIZE         256
40
41
42 extern FILE *logfile;
43
44 typedef struct {
45     uint32_t leds;
46     uint32_t brk;
47     uint32_t gpout;
48     uint32_t i2coe;
49     uint32_t i2cout;
50     uint32_t i2csel;
51     CharDriverState *display;
52     char display_text[9];
53 } MaltaFPGAState;
54
55 static PITState *pit;
56
57 /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
58 static void pic_irq_request(void *opaque, int level)
59 {
60     cpu_mips_irq_request(opaque, 2, level);
61 }
62
63 /* Malta FPGA */
64 static void malta_fpga_update_display(void *opaque)
65 {
66     char leds_text[9];
67     int i;
68     MaltaFPGAState *s = opaque;
69
70     for (i = 7 ; i >= 0 ; i--) {
71         if (s->leds & (1 << i))
72             leds_text[i] = '#';
73         else
74             leds_text[i] = ' ';
75     }
76     leds_text[8] = '\0';
77
78     qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
79     qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
80 }
81
82 static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
83 {
84     MaltaFPGAState *s = opaque;
85     uint32_t val = 0;
86     uint32_t saddr;
87
88     saddr = (addr & 0xfffff);
89
90     switch (saddr) {
91
92     /* SWITCH Register */
93     case 0x00200:
94         val = 0x00000000;               /* All switches closed */
95         break;
96
97     /* STATUS Register */
98     case 0x00208:
99 #ifdef TARGET_WORDS_BIGENDIAN
100         val = 0x00000012;
101 #else
102         val = 0x00000010;
103 #endif
104         break;
105
106     /* JMPRS Register */
107     case 0x00210:
108         val = 0x00;
109         break;
110
111     /* LEDBAR Register */
112     case 0x00408:
113         val = s->leds;
114         break;
115
116     /* BRKRES Register */
117     case 0x00508:
118         val = s->brk;
119         break;
120
121     /* GPOUT Register */
122     case 0x00a00:
123         val = s->gpout;
124         break;
125
126     /* XXX: implement a real I2C controller */
127
128     /* GPINP Register */
129     case 0x00a08:
130         /* IN = OUT until a real I2C control is implemented */
131         if (s->i2csel)
132             val = s->i2cout;
133         else
134             val = 0x00;
135         break;
136
137     /* I2CINP Register */
138     case 0x00b00:
139         val = 0x00000003;
140         break;
141
142     /* I2COE Register */
143     case 0x00b08:
144         val = s->i2coe;
145         break;
146
147     /* I2COUT Register */
148     case 0x00b10:
149         val = s->i2cout;
150         break;
151
152     /* I2CSEL Register */
153     case 0x00b18:
154         val = s->i2cout;
155         break;
156
157     default:
158 #if 0
159         printf ("malta_fpga_read: Bad register offset 0x%x\n", (int)addr);
160 #endif
161         break;
162     }
163     return val;
164 }
165
166 static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
167                               uint32_t val)
168 {
169     MaltaFPGAState *s = opaque;
170     uint32_t saddr;
171
172     saddr = (addr & 0xfffff);
173
174     switch (saddr) {
175
176     /* SWITCH Register */
177     case 0x00200:
178         break;
179
180     /* JMPRS Register */
181     case 0x00210:
182         break;
183
184     /* LEDBAR Register */
185     /* XXX: implement a 8-LED array */
186     case 0x00408:
187         s->leds = val & 0xff;
188         break;
189
190     /* ASCIIWORD Register */
191     case 0x00410:
192         snprintf(s->display_text, 9, "%08X", val);
193         malta_fpga_update_display(s);
194         break;
195
196     /* ASCIIPOS0 to ASCIIPOS7 Registers */
197     case 0x00418:
198     case 0x00420:
199     case 0x00428:
200     case 0x00430:
201     case 0x00438:
202     case 0x00440:
203     case 0x00448:
204     case 0x00450:
205         s->display_text[(saddr - 0x00418) >> 3] = (char) val;
206         malta_fpga_update_display(s);
207         break;
208
209     /* SOFTRES Register */
210     case 0x00500:
211         if (val == 0x42)
212             qemu_system_reset_request ();
213         break;
214
215     /* BRKRES Register */
216     case 0x00508:
217         s->brk = val & 0xff;
218         break;
219
220     /* GPOUT Register */
221     case 0x00a00:
222         s->gpout = val & 0xff;
223         break;
224
225     /* I2COE Register */
226     case 0x00b08:
227         s->i2coe = val & 0x03;
228         break;
229
230     /* I2COUT Register */
231     case 0x00b10:
232         s->i2cout = val & 0x03;
233         break;
234
235     /* I2CSEL Register */
236     case 0x00b18:
237         s->i2cout = val & 0x01;
238         break;
239
240     default:
241 #if 0
242         printf ("malta_fpga_write: Bad register offset 0x%x\n", (int)addr);
243 #endif
244         break;
245     }
246 }
247
248 static CPUReadMemoryFunc *malta_fpga_read[] = {
249    malta_fpga_readl,
250    malta_fpga_readl,
251    malta_fpga_readl
252 };
253
254 static CPUWriteMemoryFunc *malta_fpga_write[] = {
255    malta_fpga_writel,
256    malta_fpga_writel,
257    malta_fpga_writel
258 };
259
260 void malta_fpga_reset(void *opaque)
261 {
262     MaltaFPGAState *s = opaque;
263
264     s->leds   = 0x00;
265     s->brk    = 0x0a;
266     s->gpout  = 0x00;
267     s->i2coe  = 0x0;
268     s->i2cout = 0x3;
269     s->i2csel = 0x1;
270
271     s->display_text[8] = '\0';
272     snprintf(s->display_text, 9, "        ");
273     malta_fpga_update_display(s);
274 }
275
276 MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
277 {
278     MaltaFPGAState *s;
279     int malta;
280
281     s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
282
283     malta = cpu_register_io_memory(0, malta_fpga_read,
284                                    malta_fpga_write, s);
285     cpu_register_physical_memory(base, 0x100000, malta);
286
287     s->display = qemu_chr_open("vc");
288     qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
289     qemu_chr_printf(s->display, "+--------+\r\n");
290     qemu_chr_printf(s->display, "+        +\r\n");
291     qemu_chr_printf(s->display, "+--------+\r\n");
292     qemu_chr_printf(s->display, "\n");
293     qemu_chr_printf(s->display, "Malta ASCII\r\n");
294     qemu_chr_printf(s->display, "+--------+\r\n");
295     qemu_chr_printf(s->display, "+        +\r\n");
296     qemu_chr_printf(s->display, "+--------+\r\n");
297
298     malta_fpga_reset(s);
299     qemu_register_reset(malta_fpga_reset, s);
300
301     return s;
302 }
303
304 /* Audio support */
305 #ifdef HAS_AUDIO
306 static void audio_init (PCIBus *pci_bus)
307 {
308     struct soundhw *c;
309     int audio_enabled = 0;
310
311     for (c = soundhw; !audio_enabled && c->name; ++c) {
312         audio_enabled = c->enabled;
313     }
314
315     if (audio_enabled) {
316         AudioState *s;
317
318         s = AUD_init ();
319         if (s) {
320             for (c = soundhw; c->name; ++c) {
321                 if (c->enabled) {
322                     if (c->isa) {
323                         fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
324                         exit(1);
325                     }
326                     else {
327                         if (pci_bus) {
328                             c->init.init_pci (pci_bus, s);
329                         }
330                     }
331                 }
332             }
333         }
334     }
335 }
336 #endif
337
338 /* Network support */
339 static void network_init (PCIBus *pci_bus)
340 {
341     int i;
342     NICInfo *nd;
343
344     for(i = 0; i < nb_nics; i++) {
345         nd = &nd_table[i];
346         if (!nd->model) {
347             nd->model = "pcnet";
348         }
349         if (i == 0  && strcmp(nd->model, "pcnet") == 0) {
350             /* The malta board has a PCNet card using PCI SLOT 11 */
351             pci_nic_init(pci_bus, nd, 88);
352         } else {
353             pci_nic_init(pci_bus, nd, -1);
354         }
355     }
356 }
357
358 /* ROM and pseudo bootloader
359
360    The following code implements a very very simple bootloader. It first
361    loads the registers a0 to a3 to the values expected by the OS, and
362    then jump at the kernel address.
363
364    The bootloader should pass the locations of the kernel arguments and
365    environment variables tables. Those tables contain the 32-bit address
366    of NULL terminated strings. The environment variables table should be
367    terminated by a NULL address.
368
369    For a simpler implementation, the number of kernel arguments is fixed
370    to two (the name of the kernel and the command line), and the two
371    tables are actually the same one.
372
373    The registers a0 to a3 should contain the following values:
374      a0 - number of kernel arguments
375      a1 - 32-bit address of the kernel arguments table
376      a2 - 32-bit address of the environment variables table
377      a3 - RAM size in bytes
378 */
379
380 static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
381 {
382     uint32_t *p;
383
384     /* Small bootloader */
385     p = (uint32_t *) (phys_ram_base + bios_offset);
386     stl_raw(p++, 0x0bf00010);                               /* j 0x1fc00040 */
387     stl_raw(p++, 0x00000000);                               /* nop */
388
389     /* Second part of the bootloader */
390     p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
391     stl_raw(p++, 0x3c040000);                               /* lui a0, 0 */
392     stl_raw(p++, 0x34840002);                               /* ori a0, a0, 2 */
393     stl_raw(p++, 0x3c050000 | ((ENVP_ADDR) >> 16));         /* lui a1, high(ENVP_ADDR) */
394     stl_raw(p++, 0x34a50000 | ((ENVP_ADDR) & 0xffff));      /* ori a1, a0, low(ENVP_ADDR) */
395     stl_raw(p++, 0x3c060000 | ((ENVP_ADDR + 8) >> 16));     /* lui a2, high(ENVP_ADDR + 8) */
396     stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));  /* ori a2, a2, low(ENVP_ADDR + 8) */
397     stl_raw(p++, 0x3c070000 | ((env->ram_size) >> 16));     /* lui a3, high(env->ram_size) */
398     stl_raw(p++, 0x34e70000 | ((env->ram_size) & 0xffff));  /* ori a3, a3, low(env->ram_size) */
399     stl_raw(p++, 0x3c1f0000 | ((kernel_addr) >> 16));       /* lui ra, high(kernel_addr) */;
400     stl_raw(p++, 0x37ff0000 | ((kernel_addr) & 0xffff));    /* ori ra, ra, low(kernel_addr) */
401     stl_raw(p++, 0x03e00008);                               /* jr ra */
402     stl_raw(p++, 0x00000000);                               /* nop */
403 }
404
405 static void prom_set(int index, const char *string, ...)
406 {
407     va_list ap;
408     uint32_t *p;
409     uint32_t table_addr;
410     char *s;
411
412     if (index >= ENVP_NB_ENTRIES)
413         return;
414
415     p = (uint32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
416     p += index;
417
418     if (string == NULL) {
419         stl_raw(p, 0);
420         return;
421     }
422
423     table_addr = ENVP_ADDR + sizeof(uint32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
424     s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
425
426     stl_raw(p, table_addr);
427
428     va_start(ap, string);
429     vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
430     va_end(ap);
431 }
432
433 /* Kernel */
434 static int64_t load_kernel (CPUState *env)
435 {
436     int64_t kernel_addr = 0;
437     int index = 0;
438     long initrd_size;
439
440     if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
441         fprintf(stderr, "qemu: could not load kernel '%s'\n",
442                 env->kernel_filename);
443       exit(1);
444     }
445
446     /* load initrd */
447     initrd_size = 0;
448     if (env->initrd_filename) {
449         initrd_size = load_image(env->initrd_filename,
450                                  phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
451         if (initrd_size == (target_ulong) -1) {
452             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
453                     env->initrd_filename);
454             exit(1);
455         }
456     }
457
458     /* Store command line.  */
459     prom_set(index++, env->kernel_filename);
460     if (initrd_size > 0)
461         prom_set(index++, "rd_start=0x%08x rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
462     else
463         prom_set(index++, env->kernel_cmdline);
464
465     /* Setup minimum environment variables */
466     prom_set(index++, "memsize");
467     prom_set(index++, "%i", env->ram_size);
468     prom_set(index++, "modetty0");
469     prom_set(index++, "38400n8r");
470     prom_set(index++, NULL);
471
472     return kernel_addr;
473 }
474
475 static void main_cpu_reset(void *opaque)
476 {
477     CPUState *env = opaque;
478     cpu_reset(env);
479
480     /* The bootload does not need to be rewritten as it is located in a
481        read only location. The kernel location and the arguments table
482        location does not change. */
483     if (env->kernel_filename)
484         load_kernel (env);
485 }
486
487 void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
488                       DisplayState *ds, const char **fd_filename, int snapshot,
489                       const char *kernel_filename, const char *kernel_cmdline,
490                       const char *initrd_filename)
491 {
492     char buf[1024];
493     unsigned long bios_offset;
494     int64_t kernel_addr;
495     PCIBus *pci_bus;
496     CPUState *env;
497     RTCState *rtc_state;
498     /* fdctrl_t *floppy_controller; */
499     MaltaFPGAState *malta_fpga;
500     int ret;
501
502     env = cpu_init();
503     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
504     qemu_register_reset(main_cpu_reset, env);
505
506     /* allocate RAM */
507     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
508
509     /* Map the bios at two physical locations, as on the real board */
510     bios_offset = ram_size + vga_ram_size;
511     cpu_register_physical_memory(0x1e000000LL,
512                                  BIOS_SIZE, bios_offset | IO_MEM_ROM);
513     cpu_register_physical_memory(0x1fc00000LL,
514                                  BIOS_SIZE, bios_offset | IO_MEM_ROM);
515
516     /* Load a BIOS image except if a kernel image has been specified. In
517        the later case, just write a small bootloader to the flash
518        location. */
519     if (kernel_filename) {
520         env->ram_size = ram_size;
521         env->kernel_filename = kernel_filename;
522         env->kernel_cmdline = kernel_cmdline;
523         env->initrd_filename = initrd_filename;
524         kernel_addr = load_kernel(env);
525         write_bootloader(env, bios_offset, kernel_addr);
526     } else {
527         snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
528         ret = load_image(buf, phys_ram_base + bios_offset);
529         if (ret != BIOS_SIZE) {
530             fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
531                     buf);
532             exit(1);
533         }
534     }
535
536     /* Board ID = 0x420 (Malta Board with CoreLV)
537        XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
538        map to the board ID. */
539     stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
540
541     /* Init internal devices */
542     cpu_mips_clock_init(env);
543     cpu_mips_irqctrl_init();
544
545     /* FPGA */
546     malta_fpga = malta_fpga_init(0x1f000000LL);
547
548     /* Interrupt controller */
549     isa_pic = pic_init(pic_irq_request, env);
550
551     /* Northbridge */
552     pci_bus = pci_gt64120_init(isa_pic);
553
554     /* Southbridge */
555     piix4_init(pci_bus, 80);
556     pci_piix3_ide_init(pci_bus, bs_table, 81);
557     usb_uhci_init(pci_bus, 82);
558     piix4_pm_init(pci_bus, 83);
559     pit = pit_init(0x40, 0);
560     DMA_init(0);
561
562     /* Super I/O */
563     kbd_init();
564     rtc_state = rtc_init(0x70, 8);
565     serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
566     parallel_init(0x378, 7, parallel_hds[0]);
567     /* XXX: The floppy controller does not work correctly, something is
568        probably wrong.
569     floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
570
571     /* Sound card */
572 #ifdef HAS_AUDIO
573     audio_init(pci_bus);
574 #endif
575
576     /* Network card */
577     network_init(pci_bus);
578 }
579
580 QEMUMachine mips_malta_machine = {
581     "malta",
582     "MIPS Malta Core LV",
583     mips_malta_init,
584 };