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 "drivers/pci.h"
27 #include "arch/common/nvram.h"
28 #include "drivers/drivers.h"
29 #include "qemu/qemu.h"
30 #include "libopenbios/ofmem.h"
31 #include "openbios-version.h"
32 #include "libc/byteorder.h"
33 #include "libc/vsprintf.h"
34 #define NO_QEMU_PROTOS
35 #include "arch/common/fw_cfg.h"
36 #include "arch/ppc/processor.h"
38 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
41 unsigned long iu_version
;
43 int icache_size
, dcache_size
;
44 int icache_sets
, dcache_sets
;
45 int icache_block_size
, dcache_block_size
;
47 void (*initfn
)(const struct cpudef
*cpu
);
50 static uint16_t machine_id
= 0;
52 extern void unexpected_excep( int vector
);
55 unexpected_excep( int vector
)
57 printk("openbios panic: Unexpected exception %x\n", vector
);
76 return machine_id
== ARCH_HEATHROW
;
81 return (machine_id
== ARCH_MAC99
) ||
82 (machine_id
== ARCH_MAC99_U3
);
85 static const pci_arch_t known_arch
[] = {
88 .vendor_id
= PCI_VENDOR_ID_MOTOROLA
,
89 .device_id
= PCI_DEVICE_ID_MOTOROLA_RAVEN
,
90 .cfg_addr
= 0x80800000,
91 .cfg_data
= 0x800c0000,
92 .cfg_base
= 0x80000000,
93 .cfg_len
= 0x00100000,
94 .host_mem_base
= 0xf0000000,
95 .pci_mem_base
= 0xf0000000,
96 .mem_len
= 0x10000000,
97 .io_base
= 0x80000000,
101 .irqs
= { 9, 11, 9, 11 }
105 .vendor_id
= PCI_VENDOR_ID_APPLE
,
106 .device_id
= PCI_DEVICE_ID_APPLE_UNI_N_PCI
,
107 .cfg_addr
= 0xf2800000,
108 .cfg_data
= 0xf2c00000,
109 .cfg_base
= 0xf2000000,
110 .cfg_len
= 0x02000000,
111 .host_mem_base
= 0x80000000,
112 .pci_mem_base
= 0x80000000,
113 .mem_len
= 0x10000000,
114 .io_base
= 0xf2000000,
115 .io_len
= 0x00800000,
118 .irqs
= { 0x1b, 0x1c, 0x1d, 0x1e }
122 .vendor_id
= PCI_VENDOR_ID_APPLE
,
123 .device_id
= PCI_DEVICE_ID_APPLE_U3_AGP
,
124 .cfg_addr
= 0xf0800000,
125 .cfg_data
= 0xf0c00000,
126 .cfg_base
= 0xf0000000,
127 .cfg_len
= 0x02000000,
128 .host_mem_base
= 0x80000000,
129 .pci_mem_base
= 0x80000000,
130 .mem_len
= 0x10000000,
131 .io_base
= 0xf2000000,
132 .io_len
= 0x00800000,
135 .irqs
= { 0x1b, 0x1c, 0x1d, 0x1e }
139 .vendor_id
= PCI_VENDOR_ID_MOTOROLA
,
140 .device_id
= PCI_DEVICE_ID_MOTOROLA_MPC106
,
141 .cfg_addr
= 0xfec00000,
142 .cfg_data
= 0xfee00000,
143 .cfg_base
= 0x80000000,
144 .cfg_len
= 0x7f000000,
145 .host_mem_base
= 0x80000000,
146 .pci_mem_base
= 0x80000000,
147 .mem_len
= 0x01000000,
148 .io_base
= 0xfe000000,
149 .io_len
= 0x00800000,
152 .irqs
= { 21, 22, 23, 24 }
155 uint32_t isa_io_base
;
163 arch
= &known_arch
[ARCH_HEATHROW
];
167 fw_cfg_read(FW_CFG_SIGNATURE
, buf
, 4);
169 if (strncmp(buf
, "QEMU", 4) == 0) {
170 temp
= fw_cfg_read_i32(FW_CFG_ID
);
172 machine_id
= fw_cfg_read_i16(FW_CFG_MACHINE_ID
);
173 arch
= &known_arch
[machine_id
];
177 isa_io_base
= arch
->io_base
;
180 printk("Incompatible configuration device version, freezing\n");
188 printk("of_startup returned!\n");
194 cpu_generic_init(const struct cpudef
*cpu
)
196 unsigned long iu_version
;
199 fword("find-device");
204 fword("device-name");
207 fword("device-type");
210 : "=r"(iu_version
) :);
213 push_str("cpu-version");
216 PUSH(cpu
->dcache_size
);
218 push_str("dcache-size");
221 PUSH(cpu
->icache_size
);
223 push_str("icache-size");
226 PUSH(cpu
->dcache_sets
);
228 push_str("dcache-sets");
231 PUSH(cpu
->icache_sets
);
233 push_str("icache-sets");
236 PUSH(cpu
->dcache_block_size
);
238 push_str("dcache-block-size");
241 PUSH(cpu
->icache_block_size
);
243 push_str("icache-block-size");
246 PUSH(fw_cfg_read_i32(FW_CFG_PPC_TBFREQ
));
248 push_str("timebase-frequency");
251 PUSH(fw_cfg_read_i32(FW_CFG_PPC_CPUFREQ
));
253 push_str("clock-frequency");
257 fword("encode-string");
263 cpu_add_pir_property(void)
267 asm("mfspr %0, 1023\n"
276 cpu_604_init(const struct cpudef
*cpu
)
278 cpu_generic_init(cpu
);
279 cpu_add_pir_property();
281 fword("finish-device");
285 cpu_750_init(const struct cpudef
*cpu
)
287 cpu_generic_init(cpu
);
294 fword("finish-device");
298 cpu_g4_init(const struct cpudef
*cpu
)
300 cpu_generic_init(cpu
);
301 cpu_add_pir_property();
303 fword("finish-device");
306 #ifdef CONFIG_PPC_64BITSUPPORT
307 /* In order to get 64 bit aware handlers that rescue all our
308 GPRs from getting truncated to 32 bits, we need to patch the
309 existing handlers so they jump to our 64 bit aware ones. */
311 ppc64_patch_handlers(void)
313 uint32_t *dsi
= (uint32_t *)0x300UL
;
314 uint32_t *isi
= (uint32_t *)0x400UL
;
316 // Patch the first DSI handler instruction to: ba 0x2000
319 // Patch the first ISI handler instruction to: ba 0x2200
322 // Invalidate the cache lines
323 asm ( "icbi 0, %0" : : "r"(dsi
) );
324 asm ( "icbi 0, %0" : : "r"(isi
) );
329 cpu_970_init(const struct cpudef
*cpu
)
331 cpu_generic_init(cpu
);
340 fword("encode-bytes");
344 fword("finish-device");
346 #ifdef CONFIG_PPC_64BITSUPPORT
347 /* The 970 is a PPC64 CPU, so we need to activate
348 * 64bit aware interrupt handlers */
350 ppc64_patch_handlers();
353 /* The 970 also implements the HIOR which we need to set to 0 */
358 static const struct cpudef ppc_defs
[] = {
360 .iu_version
= 0x00040000,
361 .name
= "PowerPC,604",
362 .icache_size
= 0x4000,
363 .dcache_size
= 0x4000,
366 .icache_block_size
= 0x20,
367 .dcache_block_size
= 0x20,
368 .clock_frequency
= 0x07de2900,
369 .initfn
= cpu_604_init
,
371 { // XXX find out real values
372 .iu_version
= 0x00090000,
373 .name
= "PowerPC,604e",
374 .icache_size
= 0x4000,
375 .dcache_size
= 0x4000,
378 .icache_block_size
= 0x20,
379 .dcache_block_size
= 0x20,
380 .clock_frequency
= 0x07de2900,
381 .initfn
= cpu_604_init
,
383 { // XXX find out real values
384 .iu_version
= 0x000a0000,
385 .name
= "PowerPC,604r",
386 .icache_size
= 0x4000,
387 .dcache_size
= 0x4000,
390 .icache_block_size
= 0x20,
391 .dcache_block_size
= 0x20,
392 .clock_frequency
= 0x07de2900,
393 .initfn
= cpu_604_init
,
395 { // XXX find out real values
396 .iu_version
= 0x80040000,
397 .name
= "PowerPC,MPC86xx",
398 .icache_size
= 0x8000,
399 .dcache_size
= 0x8000,
402 .icache_block_size
= 0x20,
403 .dcache_block_size
= 0x20,
404 .clock_frequency
= 0x14dc9380,
405 .initfn
= cpu_750_init
,
408 .iu_version
= 0x000080000,
409 .name
= "PowerPC,750",
410 .icache_size
= 0x8000,
411 .dcache_size
= 0x8000,
414 .icache_block_size
= 0x20,
415 .dcache_block_size
= 0x20,
416 .clock_frequency
= 0x14dc9380,
417 .initfn
= cpu_750_init
,
419 { // XXX find out real values
420 .iu_version
= 0x10080000,
421 .name
= "PowerPC,750",
422 .icache_size
= 0x8000,
423 .dcache_size
= 0x8000,
426 .icache_block_size
= 0x20,
427 .dcache_block_size
= 0x20,
428 .clock_frequency
= 0x14dc9380,
429 .initfn
= cpu_750_init
,
431 { // XXX find out real values
432 .iu_version
= 0x70000000,
433 .name
= "PowerPC,750",
434 .icache_size
= 0x8000,
435 .dcache_size
= 0x8000,
438 .icache_block_size
= 0x20,
439 .dcache_block_size
= 0x20,
440 .clock_frequency
= 0x14dc9380,
441 .initfn
= cpu_750_init
,
443 { // XXX find out real values
444 .iu_version
= 0x70020000,
445 .name
= "PowerPC,750",
446 .icache_size
= 0x8000,
447 .dcache_size
= 0x8000,
450 .icache_block_size
= 0x20,
451 .dcache_block_size
= 0x20,
452 .clock_frequency
= 0x14dc9380,
453 .initfn
= cpu_750_init
,
455 { // XXX find out real values
456 .iu_version
= 0x800c0000,
457 .name
= "PowerPC,74xx",
458 .icache_size
= 0x8000,
459 .dcache_size
= 0x8000,
462 .icache_block_size
= 0x20,
463 .dcache_block_size
= 0x20,
464 .clock_frequency
= 0x14dc9380,
465 .initfn
= cpu_750_init
,
468 .iu_version
= 0x0000c0000,
469 .name
= "PowerPC,G4",
470 .icache_size
= 0x8000,
471 .dcache_size
= 0x8000,
474 .icache_block_size
= 0x20,
475 .dcache_block_size
= 0x20,
476 .clock_frequency
= 0x1dcd6500,
477 .initfn
= cpu_g4_init
,
480 .iu_version
= 0x00390000,
481 .name
= "PowerPC,970",
482 .icache_size
= 0x10000,
483 .dcache_size
= 0x8000,
484 .icache_sets
= 0x200,
486 .icache_block_size
= 0x80,
487 .dcache_block_size
= 0x80,
488 .clock_frequency
= 0x5f5e1000,
489 .initfn
= cpu_970_init
,
491 { // XXX find out real values
492 .iu_version
= 0x003C0000,
493 .name
= "PowerPC,970FX",
494 .icache_size
= 0x10000,
495 .dcache_size
= 0x8000,
498 .icache_block_size
= 0x80,
499 .dcache_block_size
= 0x80,
500 .clock_frequency
= 0x1dcd6500,
501 .initfn
= cpu_970_init
,
505 static const struct cpudef
*
508 unsigned long iu_version
;
512 : "=r"(iu_version
) :);
513 iu_version
&= 0xffff0000;
515 for (i
= 0; i
< sizeof(ppc_defs
)/sizeof(struct cpudef
); i
++) {
516 if (iu_version
== ppc_defs
[i
].iu_version
)
519 printk("Unknown cpu (pvr %lx), freezing!\n", iu_version
);
523 static void go( void );
530 feval("saved-program-state >sps.entry @");
533 call_elf( 0, 0, addr
);
536 static void kvm_of_init(void)
538 char hypercall
[4 * 4];
541 /* Don't expose /hypervisor when not in KVM */
542 if (!fw_cfg_read_i32(FW_CFG_PPC_IS_KVM
))
546 fword("find-device");
550 push_str("hypervisor");
551 fword("device-name");
553 push_str("hypervisor");
554 fword("device-type");
558 push_str("linux,kvm");
559 fword("encode-string");
560 push_str("epapr,hypervisor-0.2");
561 fword("encode-string");
563 push_str("compatible");
566 /* Tell the guest about the hypercall instructions */
567 fw_cfg_read(FW_CFG_PPC_KVM_HC
, hypercall
, 4 * 4);
568 hc32
= (uint32_t*)hypercall
;
580 push_str("hcall-instructions");
583 /* ePAPR requires us to provide a unique guest id */
584 PUSH(fw_cfg_read_i32(FW_CFG_PPC_KVM_PID
));
586 push_str("guest-id");
589 /* ePAPR requires us to provide a guest name */
590 push_str("KVM guest");
591 fword("encode-string");
592 push_str("guest-name");
595 fword("finish-device");
605 const struct cpudef
*cpu
;
606 char buf
[64], qemu_uuid
[16];
607 const char *stdin_path
, *stdout_path
, *boot_path
;
610 ofmem_t
*ofmem
= ofmem_arch_get_private();
615 #ifdef CONFIG_DRIVER_PCI
620 printk("=============================================================\n");
621 printk(PROGRAM_NAME
" " OPENBIOS_VERSION_STR
" [%s]\n",
622 OPENBIOS_BUILD_DATE
);
624 fw_cfg_read(FW_CFG_SIGNATURE
, buf
, 4);
626 printk("Configuration device id %s", buf
);
628 temp
= fw_cfg_read_i32(FW_CFG_ID
);
629 printk(" version %d machine id %d\n", temp
, machine_id
);
631 temp
= fw_cfg_read_i32(FW_CFG_NB_CPUS
);
633 printk("CPUs: %x\n", temp
);
635 ram_size
= ofmem
->ramsize
;
637 printk("Memory: %lldM\n", ram_size
/ 1024 / 1024);
639 fw_cfg_read(FW_CFG_UUID
, qemu_uuid
, 16);
641 printk("UUID: " UUID_FMT
"\n", qemu_uuid
[0], qemu_uuid
[1], qemu_uuid
[2],
642 qemu_uuid
[3], qemu_uuid
[4], qemu_uuid
[5], qemu_uuid
[6],
643 qemu_uuid
[7], qemu_uuid
[8], qemu_uuid
[9], qemu_uuid
[10],
644 qemu_uuid
[11], qemu_uuid
[12], qemu_uuid
[13], qemu_uuid
[14],
647 /* set device tree root info */
650 fword("find-device");
653 case ARCH_HEATHROW
: /* OldWorld */
657 push_str("Power Macintosh");
662 push_str("AAPL,PowerMac G3");
663 fword("encode-string");
665 fword("encode-string");
667 push_str("compatible");
672 push_str("device-tree");
673 fword("encode-string");
674 push_str("AAPL,original-name");
679 push_str("AAPL,cpu-id");
682 PUSH(66 * 1000 * 1000);
684 push_str("clock-frequency");
695 push_str("PowerMac2,1");
700 push_str("PowerMac2,1");
701 fword("encode-string");
703 fword("encode-string");
705 push_str("Power Macintosh");
706 fword("encode-string");
708 push_str("compatible");
714 fword("device-type");
716 PUSH(100 * 1000 * 1000);
718 push_str("clock-frequency");
723 /* Perhaps we can store UUID here ? */
725 push_str("0000000000000");
726 fword("encode-string");
727 push_str("system-id");
733 fword("find-device");
737 /* TODO Adjust this when #address-cells gets increased for ppc64. */
739 fword("encode-phys");
740 /* This needs adjusting if #size-cells gets increased.
741 Alternatively use multiple (address, size) tuples. */
742 PUSH(ram_size
& 0xffffffff);
750 printk("CPU type %s\n", cpu
->name
);
752 snprintf(buf
, sizeof(buf
), "/cpus/%s", cpu
->name
);
753 ofmem_register(find_dev("/memory"), find_dev(buf
));
754 node_methods_init(buf
);
757 /* OldWorld Macs don't have an /rtas node. */
758 switch (machine_id
) {
761 if (!(ph
= find_dev("/rtas"))) {
762 printk("Warning: No /rtas node\n");
764 unsigned long size
= 0x1000;
765 while (size
< (unsigned long)of_rtas_end
- (unsigned long)of_rtas_start
)
767 set_property(ph
, "rtas-size", (char*)&size
, sizeof(size
));
768 set_int_property(ph
, "rtas-version", is_apple() ? 0x41 : 1);
774 if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC
)) {
775 if (CONFIG_SERIAL_PORT
) {
777 stdout_path
= "scca";
780 stdout_path
= "sccb";
783 /* Some bootloaders force the output to the screen device, so
784 let's create a screen alias for the serial device too */
785 push_str("/aliases");
786 fword("find-device");
788 push_str(stdout_path
);
789 fword("pathres-resolve-aliases");
790 fword("encode-string");
794 stdin_path
= "adb-keyboard";
795 stdout_path
= "screen";
800 /* Setup nvram variables */
801 push_str("/options");
802 fword("find-device");
804 uint16_t boot_device
= fw_cfg_read_i16(FW_CFG_BOOT_DEVICE
);
805 switch (boot_device
) {
815 /* Setup default boot devices */
816 snprintf(buf
, sizeof(buf
), "%s:,\\\\:tbxi %s:,\\ppc\\bootinfo.txt", boot_path
, boot_path
);
818 fword("encode-string");
819 push_str("boot-device");
822 /* Set up other properties */
824 fword("find-device");
826 push_str(stdin_path
);
832 push_str(stdout_path
);
838 push_str(stdin_path
);
839 fword("pathres-resolve-aliases");
840 push_str("input-device");
843 push_str(stdout_path
);
844 fword("pathres-resolve-aliases");
845 push_str("output-device");
848 push_str(stdin_path
);
851 push_str(stdout_path
);
855 if( getbool("tty-interface?") == 1 )
857 fword("activate-tty-interface");
861 bind_func("platform-boot", boot
);
862 bind_func("(go)", go
);