Files
openbios/arch/sparc64/openbios.c
Blue Swirl 3038a07be7 Fix fake CPU ID value (Igor Kovalenko)
Small correction: cpuid property of qemu cpu should be "0" for the
linux kernel to boot on qemu. This is because kernel is reading cpu
registers to find out current smp processor ID and it happens to find
out "0" cpuid because corresponding register is zeroed by qemu.
Currently kernel fails since there is no "0" cpu node in tree.


git-svn-id: svn://coreboot.org/openbios/openbios-devel@283 f158a5a8-5612-0410-a976-696ce0be7e32
2008-12-11 17:10:03 +00:00

936 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,
.cfg_data = 0,
.cfg_base = 0x80000000ULL,
.cfg_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(0);
fword("encode-int");
push_str("cpuid");
fword("property");
fword("finish-device");
// MMU node
snprintf(nodebuff, sizeof(nodebuff), "/%s", cpu->name);
push_str(nodebuff);
fword("find-device");
fword("new-device");
push_str("mmu");
fword("device-name");
fword("finish-device");
snprintf(nodebuff, sizeof(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 %llx size %llx\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;
}