| /* tag: openbios forth environment, executable code |
| * |
| * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer |
| * |
| * See the file "COPYING" for further information about |
| * the copyright and warranty status of this work. |
| */ |
| |
| #include "config.h" |
| #include "libopenbios/openbios.h" |
| #include "libopenbios/bindings.h" |
| #include "libopenbios/console.h" |
| #include "context.h" |
| #include "libopenbios/initprogram.h" |
| #include "drivers/drivers.h" |
| #include "dict.h" |
| #include "arch/common/nvram.h" |
| #include "packages/nvram.h" |
| #include "libopenbios/sys_info.h" |
| #include "openbios.h" |
| #include "drivers/pci.h" |
| #include "asm/pci.h" |
| #include "boot.h" |
| #include "../../drivers/timer.h" // XXX |
| #define NO_QEMU_PROTOS |
| #include "arch/common/fw_cfg.h" |
| #include "arch/sparc64/ofmem_sparc64.h" |
| #include "spitfire.h" |
| #include "libc/vsprintf.h" |
| |
| #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" |
| |
| #define APB_SPECIAL_BASE 0x1fe00000000ULL |
| #define APB_MEM_BASE 0x1ff00000000ULL |
| |
| #define MEMORY_SIZE (512*1024) /* 512K ram for hosted system */ |
| |
| // XXX |
| #define NVRAM_BASE 0x2000 |
| #define NVRAM_SIZE 0x2000 |
| #define NVRAM_IDPROM 0x1fd8 |
| #define NVRAM_IDPROM_SIZE 32 |
| #define NVRAM_OB_START (0) |
| #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15) |
| |
| static uint8_t idprom[NVRAM_IDPROM_SIZE]; |
| |
| struct hwdef { |
| pci_arch_t pci; |
| uint16_t machine_id_low, machine_id_high; |
| }; |
| |
| static const struct hwdef hwdefs[] = { |
| { |
| .pci = { |
| .name = "SUNW,sabre", |
| .vendor_id = PCI_VENDOR_ID_SUN, |
| .device_id = PCI_DEVICE_ID_SUN_SABRE, |
| .cfg_addr = APB_SPECIAL_BASE + 0x1000000ULL, // PCI bus configuration space |
| .cfg_data = APB_MEM_BASE, // PCI bus memory space |
| .cfg_base = APB_SPECIAL_BASE, |
| .cfg_len = 0x1000000, |
| .host_pci_base = APB_MEM_BASE, |
| .pci_mem_base = 0x20000000, /* avoid VGA at 0xa0000 */ |
| .mem_len = 0xf0000000, |
| .io_base = APB_SPECIAL_BASE + 0x2000000ULL, // PCI Bus I/O space |
| .io_len = 0x1000000, |
| .host_ranges = { |
| { .type = CONFIGURATION_SPACE, .parentaddr = 0, .childaddr = APB_SPECIAL_BASE + 0x1000000ULL, .len = 0x1000000 }, |
| { .type = IO_SPACE, .parentaddr = 0, .childaddr = APB_SPECIAL_BASE + 0x2000000ULL, .len = 0x1000000 }, |
| { .type = MEMORY_SPACE_32, .parentaddr = 0, .childaddr = APB_MEM_BASE, .len = 0xf0000000 }, |
| { .type = 0, .parentaddr = 0, .childaddr = 0, .len = 0 } |
| }, |
| .irqs = { 0, 1, 2, 3 }, |
| }, |
| .machine_id_low = 0, |
| .machine_id_high = 255, |
| }, |
| }; |
| |
| struct cpudef { |
| unsigned long iu_version; |
| const char *name; |
| unsigned long ecache_associativity; |
| unsigned long ecache_line_size; |
| unsigned long ecache_size; |
| unsigned long num_dtlb_entries; |
| unsigned long dcache_associativity; |
| unsigned long dcache_line_size; |
| unsigned long dcache_size; |
| unsigned long num_itlb_entries; |
| unsigned long icache_associativity; |
| unsigned long icache_line_size; |
| unsigned long icache_size; |
| }; |
| |
| /* |
| ( addr -- ? ) |
| */ |
| |
| static void |
| set_trap_table(void) |
| { |
| unsigned long addr; |
| volatile struct context *ctx = __context; |
| |
| addr = POP(); |
| |
| /* Update %tba to be updated on exit */ |
| ctx->tba = (uint64_t)addr; |
| } |
| |
| /* Reset control register is defined in 17.2.7.3 of US IIi User Manual */ |
| static void |
| sparc64_reset_all(void) |
| { |
| unsigned long addr = 0x1fe0000f020ULL; |
| unsigned long val = 1 << 29; |
| |
| asm("stxa %0, [%1] 0x15\n\t" |
| : : "r" (val), "r" (addr) : "memory"); |
| } |
| |
| /* Power off */ |
| static void |
| sparc64_power_off(void) |
| { |
| /* Locate address of ebus power device */ |
| phandle_t ph; |
| uint32_t addr; |
| volatile uint32_t *p; |
| int len; |
| |
| ph = find_dev("/pci/pci@1,1/ebus/power"); |
| if (ph) { |
| addr = get_int_property(ph, "address", &len); |
| |
| if (len) { |
| /* Set bit 24 to invoke power off */ |
| p = cell2pointer(addr); |
| *p = 0x1000000; |
| } |
| } |
| } |
| |
| /* PCI Target Address Space Register (see UltraSPARC IIi User's Manual |
| section 19.3.0.4) */ |
| #define PBM_PCI_TARGET_AS 0x2028 |
| #define PBM_PCI_TARGET_AS_CD_ENABLE 0x40 |
| |
| static void |
| sparc64_set_tas_register(unsigned long val) |
| { |
| unsigned long addr = APB_SPECIAL_BASE + PBM_PCI_TARGET_AS; |
| |
| asm("stxa %0, [%1] 0x15\n\t" |
| : : "r" (val), "r" (addr) : "memory"); |
| } |
| |
| /* space?@ and and space?! words */ |
| static uint8_t |
| sparc64_asi_loadb(uint8_t asi, unsigned long address) |
| { |
| uint8_t asi_save; |
| uint8_t ret = 0; |
| |
| __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save)); |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi)); |
| |
| __asm__ __volatile__("ldub [%1], %0" |
| : "=r" (ret) |
| : "r" (address)); |
| |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save)); |
| |
| return ret; |
| } |
| |
| /* spacec@ */ |
| static void |
| spacec_read(void) |
| { |
| uint8_t ret; |
| |
| uint8_t asi = POP(); |
| ucell address = POP(); |
| |
| ret = sparc64_asi_loadb(asi, address); |
| |
| PUSH(ret); |
| } |
| |
| static uint16_t |
| sparc64_asi_loadw(uint8_t asi, unsigned long address) |
| { |
| uint8_t asi_save; |
| uint16_t ret; |
| |
| __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save)); |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi)); |
| |
| __asm__ __volatile__("lduw [%1], %0" |
| : "=r" (ret) |
| : "r" (address)); |
| |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save)); |
| |
| return ret; |
| } |
| |
| /* spacew@ */ |
| static void |
| spacew_read(void) |
| { |
| uint16_t ret; |
| |
| uint8_t asi = POP(); |
| ucell address = POP(); |
| |
| ret = sparc64_asi_loadw(asi, address); |
| |
| PUSH(ret); |
| } |
| |
| static uint32_t |
| sparc64_asi_loadl(uint8_t asi, unsigned long address) |
| { |
| uint8_t asi_save; |
| uint32_t ret; |
| |
| __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save)); |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi)); |
| |
| __asm__ __volatile__("ld [%1], %0" |
| : "=r" (ret) |
| : "r" (address)); |
| |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save)); |
| |
| return ret; |
| } |
| |
| /* spacel@ */ |
| static void |
| spacel_read(void) |
| { |
| uint32_t ret; |
| |
| uint8_t asi = POP(); |
| ucell address = POP(); |
| |
| ret = sparc64_asi_loadl(asi, address); |
| |
| PUSH(ret); |
| } |
| |
| static uint64_t |
| sparc64_asi_loadx(uint8_t asi, unsigned long address) |
| { |
| uint8_t asi_save; |
| uint64_t ret = 0; |
| |
| __asm__ __volatile__("rd %%asi, %0" : "=r" (asi_save)); |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi)); |
| |
| __asm__ __volatile__("ldx [%1], %0" |
| : "=r" (ret) |
| : "r" (address)); |
| |
| __asm__ __volatile__("wr %0, 0, %%asi" : : "r" (asi_save)); |
| |
| return ret; |
| } |
| |
| /* spacex@ */ |
| static void |
| spacex_read(void) |
| { |
| uint64_t ret; |
| |
| uint8_t asi = POP(); |
| ucell address = POP(); |
| |
| ret = sparc64_asi_loadx(asi, address); |
| |
| PUSH(ret); |
| } |
| |
| static void cpu_generic_init(const struct cpudef *cpu, uint32_t clock_frequency) |
| { |
| unsigned long iu_version; |
| |
| push_str("/"); |
| fword("find-device"); |
| |
| fword("new-device"); |
| |
| push_str(cpu->name); |
| fword("device-name"); |
| |
| push_str("cpu"); |
| fword("device-type"); |
| |
| asm("rdpr %%ver, %0\n" |
| : "=r"(iu_version) :); |
| |
| PUSH((iu_version >> 48) & 0xff); |
| fword("encode-int"); |
| push_str("manufacturer#"); |
| fword("property"); |
| |
| PUSH((iu_version >> 32) & 0xff); |
| fword("encode-int"); |
| push_str("implementation#"); |
| fword("property"); |
| |
| PUSH((iu_version >> 24) & 0xff); |
| fword("encode-int"); |
| push_str("mask#"); |
| fword("property"); |
| |
| PUSH(9); |
| fword("encode-int"); |
| push_str("sparc-version"); |
| fword("property"); |
| |
| PUSH(0); |
| fword("encode-int"); |
| push_str("cpuid"); |
| fword("property"); |
| |
| PUSH(0); |
| fword("encode-int"); |
| push_str("upa-portid"); |
| fword("property"); |
| |
| PUSH(clock_frequency); |
| fword("encode-int"); |
| push_str("clock-frequency"); |
| fword("property"); |
| |
| PUSH(cpu->ecache_associativity); |
| fword("encode-int"); |
| push_str("ecache-associativity"); |
| fword("property"); |
| |
| PUSH(cpu->ecache_line_size); |
| fword("encode-int"); |
| push_str("ecache-line-size"); |
| fword("property"); |
| |
| PUSH(cpu->ecache_size); |
| fword("encode-int"); |
| push_str("ecache-size"); |
| fword("property"); |
| |
| PUSH(cpu->dcache_associativity); |
| fword("encode-int"); |
| push_str("dcache-associativity"); |
| fword("property"); |
| |
| PUSH(cpu->dcache_line_size); |
| fword("encode-int"); |
| push_str("dcache-line-size"); |
| fword("property"); |
| |
| PUSH(cpu->dcache_size); |
| fword("encode-int"); |
| push_str("dcache-size"); |
| fword("property"); |
| |
| PUSH(cpu->icache_associativity); |
| fword("encode-int"); |
| push_str("icache-associativity"); |
| fword("property"); |
| |
| PUSH(cpu->ecache_line_size); |
| fword("encode-int"); |
| push_str("icache-line-size"); |
| fword("property"); |
| |
| PUSH(cpu->ecache_size); |
| fword("encode-int"); |
| push_str("icache-size"); |
| fword("property"); |
| |
| PUSH(cpu->num_itlb_entries); |
| fword("encode-int"); |
| push_str("#itlb-entries"); |
| fword("property"); |
| |
| PUSH(cpu->num_dtlb_entries); |
| fword("encode-int"); |
| push_str("#dtlb-entries"); |
| fword("property"); |
| |
| fword("finish-device"); |
| |
| // Trap table |
| push_str("/openprom/client-services"); |
| fword("find-device"); |
| bind_func("SUNW,set-trap-table", set_trap_table); |
| |
| // Reset |
| bind_func("sparc64-reset-all", sparc64_reset_all); |
| push_str("' sparc64-reset-all to reset-all"); |
| fword("eval"); |
| } |
| |
| static const struct cpudef sparc_defs[] = { |
| { |
| .iu_version = (0x04ULL << 48) | (0x02ULL << 32), |
| .name = "FJSV,GP", |
| }, |
| { |
| .iu_version = (0x04ULL << 48) | (0x03ULL << 32), |
| .name = "FJSV,GPUSK", |
| }, |
| { |
| .iu_version = (0x04ULL << 48) | (0x04ULL << 32), |
| .name = "FJSV,GPUSC", |
| }, |
| { |
| .iu_version = (0x04ULL << 48) | (0x05ULL << 32), |
| .name = "FJSV,GPUZC", |
| }, |
| { |
| .iu_version = (0x17ULL << 48) | (0x10ULL << 32), |
| .name = "SUNW,UltraSPARC", |
| .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000, |
| .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000, |
| .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000, |
| .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40, |
| }, |
| { |
| .iu_version = (0x17ULL << 48) | (0x11ULL << 32), |
| .name = "SUNW,UltraSPARC-II", |
| .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000, |
| .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000, |
| .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000, |
| .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40, |
| }, |
| { |
| .iu_version = (0x17ULL << 48) | (0x12ULL << 32), |
| .name = "SUNW,UltraSPARC-IIi", |
| .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x40000, |
| .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000, |
| .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000, |
| .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40, |
| }, |
| { |
| .iu_version = (0x17ULL << 48) | (0x13ULL << 32), |
| .name = "SUNW,UltraSPARC-IIe", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x14ULL << 32), |
| .name = "SUNW,UltraSPARC-III", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x15ULL << 32), |
| .name = "SUNW,UltraSPARC-III+", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x16ULL << 32), |
| .name = "SUNW,UltraSPARC-IIIi", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x18ULL << 32), |
| .name = "SUNW,UltraSPARC-IV", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x19ULL << 32), |
| .name = "SUNW,UltraSPARC-IV+", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x22ULL << 32), |
| .name = "SUNW,UltraSPARC-IIIi+", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x23ULL << 32), |
| .name = "SUNW,UltraSPARC-T1", |
| }, |
| { |
| .iu_version = (0x3eULL << 48) | (0x24ULL << 32), |
| .name = "SUNW,UltraSPARC-T2", |
| }, |
| { |
| .iu_version = (0x22ULL << 48) | (0x10ULL << 32), |
| .name = "SUNW,UltraSPARC", |
| }, |
| }; |
| |
| static const struct cpudef * |
| id_cpu(void) |
| { |
| unsigned long iu_version; |
| unsigned int i; |
| |
| asm("rdpr %%ver, %0\n" |
| : "=r"(iu_version) :); |
| iu_version &= 0xffffffff00000000ULL; |
| |
| for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) { |
| if (iu_version == sparc_defs[i].iu_version) |
| return &sparc_defs[i]; |
| } |
| printk("Unknown cpu (psr %lx), freezing!\n", iu_version); |
| for (;;); |
| } |
| |
| static void nvram_read(uint16_t offset, char *buf, unsigned int nbytes) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nbytes; i++) { |
| buf[i] = inb(NVRAM_BASE + offset + i); |
| } |
| } |
| |
| static void nvram_write(uint16_t offset, const char *buf, unsigned int nbytes) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nbytes; i++) { |
| outb(buf[i], NVRAM_BASE + offset + i); |
| } |
| } |
| |
| static uint8_t qemu_uuid[16]; |
| |
| void arch_nvram_get(char *data) |
| { |
| char *obio_cmdline; |
| uint32_t size = 0; |
| const struct cpudef *cpu; |
| char buf[256]; |
| uint32_t temp; |
| uint64_t ram_size; |
| uint32_t clock_frequency; |
| uint16_t machine_id, nographic; |
| const char *stdin_path, *stdout_path; |
| char *bootorder_file, *boot_path; |
| uint32_t bootorder_sz, sz; |
| phandle_t display_ph; |
| |
| fw_cfg_init(); |
| |
| fw_cfg_read(FW_CFG_SIGNATURE, buf, 4); |
| buf[4] = '\0'; |
| |
| printk("Configuration device id %s", buf); |
| |
| temp = fw_cfg_read_i32(FW_CFG_ID); |
| machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID); |
| |
| printk(" version %d machine id %d\n", temp, machine_id); |
| |
| if (temp != 1) { |
| printk("Incompatible configuration device version, freezing\n"); |
| for(;;); |
| } |
| |
| kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE); |
| if (kernel_size) { |
| kernel_image = fw_cfg_read_i64(FW_CFG_KERNEL_ADDR); |
| |
| /* Map kernel memory the same as SILO */ |
| ofmem_map(PAGE_ALIGN(kernel_image) - 0x4000, IMAGE_VIRT_ADDR, PAGE_ALIGN(kernel_size), -1); |
| } |
| |
| size = fw_cfg_read_i32(FW_CFG_CMDLINE_SIZE); |
| if (size) { |
| obio_cmdline = (char *)malloc(size + 1); |
| fw_cfg_read(FW_CFG_CMDLINE_DATA, obio_cmdline, size); |
| obio_cmdline[size] = '\0'; |
| } else { |
| obio_cmdline = strdup(""); |
| } |
| qemu_cmdline = (uint64_t)obio_cmdline; |
| cmdline_size = size; |
| |
| initrd_size = fw_cfg_read_i32(FW_CFG_INITRD_SIZE); |
| if (initrd_size) { |
| initrd_image = fw_cfg_read_i32(FW_CFG_INITRD_ADDR); |
| |
| /* Map initrd memory the same as SILO */ |
| ofmem_map(PAGE_ALIGN(initrd_image), INITRD_VIRT_ADDR, PAGE_ALIGN(initrd_size), -1); |
| } |
| |
| if (kernel_size) |
| printk("kernel phys %llx virt %x size 0x%llx\n", kernel_image, IMAGE_VIRT_ADDR + 0x4000, kernel_size); |
| if (initrd_size) |
| printk("initrd phys %llx virt %x size 0x%llx\n", initrd_image, INITRD_VIRT_ADDR, initrd_size); |
| if (size) |
| printk("kernel cmdline %s\n", obio_cmdline); |
| |
| nvram_read(NVRAM_OB_START, data, NVRAM_OB_SIZE); |
| |
| temp = fw_cfg_read_i32(FW_CFG_NB_CPUS); |
| |
| printk("CPUs: %x", temp); |
| |
| clock_frequency = 100000000; |
| |
| cpu = id_cpu(); |
| //cpu->initfn(); |
| cpu_generic_init(cpu, clock_frequency); |
| printk(" x %s\n", cpu->name); |
| |
| // Add /uuid |
| fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16); |
| |
| printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], |
| qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], |
| qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], |
| qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], |
| qemu_uuid[15]); |
| |
| push_str("/"); |
| fword("find-device"); |
| |
| PUSH((long)&qemu_uuid); |
| PUSH(16); |
| fword("encode-bytes"); |
| push_str("uuid"); |
| fword("property"); |
| |
| // Add /idprom |
| nvram_read(NVRAM_IDPROM, (char *)idprom, NVRAM_IDPROM_SIZE); |
| |
| PUSH((long)&idprom); |
| PUSH(32); |
| fword("encode-bytes"); |
| push_str("idprom"); |
| fword("property"); |
| |
| PUSH(500 * 1000 * 1000); |
| fword("encode-int"); |
| push_str("clock-frequency"); |
| fword("property"); |
| |
| ram_size = fw_cfg_read_i64(FW_CFG_RAM_SIZE); |
| |
| ob_mmu_init(cpu->name, ram_size); |
| |
| /* Setup nvram variables */ |
| push_str("/options"); |
| fword("find-device"); |
| |
| /* Boot order */ |
| bootorder_file = fw_cfg_read_file("bootorder", &bootorder_sz); |
| |
| if (bootorder_file == NULL) { |
| switch (fw_cfg_read_i16(FW_CFG_BOOT_DEVICE)) { |
| case 'a': |
| push_str("/obio/SUNW,fdtwo"); |
| break; |
| case 'c': |
| push_str("disk:a"); |
| break; |
| default: |
| case 'd': |
| push_str("cdrom:f cdrom"); |
| break; |
| case 'n': |
| push_str("net"); |
| break; |
| } |
| |
| fword("encode-string"); |
| push_str("boot-device"); |
| fword("property"); |
| } else { |
| sz = bootorder_sz * (3 * 2); |
| boot_device = malloc(sz); |
| memset(boot_device, 0, sz); |
| |
| while ((boot_path = strsep(&bootorder_file, "\n")) != NULL) { |
| snprintf(buf, sizeof(buf), |
| "%s:f " |
| "%s:a " |
| "%s ", |
| boot_path, boot_path, boot_path); |
| |
| strncat(boot_device, buf, sz); |
| } |
| |
| push_str(boot_device); |
| fword("encode-string"); |
| push_str("boot-device"); |
| fword("property"); |
| } |
| |
| push_str(obio_cmdline); |
| fword("encode-string"); |
| push_str("boot-file"); |
| fword("property"); |
| |
| /* Set up other properties */ |
| push_str("/chosen"); |
| fword("find-device"); |
| |
| nographic = fw_cfg_read_i16(FW_CFG_NOGRAPHIC); |
| |
| /* Check to see if any framebuffer present */ |
| display_ph = dt_iterate_type(0, "display"); |
| if (display_ph == 0) { |
| nographic = 1; |
| } |
| |
| if (nographic) { |
| stdin_path = stdout_path = "ttya"; |
| } else { |
| stdin_path = "keyboard"; |
| stdout_path = "screen"; |
| } |
| |
| push_str(stdin_path); |
| push_str("input-device"); |
| fword("$setenv"); |
| |
| push_str(stdout_path); |
| push_str("output-device"); |
| fword("$setenv"); |
| } |
| |
| void arch_nvram_put(char *data) |
| { |
| nvram_write(0, data, NVRAM_OB_SIZE); |
| } |
| |
| int arch_nvram_size(void) |
| { |
| return NVRAM_OB_SIZE; |
| } |
| |
| void setup_timers(void) |
| { |
| } |
| |
| void udelay(unsigned int usecs) |
| { |
| volatile int i; |
| |
| for (i = 0; i < usecs * 100; i++); |
| } |
| |
| static void init_memory(void) |
| { |
| phys_addr_t phys; |
| ucell virt; |
| |
| /* Claim the memory from OFMEM (align to 512K so we only take 1 TLB slot) */ |
| phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE_512K); |
| if (!phys) |
| printk("panic: not enough physical memory on host system.\n"); |
| |
| virt = ofmem_claim_virt(-1, MEMORY_SIZE, PAGE_SIZE_512K); |
| if (!virt) |
| printk("panic: not enough virtual memory on host system.\n"); |
| |
| /* Generate the mapping (and lock translation into the TLBs) */ |
| ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys) | SPITFIRE_TTE_LOCKED); |
| |
| /* we push start and end of memory to the stack |
| * so that it can be used by the forth word QUIT |
| * to initialize the memory allocator |
| */ |
| |
| PUSH(virt); |
| PUSH(virt + MEMORY_SIZE); |
| } |
| |
| /* ( size -- virt ) */ |
| static void |
| dma_alloc(void) |
| { |
| ucell size = POP(); |
| ucell addr; |
| int ret; |
| |
| /* OpenBIOS doesn't enable the sun4u IOMMU so we can fall back to |
| * using ofmem_posix_memalign */ |
| ret = ofmem_posix_memalign((void *)&addr, size, PAGE_SIZE); |
| |
| if (ret) { |
| PUSH(0); |
| } else { |
| PUSH(addr); |
| } |
| } |
| |
| /* ( virt devaddr size -- ) */ |
| static void |
| dma_sync(void) |
| { |
| ucell size = POP(); |
| POP(); |
| ucell virt = POP(); |
| ucell va; |
| |
| for (va = virt; va < virt + size; va += PAGE_SIZE_8K) { |
| itlb_demap(va); |
| dtlb_demap(va); |
| } |
| } |
| |
| extern volatile uint64_t *obp_ticks_pointer; |
| |
| static void |
| arch_init( void ) |
| { |
| openbios_init(); |
| modules_init(); |
| |
| bind_func("sparc64-dma-alloc", dma_alloc); |
| feval("['] sparc64-dma-alloc to (dma-alloc)"); |
| bind_func("sparc64-dma-sync", dma_sync); |
| feval("['] sparc64-dma-sync to (dma-sync)"); |
| |
| #ifdef CONFIG_DRIVER_PCI |
| push_str("/"); |
| fword("find-device"); |
| feval("\" /\" open-dev to my-self"); |
| |
| ob_pci_init(); |
| |
| /* Set TAS register to match the virtual-dma properties |
| set during sabre configure */ |
| sparc64_set_tas_register(PBM_PCI_TARGET_AS_CD_ENABLE); |
| |
| feval("0 to my-self"); |
| #endif |
| nvconf_init(); |
| device_end(); |
| |
| /* Point to the Forth obp-ticks variable */ |
| fword("obp-ticks"); |
| obp_ticks_pointer = cell2pointer(POP()); |
| |
| /* Bind to space?@ functions */ |
| bind_func("spacec@", spacec_read); |
| bind_func("spacew@", spacew_read); |
| bind_func("spacel@", spacel_read); |
| bind_func("spacex@", spacex_read); |
| |
| /* Bind power functions */ |
| bind_func("sparc64-power-off", sparc64_power_off); |
| push_str("' sparc64-power-off to power-off"); |
| fword("eval"); |
| |
| bind_func("platform-boot", boot ); |
| } |
| |
| unsigned long isa_io_base; |
| |
| extern struct _console_ops arch_console_ops; |
| |
| int openbios(void) |
| { |
| unsigned int i; |
| uint16_t machine_id; |
| const struct hwdef *hwdef = NULL; |
| |
| |
| for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) { |
| isa_io_base = hwdefs[i].pci.io_base; |
| machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID); |
| if (hwdefs[i].machine_id_low <= machine_id && |
| hwdefs[i].machine_id_high >= machine_id) { |
| hwdef = &hwdefs[i]; |
| arch = &hwdefs[i].pci; |
| break; |
| } |
| } |
| if (!hwdef) |
| for(;;); // Internal inconsistency, hang |
| |
| #ifdef CONFIG_DEBUG_CONSOLE |
| init_console(arch_console_ops); |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED); |
| #endif |
| printk("OpenBIOS for Sparc64\n"); |
| #endif |
| |
| ofmem_init(); |
| |
| collect_sys_info(&sys_info); |
| |
| dict = (unsigned char *)sys_info.dict_start; |
| dicthead = (cell)sys_info.dict_end; |
| last = sys_info.dict_last; |
| dictlimit = sys_info.dict_limit; |
| |
| forth_init(); |
| |
| #ifdef CONFIG_DEBUG_BOOT |
| printk("forth started.\n"); |
| printk("initializing memory..."); |
| #endif |
| |
| init_memory(); |
| |
| #ifdef CONFIG_DEBUG_BOOT |
| printk("done\n"); |
| #endif |
| |
| PUSH_xt( bind_noname_func(arch_init) ); |
| fword("PREPOST-initializer"); |
| |
| PC = (ucell)findword("initialize-of"); |
| |
| if (!PC) { |
| printk("panic: no dictionary entry point.\n"); |
| return -1; |
| } |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("done (%d bytes).\n", dicthead); |
| printk("Jumping to dictionary...\n"); |
| #endif |
| |
| enterforth((xt_t)PC); |
| printk("falling off...\n"); |
| free(dict); |
| return 0; |
| } |