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         /* Mark the kernel memory as mapped 1:1 and in use */
568         ofmem_claim_phys(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
569         ofmem_claim_virt(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0);
570         ofmem_map(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), -1);
571     }
572 
573     size = fw_cfg_read_i32(FW_CFG_CMDLINE_SIZE);
574     if (size) {
575 	obio_cmdline = (char *)malloc(size + 1);
576         fw_cfg_read(FW_CFG_CMDLINE_DATA, obio_cmdline, size);
577 	obio_cmdline[size] = '\0';
578     } else {
579 	obio_cmdline = strdup("");
580     }
581     qemu_cmdline = (uint64_t)obio_cmdline;
582     cmdline_size = size;
583 
584     initrd_size = fw_cfg_read_i32(FW_CFG_INITRD_SIZE);
585     if (initrd_size) {
586         initrd_image = fw_cfg_read_i32(FW_CFG_INITRD_ADDR);
587 
588         /* Mark initrd memory as mapped 1:1 and in use */
589         ofmem_claim_phys(PAGE_ALIGN(initrd_image), PAGE_ALIGN(initrd_size), 0);
590         ofmem_claim_virt(PAGE_ALIGN(initrd_image), PAGE_ALIGN(initrd_size), 0);
591         ofmem_map(PAGE_ALIGN(initrd_image), PAGE_ALIGN(initrd_image), PAGE_ALIGN(initrd_size), -1);
592     }
593 
594     if (kernel_size)
595         printk("kernel addr %llx size %llx\n", kernel_image, kernel_size);
596     if (size)
597         printk("kernel cmdline %s\n", obio_cmdline);
598 
599     nvram_read(NVRAM_OB_START, data, NVRAM_OB_SIZE);
600 
601     temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
602 
603     printk("CPUs: %x", temp);
604 
605     clock_frequency = 100000000;
606 
607     cpu = id_cpu();
608     //cpu->initfn();
609     cpu_generic_init(cpu, clock_frequency);
610     printk(" x %s\n", cpu->name);
611 
612     // Add /uuid
613     fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
614 
615     printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
616            qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
617            qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
618            qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
619            qemu_uuid[15]);
620 
621     push_str("/");
622     fword("find-device");
623 
624     PUSH((long)&qemu_uuid);
625     PUSH(16);
626     fword("encode-bytes");
627     push_str("uuid");
628     fword("property");
629 
630     // Add /idprom
631     nvram_read(NVRAM_IDPROM, (char *)idprom, NVRAM_IDPROM_SIZE);
632 
633     PUSH((long)&idprom);
634     PUSH(32);
635     fword("encode-bytes");
636     push_str("idprom");
637     fword("property");
638 
639     PUSH(500 * 1000 * 1000);
640     fword("encode-int");
641     push_str("clock-frequency");
642     fword("property");
643 
644     ram_size = fw_cfg_read_i64(FW_CFG_RAM_SIZE);
645 
646     ob_mmu_init(cpu->name, ram_size);
647 
648     /* Setup nvram variables */
649     push_str("/options");
650     fword("find-device");
651 
652     /* Boot order */
653     bootorder_file = fw_cfg_read_file("bootorder", &bootorder_sz);
654 
655     if (bootorder_file == NULL) {
656         switch (fw_cfg_read_i16(FW_CFG_BOOT_DEVICE)) {
657         case 'a':
658             push_str("/obio/SUNW,fdtwo");
659             break;
660         case 'c':
661             push_str("disk:a");
662             break;
663         default:
664         case 'd':
665             push_str("cdrom:f cdrom");
666             break;
667         case 'n':
668             push_str("net");
669             break;
670         }
671 
672         fword("encode-string");
673         push_str("boot-device");
674         fword("property");
675     } else {
676         sz = bootorder_sz * (3 * 2);
677         boot_device = malloc(sz);
678         memset(boot_device, 0, sz);
679 
680         while ((boot_path = strsep(&bootorder_file, "\n")) != NULL) {
681             snprintf(buf, sizeof(buf),
682                      "%s:f "
683                      "%s:a "
684                      "%s ",
685                      boot_path, boot_path, boot_path);
686 
687             strncat(boot_device, buf, sz);
688         }
689 
690         push_str(boot_device);
691         fword("encode-string");
692         push_str("boot-device");
693         fword("property");
694     }
695 
696     push_str(obio_cmdline);
697     fword("encode-string");
698     push_str("boot-file");
699     fword("property");
700 
701     /* Set up other properties */
702     push_str("/chosen");
703     fword("find-device");
704 
705     nographic = fw_cfg_read_i16(FW_CFG_NOGRAPHIC);
706 
707     /* Check to see if any framebuffer present */
708     display_ph = dt_iterate_type(0, "display");
709     if (display_ph == 0) {
710         nographic = 1;
711     }
712 
713     if (nographic) {
714         stdin_path = stdout_path = "ttya";
715     } else {
716         stdin_path = "keyboard";
717         stdout_path = "screen";
718     }
719 
720     push_str(stdin_path);
721     push_str("input-device");
722     fword("$setenv");
723 
724     push_str(stdout_path);
725     push_str("output-device");
726     fword("$setenv");
727 }
728 
arch_nvram_put(char * data)729 void arch_nvram_put(char *data)
730 {
731     nvram_write(0, data, NVRAM_OB_SIZE);
732 }
733 
arch_nvram_size(void)734 int arch_nvram_size(void)
735 {
736     return NVRAM_OB_SIZE;
737 }
738 
setup_timers(void)739 void setup_timers(void)
740 {
741 }
742 
udelay(unsigned int usecs)743 void udelay(unsigned int usecs)
744 {
745     volatile int i;
746 
747     for (i = 0; i < usecs * 100; i++);
748 }
749 
init_memory(void)750 static void init_memory(void)
751 {
752     phys_addr_t phys;
753     ucell virt;
754 
755     /* Claim the memory from OFMEM (align to 512K so we only take 1 TLB slot) */
756     phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE_512K);
757     if (!phys)
758         printk("panic: not enough physical memory on host system.\n");
759 
760     virt = ofmem_claim_virt(-1, MEMORY_SIZE, PAGE_SIZE_512K);
761     if (!virt)
762         printk("panic: not enough virtual memory on host system.\n");
763 
764     /* Generate the mapping (and lock translation into the TLBs) */
765     ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys) | SPITFIRE_TTE_LOCKED);
766 
767     /* we push start and end of memory to the stack
768      * so that it can be used by the forth word QUIT
769      * to initialize the memory allocator
770      */
771 
772     PUSH(virt);
773     PUSH(virt + MEMORY_SIZE);
774 }
775 
776 /* ( size -- virt ) */
777 static void
dma_alloc(void)778 dma_alloc(void)
779 {
780     ucell size = POP();
781     ucell addr;
782     int ret;
783 
784     /* OpenBIOS doesn't enable the sun4u IOMMU so we can fall back to
785      * using ofmem_posix_memalign */
786     ret = ofmem_posix_memalign((void *)&addr, size, PAGE_SIZE);
787 
788     if (ret) {
789         PUSH(0);
790     } else {
791         PUSH(addr);
792     }
793 }
794 
795 /* ( virt devaddr size -- ) */
796 static void
dma_sync(void)797 dma_sync(void)
798 {
799     ucell size = POP();
800     POP();
801     ucell virt = POP();
802     ucell va;
803 
804     for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
805         itlb_demap(va);
806         dtlb_demap(va);
807     }
808 }
809 
810 extern volatile uint64_t *obp_ticks_pointer;
811 
812 static void
arch_init(void)813 arch_init( void )
814 {
815 	openbios_init();
816 	modules_init();
817 
818     bind_func("sparc64-dma-alloc", dma_alloc);
819     feval("['] sparc64-dma-alloc to (dma-alloc)");
820     bind_func("sparc64-dma-sync", dma_sync);
821     feval("['] sparc64-dma-sync to (dma-sync)");
822 
823 #ifdef CONFIG_DRIVER_PCI
824         push_str("/");
825         fword("find-device");
826         feval("\" /\" open-dev to my-self");
827 
828         ob_pci_init();
829 
830         /* Set TAS register to match the virtual-dma properties
831            set during sabre configure */
832         sparc64_set_tas_register(PBM_PCI_TARGET_AS_CD_ENABLE);
833 
834         feval("0 to my-self");
835 #endif
836         nvconf_init();
837         device_end();
838 
839         /* Point to the Forth obp-ticks variable */
840         fword("obp-ticks");
841         obp_ticks_pointer = cell2pointer(POP());
842 
843         /* Bind to space?@ functions */
844         bind_func("spacec@", spacec_read);
845         bind_func("spacew@", spacew_read);
846         bind_func("spacel@", spacel_read);
847         bind_func("spacex@", spacex_read);
848 
849         /* Bind power functions */
850         bind_func("sparc64-power-off", sparc64_power_off);
851         push_str("' sparc64-power-off to power-off");
852         fword("eval");
853 
854 	bind_func("platform-boot", boot );
855 }
856 
857 unsigned long isa_io_base;
858 
859 extern struct _console_ops arch_console_ops;
860 
openbios(void)861 int openbios(void)
862 {
863         unsigned int i;
864         uint16_t machine_id;
865         const struct hwdef *hwdef = NULL;
866 
867 
868         for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
869             isa_io_base = hwdefs[i].pci.io_base;
870             machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
871             if (hwdefs[i].machine_id_low <= machine_id &&
872                 hwdefs[i].machine_id_high >= machine_id) {
873                 hwdef = &hwdefs[i];
874                 arch = &hwdefs[i].pci;
875                 break;
876             }
877         }
878         if (!hwdef)
879             for(;;); // Internal inconsistency, hang
880 
881 #ifdef CONFIG_DEBUG_CONSOLE
882         init_console(arch_console_ops);
883 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
884 	uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
885 #endif
886         printk("OpenBIOS for Sparc64\n");
887 #endif
888 
889         ofmem_init();
890 
891         collect_sys_info(&sys_info);
892 
893         dict = (unsigned char *)sys_info.dict_start;
894         dicthead = (cell)sys_info.dict_end;
895         last = sys_info.dict_last;
896         dictlimit = sys_info.dict_limit;
897 
898 	forth_init();
899 
900 #ifdef CONFIG_DEBUG_BOOT
901 	printk("forth started.\n");
902 	printk("initializing memory...");
903 #endif
904 
905 	init_memory();
906 
907 #ifdef CONFIG_DEBUG_BOOT
908 	printk("done\n");
909 #endif
910 
911 	PUSH_xt( bind_noname_func(arch_init) );
912 	fword("PREPOST-initializer");
913 
914 	PC = (ucell)findword("initialize-of");
915 
916 	if (!PC) {
917 		printk("panic: no dictionary entry point.\n");
918 		return -1;
919 	}
920 #ifdef CONFIG_DEBUG_DICTIONARY
921 	printk("done (%d bytes).\n", dicthead);
922 	printk("Jumping to dictionary...\n");
923 #endif
924 
925 	enterforth((xt_t)PC);
926         printk("falling off...\n");
927         free(dict);
928 	return 0;
929 }
930