1 /* tag: openbios forth environment, executable code
3 * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
5 * See the file "COPYING" for further information about
6 * the copyright and warranty status of this work.
10 #include "libopenbios/openbios.h"
11 #include "libopenbios/bindings.h"
12 #include "libopenbios/console.h"
13 #include "drivers/drivers.h"
14 #include "asm/types.h"
16 #include "kernel/kernel.h"
17 #include "kernel/stack.h"
18 #include "arch/common/nvram.h"
19 #include "packages/nvram.h"
20 #include "../../drivers/timer.h" // XXX
21 #include "libopenbios/sys_info.h"
27 #include "libopenbios/video.h"
28 #define NO_QEMU_PROTOS
29 #include "arch/common/fw_cfg.h"
30 #include "arch/sparc32/ofmem_sparc32.h"
32 #define MEMORY_SIZE (128*1024) /* 128K ram for hosted system */
33 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
34 #define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00)
36 int qemu_machine_type;
39 uint64_t iommu_base, slavio_base;
40 uint64_t intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
41 unsigned long fd_offset, counter_offset, intr_offset;
42 unsigned long aux1_offset, aux2_offset;
43 uint64_t dma_base, esp_base, le_base;
47 int machine_id_low, machine_id_high;
50 static const struct hwdef hwdefs[] = {
53 .iommu_base = 0x10000000,
54 .tcx_base = 0x50000000,
55 .slavio_base = 0x71000000,
56 .ms_kb_base = 0x71000000,
57 .serial_base = 0x71100000,
58 .nvram_base = 0x71200000,
59 .fd_offset = 0x00400000,
60 .counter_offset = 0x00d00000,
61 .intr_offset = 0x00e00000,
63 .aux1_offset = 0x00900000,
64 .aux2_offset = 0x00910000,
65 .dma_base = 0x78400000,
66 .esp_base = 0x78800000,
67 .le_base = 0x78c00000,
70 .machine_id_high = 63,
74 .iommu_base = 0xfe0000000ULL,
75 .tcx_base = 0xe20000000ULL,
76 .slavio_base = 0xff1000000ULL,
77 .ms_kb_base = 0xff1000000ULL,
78 .serial_base = 0xff1100000ULL,
79 .nvram_base = 0xff1200000ULL,
80 .fd_offset = 0x00700000, // 0xff1700000ULL,
81 .counter_offset = 0x00300000, // 0xff1300000ULL,
82 .intr_offset = 0x00400000, // 0xff1400000ULL,
84 .aux1_offset = 0x00800000, // 0xff1800000ULL,
85 .aux2_offset = 0x00a01000, // 0xff1a01000ULL,
86 .dma_base = 0xef0400000ULL,
87 .esp_base = 0xef0800000ULL,
88 .le_base = 0xef0c00000ULL,
91 .machine_id_high = 65,
95 .iommu_base = 0xfe0000000ULL,
96 .tcx_base = 0xe20000000ULL,
97 .slavio_base = 0xff1000000ULL,
98 .ms_kb_base = 0xff1000000ULL,
99 .serial_base = 0xff1100000ULL,
100 .nvram_base = 0xff1200000ULL,
102 .counter_offset = 0x00300000, // 0xff1300000ULL,
103 .intr_offset = 0x00400000, // 0xff1400000ULL,
105 .aux1_offset = 0x00800000, // 0xff1800000ULL,
106 .aux2_offset = 0x00a01000, // 0xff1a01000ULL, XXX should not exist
107 .dma_base = 0xef0081000ULL,
108 .esp_base = 0xef0080000ULL,
109 .le_base = 0xef0060000ULL,
111 .machine_id_low = 66,
112 .machine_id_high = 66,
116 static const struct hwdef *hwdef;
118 void setup_timers(void)
122 void udelay(unsigned int usecs)
126 void mdelay(unsigned int msecs)
130 static void mb86904_init(void)
134 push_str("cache-line-size");
139 push_str("cache-nlines");
144 push_str("mask_rev");
148 static void tms390z55_init(void)
151 fword("encode-string");
152 push_str("ecache-parity?");
156 fword("encode-string");
161 fword("encode-string");
166 fword("encode-string");
167 push_str("cache-physical?");
212 static void rt625_init(void)
216 push_str("cache-line-size");
221 push_str("cache-nlines");
226 static void bad_cpu_init(void)
228 printk("This CPU is not supported yet, freezing.\n");
233 unsigned long iu_version;
235 int psr_impl, psr_vers, impl, vers;
236 int dcache_line_size, dcache_lines, dcache_assoc;
237 int icache_line_size, icache_lines, icache_assoc;
238 int ecache_line_size, ecache_lines, ecache_assoc;
240 void (*initfn)(void);
243 static const struct cpudef sparc_defs[] = {
245 .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
246 .name = "FMI,MB86900",
247 .initfn = bad_cpu_init,
250 .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
251 .name = "FMI,MB86904",
256 .dcache_line_size = 0x10,
257 .dcache_lines = 0x200,
259 .icache_line_size = 0x20,
260 .icache_lines = 0x200,
262 .ecache_line_size = 0x20,
263 .ecache_lines = 0x4000,
266 .initfn = mb86904_init,
269 .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
270 .name = "FMI,MB86907",
275 .dcache_line_size = 0x20,
276 .dcache_lines = 0x200,
278 .icache_line_size = 0x20,
279 .icache_lines = 0x200,
281 .ecache_line_size = 0x20,
282 .ecache_lines = 0x4000,
285 .initfn = mb86904_init,
288 .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
289 .name = "LSI,L64811",
290 .initfn = bad_cpu_init,
293 .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
294 .name = "CY,CY7C601",
300 .initfn = bad_cpu_init,
303 .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
304 .name = "CY,CY7C611",
305 .initfn = bad_cpu_init,
308 .iu_version = 0x40000000,
309 .name = "TI,TMS390Z55",
314 .dcache_line_size = 0x20,
315 .dcache_lines = 0x80,
317 .icache_line_size = 0x40,
318 .icache_lines = 0x40,
320 .ecache_line_size = 0x20,
321 .ecache_lines = 0x8000,
324 .initfn = tms390z55_init,
327 .iu_version = 0x41000000,
328 .name = "TI,TMS390S10",
333 .dcache_line_size = 0x10,
334 .dcache_lines = 0x80,
336 .icache_line_size = 0x20,
337 .icache_lines = 0x80,
339 .ecache_line_size = 0x20,
340 .ecache_lines = 0x8000,
343 .initfn = tms390z55_init,
346 .iu_version = 0x42000000,
347 .name = "TI,TMS390S10",
352 .dcache_line_size = 0x10,
353 .dcache_lines = 0x80,
355 .icache_line_size = 0x20,
356 .icache_lines = 0x80,
358 .ecache_line_size = 0x20,
359 .ecache_lines = 0x8000,
362 .initfn = tms390z55_init,
365 .iu_version = 0x43000000,
366 .name = "TI,TMS390S10",
371 .dcache_line_size = 0x10,
372 .dcache_lines = 0x80,
374 .icache_line_size = 0x20,
375 .icache_lines = 0x80,
377 .ecache_line_size = 0x20,
378 .ecache_lines = 0x8000,
381 .initfn = tms390z55_init,
384 .iu_version = 0x44000000,
385 .name = "TI,TMS390S10",
390 .dcache_line_size = 0x10,
391 .dcache_lines = 0x80,
393 .icache_line_size = 0x20,
394 .icache_lines = 0x80,
396 .ecache_line_size = 0x20,
397 .ecache_lines = 0x8000,
400 .initfn = tms390z55_init,
403 .iu_version = 0x1e000000,
404 .name = "Ross,RT625",
409 .dcache_line_size = 0x20,
410 .dcache_lines = 0x80,
412 .icache_line_size = 0x40,
413 .icache_lines = 0x40,
415 .ecache_line_size = 0x20,
416 .ecache_lines = 0x8000,
419 .initfn = rt625_init,
422 .iu_version = 0x1f000000,
423 .name = "Ross,RT620",
428 .dcache_line_size = 0x20,
429 .dcache_lines = 0x80,
431 .icache_line_size = 0x40,
432 .icache_lines = 0x40,
434 .ecache_line_size = 0x20,
435 .ecache_lines = 0x8000,
438 .initfn = rt625_init,
441 .iu_version = 0x20000000,
443 .initfn = bad_cpu_init,
446 .iu_version = 0x50000000,
447 .name = "MC,MN10501",
448 .initfn = bad_cpu_init,
451 .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
452 .name = "Weitek,W8601",
453 .initfn = bad_cpu_init,
456 .iu_version = 0xf2000000,
458 .initfn = bad_cpu_init,
461 .iu_version = 0xf3000000,
463 .initfn = bad_cpu_init,
467 static const struct cpudef *
470 unsigned long iu_version;
474 : "=r"(iu_version) :);
475 iu_version &= 0xff000000;
477 for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) {
478 if (iu_version == sparc_defs[i].iu_version)
479 return &sparc_defs[i];
481 printk("Unknown cpu (psr %lx), freezing!\n", iu_version);
485 static void setup_cpu(int mid_offset)
489 const struct cpudef *cpu;
492 temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
494 printk("CPUs: %x", temp);
496 printk(" x %s\n", cpu->name);
497 for (i = 0; i < temp; i++) {
499 fword("find-device");
504 fword("device-name");
507 fword("device-type");
511 push_str("psr-implementation");
516 push_str("psr-version");
521 push_str("implementation");
531 push_str("page-size");
534 PUSH(cpu->dcache_line_size);
536 push_str("dcache-line-size");
539 PUSH(cpu->dcache_lines);
541 push_str("dcache-nlines");
544 PUSH(cpu->dcache_assoc);
546 push_str("dcache-associativity");
549 PUSH(cpu->icache_line_size);
551 push_str("icache-line-size");
554 PUSH(cpu->icache_lines);
556 push_str("icache-nlines");
559 PUSH(cpu->icache_assoc);
561 push_str("icache-associativity");
564 PUSH(cpu->ecache_line_size);
566 push_str("ecache-line-size");
569 PUSH(cpu->ecache_lines);
571 push_str("ecache-nlines");
574 PUSH(cpu->ecache_assoc);
576 push_str("ecache-associativity");
586 push_str("mmu-nctx");
591 push_str("sparc-version");
595 fword("encode-string");
596 push_str("cache-coherence?");
599 PUSH(i + mid_offset);
606 fword("finish-device");
610 static void dummy_mach_init(uint64_t base)
616 const char *banner_name;
619 void (*initfn)(uint64_t base);
622 static const struct machdef sun4m_defs[] = {
625 .banner_name = "SPARCstation 5",
626 .model = "SUNW,501-3059",
627 .name = "SUNW,SPARCstation-5",
632 .banner_name = "SPARCstation Voyager",
633 .model = "SUNW,501-2581",
634 .name = "SUNW,SPARCstation-Voyager",
635 .initfn = dummy_mach_init,
639 .banner_name = "SPARCstation LX",
640 .model = "SUNW,501-2031",
641 .name = "SUNW,SPARCstation-LX",
642 .initfn = dummy_mach_init,
646 .banner_name = "SPARCstation 4",
647 .model = "SUNW,501-2572",
648 .name = "SUNW,SPARCstation-4",
653 .banner_name = "SPARCstation Classic",
654 .model = "SUNW,501-2326",
655 .name = "SUNW,SPARCstation-Classic",
656 .initfn = dummy_mach_init,
660 .banner_name = "Tadpole S3 GX",
662 .name = "Tadpole_S3GX",
667 .banner_name = "SPARCstation 10 (1 X 390Z55)",
668 .model = "SUNW,S10,501-2365",
669 .name = "SUNW,SPARCstation-10",
670 .initfn = ob_eccmemctl_init,
674 .banner_name = "SPARCstation 20 (1 X 390Z55)",
675 .model = "SUNW,S20,501-2324",
676 .name = "SUNW,SPARCstation-20",
677 .initfn = ob_eccmemctl_init,
681 .banner_name = "SPARCsystem 600(1 X 390Z55)",
683 .name = "SUNW,SPARCsystem-600",
684 .initfn = ob_eccmemctl_init,
688 static const struct machdef *
689 id_machine(uint16_t machine_id)
693 for (i = 0; i < sizeof(sun4m_defs)/sizeof(struct machdef); i++) {
694 if (machine_id == sun4m_defs[i].machine_id)
695 return &sun4m_defs[i];
697 printk("Unknown machine (ID %d), freezing!\n", machine_id);
701 static void setup_machine(uint64_t base)
704 const struct machdef *mach;
706 machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
707 mach = id_machine(machine_id);
710 fword("find-device");
711 push_str(mach->banner_name);
712 fword("encode-string");
713 push_str("banner-name");
717 push_str(mach->model);
718 fword("encode-string");
722 push_str(mach->name);
723 fword("encode-string");
731 static void setup_uuid(void)
733 static uint8_t qemu_uuid[16];
735 fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
737 printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
738 qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
739 qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
740 qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
744 fword("find-device");
746 PUSH((long)&qemu_uuid);
748 fword("encode-bytes");
753 static void setup_stdio(void)
756 const char *stdin, *stdout;
758 fw_cfg_read(FW_CFG_NOGRAPHIC, &nographic, 1);
760 obp_stdin = PROMDEV_TTYA;
761 obp_stdout = PROMDEV_TTYA;
765 obp_stdin = PROMDEV_KBD;
766 obp_stdout = PROMDEV_SCREEN;
772 push_str("input-device");
776 push_str("output-device");
779 obp_stdin_path = stdin;
780 obp_stdout_path = stdout;
783 static void init_memory(void)
788 /* Claim the memory from OFMEM */
789 phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE);
791 printk("panic: not enough physical memory on host system.\n");
793 virt = ofmem_claim_virt(OF_CODE_START - MEMORY_SIZE, MEMORY_SIZE, 0);
795 printk("panic: not enough virtual memory on host system.\n");
797 /* Generate the mapping (and lock translation into the TLBs) */
798 ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys));
800 /* we push start and end of memory to the stack
801 * so that it can be used by the forth word QUIT
802 * to initialize the memory allocator
806 PUSH(virt + MEMORY_SIZE);
813 const char *kernel_cmdline;
817 unsigned long mem_size;
821 fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
824 printk("Configuration device id %s", buf);
826 temp = fw_cfg_read_i32(FW_CFG_ID);
827 machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
829 printk(" version %d machine id %d\n", temp, machine_id);
832 printk("Incompatible configuration device version, freezing\n");
836 graphic_depth = fw_cfg_read_i16(FW_CFG_SUN4M_DEPTH);
841 ob_init_iommu(hwdef->iommu_base);
842 #ifdef CONFIG_DRIVER_OBIO
843 mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE);
844 ob_obio_init(hwdef->slavio_base, hwdef->fd_offset,
845 hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu,
846 hwdef->aux1_offset, hwdef->aux2_offset,
849 setup_machine(hwdef->slavio_base);
853 #ifdef CONFIG_DRIVER_SBUS
854 #ifdef CONFIG_DEBUG_CONSOLE_VIDEO
857 ob_sbus_init(hwdef->iommu_base + 0x1000ULL, qemu_machine_type);
861 setup_cpu(hwdef->mid_offset);
864 /* Initialiase openprom romvec */
865 romvec = init_openprom();
867 kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
869 kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR);
871 /* Mark the kernel memory as in use */
872 ofmem_claim_phys(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
873 ofmem_claim_virt(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
876 kernel_cmdline = (const char *) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE);
877 if (kernel_cmdline) {
878 cmdline = strdup(kernel_cmdline);
879 obp_arg.argv[1] = cmdline;
881 cmdline = strdup("");
883 qemu_cmdline = (uint32_t)cmdline;
885 /* Setup nvram variables */
886 push_str("/options");
887 fword("find-device");
889 fword("encode-string");
890 push_str("boot-file");
893 boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
895 switch (boot_device) {
904 push_str("cdrom:d cdrom");
911 fword("encode-string");
912 push_str("boot-device");
917 bind_func("platform-boot", boot );
918 bind_func("(go)", go );
920 /* Set up other properties */
922 fword("find-device");
926 /* Enable interrupts */
928 temp = (temp & ~PSR_PIL) | (13 << 8); /* Enable CPU timer interrupt (level 14) */
932 extern struct _console_ops arch_console_ops;
938 for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
939 if (hwdefs[i].machine_id_low <= qemu_machine_type &&
940 hwdefs[i].machine_id_high >= qemu_machine_type) {
946 for(;;); // Internal inconsistency, hang
948 #ifdef CONFIG_DEBUG_CONSOLE
949 init_console(arch_console_ops);
951 /* Make sure we setup OFMEM before the MMU as we need malloc() to setup page tables */
954 #ifdef CONFIG_DRIVER_SBUS
957 #ifdef CONFIG_DEBUG_CONSOLE
958 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
959 escc_uart_init(hwdef->serial_base | (CONFIG_SERIAL_PORT? 0ULL: 4ULL),
960 CONFIG_SERIAL_SPEED);
962 #ifdef CONFIG_DEBUG_CONSOLE_VIDEO
963 kbd_init(hwdef->ms_kb_base);
967 collect_sys_info(&sys_info);
969 dict = (unsigned char *)sys_info.dict_start;
970 dicthead = (cell)sys_info.dict_end;
971 last = sys_info.dict_last;
972 dictlimit = sys_info.dict_limit;
976 #ifdef CONFIG_DEBUG_BOOT
977 printk("forth started.\n");
978 printk("initializing memory...");
983 #ifdef CONFIG_DEBUG_BOOT
987 PUSH_xt( bind_noname_func(arch_init) );
988 fword("PREPOST-initializer");
990 PC = (ucell)findword("initialize-of");
993 printk("panic: no dictionary entry point.\n");
996 #ifdef CONFIG_DEBUG_DICTIONARY
997 printk("done (%d bytes).\n", dicthead);
998 printk("Jumping to dictionary...\n");
1001 enterforth((xt_t)PC);