Files
openbios/arch/sparc64/openbios.c
Blue Swirl b098842b5b Use firmware configuration instead of NVRAM (initial patch by Aurelien Jarno)
Use firmware configuration device for boot device, kernel, initrd and
kernel command line parameters on PPC, Sparc32 and Sparc64.


git-svn-id: svn://coreboot.org/openbios/trunk/openbios-devel@479 f158a5a8-5612-0410-a976-696ce0be7e32
2009-03-08 09:45:25 +00:00

535 lines
12 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 "openbios/config.h"
#include "openbios/bindings.h"
#include "openbios/drivers.h"
#include "dict.h"
#include "openbios/nvram.h"
#include "sys_info.h"
#include "openbios.h"
#include "openbios/pci.h"
#include "asm/pci.h"
#include "boot.h"
#include "../../drivers/timer.h" // XXX
#define NO_QEMU_PROTOS
#include "openbios/fw_cfg.h"
#include "video_subr.h"
#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define NVRAM_ADDR_LO 0x74
#define NVRAM_ADDR_HI 0x75
#define NVRAM_DATA 0x77
#define APB_SPECIAL_BASE 0x1fe00000000ULL
#define APB_MEM_BASE 0x1ff00000000ULL
#define MEMORY_SIZE (512*1024) /* 512K ram for hosted system */
#define DICTIONARY_SIZE (256*1024) /* 256K for the dictionary */
static ucell *memory;
// XXX
#define NVRAM_SIZE 0x2000
#define NVRAM_IDPROM 0x1fd8
#define NVRAM_IDPROM_SIZE 32
#define NVRAM_OB_START (0)
#define NVRAM_OB_SIZE ((0x1fd0 - NVRAM_OB_START) & ~15)
#define OBIO_CMDLINE_MAX 256
static char obio_cmdline[OBIO_CMDLINE_MAX];
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,
.cfg_data = APB_MEM_BASE,
.cfg_base = 0x80000000ULL,
.cfg_len = 0,
.mem_base = APB_MEM_BASE + 0x400000ULL,
.mem_len = 0x10000000,
.io_base = APB_SPECIAL_BASE + 0x2000000ULL,
.io_len = 0x10000,
.irqs = { 0, 1, 2, 3 },
},
.machine_id_low = 0,
.machine_id_high = 255,
},
};
struct cpudef {
unsigned long iu_version;
const char *name;
};
/*
( addr -- ? )
*/
static void
set_trap_table(void)
{
unsigned long addr;
addr = POP();
asm("wrpr %0, %%tba\n"
: : "r" (addr));
}
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(clock_frequency);
fword("encode-int");
push_str("clock-frequency");
fword("property");
fword("finish-device");
// Trap table
push_str("/openprom/client-services");
fword("find-device");
bind_func("SUNW,set-trap-table", set_trap_table);
}
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",
},
{
.iu_version = (0x17ULL << 48) | (0x11ULL << 32),
.name = "SUNW,UltraSPARC-II",
},
{
.iu_version = (0x17ULL << 48) | (0x12ULL << 32),
.name = "SUNW,UltraSPARC-IIi",
},
{
.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 uint8_t nvram_read_byte(uint16_t offset)
{
outb(offset & 0xff, NVRAM_ADDR_LO);
outb(offset >> 8, NVRAM_ADDR_HI);
return inb(NVRAM_DATA);
}
static void nvram_read(uint16_t offset, char *buf, unsigned int nbytes)
{
unsigned int i;
for (i = 0; i < nbytes; i++)
buf[i] = nvram_read_byte(offset + i);
}
static void nvram_write_byte(uint16_t offset, uint8_t val)
{
outb(offset & 0xff, NVRAM_ADDR_LO);
outb(offset >> 8, NVRAM_ADDR_HI);
outb(val, NVRAM_DATA);
}
static void nvram_write(uint16_t offset, const char *buf, unsigned int nbytes)
{
unsigned int i;
for (i = 0; i < nbytes; i++)
nvram_write_byte(offset + i, buf[i]);
}
static uint8_t qemu_uuid[16];
void arch_nvram_get(char *data)
{
uint32_t size = 0;
const struct cpudef *cpu;
const char *bootpath;
char buf[256];
uint32_t temp;
uint64_t ram_size;
uint32_t clock_frequency;
uint16_t machine_id;
const char *stdin_path, *stdout_path;
const char *kernel_cmdline;
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);
kernel_cmdline = (const char *) fw_cfg_read_i64(FW_CFG_KERNEL_CMDLINE);
if (kernel_cmdline) {
size = strlen(kernel_cmdline);
if (size > OBIO_CMDLINE_MAX - 1)
size = OBIO_CMDLINE_MAX - 1;
memcpy(&obio_cmdline, kernel_cmdline, size);
}
obio_cmdline[size] = '\0';
qemu_cmdline = (uint64_t)obio_cmdline;
cmdline_size = size;
boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
if (kernel_size)
printk("kernel addr %llx size %llx\n", kernel_image, kernel_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);
push_str("/chosen");
fword("find-device");
if (boot_device == 'c')
bootpath = "disk:a";
else
bootpath = "cdrom:a";
push_str(bootpath);
fword("encode-string");
push_str("bootpath");
fword("property");
push_str(obio_cmdline);
fword("encode-string");
push_str("bootargs");
fword("property");
if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC)) {
stdin_path = stdout_path = "/pci/pci/pci/ebus/su";
} else {
stdin_path = "/pci/pci/pci/ebus/kb_ps2";
stdout_path = "/pci/pci/pci/QEMU,VGA";
}
push_str(stdin_path);
fword("open-dev");
fword("encode-int");
push_str("stdin");
fword("property");
push_str(stdout_path);
fword("open-dev");
fword("encode-int");
push_str("stdout");
fword("property");
push_str(stdin_path);
push_str("input-device");
fword("$setenv");
push_str(stdout_path);
push_str("output-device");
fword("$setenv");
push_str(stdin_path);
fword("input");
push_str(stdout_path);
fword("output");
}
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)
{
}
static void init_memory(void)
{
memory = malloc(MEMORY_SIZE);
if (!memory)
printk("panic: not enough memory on host system.\n");
/* 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((ucell)memory);
PUSH((ucell)memory + (ucell)MEMORY_SIZE);
}
static void
arch_init( void )
{
modules_init();
#ifdef CONFIG_DRIVER_PCI
ob_pci_init();
#endif
nvconf_init();
device_end();
bind_func("platform-boot", boot );
}
unsigned long isa_io_base;
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
#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
#endif
/* Clear the screen. */
cls();
printk("OpenBIOS for Sparc64\n");
#endif
collect_sys_info(&sys_info);
dict = malloc(DICTIONARY_SIZE);
load_dictionary((char *)sys_info.dict_start,
(unsigned long)sys_info.dict_end
- (unsigned long)sys_info.dict_start);
#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;
}