Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / main.c
1 /*
2  * Open Hack'Ware BIOS main.
3  * 
4  * Copyright (c) 2004-2005 Jocelyn Mayer
5  * 
6  *   This program is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU General Public License V2
8  *   as published by the Free Software Foundation
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 /*
21  * Status:
22  * - boots Linux 2.4 from floppy and IDE
23  * - preliminary residual data support
24  * - can find PREP boot images and Apple boot blocs
25  *
26  * TODO:
27  * 1/ Cleanify boot partitions:
28  *    allow more than one boot bloc + fix PREP load again
29  * 2/ add ATAPI driver
30  * 3/ add a prompt to let the user choose its boot device / PREP image
31  * 4/ add POST
32  * 5/ add VGA driver (SVGA/VESA ?)
33  * 6/ add a user accessible setup
34  * 7/ add netboot
35  */
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include "bios.h"
40
41 #include "char.h"
42
43 //#define DEBUG_MEMORY 1
44
45 /* Version string */
46 const unsigned char *BIOS_str =
47 "PPC Open Hack'Ware BIOS for qemu version " BIOS_VERSION "\n";
48 const unsigned char *copyright = "Copyright 2003-2005 Jocelyn Mayer\n";
49
50 uint32_t isa_io_base = ISA_IO_BASE;
51
52 /* Temporary hack: boots only from floppy */
53 int boot_device = 'a';
54
55 /* Some other PPC helper */
56 /* Setup a memory mapping, using BAT0
57  * BATU:
58  * BEPI  : bloc virtual address
59  * BL    : area size bits (128 kB is 0, 256 1, 512 3, ...
60  * Vs/Vp
61  * BATL:
62  * BPRN  : bloc real address align on 4MB boundary
63  * WIMG  : cache access mode : not used
64  * PP    : protection bits
65  */
66 static void BAT_setup (int nr, uint32_t virtual, uint32_t physical,
67                        uint32_t size, int Vs, int Vp, int PP)
68 {
69     uint32_t sz_bits, tmp_sz, align, tmp;
70     
71     sz_bits = 0;
72     align = 131072;
73     DPRINTF("Set BAT %d v=%0x p=%0x size=%0x\n", nr, virtual, physical, size);
74     if (size < 131072)
75         size = 131072;
76     for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) {
77         sz_bits = (sz_bits << 1) + 1;
78         align = align << 1;
79     }
80     tmp = virtual & ~(align - 1);  /* Align virtual area start */
81     tmp |= sz_bits << 2;           /* Fix BAT size             */
82     tmp |= Vs << 1;                /* Supervisor access        */
83     tmp |= Vp;                     /* User access              */
84     DPRINTF("Set BATU%d to %0x\n", nr, tmp);
85     switch (nr) {
86     case 0:
87         /* Setup IBAT0U */
88         MTSPR(528, tmp);
89         /* Setup DBAT0U */
90         MTSPR(536, tmp);
91         break;
92     case 1:
93         /* Setup DBAT1U */
94         MTSPR(538, tmp);
95         break;
96     case 2:
97         /* Setup DBAT2U */
98         MTSPR(540, tmp);
99         break;
100     }
101     tmp = physical & ~(align - 1); /* Align physical area start */
102     tmp |= 0;                      /* Don't care about WIMG     */
103     tmp |= PP;                     /* Protection                */
104     DPRINTF("Set BATL%d to %0x\n", nr, tmp);
105     switch (nr) {
106     case 0:
107         /* Setup IBAT0L */
108         MTSPR(529, tmp);
109         /* Setup DBAT0L */
110         MTSPR(537, tmp);
111         break;
112     case 1:
113         /* Setup DBAT1L */
114         MTSPR(539, tmp);
115         break;
116     case 2:
117         /* Setup DBAT2L */
118         MTSPR(541, tmp);
119         break;
120     }
121 }
122
123 typedef struct PPC_CPU_t {
124     uint32_t pvr;
125     uint32_t mask;
126     unsigned char *name;
127 } PPC_CPU_t;
128
129 static const PPC_CPU_t CPU_PPC[] = {
130     /* For now, know only G3 */
131     {
132         0x00080000,
133         0xFFFF0000,
134         "PowerPC,G3",
135     },
136     {
137         0x00000000,
138         0x00000000,
139         "PowerPC,generic",
140     },
141 };
142
143 static const unsigned char *CPU_get_name (uint32_t pvr)
144 {
145     int i;
146
147     for (i = 0;; i++) {
148         if ((pvr & CPU_PPC[i].mask) == CPU_PPC[i].pvr)
149             return CPU_PPC[i].name;
150     }
151
152     return NULL;
153 }
154
155 #define TB_FREQ (10 * 1000 * 1000) // XXX: should calibrate
156 void usleep (uint32_t usec)
157 {
158 #if 0 // Buggy: makes OpenDarwin crash (!)
159     uint32_t tb0[2], tb1[2], count[2];
160     uint32_t tpu;
161     int wrap = 0;
162
163     tpu = TB_FREQ / (1000 * 1000);
164     mul64(count, usec, tpu);
165     mftb(tb0);
166     add64(count, count, tb0);
167     if (count[0] < tb0[0])
168         wrap = 1;
169     while (1) {
170         mftb(tb1);
171         if (wrap == 1 && tb1[0] < tb0[0])
172             wrap = 0;
173         if (wrap == 0 &&
174             (tb1[0] > count[0] ||
175              (tb1[0] == count[0] && tb1[1] >= count[1])))
176             break;
177         tb0[0] = tb1[0];
178     }
179 #else
180     uint32_t i, j;
181     
182     for (i = 0; i < (usec >> 16) * 50; i++) {
183         for (j = 0; j < (usec & 0xFFFF) * 50; j++) {
184             continue;
185         }
186     }
187 #endif
188 }
189
190 void sleep (int sec)
191 {
192     int i;
193
194     for (i = 0; i < sec; i++)
195         usleep(1 * 1000 * 1000);
196 }
197
198 /* Stolen from Linux code */
199 #define CRCPOLY_LE 0xedb88320
200
201 uint32_t crc32 (uint32_t crc, const uint8_t *p, int len)
202 {
203     int i;
204
205     while (len--) {
206         crc ^= *p++;
207         for (i = 0; i < 8; i++)
208             crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
209     }
210
211     return crc;
212 }
213
214 /* Fake write */
215 int write (unused int fd, unused const char *buf, int len)
216 {
217     return len;
218 }
219
220 /* BIOS library functions */
221 /* Fake memory management (to be removed) */
222 void *mem_align (unused int align)
223 {
224     return malloc(0);
225 }
226 #if 1
227 void free (unused void *p)
228 {
229 }
230 #endif
231
232 void freep (void *p)
233 {
234     void **_p = p;
235
236     free(*_p);
237     *_p = NULL;
238 }
239
240 static inline int in_area (const void *buf,
241                            const void *start, const void *end)
242 {
243     return buf >= start && buf <= end;
244 }
245
246 #ifdef DEBUG_MEMORY
247 static void *load_dest, *load_end;
248 static int relax_check;
249 #endif
250
251 void set_loadinfo (unused void *load_base, unused uint32_t size)
252 {
253 #ifdef DEBUG_MEMORY
254     load_dest = load_base;
255     load_end = (char *)load_dest + size;
256 #endif
257 }
258
259 void set_check (unused int do_it)
260 {
261 #ifdef DEBUG_MEMORY
262     relax_check = do_it == 0 ? 1 : 0;
263 #endif
264 }
265
266 void check_location (unused const void *buf,
267                      unused const char *func,
268                      unused const char *name)
269 {
270 #ifdef DEBUG_MEMORY
271     if (relax_check != 0)
272         return;
273     if (!in_area(buf, &_data_start, &_data_end) &&
274         !in_area(buf, &_OF_vars_start, &_OF_vars_end) &&
275         !in_area(buf, &_sdata_start, &_sdata_end) &&
276         !in_area(buf, &_ro_start, &_ro_end) &&
277         !in_area(buf, &_RTAS_data_start, &_RTAS_data_end) &&
278         !in_area(buf, &_bss_start, &_bss_end) &&
279         !in_area(buf, &_ram_start, malloc_base) &&
280         /* Let's say 64 kB of stack is enough */
281         !in_area(buf, (void *)0x5ff0000, (void *)0x6000000) &&
282         !in_area(buf, load_dest, load_end) &&
283         /* IO area */
284         !in_area(buf, (void *)0x80000000, (void *)0x88000000)) {
285         printf("**************************************************************"
286                "**************\n");
287         printf("%s: %s: %p\n", func, name, buf);
288         printf("    data:       %p %p\n", &_data_start, &_data_end);
289         printf("    OF_vars:    %p %p\n", &_OF_vars_start, &_OF_vars_end);
290         printf("    sdata:      %p %p\n", &_sdata_start, &_sdata_end);
291         printf("    rodata:     %p %p\n", &_ro_start, &_ro_end);
292         printf("    RTAS_data:  %p %p\n", &_RTAS_data_start, &_RTAS_data_end);
293         printf("    bss:        %p %p\n", &_bss_start, &_bss_end);
294         printf("    mallocated: %p %p\n", &_ram_start, malloc_base);
295         printf("    stack     : %p %p\n", (void *)0x5ff0000,
296                (void *)0x6000000);
297         printf("    load image: %p %p\n", load_dest, load_end);
298         printf("**************************************************************"
299                "**************\n");
300         bug();
301     }
302 #endif
303 }
304
305 /* No overflow check here... */
306 long strtol (const unsigned char *str, unsigned char **end, int base)
307 {
308     long ret = 0, tmp, sign = 1;
309
310     check_location(str, __func__, "str");
311     if (base < 0 || base > 36)
312         return 0;
313     for (; *str == ' '; str++)
314         continue;
315     if (*str == '-') {
316         sign = -1;
317         str++;
318     }
319     for (;; str++) {
320         tmp = *str;
321         if (tmp < '0')
322             break;
323         if (base <= 10) {
324             if (tmp > '0' + base - 1)
325                 break;
326             tmp -= '0';
327         } else {
328             if (tmp <= '9') {
329                 tmp -= '0';
330             } else {
331                 tmp &= ~0x20;
332                 if (tmp < 'A' || tmp > 'A' + base - 11)
333                     break;
334                 tmp += 10 - 'A';
335             }
336         }
337         ret = (ret * base) + tmp;
338     }
339     if (sign == -1)
340         ret = -ret;
341     if (end != NULL)
342         *end = (unsigned char *)str;
343
344     return ret;
345 }
346
347 nvram_t *nvram;
348 int arch;
349 /* HACK... */
350 int vga_width, vga_height, vga_depth;
351
352 part_t *boot_part;
353
354 /* XXX: to fix */
355 void mm_init (uint32_t memsize);
356 int page_descrs_init (void);
357
358 int main (void)
359 {
360     bloc_device_t *bd;
361     pci_host_t *pci_main;
362     void *res, *bootinfos;
363     void *boot_image, *cmdline, *ramdisk;
364     void *load_base, *load_entry, *last_alloc, *load_end;
365     uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size;
366     uint32_t boot_nb;
367     int boot_device, i;
368     static const uint32_t isa_base_tab[3] = {
369         0x80000000, /* PREP */
370         0xFE000000, /* Grackle (Heathrow) */
371         0xF2000000, /* UniNorth (Mac99)  */
372     };
373
374     /* Retrieve NVRAM configuration */
375     for(i = 0; i < 3; i++) {
376         isa_io_base = isa_base_tab[i];
377     nvram = NVRAM_get_config(&memsize, &boot_device,
378                              &boot_image, &boot_image_size,
379                              &cmdline, &cmdline_size,
380                              &ramdisk, &ramdisk_size);
381         if (nvram)
382             break;
383         }
384     if (i == 3) {
385         ERROR("Unable to load configuration from NVRAM. Aborting...\n");
386         return -1;
387     }
388 #if 1
389     mm_init(memsize);
390 #endif
391 #if 1
392     page_descrs_init();
393 #endif
394 #ifdef USE_OPENFIRMWARE
395     OF_init();
396 #endif
397     pci_main = pci_init();
398     if (pci_main == NULL)
399         ERROR("Unable to configure PCI\n");
400 #ifdef USE_OPENFIRMWARE
401     /* XXX: this mess needs a serious cleanup... */
402     {
403         const unsigned char *cpu_name;
404         uint32_t pvr = mfpvr();
405
406         cpu_name = CPU_get_name(pvr);
407         OF_register_cpu(cpu_name, 0, pvr,
408                         200 * 1000 * 1000, 200 * 1000 * 1000,
409                         100 * 1000 * 1000, 100 * 1000 * 1000,
410                         0x0092);
411     }
412     OF_register_memory(memsize, 512 * 1024 /* TOFIX */);
413     /* Claim memory used by the BIOS */
414     OF_claim_virt(0x05800000, 0x00080000, NULL);
415     OF_register_bootargs(cmdline);
416 #endif
417     if (isa_io_base == 0x80000000 || 1) {
418         pc_serial_register(0x3F8);
419 #ifdef USE_OPENFIRMWARE
420         OF_register_bus("isa", isa_io_base, "ISA");
421         OF_register_serial("isa", "com1", 0x3F8, 4);
422         OF_register_stdio("com1", "com1");
423 #endif
424     }
425 #ifdef USE_OPENFIRMWARE
426     RTAS_init();
427 #endif
428     /* Get a console */
429     console_open();
430     printf("%s", BIOS_str);
431     printf("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n");
432     printf("%s\n", copyright);
433     printf("Memory size: %d MB. \nBooting from device %c\n",
434            memsize >> 20, boot_device);
435     vga_puts(BIOS_str);
436     vga_puts("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n");
437     vga_puts(copyright);
438     vga_puts("\n");
439
440 #if 0
441     /* QEMU is quite incoherent: d is cdrom, not second drive */
442     /* XXX: should probe CD-ROM position */
443     if (boot_device == 'd')
444         boot_device = 'e';
445 #endif
446     /* Open boot device */
447     boot_part = bd_probe(boot_device);
448     if (boot_device == 'm') {
449         bd = bd_get('m');
450         if (bd == NULL) {
451             ERROR("Unable to get memory bloc device\n");
452             return -1;
453         }
454         printf("boot device: %p image %p size %d\n",
455                bd, boot_image, boot_image_size);
456         bd_ioctl(bd, MEM_SET_ADDR, boot_image);
457         bd_ioctl(bd, MEM_SET_SIZE, &boot_image_size);
458         boot_part = part_probe(bd, 1);
459         bd_put(bd);
460         printf("boot device: %p\n", bd);
461     }
462     if (boot_part == NULL) {
463         ERROR("Found no boot partition!\n");
464         return -1;
465     }
466     ERROR("Found boot partition : %p %p\n", boot_part, part_fs(boot_part));
467     mem_align(0x00001000);
468     res = malloc(0x4000);
469     last_alloc = malloc(0);
470     boot_nb = 0;
471     DPRINTF("Load base: %p - residual data: %p %p %p %p\n",
472             load_base, res, last_alloc, boot_part, part_fs(boot_part));
473     /* Load the whole boot image */
474     if (bootfile_load((void *)&load_base, (void *)&load_entry,
475                       (void *)&load_end, boot_part, -1, NULL, 0) < 0) {
476         printf("Unable to load boot file\n");
477         return -1;
478     }
479 #ifdef USE_OPENFIRMWARE
480     DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n",
481             res, load_base, &OF_entry, load_entry);
482 #else
483     DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n",
484             res, load_base, NULL, load_entry);
485 #endif
486     DPRINTF("Boot: %0x %0x %0x %0x\n", *(uint32_t *)load_entry,
487             *((uint32_t *)load_entry + 1),
488             *((uint32_t *)load_entry + 2),
489             *((uint32_t *)load_entry + 3));
490     /* Fill residual data structure */
491     residual_build(res, memsize, (uint32_t)load_base,
492                    (uint32_t)boot_nb * part_blocsize(boot_part),
493                    (uint32_t)last_alloc);
494     /* Fill bootinfos */
495     bootinfos = (void *)(((uint32_t)load_end + (1 << 20) - 1) & ~((1 << 20) - 1));
496     if (boot_image != NULL && cmdline == NULL) {
497         cmdline = bootinfos + 0x1000;
498         *(char *)cmdline = '\0';
499     }
500     set_check(0);
501     prepare_bootinfos(bootinfos, memsize, cmdline, ramdisk, ramdisk_size);
502     set_check(1);
503     if (part_flags(boot_part) & PART_PREP) {
504         vga_prep_init();
505     }
506     /* Format NVRAM */
507     NVRAM_format(nvram);
508     /* Setup MMU and boot the loaded image */
509     DPRINTF("\nSet up MMU context\n");
510     /* Map all memory with transparent mapping */
511     BAT_setup(0, 0x00000000, 0x00000000, memsize, 1, 0, 2);
512     /* Open IO ports */
513     BAT_setup(1, isa_io_base, isa_io_base, 0x00800000, 1, 1, 2);
514 #if 0
515     /* Open the frame-buffer area */
516     BAT_setup(2, vga_fb_phys_addr, vga_fb_phys_addr, 0x00200000, 1, 1, 2);
517 #else
518     if (pci_main != NULL) {
519         uint32_t mem_start, mem_size;
520         pci_get_mem_range(pci_main, &mem_start, &mem_size);
521         BAT_setup(2, mem_start, mem_start, mem_size, 1, 1, 2);
522     }
523 #endif
524     /* Enable MMU */
525     MMU_on();
526     usleep(500);
527     dprintf("Boot: %08x %08x %08x %08x\n", *(uint32_t *)load_base,
528             *(uint32_t *)(load_base + 4), *(uint32_t *)(load_base + 8),
529             *(uint32_t *)(load_base + 12));
530     dprintf("Bootinfos at : %p\n", bootinfos);
531     printf("\nNow boot it... (%p)\n\n", malloc(0));
532     usleep(500);
533     {
534         register uint32_t r1 __asm__ ("r1");
535         printf("stack: %0x malloc_base: %p 0x05800000 0x06000000\n",
536                r1, malloc(0));
537     }
538     
539     if (part_flags(boot_part) & PART_PREP) {
540         printf("PREP boot... %p %p\n", load_entry, load_base);
541         /* Hack for Linux to boot without OpenFirmware */
542         put_be32(load_base, 0xdeadc0de);
543     }
544     transfer_handler(res                      /* residual data          */,
545                      load_base                /* load address           */,
546 #ifdef USE_OPENFIRMWARE
547                      &OF_entry                /* OF entry point         */,
548 #else
549                      NULL,
550 #endif
551                      bootinfos                /* bootinfos for Linux    */,
552                      cmdline                  /* command line for Linux */,
553                      NULL                     /* unused for now         */,
554                      load_entry               /* start address     */,
555 #if 0
556                      mem_align(0x00100000)    /* Stack base             */
557 #else
558                      (void *)0x05800000
559 #endif
560                      );
561     /* Should never come here */
562
563     return 0;
564 }