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