1 /* tag: openbios forth environment, executable code
2  *
3  * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
4  *
5  * See the file "COPYING" for further information about
6  * the copyright and warranty status of this work.
7  */
8 
9 #include "config.h"
10 #include "libopenbios/openbios.h"
11 #include "libopenbios/bindings.h"
12 #include "libopenbios/console.h"
13 #include "context.h"
14 #include "libopenbios/initprogram.h"
15 #include "drivers/drivers.h"
16 #include "dict.h"
17 #include "arch/common/nvram.h"
18 #include "packages/nvram.h"
19 #include "libopenbios/sys_info.h"
20 #include "openbios.h"
21 #include "drivers/pci.h"
22 #include "asm/pci.h"
23 #include "boot.h"
24 #include "../../drivers/timer.h" // XXX
25 #define NO_QEMU_PROTOS
26 #include "arch/common/fw_cfg.h"
27 #include "arch/sparc64/ofmem_sparc64.h"
28 #include "spitfire.h"
29 #include "libc/vsprintf.h"
30 
31 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
32 
33 #define APB_SPECIAL_BASE     0x1fe00000000ULL
34 #define APB_MEM_BASE         0x1ff00000000ULL
35 
36 #define MEMORY_SIZE     (512*1024)      /* 512K ram for hosted system */
37 
38 // XXX
39 #define NVRAM_BASE       0x2000
40 #define NVRAM_SIZE       0x2000
41 #define NVRAM_IDPROM     0x1fd8
42 #define NVRAM_IDPROM_SIZE 32
43 #define NVRAM_OB_START   (0)
44 #define NVRAM_OB_SIZE    ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
45 
46 static uint8_t idprom[NVRAM_IDPROM_SIZE];
47 
48 struct hwdef {
49     pci_arch_t pci;
50     uint16_t machine_id_low, machine_id_high;
51 };
52 
53 static const struct hwdef hwdefs[] = {
54     {
55         .pci = {
56             .name = "SUNW,sabre",
57             .vendor_id = PCI_VENDOR_ID_SUN,
58             .device_id = PCI_DEVICE_ID_SUN_SABRE,
59             .cfg_addr = APB_SPECIAL_BASE + 0x1000000ULL, // PCI bus configuration space
60             .cfg_data = APB_MEM_BASE,                    // PCI bus memory space
61             .cfg_base = APB_SPECIAL_BASE,
62             .cfg_len = 0x1000000,
63             .host_pci_base = APB_MEM_BASE,
64             .pci_mem_base = 0x20000000, /* avoid VGA at 0xa0000 */
65             .mem_len = 0xf0000000,
66             .io_base = APB_SPECIAL_BASE + 0x2000000ULL, // PCI Bus I/O space
67             .io_len = 0x1000000,
68             .host_ranges = {
69                 { .type = CONFIGURATION_SPACE, .parentaddr = 0, .childaddr = APB_SPECIAL_BASE + 0x1000000ULL, .len = 0x1000000 },
70                 { .type = IO_SPACE, .parentaddr = 0, .childaddr = APB_SPECIAL_BASE + 0x2000000ULL, .len = 0x1000000 },
71                 { .type = MEMORY_SPACE_32, .parentaddr = 0, .childaddr = APB_MEM_BASE, .len = 0xf0000000 },
72                 { .type = 0, .parentaddr = 0, .childaddr = 0, .len = 0 }
73             },
74             .irqs = { 0, 1, 2, 3 },
75         },
76         .machine_id_low = 0,
77         .machine_id_high = 255,
78     },
79 };
80 
81 struct cpudef {
82     unsigned long iu_version;
83     const char *name;
84     unsigned long ecache_associativity;
85     unsigned long ecache_line_size;
86     unsigned long ecache_size;
87     unsigned long num_dtlb_entries;
88     unsigned long dcache_associativity;
89     unsigned long dcache_line_size;
90     unsigned long dcache_size;
91     unsigned long num_itlb_entries;
92     unsigned long icache_associativity;
93     unsigned long icache_line_size;
94     unsigned long icache_size;
95 };
96 
97 /*
98   ( addr -- ? )
99 */
100 
101 static void
set_trap_table(void)102 set_trap_table(void)
103 {
104     unsigned long addr;
105     volatile struct context *ctx = __context;
106 
107     addr = POP();
108 
109     /* Update %tba to be updated on exit */
110     ctx->tba = (uint64_t)addr;
111 }
112 
113 /* Reset control register is defined in 17.2.7.3 of US IIi User Manual */
114 static void
sparc64_reset_all(void)115 sparc64_reset_all(void)
116 {
117     unsigned long addr = 0x1fe0000f020ULL;
118     unsigned long val = 1 << 29;
119 
120     asm("stxa %0, [%1] 0x15\n\t"
121         : : "r" (val), "r" (addr) : "memory");
122 }
123 
124 /* Power off */
125 static void
sparc64_power_off(void)126 sparc64_power_off(void)
127 {
128     /* Locate address of ebus power device */
129     phandle_t ph;
130     uint32_t addr;
131     volatile uint32_t *p;
132     int len;
133 
134     ph = find_dev("/pci/pci@1,1/ebus/power");
135     if (ph) {
136         addr = get_int_property(ph, "address", &len);
137 
138         if (len) {
139             /* Set bit 24 to invoke power off */
140             p = cell2pointer(addr);
141             *p = 0x1000000;
142         }
143     }
144 }
145 
146 /* PCI Target Address Space Register (see UltraSPARC IIi User's Manual
147   section 19.3.0.4) */
148 #define PBM_PCI_TARGET_AS              0x2028
149 #define PBM_PCI_TARGET_AS_CD_ENABLE    0x40
150 
151 static void
sparc64_set_tas_register(unsigned long val)152 sparc64_set_tas_register(unsigned long val)
153 {
154     unsigned long addr = APB_SPECIAL_BASE + PBM_PCI_TARGET_AS;
155 
156     asm("stxa %0, [%1] 0x15\n\t"
157         : : "r" (val), "r" (addr) : "memory");
158 }
159 
160 /* space?@ and and space?! words */
161 static uint8_t
sparc64_asi_loadb(uint8_t asi,unsigned long address)162 sparc64_asi_loadb(uint8_t asi, unsigned long address)
163 {
164     uint8_t asi_save;
165     uint8_t ret = 0;
166 
167     __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save));
168     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi));
169 
170     __asm__ __volatile__("ldub [%1], %0"
171         : "=r" (ret)
172         : "r" (address));
173 
174     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save));
175 
176     return ret;
177 }
178 
179 /* spacec@ */
180 static void
spacec_read(void)181 spacec_read(void)
182 {
183     uint8_t ret;
184 
185     uint8_t asi = POP();
186     ucell address = POP();
187 
188     ret = sparc64_asi_loadb(asi, address);
189 
190     PUSH(ret);
191 }
192 
193 static uint16_t
sparc64_asi_loadw(uint8_t asi,unsigned long address)194 sparc64_asi_loadw(uint8_t asi, unsigned long address)
195 {
196     uint8_t asi_save;
197     uint16_t ret;
198 
199     __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save));
200     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi));
201 
202     __asm__ __volatile__("lduw [%1], %0"
203         : "=r" (ret)
204         : "r" (address));
205 
206     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save));
207 
208     return ret;
209 }
210 
211 /* spacew@ */
212 static void
spacew_read(void)213 spacew_read(void)
214 {
215     uint16_t ret;
216 
217     uint8_t asi = POP();
218     ucell address = POP();
219 
220     ret = sparc64_asi_loadw(asi, address);
221 
222     PUSH(ret);
223 }
224 
225 static uint32_t
sparc64_asi_loadl(uint8_t asi,unsigned long address)226 sparc64_asi_loadl(uint8_t asi, unsigned long address)
227 {
228     uint8_t asi_save;
229     uint32_t ret;
230 
231     __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save));
232     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi));
233 
234     __asm__ __volatile__("ld [%1], %0"
235         : "=r" (ret)
236         : "r" (address));
237 
238     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save));
239 
240     return ret;
241 }
242 
243 /* spacel@ */
244 static void
spacel_read(void)245 spacel_read(void)
246 {
247     uint32_t ret;
248 
249     uint8_t asi = POP();
250     ucell address = POP();
251 
252     ret = sparc64_asi_loadl(asi, address);
253 
254     PUSH(ret);
255 }
256 
257 static uint64_t
sparc64_asi_loadx(uint8_t asi,unsigned long address)258 sparc64_asi_loadx(uint8_t asi, unsigned long address)
259 {
260     uint8_t asi_save;
261     uint64_t ret = 0;
262 
263     __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save));
264     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi));
265 
266     __asm__ __volatile__("ldx [%1], %0"
267         : "=r" (ret)
268         : "r" (address));
269 
270     __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save));
271 
272     return ret;
273 }
274 
275 /* spacex@ */
276 static void
spacex_read(void)277 spacex_read(void)
278 {
279     uint64_t ret;
280 
281     uint8_t asi = POP();
282     ucell address = POP();
283 
284     ret = sparc64_asi_loadx(asi, address);
285 
286     PUSH(ret);
287 }
288 
cpu_generic_init(const struct cpudef * cpu,uint32_t clock_frequency)289 static void cpu_generic_init(const struct cpudef *cpu, uint32_t clock_frequency)
290 {
291     unsigned long iu_version;
292 
293     push_str("/");
294     fword("find-device");
295 
296     fword("new-device");
297 
298     push_str(cpu->name);
299     fword("device-name");
300 
301     push_str("cpu");
302     fword("device-type");
303 
304     asm("rdpr %%ver, %0\n"
305         : "=r"(iu_version) :);
306 
307     PUSH((iu_version >> 48) & 0xff);
308     fword("encode-int");
309     push_str("manufacturer#");
310     fword("property");
311 
312     PUSH((iu_version >> 32) & 0xff);
313     fword("encode-int");
314     push_str("implementation#");
315     fword("property");
316 
317     PUSH((iu_version >> 24) & 0xff);
318     fword("encode-int");
319     push_str("mask#");
320     fword("property");
321 
322     PUSH(9);
323     fword("encode-int");
324     push_str("sparc-version");
325     fword("property");
326 
327     PUSH(0);
328     fword("encode-int");
329     push_str("cpuid");
330     fword("property");
331 
332     PUSH(0);
333     fword("encode-int");
334     push_str("upa-portid");
335     fword("property");
336 
337     PUSH(clock_frequency);
338     fword("encode-int");
339     push_str("clock-frequency");
340     fword("property");
341 
342     PUSH(cpu->ecache_associativity);
343     fword("encode-int");
344     push_str("ecache-associativity");
345     fword("property");
346 
347     PUSH(cpu->ecache_line_size);
348     fword("encode-int");
349     push_str("ecache-line-size");
350     fword("property");
351 
352     PUSH(cpu->ecache_size);
353     fword("encode-int");
354     push_str("ecache-size");
355     fword("property");
356 
357     PUSH(cpu->dcache_associativity);
358     fword("encode-int");
359     push_str("dcache-associativity");
360     fword("property");
361 
362     PUSH(cpu->dcache_line_size);
363     fword("encode-int");
364     push_str("dcache-line-size");
365     fword("property");
366 
367     PUSH(cpu->dcache_size);
368     fword("encode-int");
369     push_str("dcache-size");
370     fword("property");
371 
372     PUSH(cpu->icache_associativity);
373     fword("encode-int");
374     push_str("icache-associativity");
375     fword("property");
376 
377     PUSH(cpu->ecache_line_size);
378     fword("encode-int");
379     push_str("icache-line-size");
380     fword("property");
381 
382     PUSH(cpu->ecache_size);
383     fword("encode-int");
384     push_str("icache-size");
385     fword("property");
386 
387     PUSH(cpu->num_itlb_entries);
388     fword("encode-int");
389     push_str("#itlb-entries");
390     fword("property");
391 
392     PUSH(cpu->num_dtlb_entries);
393     fword("encode-int");
394     push_str("#dtlb-entries");
395     fword("property");
396 
397     fword("finish-device");
398 
399     // Trap table
400     push_str("/openprom/client-services");
401     fword("find-device");
402     bind_func("SUNW,set-trap-table", set_trap_table);
403 
404     // Reset
405     bind_func("sparc64-reset-all", sparc64_reset_all);
406     push_str("' sparc64-reset-all to reset-all");
407     fword("eval");
408 }
409 
410 static const struct cpudef sparc_defs[] = {
411     {
412         .iu_version = (0x04ULL << 48) | (0x02ULL << 32),
413         .name = "FJSV,GP",
414     },
415     {
416         .iu_version = (0x04ULL << 48) | (0x03ULL << 32),
417         .name = "FJSV,GPUSK",
418     },
419     {
420         .iu_version = (0x04ULL << 48) | (0x04ULL << 32),
421         .name = "FJSV,GPUSC",
422     },
423     {
424         .iu_version = (0x04ULL << 48) | (0x05ULL << 32),
425         .name = "FJSV,GPUZC",
426     },
427     {
428         .iu_version = (0x17ULL << 48) | (0x10ULL << 32),
429         .name = "SUNW,UltraSPARC",
430 	.ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
431 	.dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
432 	.icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
433 	.num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
434     },
435     {
436         .iu_version = (0x17ULL << 48) | (0x11ULL << 32),
437         .name = "SUNW,UltraSPARC-II",
438 	.ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
439 	.dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
440 	.icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
441 	.num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
442     },
443     {
444         .iu_version = (0x17ULL << 48) | (0x12ULL << 32),
445         .name = "SUNW,UltraSPARC-IIi",
446 	.ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x40000,
447 	.dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
448 	.icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
449 	.num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
450     },
451     {
452         .iu_version = (0x17ULL << 48) | (0x13ULL << 32),
453         .name = "SUNW,UltraSPARC-IIe",
454     },
455     {
456         .iu_version = (0x3eULL << 48) | (0x14ULL << 32),
457         .name = "SUNW,UltraSPARC-III",
458     },
459     {
460         .iu_version = (0x3eULL << 48) | (0x15ULL << 32),
461         .name = "SUNW,UltraSPARC-III+",
462     },
463     {
464         .iu_version = (0x3eULL << 48) | (0x16ULL << 32),
465         .name = "SUNW,UltraSPARC-IIIi",
466     },
467     {
468         .iu_version = (0x3eULL << 48) | (0x18ULL << 32),
469         .name = "SUNW,UltraSPARC-IV",
470     },
471     {
472         .iu_version = (0x3eULL << 48) | (0x19ULL << 32),
473         .name = "SUNW,UltraSPARC-IV+",
474     },
475     {
476         .iu_version = (0x3eULL << 48) | (0x22ULL << 32),
477         .name = "SUNW,UltraSPARC-IIIi+",
478     },
479     {
480         .iu_version = (0x3eULL << 48) | (0x23ULL << 32),
481         .name = "SUNW,UltraSPARC-T1",
482     },
483     {
484         .iu_version = (0x3eULL << 48) | (0x24ULL << 32),
485         .name = "SUNW,UltraSPARC-T2",
486     },
487     {
488         .iu_version = (0x22ULL << 48) | (0x10ULL << 32),
489         .name = "SUNW,UltraSPARC",
490     },
491 };
492 
493 static const struct cpudef *
id_cpu(void)494 id_cpu(void)
495 {
496     unsigned long iu_version;
497     unsigned int i;
498 
499     asm("rdpr %%ver, %0\n"
500         : "=r"(iu_version) :);
501     iu_version &= 0xffffffff00000000ULL;
502 
503     for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) {
504         if (iu_version == sparc_defs[i].iu_version)
505             return &sparc_defs[i];
506     }
507     printk("Unknown cpu (psr %lx), freezing!\n", iu_version);
508     for (;;);
509 }
510 
nvram_read(uint16_t offset,char * buf,unsigned int nbytes)511 static void nvram_read(uint16_t offset, char *buf, unsigned int nbytes)
512 {
513     unsigned int i;
514 
515     for (i = 0; i < nbytes; i++) {
516         buf[i] = inb(NVRAM_BASE + offset + i);
517     }
518 }
519 
nvram_write(uint16_t offset,const char * buf,unsigned int nbytes)520 static void nvram_write(uint16_t offset, const char *buf, unsigned int nbytes)
521 {
522     unsigned int i;
523 
524     for (i = 0; i < nbytes; i++) {
525         outb(buf[i], NVRAM_BASE + offset + i);
526     }
527 }
528 
529 static uint8_t qemu_uuid[16];
530 
arch_nvram_get(char * data)531 void arch_nvram_get(char *data)
532 {
533     char *obio_cmdline;
534     uint32_t size = 0;
535     const struct cpudef *cpu;
536     char buf[256];
537     uint32_t temp;
538     uint64_t ram_size;
539     uint32_t clock_frequency;
540     uint16_t machine_id, nographic;
541     const char *stdin_path, *stdout_path;
542     char *bootorder_file, *boot_path;
543     uint32_t bootorder_sz, sz;
544     phandle_t display_ph;
545 
546     fw_cfg_init();
547 
548     fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
549     buf[4] = '\0';
550 
551     printk("Configuration device id %s", buf);
552 
553     temp = fw_cfg_read_i32(FW_CFG_ID);
554     machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
555 
556     printk(" version %d machine id %d\n", temp, machine_id);
557 
558     if (temp != 1) {
559         printk("Incompatible configuration device version, freezing\n");
560         for(;;);
561     }
562 
563     kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
564     if (kernel_size) {
565         kernel_image = fw_cfg_read_i64(FW_CFG_KERNEL_ADDR);
566 
567         /* Map kernel memory the same as SILO */
568         ofmem_map(PAGE_ALIGN(kernel_image) - 0x4000, IMAGE_VIRT_ADDR, PAGE_ALIGN(kernel_size), -1);
569     }
570 
571     size = fw_cfg_read_i32(FW_CFG_CMDLINE_SIZE);
572     if (size) {
573 	obio_cmdline = (char *)malloc(size + 1);
574         fw_cfg_read(FW_CFG_CMDLINE_DATA, obio_cmdline, size);
575 	obio_cmdline[size] = '\0';
576     } else {
577 	obio_cmdline = strdup("");
578     }
579     qemu_cmdline = (uint64_t)obio_cmdline;
580     cmdline_size = size;
581 
582     initrd_size = fw_cfg_read_i32(FW_CFG_INITRD_SIZE);
583     if (initrd_size) {
584         initrd_image = fw_cfg_read_i32(FW_CFG_INITRD_ADDR);
585 
586         /* Map initrd memory the same as SILO  */
587         ofmem_map(PAGE_ALIGN(initrd_image), INITRD_VIRT_ADDR, PAGE_ALIGN(initrd_size), -1);
588     }
589 
590     if (kernel_size)
591         printk("kernel phys %llx virt %x size 0x%llx\n", kernel_image, IMAGE_VIRT_ADDR + 0x4000, kernel_size);
592     if (initrd_size)
593         printk("initrd phys %llx virt %x size 0x%llx\n", initrd_image, INITRD_VIRT_ADDR, initrd_size);
594     if (size)
595         printk("kernel cmdline %s\n", obio_cmdline);
596 
597     nvram_read(NVRAM_OB_START, data, NVRAM_OB_SIZE);
598 
599     temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
600 
601     printk("CPUs: %x", temp);
602 
603     clock_frequency = 100000000;
604 
605     cpu = id_cpu();
606     //cpu->initfn();
607     cpu_generic_init(cpu, clock_frequency);
608     printk(" x %s\n", cpu->name);
609 
610     // Add /uuid
611     fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
612 
613     printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
614            qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
615            qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
616            qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
617            qemu_uuid[15]);
618 
619     push_str("/");
620     fword("find-device");
621 
622     PUSH((long)&qemu_uuid);
623     PUSH(16);
624     fword("encode-bytes");
625     push_str("uuid");
626     fword("property");
627 
628     // Add /idprom
629     nvram_read(NVRAM_IDPROM, (char *)idprom, NVRAM_IDPROM_SIZE);
630 
631     PUSH((long)&idprom);
632     PUSH(32);
633     fword("encode-bytes");
634     push_str("idprom");
635     fword("property");
636 
637     PUSH(500 * 1000 * 1000);
638     fword("encode-int");
639     push_str("clock-frequency");
640     fword("property");
641 
642     ram_size = fw_cfg_read_i64(FW_CFG_RAM_SIZE);
643 
644     ob_mmu_init(cpu->name, ram_size);
645 
646     /* Setup nvram variables */
647     push_str("/options");
648     fword("find-device");
649 
650     /* Boot order */
651     bootorder_file = fw_cfg_read_file("bootorder", &bootorder_sz);
652 
653     if (bootorder_file == NULL) {
654         switch (fw_cfg_read_i16(FW_CFG_BOOT_DEVICE)) {
655         case 'a':
656             push_str("/obio/SUNW,fdtwo");
657             break;
658         case 'c':
659             push_str("disk:a");
660             break;
661         default:
662         case 'd':
663             push_str("cdrom:f cdrom");
664             break;
665         case 'n':
666             push_str("net");
667             break;
668         }
669 
670         fword("encode-string");
671         push_str("boot-device");
672         fword("property");
673     } else {
674         sz = bootorder_sz * (3 * 2);
675         boot_device = malloc(sz);
676         memset(boot_device, 0, sz);
677 
678         while ((boot_path = strsep(&bootorder_file, "\n")) != NULL) {
679             snprintf(buf, sizeof(buf),
680                      "%s:f "
681                      "%s:a "
682                      "%s ",
683                      boot_path, boot_path, boot_path);
684 
685             strncat(boot_device, buf, sz);
686         }
687 
688         push_str(boot_device);
689         fword("encode-string");
690         push_str("boot-device");
691         fword("property");
692     }
693 
694     push_str(obio_cmdline);
695     fword("encode-string");
696     push_str("boot-file");
697     fword("property");
698 
699     /* Set up other properties */
700     push_str("/chosen");
701     fword("find-device");
702 
703     nographic = fw_cfg_read_i16(FW_CFG_NOGRAPHIC);
704 
705     /* Check to see if any framebuffer present */
706     display_ph = dt_iterate_type(0, "display");
707     if (display_ph == 0) {
708         nographic = 1;
709     }
710 
711     if (nographic) {
712         stdin_path = stdout_path = "ttya";
713     } else {
714         stdin_path = "keyboard";
715         stdout_path = "screen";
716     }
717 
718     push_str(stdin_path);
719     push_str("input-device");
720     fword("$setenv");
721 
722     push_str(stdout_path);
723     push_str("output-device");
724     fword("$setenv");
725 }
726 
arch_nvram_put(char * data)727 void arch_nvram_put(char *data)
728 {
729     nvram_write(0, data, NVRAM_OB_SIZE);
730 }
731 
arch_nvram_size(void)732 int arch_nvram_size(void)
733 {
734     return NVRAM_OB_SIZE;
735 }
736 
setup_timers(void)737 void setup_timers(void)
738 {
739 }
740 
udelay(unsigned int usecs)741 void udelay(unsigned int usecs)
742 {
743     volatile int i;
744 
745     for (i = 0; i < usecs * 100; i++);
746 }
747 
init_memory(void)748 static void init_memory(void)
749 {
750     phys_addr_t phys;
751     ucell virt;
752 
753     /* Claim the memory from OFMEM (align to 512K so we only take 1 TLB slot) */
754     phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE_512K);
755     if (!phys)
756         printk("panic: not enough physical memory on host system.\n");
757 
758     virt = ofmem_claim_virt(-1, MEMORY_SIZE, PAGE_SIZE_512K);
759     if (!virt)
760         printk("panic: not enough virtual memory on host system.\n");
761 
762     /* Generate the mapping (and lock translation into the TLBs) */
763     ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys) | SPITFIRE_TTE_LOCKED);
764 
765     /* we push start and end of memory to the stack
766      * so that it can be used by the forth word QUIT
767      * to initialize the memory allocator
768      */
769 
770     PUSH(virt);
771     PUSH(virt + MEMORY_SIZE);
772 }
773 
774 /* ( size -- virt ) */
775 static void
dma_alloc(void)776 dma_alloc(void)
777 {
778     ucell size = POP();
779     ucell addr;
780     int ret;
781 
782     /* OpenBIOS doesn't enable the sun4u IOMMU so we can fall back to
783      * using ofmem_posix_memalign */
784     ret = ofmem_posix_memalign((void *)&addr, size, PAGE_SIZE);
785 
786     if (ret) {
787         PUSH(0);
788     } else {
789         PUSH(addr);
790     }
791 }
792 
793 /* ( virt devaddr size -- ) */
794 static void
dma_sync(void)795 dma_sync(void)
796 {
797     ucell size = POP();
798     POP();
799     ucell virt = POP();
800     ucell va;
801 
802     for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
803         itlb_demap(va);
804         dtlb_demap(va);
805     }
806 }
807 
808 extern volatile uint64_t *obp_ticks_pointer;
809 
810 static void
arch_init(void)811 arch_init( void )
812 {
813 	openbios_init();
814 	modules_init();
815 
816     bind_func("sparc64-dma-alloc", dma_alloc);
817     feval("['] sparc64-dma-alloc to (dma-alloc)");
818     bind_func("sparc64-dma-sync", dma_sync);
819     feval("['] sparc64-dma-sync to (dma-sync)");
820 
821 #ifdef CONFIG_DRIVER_PCI
822         push_str("/");
823         fword("find-device");
824         feval("\" /\" open-dev to my-self");
825 
826         ob_pci_init();
827 
828         /* Set TAS register to match the virtual-dma properties
829            set during sabre configure */
830         sparc64_set_tas_register(PBM_PCI_TARGET_AS_CD_ENABLE);
831 
832         feval("0 to my-self");
833 #endif
834         nvconf_init();
835         device_end();
836 
837         /* Point to the Forth obp-ticks variable */
838         fword("obp-ticks");
839         obp_ticks_pointer = cell2pointer(POP());
840 
841         /* Bind to space?@ functions */
842         bind_func("spacec@", spacec_read);
843         bind_func("spacew@", spacew_read);
844         bind_func("spacel@", spacel_read);
845         bind_func("spacex@", spacex_read);
846 
847         /* Bind power functions */
848         bind_func("sparc64-power-off", sparc64_power_off);
849         push_str("' sparc64-power-off to power-off");
850         fword("eval");
851 
852 	bind_func("platform-boot", boot );
853 }
854 
855 unsigned long isa_io_base;
856 
857 extern struct _console_ops arch_console_ops;
858 
openbios(void)859 int openbios(void)
860 {
861         unsigned int i;
862         uint16_t machine_id;
863         const struct hwdef *hwdef = NULL;
864 
865 
866         for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
867             isa_io_base = hwdefs[i].pci.io_base;
868             machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
869             if (hwdefs[i].machine_id_low <= machine_id &&
870                 hwdefs[i].machine_id_high >= machine_id) {
871                 hwdef = &hwdefs[i];
872                 arch = &hwdefs[i].pci;
873                 break;
874             }
875         }
876         if (!hwdef)
877             for(;;); // Internal inconsistency, hang
878 
879 #ifdef CONFIG_DEBUG_CONSOLE
880         init_console(arch_console_ops);
881 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
882 	uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
883 #endif
884         printk("OpenBIOS for Sparc64\n");
885 #endif
886 
887         ofmem_init();
888 
889         collect_sys_info(&sys_info);
890 
891         dict = (unsigned char *)sys_info.dict_start;
892         dicthead = (cell)sys_info.dict_end;
893         last = sys_info.dict_last;
894         dictlimit = sys_info.dict_limit;
895 
896 	forth_init();
897 
898 #ifdef CONFIG_DEBUG_BOOT
899 	printk("forth started.\n");
900 	printk("initializing memory...");
901 #endif
902 
903 	init_memory();
904 
905 #ifdef CONFIG_DEBUG_BOOT
906 	printk("done\n");
907 #endif
908 
909 	PUSH_xt( bind_noname_func(arch_init) );
910 	fword("PREPOST-initializer");
911 
912 	PC = (ucell)findword("initialize-of");
913 
914 	if (!PC) {
915 		printk("panic: no dictionary entry point.\n");
916 		return -1;
917 	}
918 #ifdef CONFIG_DEBUG_DICTIONARY
919 	printk("done (%d bytes).\n", dicthead);
920 	printk("Jumping to dictionary...\n");
921 #endif
922 
923 	enterforth((xt_t)PC);
924         printk("falling off...\n");
925         free(dict);
926 	return 0;
927 }
928