mirror of
https://gitlab.com/qemu-project/openbios.git
synced 2024-02-13 08:34:06 +08:00
git-svn-id: svn://coreboot.org/openbios/openbios-devel@270 f158a5a8-5612-0410-a976-696ce0be7e32
938 lines
21 KiB
C
938 lines
21 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 "asm/types.h"
|
|
#include "dict.h"
|
|
#include "openbios/kernel.h"
|
|
#include "openbios/stack.h"
|
|
#include "openbios/nvram.h"
|
|
#include "sys_info.h"
|
|
#include "openbios.h"
|
|
#include "openbios/pci.h"
|
|
#include "asm/pci.h"
|
|
#include "libc/byteorder.h"
|
|
#define cpu_to_be16(x) __cpu_to_be16(x)
|
|
#include "openbios/firmware_abi.h"
|
|
#include "boot.h"
|
|
#include "../../drivers/timer.h" // XXX
|
|
#include "asi.h"
|
|
#include "spitfire.h"
|
|
#include "libc/vsprintf.h"
|
|
#define NO_QEMU_PROTOS
|
|
#include "openbios/fw_cfg.h"
|
|
|
|
#define BIOS_CFG_CMD 0x510
|
|
#define BIOS_CFG_DATA 0x511
|
|
|
|
#define APB_SPECIAL_BASE 0x1fe00000000ULL
|
|
#define PCI_CONFIG (APB_SPECIAL_BASE + 0x1000000ULL)
|
|
#define APB_MEM_BASE 0x1ff00000000ULL
|
|
|
|
static unsigned char intdict[256 * 1024];
|
|
|
|
// XXX
|
|
#define NVRAM_SIZE 0x2000
|
|
#define NVRAM_IDPROM 0x1fd0
|
|
#define NVRAM_OB_START (sizeof(ohwcfg_v3_t) + sizeof(struct sparc_arch_cfg))
|
|
#define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
|
|
|
|
ohwcfg_v3_t nv_info;
|
|
|
|
#define OBIO_CMDLINE_MAX 256
|
|
static char obio_cmdline[OBIO_CMDLINE_MAX];
|
|
|
|
static uint8_t idprom[32];
|
|
|
|
struct hwdef {
|
|
pci_arch_t pci;
|
|
uint8_t machine_id_low, machine_id_high;
|
|
};
|
|
|
|
static const struct hwdef hwdefs[] = {
|
|
{
|
|
.pci.cfg_addr = PCI_CONFIG,
|
|
.pci.cfg_data = 0,
|
|
.pci.cfg_base = 0x80000000ULL,
|
|
.pci.cfg_len = 0,
|
|
.pci.mem_base = 0,
|
|
.pci.mem_len = 0,
|
|
.pci.io_base = 0,
|
|
.pci.io_len = 0,
|
|
.machine_id_low = 0,
|
|
.machine_id_high = 255,
|
|
},
|
|
};
|
|
|
|
struct cpudef {
|
|
unsigned long iu_version;
|
|
const char *name;
|
|
};
|
|
|
|
#define PAGE_SIZE_4M (4 * 1024 * 1024)
|
|
#define PAGE_SIZE_512K (512 * 1024)
|
|
#define PAGE_SIZE_64K (64 * 1024)
|
|
#define PAGE_SIZE_8K (8 * 1024)
|
|
#define PAGE_MASK_4M (4 * 1024 * 1024 - 1)
|
|
#define PAGE_MASK_512K (512 * 1024 - 1)
|
|
#define PAGE_MASK_64K (64 * 1024 - 1)
|
|
#define PAGE_MASK_8K (8 * 1024 - 1)
|
|
|
|
#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
|
|
|
static void
|
|
mmu_open(void)
|
|
{
|
|
RET(-1);
|
|
}
|
|
|
|
static void
|
|
mmu_close(void)
|
|
{
|
|
}
|
|
|
|
static int
|
|
spitfire_translate(unsigned long virt, unsigned long *p_phys,
|
|
unsigned long *p_data, unsigned long *p_size)
|
|
{
|
|
unsigned long phys, tag, data, mask, size;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
data = spitfire_get_dtlb_data(i);
|
|
if (data & 0x8000000000000000) { // Valid entry?
|
|
switch ((data >> 61) & 3) {
|
|
default:
|
|
case 0x0: // 8k
|
|
mask = 0xffffffffffffe000ULL;
|
|
size = PAGE_SIZE_8K;
|
|
break;
|
|
case 0x1: // 64k
|
|
mask = 0xffffffffffff0000ULL;
|
|
size = PAGE_SIZE_64K;
|
|
break;
|
|
case 0x2: // 512k
|
|
mask = 0xfffffffffff80000ULL;
|
|
size = PAGE_SIZE_512K;
|
|
break;
|
|
case 0x3: // 4M
|
|
mask = 0xffffffffffc00000ULL;
|
|
size = PAGE_SIZE_4M;
|
|
break;
|
|
}
|
|
tag = spitfire_get_dtlb_tag(i);
|
|
if ((virt & mask) == (tag & mask)) {
|
|
phys = data & mask & 0x000001fffffff000;
|
|
phys |= virt & ~mask;
|
|
*p_phys = phys;
|
|
*p_data = data & 0xfff;
|
|
*p_size = size;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
3.6.5 translate
|
|
( virt -- false | phys.lo ... phys.hi mode true )
|
|
*/
|
|
static void
|
|
mmu_translate(void)
|
|
{
|
|
unsigned long virt, phys, data, size;
|
|
|
|
virt = POP();
|
|
|
|
if (spitfire_translate(virt, &phys, &data, &size)) {
|
|
PUSH(phys & 0xffffffff);
|
|
PUSH(phys >> 32);
|
|
PUSH(data);
|
|
PUSH(-1);
|
|
return;
|
|
}
|
|
PUSH(0);
|
|
}
|
|
|
|
static void
|
|
dtlb_load2(unsigned long vaddr, unsigned long tte_data)
|
|
{
|
|
asm("stxa %0, [%1] %2\n"
|
|
"stxa %3, [%%g0] %4\n"
|
|
: : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
|
|
"r" (tte_data), "i" (ASI_DTLB_DATA_IN));
|
|
}
|
|
|
|
static void
|
|
dtlb_load3(unsigned long vaddr, unsigned long tte_data,
|
|
unsigned long tte_index)
|
|
{
|
|
asm("stxa %0, [%1] %2\n"
|
|
"stxa %3, [%4] %5\n"
|
|
: : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
|
|
"r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS));
|
|
}
|
|
|
|
/*
|
|
( index tte_data vaddr -- ? )
|
|
*/
|
|
static void
|
|
dtlb_load(void)
|
|
{
|
|
unsigned long vaddr, tte_data, idx;
|
|
|
|
vaddr = POP();
|
|
tte_data = POP();
|
|
idx = POP();
|
|
dtlb_load3(vaddr, tte_data, idx);
|
|
}
|
|
|
|
static void
|
|
itlb_load2(unsigned long vaddr, unsigned long tte_data)
|
|
{
|
|
asm("stxa %0, [%1] %2\n"
|
|
"stxa %3, [%%g0] %4\n"
|
|
: : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
|
|
"r" (tte_data), "i" (ASI_ITLB_DATA_IN));
|
|
}
|
|
|
|
static void
|
|
itlb_load3(unsigned long vaddr, unsigned long tte_data,
|
|
unsigned long tte_index)
|
|
{
|
|
asm("stxa %0, [%1] %2\n"
|
|
"stxa %3, [%4] %5\n"
|
|
: : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
|
|
"r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS));
|
|
}
|
|
|
|
/*
|
|
( index tte_data vaddr -- ? )
|
|
*/
|
|
static void
|
|
itlb_load(void)
|
|
{
|
|
unsigned long vaddr, tte_data, idx;
|
|
|
|
vaddr = POP();
|
|
tte_data = POP();
|
|
idx = POP();
|
|
itlb_load3(vaddr, tte_data, idx);
|
|
}
|
|
|
|
static void
|
|
map_pages(unsigned long virt, unsigned long size, unsigned long phys)
|
|
{
|
|
unsigned long tte_data, currsize;
|
|
|
|
size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
|
|
while (size >= PAGE_SIZE_8K) {
|
|
currsize = size;
|
|
if (currsize >= PAGE_SIZE_4M &&
|
|
(virt & PAGE_MASK_4M) == 0 &&
|
|
(phys & PAGE_MASK_4M) == 0) {
|
|
currsize = PAGE_SIZE_4M;
|
|
tte_data = 6ULL << 60;
|
|
} else if (currsize >= PAGE_SIZE_512K &&
|
|
(virt & PAGE_MASK_512K) == 0 &&
|
|
(phys & PAGE_MASK_512K) == 0) {
|
|
currsize = PAGE_SIZE_512K;
|
|
tte_data = 4ULL << 60;
|
|
} else if (currsize >= PAGE_SIZE_64K &&
|
|
(virt & PAGE_MASK_64K) == 0 &&
|
|
(phys & PAGE_MASK_64K) == 0) {
|
|
currsize = PAGE_SIZE_64K;
|
|
tte_data = 2ULL << 60;
|
|
} else {
|
|
currsize = PAGE_SIZE_8K;
|
|
tte_data = 0;
|
|
}
|
|
tte_data |= phys | 0x8000000000000036ULL;
|
|
dtlb_load2(virt, tte_data);
|
|
itlb_load2(virt, tte_data);
|
|
size -= currsize;
|
|
phys += currsize;
|
|
virt += currsize;
|
|
}
|
|
}
|
|
|
|
/*
|
|
3.6.5 map
|
|
( phys.lo ... phys.hi virt size mode -- )
|
|
*/
|
|
static void
|
|
mmu_map(void)
|
|
{
|
|
unsigned long virt, size, mode, phys;
|
|
|
|
mode = POP();
|
|
size = POP();
|
|
virt = POP();
|
|
phys = POP();
|
|
phys <<= 32;
|
|
phys |= POP();
|
|
map_pages(virt, size, phys);
|
|
}
|
|
|
|
static void
|
|
itlb_demap(unsigned long vaddr)
|
|
{
|
|
asm("stxa %0, [%0] %1\n"
|
|
: : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
|
|
}
|
|
|
|
static void
|
|
dtlb_demap(unsigned long vaddr)
|
|
{
|
|
asm("stxa %0, [%0] %1\n"
|
|
: : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
|
|
}
|
|
|
|
static void
|
|
unmap_pages(unsigned long virt, unsigned long size)
|
|
{
|
|
unsigned long phys, data;
|
|
|
|
unsigned long tte_data, currsize;
|
|
|
|
// align size
|
|
size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
|
|
|
|
while (spitfire_translate(virt, &phys, &data, &currsize)) {
|
|
|
|
itlb_demap(virt & ~0x1fffULL);
|
|
dtlb_demap(virt & ~0x1fffULL);
|
|
|
|
size -= currsize;
|
|
virt += currsize;
|
|
}
|
|
}
|
|
|
|
/*
|
|
3.6.5 unmap
|
|
( virt size -- )
|
|
*/
|
|
static void
|
|
mmu_unmap(void)
|
|
{
|
|
unsigned long virt, size;
|
|
|
|
size = POP();
|
|
virt = POP();
|
|
unmap_pages(virt, size);
|
|
}
|
|
|
|
/*
|
|
3.6.5 claim
|
|
( virt size align -- base )
|
|
*/
|
|
static void
|
|
mmu_claim(void)
|
|
{
|
|
unsigned long virt, size, align;
|
|
|
|
align = POP();
|
|
size = POP();
|
|
virt = POP();
|
|
PUSH(virt); // XXX
|
|
}
|
|
|
|
/*
|
|
3.6.5 release
|
|
( virt size -- )
|
|
*/
|
|
static void
|
|
mmu_release(void)
|
|
{
|
|
unsigned long virt, size;
|
|
|
|
size = POP();
|
|
virt = POP();
|
|
// XXX
|
|
}
|
|
|
|
DECLARE_UNNAMED_NODE(mmu, INSTALL_OPEN, 0);
|
|
|
|
NODE_METHODS(mmu) = {
|
|
{ "open", mmu_open },
|
|
{ "close", mmu_close },
|
|
{ "translate", mmu_translate },
|
|
{ "SUNW,dtlb-load", dtlb_load },
|
|
{ "SUNW,itlb-load", itlb_load },
|
|
{ "map", mmu_map },
|
|
{ "unmap", mmu_unmap },
|
|
{ "claim", mmu_claim },
|
|
{ "release", mmu_release },
|
|
};
|
|
|
|
/*
|
|
( 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)
|
|
{
|
|
unsigned long iu_version;
|
|
char nodebuff[256];
|
|
|
|
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(1);
|
|
fword("encode-int");
|
|
push_str("cpuid");
|
|
fword("property");
|
|
|
|
fword("finish-device");
|
|
|
|
// MMU node
|
|
sprintf(nodebuff, "/%s", cpu->name);
|
|
push_str(nodebuff);
|
|
fword("find-device");
|
|
|
|
fword("new-device");
|
|
|
|
push_str("mmu");
|
|
fword("device-name");
|
|
|
|
fword("finish-device");
|
|
|
|
sprintf(nodebuff, "/%s/mmu", cpu->name);
|
|
|
|
REGISTER_NODE_METHODS(mmu, nodebuff);
|
|
|
|
push_str("/chosen");
|
|
fword("find-device");
|
|
|
|
push_str(nodebuff);
|
|
fword("open-dev");
|
|
fword("encode-int");
|
|
push_str("mmu");
|
|
fword("property");
|
|
|
|
// 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 qemu_uuid[16];
|
|
|
|
void arch_nvram_get(char *data)
|
|
{
|
|
unsigned short i;
|
|
unsigned char *nvptr = (unsigned char *)&nv_info;
|
|
uint32_t size;
|
|
const struct cpudef *cpu;
|
|
const char *bootpath;
|
|
char buf[256];
|
|
uint32_t temp;
|
|
uint64_t ram_size;
|
|
|
|
for (i = 0; i < sizeof(ohwcfg_v3_t); i++) {
|
|
outb(i & 0xff, 0x74);
|
|
outb(i >> 8, 0x75);
|
|
*nvptr++ = inb(0x77);
|
|
}
|
|
|
|
outw(__cpu_to_le16(FW_CFG_SIGNATURE), BIOS_CFG_CMD);
|
|
for (i = 0; i < 4; i++)
|
|
buf[i] = inb(BIOS_CFG_DATA);
|
|
|
|
buf[4] = '\0';
|
|
|
|
printk("Configuration device id %s", buf);
|
|
|
|
outw(__cpu_to_le16(FW_CFG_ID), BIOS_CFG_CMD);
|
|
for (i = 0; i < 4; i++)
|
|
buf[i] = inb(BIOS_CFG_DATA);
|
|
|
|
temp = __le32_to_cpu(*(uint32_t *)buf);
|
|
printk(" version %d\n", temp);
|
|
|
|
kernel_image = nv_info.kernel_image;
|
|
kernel_size = nv_info.kernel_size;
|
|
size = nv_info.cmdline_size;
|
|
if (size > OBIO_CMDLINE_MAX - 1)
|
|
size = OBIO_CMDLINE_MAX - 1;
|
|
memcpy(&obio_cmdline, (void *)(long)nv_info.cmdline, size);
|
|
obio_cmdline[size] = '\0';
|
|
qemu_cmdline = (uint64_t)obio_cmdline;
|
|
cmdline_size = size;
|
|
boot_device = nv_info.boot_devices[0];
|
|
|
|
printk("kernel addr %lx size %lx\n", kernel_image, kernel_size);
|
|
if (size)
|
|
printk("kernel cmdline %s\n", obio_cmdline);
|
|
|
|
for (i = 0; i < NVRAM_OB_SIZE; i++) {
|
|
outb((i + NVRAM_OB_START) & 0xff, 0x74);
|
|
outb((i + NVRAM_OB_START) >> 8, 0x75);
|
|
data[i] = inb(0x77);
|
|
}
|
|
|
|
outw(__cpu_to_le16(FW_CFG_NB_CPUS), BIOS_CFG_CMD);
|
|
for (i = 0; i < 4; i++)
|
|
buf[i] = inb(BIOS_CFG_DATA);
|
|
|
|
temp = __le32_to_cpu(*(uint32_t *)buf);
|
|
|
|
printk("CPUs: %x", temp);
|
|
|
|
cpu = id_cpu();
|
|
//cpu->initfn();
|
|
cpu_generic_init(cpu);
|
|
printk(" x %s\n", cpu->name);
|
|
|
|
// Add /uuid
|
|
outw(__cpu_to_le16(FW_CFG_UUID), BIOS_CFG_CMD);
|
|
for (i = 0; i < 16; i++)
|
|
qemu_uuid[i] = inb(BIOS_CFG_DATA);
|
|
|
|
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
|
|
for (i = 0; i < 32; i++) {
|
|
outb((i + 0x1fd8) & 0xff, 0x74);
|
|
outb((i + 0x1fd8) >> 8, 0x75);
|
|
idprom[i] = inb(0x77);
|
|
}
|
|
|
|
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");
|
|
|
|
push_str("/memory");
|
|
fword("find-device");
|
|
|
|
outw(__cpu_to_le16(FW_CFG_RAM_SIZE), BIOS_CFG_CMD);
|
|
for (i = 0; i < 8; i++)
|
|
buf[i] = inb(BIOS_CFG_DATA);
|
|
|
|
ram_size = __le64_to_cpu(*(uint64_t *)buf);
|
|
|
|
// All memory: 0 to RAM_size
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((int)(ram_size >> 32));
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((int)(ram_size & 0xffffffff));
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
push_str("reg");
|
|
fword("property");
|
|
|
|
// Available memory: 0 to va2pa(_start)
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((va2pa((unsigned long)&_data) - 8192) >> 32);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((va2pa((unsigned long)&_data) - 8192) & 0xffffffff);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
push_str("available");
|
|
fword("property");
|
|
|
|
// XXX
|
|
// Translations
|
|
push_str("/virtual-memory");
|
|
fword("find-device");
|
|
|
|
// 0 to 16M: 1:1
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(16 * 1024 * 1024);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x80000000);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x00000036);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
|
|
// _start to _data: ROM used
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((unsigned long)&_start);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((unsigned long)&_data - (unsigned long)&_start);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x800001ff);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0xf0000074);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
|
|
// _data to _end: end of RAM
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((unsigned long)&_data);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH((unsigned long)&_data - (unsigned long)&_start);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(((va2pa((unsigned long)&_data) - 8192) >> 32) | 0x80000000);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(((va2pa((unsigned long)&_data) - 8192) & 0xffffffff) | 0x36);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
|
|
// VGA buffer (128k): 1:1
|
|
PUSH(0x1ff);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x004a0000);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(128 * 1024);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x800001ff);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
PUSH(0x004a0076);
|
|
fword("encode-int");
|
|
fword("encode+");
|
|
|
|
push_str("translations");
|
|
fword("property");
|
|
|
|
push_str("/chosen");
|
|
fword("find-device");
|
|
|
|
if (nv_info.boot_devices[0] == 'c')
|
|
bootpath = "/pci/isa/ide0/disk@0,0:a";
|
|
else
|
|
bootpath = "/pci/isa/ide1/cdrom@0,0:a";
|
|
push_str(bootpath);
|
|
fword("encode-string");
|
|
push_str("bootpath");
|
|
fword("property");
|
|
|
|
push_str(obio_cmdline);
|
|
fword("encode-string");
|
|
push_str("bootargs");
|
|
fword("property");
|
|
}
|
|
|
|
void arch_nvram_put(char *data)
|
|
{
|
|
unsigned short i;
|
|
|
|
for (i = 0; i < NVRAM_OB_SIZE; i++) {
|
|
outb((i + NVRAM_OB_START) & 0xff, 0x74);
|
|
outb((i + NVRAM_OB_START) >> 8, 0x75);
|
|
outb(data[i], 0x77);
|
|
}
|
|
}
|
|
|
|
int arch_nvram_size(void)
|
|
{
|
|
return NVRAM_OB_SIZE;
|
|
}
|
|
|
|
void setup_timers(void)
|
|
{
|
|
}
|
|
|
|
void udelay(unsigned int usecs)
|
|
{
|
|
}
|
|
|
|
static void init_memory(void)
|
|
{
|
|
|
|
/* push start and end of available memory to the stack
|
|
* so that the forth word QUIT can initialize memory
|
|
* management. For now we use hardcoded memory between
|
|
* 0x10000 and 0x9ffff (576k). If we need more memory
|
|
* than that we have serious bloat.
|
|
*/
|
|
|
|
PUSH((ucell)&_heap);
|
|
PUSH((ucell)&_eheap);
|
|
}
|
|
|
|
static void
|
|
arch_init( void )
|
|
{
|
|
unsigned int i;
|
|
uint8_t qemu_machine_type;
|
|
const struct hwdef *hwdef;
|
|
|
|
outw(__cpu_to_le16(FW_CFG_MACHINE_ID), BIOS_CFG_CMD);
|
|
qemu_machine_type = inb(BIOS_CFG_DATA);
|
|
|
|
for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
|
|
if (hwdefs[i].machine_id_low <= qemu_machine_type &&
|
|
hwdefs[i].machine_id_high >= qemu_machine_type) {
|
|
hwdef = &hwdefs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!hwdef)
|
|
for(;;); // Internal inconsistency, hang
|
|
|
|
modules_init();
|
|
#ifdef CONFIG_DRIVER_PCI
|
|
//ob_pci_init();
|
|
#endif
|
|
#ifdef CONFIG_DRIVER_IDE
|
|
setup_timers();
|
|
ob_ide_init();
|
|
#endif
|
|
#ifdef CONFIG_DRIVER_FLOPPY
|
|
ob_floppy_init();
|
|
#endif
|
|
#ifdef CONFIG_DEBUG_CONSOLE_VIDEO
|
|
init_video();
|
|
#endif
|
|
|
|
nvconf_init();
|
|
ob_su_init(0x1fe02000000ULL, 0x3f8ULL, 0);
|
|
|
|
device_end();
|
|
|
|
bind_func("platform-boot", boot );
|
|
printk("\n"); // XXX needed for boot, why?
|
|
}
|
|
|
|
int openbios(void)
|
|
{
|
|
#ifdef CONFIG_DEBUG_CONSOLE
|
|
#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
|
|
uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
|
|
#endif
|
|
#ifdef CONFIG_DEBUG_CONSOLE_VGA
|
|
video_init();
|
|
#endif
|
|
/* Clear the screen. */
|
|
cls();
|
|
printk("OpenBIOS for Sparc64\n");
|
|
#endif
|
|
|
|
collect_sys_info(&sys_info);
|
|
|
|
dict=intdict;
|
|
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");
|
|
return 0;
|
|
}
|