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