Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / openbios.c
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 "drivers/drivers.h"
14 #include "dict.h"
15 #include "arch/common/nvram.h"
16 #include "packages/nvram.h"
17 #include "libopenbios/sys_info.h"
18 #include "openbios.h"
19 #include "drivers/pci.h"
20 #include "asm/pci.h"
21 #include "boot.h"
22 #include "../../drivers/timer.h" // XXX
23 #define NO_QEMU_PROTOS
24 #include "arch/common/fw_cfg.h"
25 #include "arch/sparc64/ofmem_sparc64.h"
26 #include "spitfire.h"
27
28 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
29
30 #define APB_SPECIAL_BASE     0x1fe00000000ULL
31 #define APB_MEM_BASE         0x1ff00000000ULL
32
33 #define MEMORY_SIZE     (512*1024)      /* 512K ram for hosted system */
34
35 // XXX
36 #define NVRAM_BASE       0x2000
37 #define NVRAM_SIZE       0x2000
38 #define NVRAM_IDPROM     0x1fd8
39 #define NVRAM_IDPROM_SIZE 32
40 #define NVRAM_OB_START   (0)
41 #define NVRAM_OB_SIZE    ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
42
43 static uint8_t idprom[NVRAM_IDPROM_SIZE];
44
45 struct hwdef {
46     pci_arch_t pci;
47     uint16_t machine_id_low, machine_id_high;
48 };
49
50 static const struct hwdef hwdefs[] = {
51     {
52         .pci = {
53             .name = "SUNW,sabre",
54             .vendor_id = PCI_VENDOR_ID_SUN,
55             .device_id = PCI_DEVICE_ID_SUN_SABRE,
56             .cfg_addr = APB_SPECIAL_BASE + 0x1000000ULL, // PCI bus configuration space
57             .cfg_data = APB_MEM_BASE,                    // PCI bus memory space
58             .cfg_base = APB_SPECIAL_BASE,
59             .cfg_len = 0x2000000,
60             .host_pci_base = APB_MEM_BASE,
61             .pci_mem_base = 0x100000, /* avoid VGA at 0xa0000 */
62             .mem_len = 0x10000000,
63             .io_base = APB_SPECIAL_BASE + 0x2000000ULL, // PCI Bus I/O space
64             .io_len = 0x10000,
65             .irqs = { 0, 1, 2, 3 },
66         },
67         .machine_id_low = 0,
68         .machine_id_high = 255,
69     },
70 };
71
72 struct cpudef {
73     unsigned long iu_version;
74     const char *name;
75     unsigned long ecache_associativity;
76     unsigned long ecache_line_size;
77     unsigned long ecache_size;
78     unsigned long num_dtlb_entries;
79     unsigned long dcache_associativity;
80     unsigned long dcache_line_size;
81     unsigned long dcache_size;
82     unsigned long num_itlb_entries;
83     unsigned long icache_associativity;
84     unsigned long icache_line_size;
85     unsigned long icache_size;
86 };
87
88 /*
89   ( addr -- ? )
90 */
91
92 extern volatile uint64_t client_tba;
93
94 static void
95 set_trap_table(void)
96 {
97     unsigned long addr;
98
99     addr = POP();
100
101     /* Update client_tba to be updated on CIF exit */
102     client_tba = addr;
103 }
104
105 /* Reset control register is defined in 17.2.7.3 of US IIi User Manual */
106 static void
107 sparc64_reset_all(void)
108 {
109     unsigned long addr = 0x1fe0000f020ULL;
110     unsigned long val = 1 << 29;
111
112     asm("stxa %0, [%1] 0x15\n\t"
113         : : "r" (val), "r" (addr) : "memory");
114 }
115
116 /* PCI Target Address Space Register (see UltraSPARC IIi User's Manual
117   section 19.3.0.4) */
118 #define PBM_PCI_TARGET_AS              0x2028
119 #define PBM_PCI_TARGET_AS_CD_ENABLE    0x40
120
121 static void
122 sparc64_set_tas_register(unsigned long val)
123 {
124     unsigned long addr = APB_SPECIAL_BASE + PBM_PCI_TARGET_AS;
125
126     asm("stxa %0, [%1] 0x15\n\t"
127         : : "r" (val), "r" (addr) : "memory");
128 }
129
130 static void cpu_generic_init(const struct cpudef *cpu, uint32_t clock_frequency)
131 {
132     unsigned long iu_version;
133
134     push_str("/");
135     fword("find-device");
136
137     fword("new-device");
138
139     push_str(cpu->name);
140     fword("device-name");
141
142     push_str("cpu");
143     fword("device-type");
144
145     asm("rdpr %%ver, %0\n"
146         : "=r"(iu_version) :);
147
148     PUSH((iu_version >> 48) & 0xff);
149     fword("encode-int");
150     push_str("manufacturer#");
151     fword("property");
152
153     PUSH((iu_version >> 32) & 0xff);
154     fword("encode-int");
155     push_str("implementation#");
156     fword("property");
157
158     PUSH((iu_version >> 24) & 0xff);
159     fword("encode-int");
160     push_str("mask#");
161     fword("property");
162
163     PUSH(9);
164     fword("encode-int");
165     push_str("sparc-version");
166     fword("property");
167
168     PUSH(0);
169     fword("encode-int");
170     push_str("cpuid");
171     fword("property");
172
173     PUSH(0);
174     fword("encode-int");
175     push_str("upa-portid");
176     fword("property");
177
178     PUSH(clock_frequency);
179     fword("encode-int");
180     push_str("clock-frequency");
181     fword("property");
182
183     PUSH(cpu->ecache_associativity);
184     fword("encode-int");
185     push_str("ecache-associativity");
186     fword("property");
187
188     PUSH(cpu->ecache_line_size);
189     fword("encode-int");
190     push_str("ecache-line-size");
191     fword("property");
192
193     PUSH(cpu->ecache_size);
194     fword("encode-int");
195     push_str("ecache-size");
196     fword("property");
197
198     PUSH(cpu->dcache_associativity);
199     fword("encode-int");
200     push_str("dcache-associativity");
201     fword("property");
202
203     PUSH(cpu->dcache_line_size);
204     fword("encode-int");
205     push_str("dcache-line-size");
206     fword("property");
207
208     PUSH(cpu->dcache_size);
209     fword("encode-int");
210     push_str("dcache-size");
211     fword("property");
212
213     PUSH(cpu->icache_associativity);
214     fword("encode-int");
215     push_str("icache-associativity");
216     fword("property");
217
218     PUSH(cpu->ecache_line_size);
219     fword("encode-int");
220     push_str("icache-line-size");
221     fword("property");
222
223     PUSH(cpu->ecache_size);
224     fword("encode-int");
225     push_str("icache-size");
226     fword("property");
227
228     PUSH(cpu->num_itlb_entries);
229     fword("encode-int");
230     push_str("#itlb-entries");
231     fword("property");
232
233     PUSH(cpu->num_dtlb_entries);
234     fword("encode-int");
235     push_str("#dtlb-entries");
236     fword("property");
237
238     fword("finish-device");
239
240     // Trap table
241     push_str("/openprom/client-services");
242     fword("find-device");
243     bind_func("SUNW,set-trap-table", set_trap_table);
244
245     // Reset
246     bind_func("sparc64-reset-all", sparc64_reset_all);
247     push_str("' sparc64-reset-all to reset-all");
248     fword("eval");
249 }
250
251 static const struct cpudef sparc_defs[] = {
252     {
253         .iu_version = (0x04ULL << 48) | (0x02ULL << 32),
254         .name = "FJSV,GP",
255     },
256     {
257         .iu_version = (0x04ULL << 48) | (0x03ULL << 32),
258         .name = "FJSV,GPUSK",
259     },
260     {
261         .iu_version = (0x04ULL << 48) | (0x04ULL << 32),
262         .name = "FJSV,GPUSC",
263     },
264     {
265         .iu_version = (0x04ULL << 48) | (0x05ULL << 32),
266         .name = "FJSV,GPUZC",
267     },
268     {
269         .iu_version = (0x17ULL << 48) | (0x10ULL << 32),
270         .name = "SUNW,UltraSPARC",
271         .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
272         .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
273         .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
274         .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
275     },
276     {
277         .iu_version = (0x17ULL << 48) | (0x11ULL << 32),
278         .name = "SUNW,UltraSPARC-II",
279         .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
280         .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
281         .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
282         .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
283     },
284     {
285         .iu_version = (0x17ULL << 48) | (0x12ULL << 32),
286         .name = "SUNW,UltraSPARC-IIi",
287         .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x40000,
288         .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
289         .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
290         .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
291     },
292     {
293         .iu_version = (0x17ULL << 48) | (0x13ULL << 32),
294         .name = "SUNW,UltraSPARC-IIe",
295     },
296     {
297         .iu_version = (0x3eULL << 48) | (0x14ULL << 32),
298         .name = "SUNW,UltraSPARC-III",
299     },
300     {
301         .iu_version = (0x3eULL << 48) | (0x15ULL << 32),
302         .name = "SUNW,UltraSPARC-III+",
303     },
304     {
305         .iu_version = (0x3eULL << 48) | (0x16ULL << 32),
306         .name = "SUNW,UltraSPARC-IIIi",
307     },
308     {
309         .iu_version = (0x3eULL << 48) | (0x18ULL << 32),
310         .name = "SUNW,UltraSPARC-IV",
311     },
312     {
313         .iu_version = (0x3eULL << 48) | (0x19ULL << 32),
314         .name = "SUNW,UltraSPARC-IV+",
315     },
316     {
317         .iu_version = (0x3eULL << 48) | (0x22ULL << 32),
318         .name = "SUNW,UltraSPARC-IIIi+",
319     },
320     {
321         .iu_version = (0x3eULL << 48) | (0x23ULL << 32),
322         .name = "SUNW,UltraSPARC-T1",
323     },
324     {
325         .iu_version = (0x3eULL << 48) | (0x24ULL << 32),
326         .name = "SUNW,UltraSPARC-T2",
327     },
328     {
329         .iu_version = (0x22ULL << 48) | (0x10ULL << 32),
330         .name = "SUNW,UltraSPARC",
331     },
332 };
333
334 static const struct cpudef *
335 id_cpu(void)
336 {
337     unsigned long iu_version;
338     unsigned int i;
339
340     asm("rdpr %%ver, %0\n"
341         : "=r"(iu_version) :);
342     iu_version &= 0xffffffff00000000ULL;
343
344     for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) {
345         if (iu_version == sparc_defs[i].iu_version)
346             return &sparc_defs[i];
347     }
348     printk("Unknown cpu (psr %lx), freezing!\n", iu_version);
349     for (;;);
350 }
351
352 static void nvram_read(uint16_t offset, char *buf, unsigned int nbytes)
353 {
354     unsigned int i;
355
356     for (i = 0; i < nbytes; i++) {
357         buf[i] = inb(NVRAM_BASE + offset + i);
358     }
359 }
360
361 static void nvram_write(uint16_t offset, const char *buf, unsigned int nbytes)
362 {
363     unsigned int i;
364
365     for (i = 0; i < nbytes; i++) {
366         outb(buf[i], NVRAM_BASE + offset + i);
367     }
368 }
369
370 static uint8_t qemu_uuid[16];
371
372 void arch_nvram_get(char *data)
373 {
374     char *obio_cmdline;
375     uint32_t size = 0;
376     const struct cpudef *cpu;
377     char buf[256];
378     uint32_t temp;
379     uint64_t ram_size;
380     uint32_t clock_frequency;
381     uint16_t machine_id;
382     const char *stdin_path, *stdout_path;
383
384     fw_cfg_init();
385
386     fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
387     buf[4] = '\0';
388
389     printk("Configuration device id %s", buf);
390
391     temp = fw_cfg_read_i32(FW_CFG_ID);
392     machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
393
394     printk(" version %d machine id %d\n", temp, machine_id);
395
396     if (temp != 1) {
397         printk("Incompatible configuration device version, freezing\n");
398         for(;;);
399     }
400
401     kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
402     if (kernel_size)
403         kernel_image = fw_cfg_read_i64(FW_CFG_KERNEL_ADDR);
404
405     size = fw_cfg_read_i32(FW_CFG_CMDLINE_SIZE);
406     if (size) {
407         obio_cmdline = (char *)malloc(size + 1);
408         fw_cfg_read(FW_CFG_CMDLINE_DATA, obio_cmdline, size);
409         obio_cmdline[size] = '\0';
410     } else {
411         obio_cmdline = strdup("");    
412     }
413     qemu_cmdline = (uint64_t)obio_cmdline;
414     cmdline_size = size;
415     boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
416
417     if (kernel_size)
418         printk("kernel addr %llx size %llx\n", kernel_image, kernel_size);
419     if (size)
420         printk("kernel cmdline %s\n", obio_cmdline);
421
422     nvram_read(NVRAM_OB_START, data, NVRAM_OB_SIZE);
423
424     temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
425
426     printk("CPUs: %x", temp);
427
428     clock_frequency = 100000000;
429
430     cpu = id_cpu();
431     //cpu->initfn();
432     cpu_generic_init(cpu, clock_frequency);
433     printk(" x %s\n", cpu->name);
434
435     // Add /uuid
436     fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
437
438     printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
439            qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
440            qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
441            qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
442            qemu_uuid[15]);
443
444     push_str("/");
445     fword("find-device");
446
447     PUSH((long)&qemu_uuid);
448     PUSH(16);
449     fword("encode-bytes");
450     push_str("uuid");
451     fword("property");
452
453     // Add /idprom
454     nvram_read(NVRAM_IDPROM, (char *)idprom, NVRAM_IDPROM_SIZE);
455
456     PUSH((long)&idprom);
457     PUSH(32);
458     fword("encode-bytes");
459     push_str("idprom");
460     fword("property");
461
462     PUSH(500 * 1000 * 1000);
463     fword("encode-int");
464     push_str("clock-frequency");
465     fword("property");
466
467     ram_size = fw_cfg_read_i64(FW_CFG_RAM_SIZE);
468
469     ob_mmu_init(cpu->name, ram_size);
470
471     /* Setup nvram variables */
472     push_str("/options");
473     fword("find-device");
474
475     switch (boot_device) {
476         case 'a':
477             push_str("/obio/SUNW,fdtwo");
478             break;
479         case 'c':
480             push_str("disk:a");
481             break;
482         default:
483         case 'd':
484             push_str("cdrom:f cdrom");
485             break;
486         case 'n':
487             push_str("net");
488             break;
489     }
490
491     fword("encode-string");
492     push_str("boot-device");
493     fword("property");
494
495     push_str(obio_cmdline);
496     fword("encode-string");
497     push_str("boot-file");
498     fword("property");
499
500     /* Set up other properties */
501     push_str("/chosen");
502     fword("find-device");
503
504     if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC)) {
505         stdin_path = stdout_path = "ttya";
506     } else {
507         stdin_path = "keyboard";
508         stdout_path = "screen";
509     }
510
511     push_str(stdin_path);
512     push_str("input-device");
513     fword("$setenv");
514
515     push_str(stdout_path);
516     push_str("output-device");
517     fword("$setenv");
518 }
519
520 void arch_nvram_put(char *data)
521 {
522     nvram_write(0, data, NVRAM_OB_SIZE);
523 }
524
525 int arch_nvram_size(void)
526 {
527     return NVRAM_OB_SIZE;
528 }
529
530 void setup_timers(void)
531 {
532 }
533
534 void udelay(unsigned int usecs)
535 {
536     volatile int i;
537
538     for (i = 0; i < usecs * 100; i++);
539 }
540
541 static void init_memory(void)
542 {
543     phys_addr_t phys;
544     ucell virt;
545     
546     /* Claim the memory from OFMEM (align to 512K so we only take 1 TLB slot) */
547     phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE_512K);
548     if (!phys)
549         printk("panic: not enough physical memory on host system.\n");
550     
551     virt = ofmem_claim_virt(-1, MEMORY_SIZE, PAGE_SIZE_512K);
552     if (!virt)
553         printk("panic: not enough virtual memory on host system.\n");
554
555     /* Generate the mapping (and lock translation into the TLBs) */
556     ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys) | SPITFIRE_TTE_LOCKED);
557
558     /* we push start and end of memory to the stack
559      * so that it can be used by the forth word QUIT
560      * to initialize the memory allocator
561      */
562     
563     PUSH(virt);
564     PUSH(virt + MEMORY_SIZE);
565 }
566
567 extern volatile uint64_t *obp_ticks_pointer;
568
569 static void
570 arch_init( void )
571 {
572         openbios_init();
573         modules_init();
574 #ifdef CONFIG_DRIVER_PCI
575         ob_pci_init();
576
577         /* Set TAS register to match the virtual-dma properties
578            set during sabre configure */
579         sparc64_set_tas_register(PBM_PCI_TARGET_AS_CD_ENABLE);
580 #endif
581         nvconf_init();
582         device_end();
583
584         /* Point to the Forth obp-ticks variable */
585         fword("obp-ticks");
586         obp_ticks_pointer = cell2pointer(POP());
587
588         bind_func("platform-boot", boot );
589         bind_func("(go)", go);
590 }
591
592 unsigned long isa_io_base;
593
594 extern struct _console_ops arch_console_ops;
595
596 int openbios(void)
597 {
598         unsigned int i;
599         uint16_t machine_id;
600         const struct hwdef *hwdef = NULL;
601
602
603         for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
604             isa_io_base = hwdefs[i].pci.io_base;
605             machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
606             if (hwdefs[i].machine_id_low <= machine_id &&
607                 hwdefs[i].machine_id_high >= machine_id) {
608                 hwdef = &hwdefs[i];
609                 arch = &hwdefs[i].pci;
610                 break;
611             }
612         }
613         if (!hwdef)
614             for(;;); // Internal inconsistency, hang
615
616 #ifdef CONFIG_DEBUG_CONSOLE
617         init_console(arch_console_ops);
618 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
619         uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
620 #endif
621         printk("OpenBIOS for Sparc64\n");
622 #endif
623
624         ofmem_init();
625
626         collect_sys_info(&sys_info);
627
628         dict = (unsigned char *)sys_info.dict_start;
629         dicthead = (cell)sys_info.dict_end;
630         last = sys_info.dict_last;
631         dictlimit = sys_info.dict_limit;
632
633         forth_init();
634
635 #ifdef CONFIG_DEBUG_BOOT
636         printk("forth started.\n");
637         printk("initializing memory...");
638 #endif
639
640         init_memory();
641
642 #ifdef CONFIG_DEBUG_BOOT
643         printk("done\n");
644 #endif
645
646         PUSH_xt( bind_noname_func(arch_init) );
647         fword("PREPOST-initializer");
648
649         PC = (ucell)findword("initialize-of");
650
651         if (!PC) {
652                 printk("panic: no dictionary entry point.\n");
653                 return -1;
654         }
655 #ifdef CONFIG_DEBUG_DICTIONARY
656         printk("done (%d bytes).\n", dicthead);
657         printk("Jumping to dictionary...\n");
658 #endif
659
660         enterforth((xt_t)PC);
661         printk("falling off...\n");
662         free(dict);
663         return 0;
664 }