2 * Creation Date: <2004/08/28 18:38:22 greg>
3 * Time-stamp: <2004/08/28 18:38:22 greg>
7 * Initialization for qemu
9 * Copyright (C) 2004 Greg Watson
10 * Copyright (C) 2005 Stefan Reinauer
12 * based on mol/init.c:
14 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel & David Rydh
15 * (samuel@ibrium.se, dary@lindesign.se)
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation
24 #include "libopenbios/openbios.h"
25 #include "libopenbios/bindings.h"
26 #include "libopenbios/console.h"
27 #include "drivers/pci.h"
28 #include "arch/common/nvram.h"
29 #include "drivers/drivers.h"
30 #include "qemu/qemu.h"
31 #include "libopenbios/ofmem.h"
32 #include "openbios-version.h"
33 #include "libc/byteorder.h"
34 #include "libc/vsprintf.h"
35 #define NO_QEMU_PROTOS
36 #include "arch/common/fw_cfg.h"
37 #include "arch/ppc/processor.h"
39 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
42 unsigned int iu_version;
44 int icache_size, dcache_size;
45 int icache_sets, dcache_sets;
46 int icache_block_size, dcache_block_size;
47 int tlb_sets, tlb_size;
48 void (*initfn)(const struct cpudef *cpu);
51 static uint16_t machine_id = 0;
53 extern void unexpected_excep(int vector);
56 unexpected_excep(int vector)
58 printk("openbios panic: Unexpected exception %x\n", vector);
63 extern void __divide_error(void);
80 return is_oldworld() || is_newworld();
85 return machine_id == ARCH_HEATHROW;
90 return (machine_id == ARCH_MAC99) ||
91 (machine_id == ARCH_MAC99_U3);
94 static const pci_arch_t known_arch[] = {
97 .vendor_id = PCI_VENDOR_ID_MOTOROLA,
98 .device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN,
99 .cfg_addr = 0x80000cf8,
100 .cfg_data = 0x80000cfc,
101 .cfg_base = 0x80000000,
102 .cfg_len = 0x00100000,
103 .host_pci_base = 0xc0000000,
104 .pci_mem_base = 0x100000, /* avoid VGA at 0xa0000 */
105 .mem_len = 0x10000000,
106 .io_base = 0x80000000,
107 .io_len = 0x00010000,
110 .irqs = { 9, 11, 9, 11 }
114 .vendor_id = PCI_VENDOR_ID_APPLE,
115 .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
116 .cfg_addr = 0xf2800000,
117 .cfg_data = 0xf2c00000,
118 .cfg_base = 0xf2000000,
119 .cfg_len = 0x02000000,
120 .host_pci_base = 0x0,
121 .pci_mem_base = 0x80000000,
122 .mem_len = 0x10000000,
123 .io_base = 0xf2000000,
124 .io_len = 0x00800000,
127 .irqs = { 0x1b, 0x1c, 0x1d, 0x1e }
131 .vendor_id = PCI_VENDOR_ID_APPLE,
132 .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
133 .cfg_addr = 0xf0800000,
134 .cfg_data = 0xf0c00000,
135 .cfg_base = 0xf0000000,
136 .cfg_len = 0x02000000,
137 .host_pci_base = 0x0,
138 .pci_mem_base = 0x80000000,
139 .mem_len = 0x10000000,
140 .io_base = 0xf2000000,
141 .io_len = 0x00800000,
144 .irqs = { 0x1b, 0x1c, 0x1d, 0x1e }
148 .vendor_id = PCI_VENDOR_ID_MOTOROLA,
149 .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
150 .cfg_addr = 0xfec00000,
151 .cfg_data = 0xfee00000,
152 .cfg_base = 0x80000000,
153 .cfg_len = 0x7f000000,
154 .host_pci_base = 0x0,
155 .pci_mem_base = 0x80000000,
156 .mem_len = 0x10000000,
157 .io_base = 0xfe000000,
158 .io_len = 0x00800000,
161 .irqs = { 21, 22, 23, 24 }
164 unsigned long isa_io_base;
166 extern struct _console_ops mac_console_ops, prep_console_ops;
174 arch = &known_arch[ARCH_HEATHROW];
178 fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
180 if (strncmp(buf, "QEMU", 4) == 0) {
181 temp = fw_cfg_read_i32(FW_CFG_ID);
183 machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
184 arch = &known_arch[machine_id];
188 isa_io_base = arch->io_base;
190 #ifdef CONFIG_DEBUG_CONSOLE
192 init_console(mac_console_ops);
194 init_console(prep_console_ops);
199 printk("Incompatible configuration device version, freezing\n");
208 printk("of_startup returned!\n");
213 /* -- phys.lo ... phys.hi */
215 push_physaddr(phys_addr_t value)
223 /* From drivers/timer.c */
224 extern unsigned long timer_freq;
227 cpu_generic_init(const struct cpudef *cpu)
230 fword("find-device");
235 fword("device-name");
238 fword("device-type");
242 push_str("cpu-version");
245 PUSH(cpu->dcache_size);
247 push_str("d-cache-size");
250 PUSH(cpu->icache_size);
252 push_str("i-cache-size");
255 PUSH(cpu->dcache_sets);
257 push_str("d-cache-sets");
260 PUSH(cpu->icache_sets);
262 push_str("i-cache-sets");
265 PUSH(cpu->dcache_block_size);
267 push_str("d-cache-block-size");
270 PUSH(cpu->icache_block_size);
272 push_str("i-cache-block-size");
277 push_str("tlb-sets");
282 push_str("tlb-size");
285 timer_freq = fw_cfg_read_i32(FW_CFG_PPC_TBFREQ);
288 push_str("timebase-frequency");
291 PUSH(fw_cfg_read_i32(FW_CFG_PPC_CLOCKFREQ));
293 push_str("clock-frequency");
296 PUSH(fw_cfg_read_i32(FW_CFG_PPC_BUSFREQ));
298 push_str("bus-frequency");
302 fword("encode-string");
308 cpu_add_pir_property(void)
312 asm("mfspr %0, 1023\n"
321 cpu_604_init(const struct cpudef *cpu)
323 cpu_generic_init(cpu);
324 cpu_add_pir_property();
326 fword("finish-device");
330 cpu_750_init(const struct cpudef *cpu)
332 cpu_generic_init(cpu);
339 fword("finish-device");
343 cpu_g4_init(const struct cpudef *cpu)
345 cpu_generic_init(cpu);
346 cpu_add_pir_property();
348 fword("finish-device");
351 #ifdef CONFIG_PPC_64BITSUPPORT
352 /* In order to get 64 bit aware handlers that rescue all our
353 GPRs from getting truncated to 32 bits, we need to patch the
354 existing handlers so they jump to our 64 bit aware ones. */
356 ppc64_patch_handlers(void)
358 uint32_t *dsi = (uint32_t *)0x300UL;
359 uint32_t *isi = (uint32_t *)0x400UL;
361 // Patch the first DSI handler instruction to: ba 0x2000
364 // Patch the first ISI handler instruction to: ba 0x2200
367 // Invalidate the cache lines
368 asm ("icbi 0, %0" : : "r"(dsi));
369 asm ("icbi 0, %0" : : "r"(isi));
374 cpu_970_init(const struct cpudef *cpu)
376 cpu_generic_init(cpu);
385 fword("encode-bytes");
389 fword("finish-device");
391 #ifdef CONFIG_PPC_64BITSUPPORT
392 /* The 970 is a PPC64 CPU, so we need to activate
393 * 64bit aware interrupt handlers */
395 ppc64_patch_handlers();
398 /* The 970 also implements the HIOR which we need to set to 0 */
403 static const struct cpudef ppc_defs[] = {
405 .iu_version = 0x00040000,
406 .name = "PowerPC,604",
407 .icache_size = 0x4000,
408 .dcache_size = 0x4000,
411 .icache_block_size = 0x20,
412 .dcache_block_size = 0x20,
415 .initfn = cpu_604_init,
417 { // XXX find out real values
418 .iu_version = 0x00090000,
419 .name = "PowerPC,604e",
420 .icache_size = 0x4000,
421 .dcache_size = 0x4000,
424 .icache_block_size = 0x20,
425 .dcache_block_size = 0x20,
428 .initfn = cpu_604_init,
430 { // XXX find out real values
431 .iu_version = 0x000a0000,
432 .name = "PowerPC,604r",
433 .icache_size = 0x4000,
434 .dcache_size = 0x4000,
437 .icache_block_size = 0x20,
438 .dcache_block_size = 0x20,
441 .initfn = cpu_604_init,
443 { // XXX find out real values
444 .iu_version = 0x80040000,
445 .name = "PowerPC,MPC86xx",
446 .icache_size = 0x8000,
447 .dcache_size = 0x8000,
450 .icache_block_size = 0x20,
451 .dcache_block_size = 0x20,
454 .initfn = cpu_750_init,
457 .iu_version = 0x000080000,
458 .name = "PowerPC,750",
459 .icache_size = 0x8000,
460 .dcache_size = 0x8000,
463 .icache_block_size = 0x20,
464 .dcache_block_size = 0x20,
467 .initfn = cpu_750_init,
469 { // XXX find out real values
470 .iu_version = 0x10080000,
471 .name = "PowerPC,750",
472 .icache_size = 0x8000,
473 .dcache_size = 0x8000,
476 .icache_block_size = 0x20,
477 .dcache_block_size = 0x20,
480 .initfn = cpu_750_init,
482 { // XXX find out real values
483 .iu_version = 0x70000000,
484 .name = "PowerPC,750",
485 .icache_size = 0x8000,
486 .dcache_size = 0x8000,
489 .icache_block_size = 0x20,
490 .dcache_block_size = 0x20,
493 .initfn = cpu_750_init,
495 { // XXX find out real values
496 .iu_version = 0x70020000,
497 .name = "PowerPC,750",
498 .icache_size = 0x8000,
499 .dcache_size = 0x8000,
502 .icache_block_size = 0x20,
503 .dcache_block_size = 0x20,
506 .initfn = cpu_750_init,
508 { // XXX find out real values
509 .iu_version = 0x800c0000,
510 .name = "PowerPC,74xx",
511 .icache_size = 0x8000,
512 .dcache_size = 0x8000,
515 .icache_block_size = 0x20,
516 .dcache_block_size = 0x20,
519 .initfn = cpu_750_init,
522 .iu_version = 0x0000c0000,
523 .name = "PowerPC,G4",
524 .icache_size = 0x8000,
525 .dcache_size = 0x8000,
528 .icache_block_size = 0x20,
529 .dcache_block_size = 0x20,
532 .initfn = cpu_g4_init,
535 .iu_version = 0x00390000,
536 .name = "PowerPC,970",
537 .icache_size = 0x10000,
538 .dcache_size = 0x8000,
539 .icache_sets = 0x200,
541 .icache_block_size = 0x80,
542 .dcache_block_size = 0x80,
545 .initfn = cpu_970_init,
547 { // XXX find out real values
548 .iu_version = 0x003C0000,
549 .name = "PowerPC,970FX",
550 .icache_size = 0x10000,
551 .dcache_size = 0x8000,
554 .icache_block_size = 0x80,
555 .dcache_block_size = 0x80,
558 .initfn = cpu_970_init,
561 .iu_version = 0x00350000,
562 .name = "PowerPC,POWER4",
563 .icache_size = 0x10000,
564 .dcache_size = 0x8000,
565 .icache_sets = 0x100,
567 .icache_block_size = 0x80,
568 .dcache_block_size = 0x80,
571 .initfn = cpu_970_init,
575 static const struct cpudef *
578 unsigned int iu_version;
581 iu_version = mfpvr() & 0xffff0000;
583 for (i = 0; i < sizeof(ppc_defs) / sizeof(struct cpudef); i++) {
584 if (iu_version == ppc_defs[i].iu_version)
587 printk("Unknown cpu (pvr %x), freezing!\n", iu_version);
592 static void go(void);
599 feval("saved-program-state >sps.entry @");
602 call_elf(0, 0, addr);
605 static void kvm_of_init(void)
607 char hypercall[4 * 4];
610 /* Don't expose /hypervisor when not in KVM */
611 if (!fw_cfg_read_i32(FW_CFG_PPC_IS_KVM))
615 fword("find-device");
619 push_str("hypervisor");
620 fword("device-name");
622 push_str("hypervisor");
623 fword("device-type");
627 push_str("linux,kvm");
628 fword("encode-string");
629 push_str("epapr,hypervisor-0.2");
630 fword("encode-string");
632 push_str("compatible");
635 /* Tell the guest about the hypercall instructions */
636 fw_cfg_read(FW_CFG_PPC_KVM_HC, hypercall, 4 * 4);
637 hc32 = (uint32_t*)hypercall;
649 push_str("hcall-instructions");
652 /* ePAPR requires us to provide a unique guest id */
653 PUSH(fw_cfg_read_i32(FW_CFG_PPC_KVM_PID));
655 push_str("guest-id");
658 /* ePAPR requires us to provide a guest name */
659 push_str("KVM guest");
660 fword("encode-string");
661 push_str("guest-name");
664 fword("finish-device");
668 * filll ( addr bytes quad -- )
671 static void ffilll(void)
673 const u32 longval = POP();
675 u32 *laddr = (u32 *)cell2pointer(POP());
678 for (len = 0; len < bytes / sizeof(u32); len++) {
690 const struct cpudef *cpu;
691 char buf[64], qemu_uuid[16];
692 const char *stdin_path, *stdout_path, *boot_path;
695 ofmem_t *ofmem = ofmem_arch_get_private();
700 #ifdef CONFIG_DRIVER_PCI
705 printk("=============================================================\n");
706 printk(PROGRAM_NAME " " OPENBIOS_VERSION_STR " [%s]\n",
707 OPENBIOS_BUILD_DATE);
709 fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
711 printk("Configuration device id %s", buf);
713 temp = fw_cfg_read_i32(FW_CFG_ID);
714 printk(" version %d machine id %d\n", temp, machine_id);
716 temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
718 printk("CPUs: %x\n", temp);
720 ram_size = ofmem->ramsize;
722 printk("Memory: %lldM\n", ram_size / 1024 / 1024);
724 fw_cfg_read(FW_CFG_UUID, qemu_uuid, 16);
726 printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
727 qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
728 qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
729 qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
732 /* set device tree root info */
735 fword("find-device");
738 case ARCH_HEATHROW: /* OldWorld */
742 push_str("Power Macintosh");
747 push_str("AAPL,PowerMac G3");
748 fword("encode-string");
750 fword("encode-string");
752 push_str("compatible");
757 push_str("device-tree");
758 fword("encode-string");
759 push_str("AAPL,original-name");
764 push_str("AAPL,cpu-id");
767 PUSH(66 * 1000 * 1000);
769 push_str("clock-frequency");
780 push_str("PowerMac3,1");
785 push_str("PowerMac3,1");
786 fword("encode-string");
788 fword("encode-string");
790 push_str("MacRISC2");
791 fword("encode-string");
793 push_str("Power Macintosh");
794 fword("encode-string");
796 push_str("compatible");
802 fword("device-type");
804 PUSH(100 * 1000 * 1000);
806 push_str("clock-frequency");
811 /* Perhaps we can store UUID here ? */
813 push_str("0000000000000");
814 fword("encode-string");
815 push_str("system-id");
821 fword("find-device");
826 fword("encode-phys");
827 /* This needs adjusting if #size-cells gets increased.
828 Alternatively use multiple (address, size) tuples. */
829 PUSH(ram_size & 0xffffffff);
837 printk("CPU type %s\n", cpu->name);
839 snprintf(buf, sizeof(buf), "/cpus/%s", cpu->name);
840 ofmem_register(find_dev("/memory"), find_dev(buf));
841 node_methods_init(buf);
844 /* OldWorld Macs don't have an /rtas node. */
845 switch (machine_id) {
848 if (!(ph = find_dev("/rtas"))) {
849 printk("Warning: No /rtas node\n");
851 unsigned long size = 0x1000;
852 while (size < (unsigned long)of_rtas_end - (unsigned long)of_rtas_start)
854 set_property(ph, "rtas-size", (char*)&size, sizeof(size));
855 set_int_property(ph, "rtas-version", is_apple() ? 0x41 : 1);
861 if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC)) {
863 if (CONFIG_SERIAL_PORT) {
865 stdout_path = "scca";
868 stdout_path = "sccb";
872 stdout_path = "ttya";
875 /* Some bootloaders force the output to the screen device, so
876 let's create a screen alias for the serial device too */
878 push_str("/aliases");
879 fword("find-device");
881 push_str(stdout_path);
882 fword("pathres-resolve-aliases");
883 fword("encode-string");
888 stdin_path = "adb-keyboard";
889 stdout_path = "screen";
891 stdin_path = "keyboard";
892 stdout_path = "screen";
898 /* Setup nvram variables */
899 push_str("/options");
900 fword("find-device");
902 /* Setup default boot devices (not overriding user settings) */
903 fword("boot-device");
904 boot_device = pop_fstr_copy();
905 if (boot_device && strcmp(boot_device, "disk") == 0) {
906 switch (fw_cfg_read_i16(FW_CFG_BOOT_DEVICE)) {
916 snprintf(buf, sizeof(buf), "%s:,\\\\:tbxi %s:,\\ppc\\bootinfo.txt %s:,%%BOOT", boot_path, boot_path, boot_path);
918 fword("encode-string");
919 push_str("boot-device");
924 /* Set up other properties */
927 fword("find-device");
929 push_str(stdin_path);
930 fword("pathres-resolve-aliases");
931 push_str("input-device");
934 push_str(stdout_path);
935 fword("pathres-resolve-aliases");
936 push_str("output-device");
940 if(getbool("tty-interface?") == 1)
942 fword("activate-tty-interface");
946 /* Implementation of filll word (required by BootX) */
947 bind_func("filll", ffilll);
949 bind_func("platform-boot", boot);
950 bind_func("(go)", go);