928 lines
22 KiB
C
928 lines
22 KiB
C
|
/* 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;
|
||
|
}
|