2 * Open Hack'Ware BIOS main.
4 * Copyright (c) 2004-2005 Jocelyn Mayer
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
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.
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
22 * - boots Linux 2.4 from floppy and IDE
23 * - preliminary residual data support
24 * - can find PREP boot images and Apple boot blocs
27 * 1/ Cleanify boot partitions:
28 * allow more than one boot bloc + fix PREP load again
30 * 3/ add a prompt to let the user choose its boot device / PREP image
32 * 5/ add VGA driver (SVGA/VESA ?)
33 * 6/ add a user accessible setup
43 //#define DEBUG_MEMORY 1
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";
50 uint32_t isa_io_base = ISA_IO_BASE;
52 /* Temporary hack: boots only from floppy */
53 int boot_device = 'a';
55 /* Some other PPC helper */
56 /* Setup a memory mapping, using BAT0
58 * BEPI : bloc virtual address
59 * BL : area size bits (128 kB is 0, 256 1, 512 3, ...
62 * BPRN : bloc real address align on 4MB boundary
63 * WIMG : cache access mode : not used
64 * PP : protection bits
66 static void BAT_setup (int nr, uint32_t virtual, uint32_t physical,
67 uint32_t size, int Vs, int Vp, int PP)
69 uint32_t sz_bits, tmp_sz, align, tmp;
73 DPRINTF("Set BAT %d v=%0x p=%0x size=%0x\n", nr, virtual, physical, size);
76 for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) {
77 sz_bits = (sz_bits << 1) + 1;
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);
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);
123 typedef struct PPC_CPU_t {
129 static const PPC_CPU_t CPU_PPC[] = {
130 /* For now, know only G3 */
143 static const unsigned char *CPU_get_name (uint32_t pvr)
148 if ((pvr & CPU_PPC[i].mask) == CPU_PPC[i].pvr)
149 return CPU_PPC[i].name;
155 #define TB_FREQ (10 * 1000 * 1000) // XXX: should calibrate
156 void usleep (uint32_t usec)
158 #if 0 // Buggy: makes OpenDarwin crash (!)
159 uint32_t tb0[2], tb1[2], count[2];
163 tpu = TB_FREQ / (1000 * 1000);
164 mul64(count, usec, tpu);
166 add64(count, count, tb0);
167 if (count[0] < tb0[0])
171 if (wrap == 1 && tb1[0] < tb0[0])
174 (tb1[0] > count[0] ||
175 (tb1[0] == count[0] && tb1[1] >= count[1])))
182 for (i = 0; i < (usec >> 16) * 50; i++) {
183 for (j = 0; j < (usec & 0xFFFF) * 50; j++) {
194 for (i = 0; i < sec; i++)
195 usleep(1 * 1000 * 1000);
198 /* Stolen from Linux code */
199 #define CRCPOLY_LE 0xedb88320
201 uint32_t crc32 (uint32_t crc, const uint8_t *p, int len)
207 for (i = 0; i < 8; i++)
208 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
215 int write (unused int fd, unused const char *buf, int len)
220 /* BIOS library functions */
221 /* Fake memory management (to be removed) */
222 void *mem_align (unused int align)
227 void free (unused void *p)
240 static inline int in_area (const void *buf,
241 const void *start, const void *end)
243 return buf >= start && buf <= end;
247 static void *load_dest, *load_end;
248 static int relax_check;
251 void set_loadinfo (unused void *load_base, unused uint32_t size)
254 load_dest = load_base;
255 load_end = (char *)load_dest + size;
259 void set_check (unused int do_it)
262 relax_check = do_it == 0 ? 1 : 0;
266 void check_location (unused const void *buf,
267 unused const char *func,
268 unused const char *name)
271 if (relax_check != 0)
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) &&
284 !in_area(buf, (void *)0x80000000, (void *)0x88000000)) {
285 printf("**************************************************************"
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,
297 printf(" load image: %p %p\n", load_dest, load_end);
298 printf("**************************************************************"
305 /* No overflow check here... */
306 long strtol (const unsigned char *str, unsigned char **end, int base)
308 long ret = 0, tmp, sign = 1;
310 check_location(str, __func__, "str");
311 if (base < 0 || base > 36)
313 for (; *str == ' '; str++)
324 if (tmp > '0' + base - 1)
332 if (tmp < 'A' || tmp > 'A' + base - 11)
337 ret = (ret * base) + tmp;
342 *end = (unsigned char *)str;
350 int vga_width, vga_height, vga_depth;
355 void mm_init (uint32_t memsize);
356 int page_descrs_init (void);
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;
368 static const uint32_t isa_base_tab[3] = {
369 0x80000000, /* PREP */
370 0xFE000000, /* Grackle (Heathrow) */
371 0xF2000000, /* UniNorth (Mac99) */
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);
385 ERROR("Unable to load configuration from NVRAM. Aborting...\n");
394 #ifdef USE_OPENFIRMWARE
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... */
403 const unsigned char *cpu_name;
404 uint32_t pvr = mfpvr();
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,
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);
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");
425 #ifdef USE_OPENFIRMWARE
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);
436 vga_puts("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n");
441 /* QEMU is quite incoherent: d is cdrom, not second drive */
442 /* XXX: should probe CD-ROM position */
443 if (boot_device == 'd')
446 /* Open boot device */
447 boot_part = bd_probe(boot_device);
448 if (boot_device == 'm') {
451 ERROR("Unable to get memory bloc device\n");
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);
460 printf("boot device: %p\n", bd);
462 if (boot_part == NULL) {
463 ERROR("Found no boot partition!\n");
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);
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");
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);
483 DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n",
484 res, load_base, NULL, load_entry);
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);
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';
501 prepare_bootinfos(bootinfos, memsize, cmdline, ramdisk, ramdisk_size);
503 if (part_flags(boot_part) & PART_PREP) {
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);
513 BAT_setup(1, isa_io_base, isa_io_base, 0x00800000, 1, 1, 2);
515 /* Open the frame-buffer area */
516 BAT_setup(2, vga_fb_phys_addr, vga_fb_phys_addr, 0x00200000, 1, 1, 2);
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);
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));
534 register uint32_t r1 __asm__ ("r1");
535 printf("stack: %0x malloc_base: %p 0x05800000 0x06000000\n",
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);
544 transfer_handler(res /* residual data */,
545 load_base /* load address */,
546 #ifdef USE_OPENFIRMWARE
547 &OF_entry /* OF entry point */,
551 bootinfos /* bootinfos for Linux */,
552 cmdline /* command line for Linux */,
553 NULL /* unused for now */,
554 load_entry /* start address */,
556 mem_align(0x00100000) /* Stack base */
561 /* Should never come here */