209 lines
5.8 KiB
C
209 lines
5.8 KiB
C
|
/*
|
||
|
*
|
||
|
*/
|
||
|
#undef BOOTSTRAP
|
||
|
#include "config.h"
|
||
|
#include "libopenbios/bindings.h"
|
||
|
#include "arch/common/nvram.h"
|
||
|
#include "drivers/drivers.h"
|
||
|
#include "libc/diskio.h"
|
||
|
#include "libc/vsprintf.h"
|
||
|
#include "libopenbios/initprogram.h"
|
||
|
#include "libopenbios/ofmem.h"
|
||
|
#include "libopenbios/sys_info.h"
|
||
|
#include "openprom.h"
|
||
|
#include "boot.h"
|
||
|
#include "context.h"
|
||
|
|
||
|
uint32_t kernel_image;
|
||
|
uint32_t kernel_size;
|
||
|
uint32_t initrd_image;
|
||
|
uint32_t initrd_size;
|
||
|
uint32_t qemu_cmdline;
|
||
|
uint32_t cmdline_size;
|
||
|
char boot_device;
|
||
|
const void *romvec;
|
||
|
|
||
|
static struct linux_mlist_v0 *totphyslist, *availlist, *prommaplist;
|
||
|
|
||
|
void setup_romvec(void)
|
||
|
{
|
||
|
/* SPARC32 is slightly unusual in that before invoking any loaders, a romvec array
|
||
|
needs to be set up to pass certain parameters using a C struct. Hence this function
|
||
|
extracts the relevant boot information and places it in obp_arg. */
|
||
|
|
||
|
int intprop, proplen, target, device, i;
|
||
|
unsigned int *intprop_ptr;
|
||
|
phandle_t chosen;
|
||
|
char *prop, *id, *name;
|
||
|
static char bootpathbuf[128], bootargsbuf[128], buf[128];
|
||
|
struct linux_mlist_v0 **pp;
|
||
|
|
||
|
/* Get the stdin and stdout paths */
|
||
|
chosen = find_dev("/chosen");
|
||
|
intprop = get_int_property(chosen, "stdin", &proplen);
|
||
|
PUSH(intprop);
|
||
|
fword("get-instance-path");
|
||
|
((struct linux_romvec *)romvec)->pv_stdin = pop_fstr_copy();
|
||
|
|
||
|
intprop = get_int_property(chosen, "stdout", &proplen);
|
||
|
PUSH(intprop);
|
||
|
fword("get-instance-path");
|
||
|
((struct linux_romvec *)romvec)->pv_stdout = pop_fstr_copy();
|
||
|
|
||
|
/* Get the name of the selected boot device, along with the device and unit number */
|
||
|
prop = get_property(chosen, "bootpath", &proplen);
|
||
|
strncpy(bootpathbuf, prop, proplen);
|
||
|
prop = get_property(chosen, "bootargs", &proplen);
|
||
|
strncpy(bootargsbuf, prop, proplen);
|
||
|
|
||
|
/* Set bootpath pointer used in romvec table to the bootpath */
|
||
|
push_str(bootpathbuf);
|
||
|
fword("pathres-resolve-aliases");
|
||
|
bootpath = pop_fstr_copy();
|
||
|
printk("bootpath: %s\n", bootpath);
|
||
|
|
||
|
/* Now do some work to get hold of the target, partition etc. */
|
||
|
push_str(bootpathbuf);
|
||
|
feval("open-dev");
|
||
|
feval("ihandle>boot-device-handle drop to my-self");
|
||
|
push_str("name");
|
||
|
fword("get-my-property");
|
||
|
POP();
|
||
|
name = pop_fstr_copy();
|
||
|
|
||
|
if (!strncmp(name, "sd", 2)) {
|
||
|
|
||
|
/*
|
||
|
Old-style SunOS disk paths are given in the form:
|
||
|
|
||
|
sd(c,t,d):s
|
||
|
|
||
|
where:
|
||
|
c = controller (Nth controller in system, usually 0)
|
||
|
t = target (my-unit phys.hi)
|
||
|
d = device/LUN (my-unit phys.lo)
|
||
|
s = slice/partition (my-args)
|
||
|
*/
|
||
|
|
||
|
/* Controller currently always 0 */
|
||
|
obp_arg.boot_dev_ctrl = 0;
|
||
|
|
||
|
/* Get the target, device and slice */
|
||
|
fword("my-unit");
|
||
|
target = POP();
|
||
|
device = POP();
|
||
|
|
||
|
fword("my-args");
|
||
|
id = pop_fstr_copy();
|
||
|
|
||
|
if (id != NULL) {
|
||
|
snprintf(buf, sizeof(buf), "sd(0,%d,%d):%c", target, device, id[0]);
|
||
|
obp_arg.dev_partition = id[0] - 'a';
|
||
|
} else {
|
||
|
snprintf(buf, sizeof(buf), "sd(0,%d,%d)", target, device);
|
||
|
obp_arg.dev_partition = 0;
|
||
|
}
|
||
|
|
||
|
obp_arg.boot_dev_unit = target;
|
||
|
|
||
|
obp_arg.boot_dev[0] = buf[0];
|
||
|
obp_arg.boot_dev[1] = buf[1];
|
||
|
obp_arg.argv[0] = buf;
|
||
|
obp_arg.argv[1] = bootargsbuf;
|
||
|
|
||
|
} else if (!strncmp(name, "SUNW,fdtwo", 10)) {
|
||
|
|
||
|
obp_arg.boot_dev_ctrl = 0;
|
||
|
obp_arg.boot_dev_unit = 0;
|
||
|
obp_arg.dev_partition = 0;
|
||
|
|
||
|
strcpy(buf, "fd()");
|
||
|
|
||
|
obp_arg.boot_dev[0] = buf[0];
|
||
|
obp_arg.boot_dev[1] = buf[1];
|
||
|
obp_arg.argv[0] = buf;
|
||
|
obp_arg.argv[1] = bootargsbuf;
|
||
|
|
||
|
} else if (!strncmp(name, "le", 2)) {
|
||
|
|
||
|
obp_arg.boot_dev_ctrl = 0;
|
||
|
obp_arg.boot_dev_unit = 0;
|
||
|
obp_arg.dev_partition = 0;
|
||
|
|
||
|
strcpy(buf, "le()");
|
||
|
|
||
|
obp_arg.boot_dev[0] = buf[0];
|
||
|
obp_arg.boot_dev[1] = buf[1];
|
||
|
obp_arg.argv[0] = buf;
|
||
|
obp_arg.argv[1] = bootargsbuf;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Generate the totphys (total memory available) list */
|
||
|
prop = get_property(s_phandle_memory, "reg", &proplen);
|
||
|
intprop_ptr = (unsigned int *)prop;
|
||
|
|
||
|
for (pp = &totphyslist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) {
|
||
|
*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0));
|
||
|
(**pp).theres_more = NULL;
|
||
|
(**pp).start_adr = (char *)intprop_ptr[1];
|
||
|
(**pp).num_bytes = intprop_ptr[2];
|
||
|
|
||
|
intprop_ptr += 3;
|
||
|
}
|
||
|
|
||
|
/* Generate the avail (physical memory available) list */
|
||
|
prop = get_property(s_phandle_memory, "available", &proplen);
|
||
|
intprop_ptr = (unsigned int *)prop;
|
||
|
|
||
|
for (pp = &availlist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) {
|
||
|
*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0));
|
||
|
(**pp).theres_more = NULL;
|
||
|
(**pp).start_adr = (char *)intprop_ptr[1];
|
||
|
(**pp).num_bytes = intprop_ptr[2];
|
||
|
|
||
|
intprop_ptr += 3;
|
||
|
}
|
||
|
|
||
|
/* Generate the prommap (taken virtual memory) list from inverse of available */
|
||
|
prop = get_property(s_phandle_mmu, "available", &proplen);
|
||
|
intprop_ptr = (unsigned int *)prop;
|
||
|
|
||
|
for (pp = &prommaplist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) {
|
||
|
*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0));
|
||
|
(**pp).theres_more = NULL;
|
||
|
(**pp).start_adr = (char *)(intprop_ptr[1] + intprop_ptr[2]);
|
||
|
|
||
|
if (i + 3 < (proplen / sizeof(int))) {
|
||
|
/* Size from next entry */
|
||
|
(**pp).num_bytes = (intprop_ptr[4] + intprop_ptr[5]) - (intprop_ptr[1] + intprop_ptr[2]);
|
||
|
} else {
|
||
|
/* Tail (size from top of virtual memory) */
|
||
|
(**pp).num_bytes = ofmem_arch_get_virt_top() - 1 - (intprop_ptr[1] + intprop_ptr[2]) + 1;
|
||
|
}
|
||
|
|
||
|
intprop_ptr += 3;
|
||
|
}
|
||
|
|
||
|
/* Finally set the memory properties */
|
||
|
((struct linux_romvec *)romvec)->pv_v0mem.v0_totphys = &totphyslist;
|
||
|
((struct linux_romvec *)romvec)->pv_v0mem.v0_available = &availlist;
|
||
|
((struct linux_romvec *)romvec)->pv_v0mem.v0_prommap = &prommaplist;
|
||
|
}
|
||
|
|
||
|
|
||
|
void boot(void)
|
||
|
{
|
||
|
/* Boot preloaded kernel */
|
||
|
if (kernel_size) {
|
||
|
printk("[sparc] Kernel already loaded\n");
|
||
|
|
||
|
PUSH(kernel_image);
|
||
|
feval("load-state >ls.entry !");
|
||
|
|
||
|
arch_init_program();
|
||
|
start_elf();
|
||
|
}
|
||
|
}
|