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 /* In order to get 64 bit aware handlers that rescue all our
307 GPRs from getting truncated to 32 bits, we need to patch the
308 existing handlers so they jump to our 64 bit aware ones. */
310 ppc64_patch_handlers(void)
312 uint32_t *dsi
= (uint32_t *)0x300UL
;
313 uint32_t *isi
= (uint32_t *)0x400UL
;
315 // Patch the first DSI handler instruction to: ba 0x2000
318 // Patch the first ISI handler instruction to: ba 0x2200
321 // Invalidate the cache lines
322 asm ( "icbi 0, %0" : : "r"(dsi
) );
323 asm ( "icbi 0, %0" : : "r"(isi
) );
327 cpu_970_init(const struct cpudef
*cpu
)
329 cpu_generic_init(cpu
);
338 fword("encode-bytes");
342 fword("finish-device");
344 /* The 970 is a PPC64 CPU, so we need to activate
345 * 64bit aware interrupt handlers */
347 ppc64_patch_handlers();
349 /* The 970 also implements the HIOR which we need to set to 0 */
354 static const struct cpudef ppc_defs
[] = {
356 .iu_version
= 0x00040000,
357 .name
= "PowerPC,604",
358 .icache_size
= 0x4000,
359 .dcache_size
= 0x4000,
362 .icache_block_size
= 0x20,
363 .dcache_block_size
= 0x20,
364 .clock_frequency
= 0x07de2900,
365 .initfn
= cpu_604_init
,
367 { // XXX find out real values
368 .iu_version
= 0x00090000,
369 .name
= "PowerPC,604e",
370 .icache_size
= 0x4000,
371 .dcache_size
= 0x4000,
374 .icache_block_size
= 0x20,
375 .dcache_block_size
= 0x20,
376 .clock_frequency
= 0x07de2900,
377 .initfn
= cpu_604_init
,
379 { // XXX find out real values
380 .iu_version
= 0x000a0000,
381 .name
= "PowerPC,604r",
382 .icache_size
= 0x4000,
383 .dcache_size
= 0x4000,
386 .icache_block_size
= 0x20,
387 .dcache_block_size
= 0x20,
388 .clock_frequency
= 0x07de2900,
389 .initfn
= cpu_604_init
,
391 { // XXX find out real values
392 .iu_version
= 0x80040000,
393 .name
= "PowerPC,MPC86xx",
394 .icache_size
= 0x8000,
395 .dcache_size
= 0x8000,
398 .icache_block_size
= 0x20,
399 .dcache_block_size
= 0x20,
400 .clock_frequency
= 0x14dc9380,
401 .initfn
= cpu_750_init
,
404 .iu_version
= 0x000080000,
405 .name
= "PowerPC,750",
406 .icache_size
= 0x8000,
407 .dcache_size
= 0x8000,
410 .icache_block_size
= 0x20,
411 .dcache_block_size
= 0x20,
412 .clock_frequency
= 0x14dc9380,
413 .initfn
= cpu_750_init
,
415 { // XXX find out real values
416 .iu_version
= 0x10080000,
417 .name
= "PowerPC,750",
418 .icache_size
= 0x8000,
419 .dcache_size
= 0x8000,
422 .icache_block_size
= 0x20,
423 .dcache_block_size
= 0x20,
424 .clock_frequency
= 0x14dc9380,
425 .initfn
= cpu_750_init
,
427 { // XXX find out real values
428 .iu_version
= 0x70000000,
429 .name
= "PowerPC,750",
430 .icache_size
= 0x8000,
431 .dcache_size
= 0x8000,
434 .icache_block_size
= 0x20,
435 .dcache_block_size
= 0x20,
436 .clock_frequency
= 0x14dc9380,
437 .initfn
= cpu_750_init
,
439 { // XXX find out real values
440 .iu_version
= 0x70020000,
441 .name
= "PowerPC,750",
442 .icache_size
= 0x8000,
443 .dcache_size
= 0x8000,
446 .icache_block_size
= 0x20,
447 .dcache_block_size
= 0x20,
448 .clock_frequency
= 0x14dc9380,
449 .initfn
= cpu_750_init
,
451 { // XXX find out real values
452 .iu_version
= 0x800c0000,
453 .name
= "PowerPC,74xx",
454 .icache_size
= 0x8000,
455 .dcache_size
= 0x8000,
458 .icache_block_size
= 0x20,
459 .dcache_block_size
= 0x20,
460 .clock_frequency
= 0x14dc9380,
461 .initfn
= cpu_750_init
,
464 .iu_version
= 0x0000c0000,
465 .name
= "PowerPC,G4",
466 .icache_size
= 0x8000,
467 .dcache_size
= 0x8000,
470 .icache_block_size
= 0x20,
471 .dcache_block_size
= 0x20,
472 .clock_frequency
= 0x1dcd6500,
473 .initfn
= cpu_g4_init
,
476 .iu_version
= 0x00390000,
477 .name
= "PowerPC,970",
478 .icache_size
= 0x10000,
479 .dcache_size
= 0x8000,
480 .icache_sets
= 0x200,
482 .icache_block_size
= 0x80,
483 .dcache_block_size
= 0x80,
484 .clock_frequency
= 0x5f5e1000,
485 .initfn
= cpu_970_init
,
487 { // XXX find out real values
488 .iu_version
= 0x003C0000,
489 .name
= "PowerPC,970FX",
490 .icache_size
= 0x10000,
491 .dcache_size
= 0x8000,
494 .icache_block_size
= 0x80,
495 .dcache_block_size
= 0x80,
496 .clock_frequency
= 0x1dcd6500,
497 .initfn
= cpu_970_init
,
501 static const struct cpudef
*
504 unsigned long iu_version
;
508 : "=r"(iu_version
) :);
509 iu_version
&= 0xffff0000;
511 for (i
= 0; i
< sizeof(ppc_defs
)/sizeof(struct cpudef
); i
++) {
512 if (iu_version
== ppc_defs
[i
].iu_version
)
515 printk("Unknown cpu (pvr %lx), freezing!\n", iu_version
);
519 static void go( void );
526 feval("saved-program-state >sps.entry @");
529 call_elf( 0, 0, addr
);
532 static void kvm_of_init(void)
534 char hypercall
[4 * 4];
537 /* Don't expose /hypervisor when not in KVM */
538 if (!fw_cfg_read_i32(FW_CFG_PPC_IS_KVM
))
542 fword("find-device");
546 push_str("hypervisor");
547 fword("device-name");
549 push_str("hypervisor");
550 fword("device-type");
554 push_str("linux,kvm");
555 fword("encode-string");
556 push_str("epapr,hypervisor-0.2");
557 fword("encode-string");
559 push_str("compatible");
562 /* Tell the guest about the hypercall instructions */
563 fw_cfg_read(FW_CFG_PPC_KVM_HC
, hypercall
, 4 * 4);
564 hc32
= (uint32_t*)hypercall
;
576 push_str("hcall-instructions");
579 /* ePAPR requires us to provide a unique guest id */
580 PUSH(fw_cfg_read_i32(FW_CFG_PPC_KVM_PID
));
582 push_str("guest-id");
585 /* ePAPR requires us to provide a guest name */
586 push_str("KVM guest");
587 fword("encode-string");
588 push_str("guest-name");
591 fword("finish-device");
601 const struct cpudef
*cpu
;
602 char buf
[64], qemu_uuid
[16];
603 const char *stdin_path
, *stdout_path
, *boot_path
;
606 ofmem_t
*ofmem
= ofmem_arch_get_private();
611 #ifdef CONFIG_DRIVER_PCI
616 printk("=============================================================\n");
617 printk(PROGRAM_NAME
" " OPENBIOS_VERSION_STR
" [%s]\n",
618 OPENBIOS_BUILD_DATE
);
620 fw_cfg_read(FW_CFG_SIGNATURE
, buf
, 4);
622 printk("Configuration device id %s", buf
);
624 temp
= fw_cfg_read_i32(FW_CFG_ID
);
625 printk(" version %d machine id %d\n", temp
, machine_id
);
627 temp
= fw_cfg_read_i32(FW_CFG_NB_CPUS
);
629 printk("CPUs: %x\n", temp
);
631 ram_size
= ofmem
->ramsize
;
633 printk("Memory: %lldM\n", ram_size
/ 1024 / 1024);
635 fw_cfg_read(FW_CFG_UUID
, qemu_uuid
, 16);
637 printk("UUID: " UUID_FMT
"\n", qemu_uuid
[0], qemu_uuid
[1], qemu_uuid
[2],
638 qemu_uuid
[3], qemu_uuid
[4], qemu_uuid
[5], qemu_uuid
[6],
639 qemu_uuid
[7], qemu_uuid
[8], qemu_uuid
[9], qemu_uuid
[10],
640 qemu_uuid
[11], qemu_uuid
[12], qemu_uuid
[13], qemu_uuid
[14],
643 /* set device tree root info */
646 fword("find-device");
649 case ARCH_HEATHROW
: /* OldWorld */
653 push_str("Power Macintosh");
658 push_str("AAPL,PowerMac G3");
659 fword("encode-string");
661 fword("encode-string");
663 push_str("compatible");
668 push_str("device-tree");
669 fword("encode-string");
670 push_str("AAPL,original-name");
675 push_str("AAPL,cpu-id");
678 PUSH(66 * 1000 * 1000);
680 push_str("clock-frequency");
691 push_str("PowerMac2,1");
696 push_str("PowerMac2,1");
697 fword("encode-string");
699 fword("encode-string");
701 push_str("Power Macintosh");
702 fword("encode-string");
704 push_str("compatible");
710 fword("device-type");
712 PUSH(100 * 1000 * 1000);
714 push_str("clock-frequency");
719 /* Perhaps we can store UUID here ? */
721 push_str("0000000000000");
722 fword("encode-string");
723 push_str("system-id");
729 fword("find-device");
733 PUSH(ram_size
>> 32);
735 PUSH(ram_size
& 0xffffffff);
749 printk("CPU type %s\n", cpu
->name
);
751 snprintf(buf
, sizeof(buf
), "/cpus/%s", cpu
->name
);
752 ofmem_register(find_dev("/memory"), find_dev(buf
));
753 node_methods_init(buf
);
756 /* OldWorld Macs don't have an /rtas node. */
757 switch (machine_id
) {
760 if (!(ph
= find_dev("/rtas"))) {
761 printk("Warning: No /rtas node\n");
763 unsigned long size
= 0x1000;
764 while (size
< (unsigned long)of_rtas_end
- (unsigned long)of_rtas_start
)
766 set_property(ph
, "rtas-size", (char*)&size
, sizeof(size
));
767 set_int_property(ph
, "rtas-version", is_apple() ? 0x41 : 1);
773 if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC
)) {
774 if (CONFIG_SERIAL_PORT
) {
776 stdout_path
= "scca";
779 stdout_path
= "sccb";
782 /* Some bootloaders force the output to the screen device, so
783 let's create a screen alias for the serial device too */
784 push_str("/aliases");
785 fword("find-device");
787 push_str(stdout_path
);
788 fword("pathres-resolve-aliases");
789 fword("encode-string");
793 stdin_path
= "adb-keyboard";
794 stdout_path
= "screen";
799 /* Setup nvram variables */
800 push_str("/options");
801 fword("find-device");
803 uint16_t boot_device
= fw_cfg_read_i16(FW_CFG_BOOT_DEVICE
);
804 switch (boot_device
) {
814 /* Setup default boot devices */
815 snprintf(buf
, sizeof(buf
), "%s:,\\\\:tbxi %s:,\\ppc\\bootinfo.txt", boot_path
, boot_path
);
817 fword("encode-string");
818 push_str("boot-device");
821 /* Set up other properties */
823 fword("find-device");
825 push_str(stdin_path
);
831 push_str(stdout_path
);
837 push_str(stdin_path
);
838 fword("pathres-resolve-aliases");
839 push_str("input-device");
842 push_str(stdout_path
);
843 fword("pathres-resolve-aliases");
844 push_str("output-device");
847 push_str(stdin_path
);
850 push_str(stdout_path
);
854 if( getbool("tty-interface?") == 1 )
856 fword("activate-tty-interface");
860 bind_func("platform-boot", boot
);
861 bind_func("(go)", go
);