ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /os/init/mpcinit.b/
implement Init;
#
# init program for Motorola 800 series (serial console only)
#
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
include "keyring.m";
kr: Keyring;
include "security.m";
auth: Auth;
Init: module
{
init: fn();
};
Shell: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
Bootpreadlen: con 128;
# option switches
UseLocalFS: con 1<<0;
EtherBoot: con 1<<1;
Prompting: con 1<<3;
lfs(): int
{
if(!ftlinit("#F/flash/flash", 1024*1024, 1024*1024))
return -1;
if(mountkfs("#X/ftldata", "main", "flash") < 0)
return -1;
if(sys->bind("#Kmain", "/n/local", sys->MREPL) < 0){
sys->print("can't bind #Kmain to /n/local: %r\n");
return -1;
}
if(sys->bind("/n/local", "/", Sys->MCREATE|Sys->MREPL) < 0){
sys->print("can't bind /n/local after /: %r\n");
return -1;
}
return 0;
}
donebind := 0;
#
# set up network mount
#
netfs(mountpt: string): int
{
sys->print("bootp ...");
fd: ref Sys->FD;
if(!donebind){
fd = sys->open("/net/ipifc/clone", sys->OWRITE);
if(fd == nil) {
sys->print("init: open /net/ipifc/clone: %r\n");
return -1;
}
if(sys->fprint(fd, "bind ether %s", "/net/ether0") < 0) {
sys->print("could not bind ether0 interface: %r\n");
return -1;
}
donebind = 1;
}else{
fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
if(fd == nil){
sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
return -1;
}
}
if(sys->fprint(fd, "bootp") < 0){
sys->print("init: bootp failed: %r\n");
return -1;
}
server := bootp();
if(server == nil)
return -1;
net := "tcp"; # how to specify il?
svcname := net + "!" + server + "!6666";
sys->print("dial %s...", svcname);
(ok, c) := sys->dial(svcname, nil);
if(ok < 0){
sys->print("can't dial %s: %r\n", svcname);
return -1;
}
sys->print("\nConnected ...\n");
if(kr != nil){
err: string;
sys->print("Authenticate ...");
ai := kr->readauthinfo("/nvfs/default");
if(ai == nil){
sys->print("readauthinfo /nvfs/default failed: %r\n");
sys->print("trying mount as `nobody'\n");
}
(c.dfd, err) = auth->client("none", ai, c.dfd);
if(c.dfd == nil){
sys->print("authentication failed: %s\n", err);
return -1;
}
}
sys->print("mount %s...", mountpt);
c.cfd = nil;
n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
if(n > 0)
return 0;
if(n < 0)
sys->print("%r");
return -1;
}
init()
{
sys = load Sys Sys->PATH;
kr = load Keyring Keyring->PATH;
auth = load Auth Auth->PATH;
if(auth != nil)
auth->init();
sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
optsw := options();
sys->print("Switch options: 0x%ux\n", optsw);
#
# Setup what we need to call a server and
# Authenticate
#
sys->bind("#l", "/net", sys->MREPL);
sys->bind("#I", "/net", sys->MAFTER);
sys->bind("#c", "/dev", sys->MAFTER);
fsready := 0;
mountpt := "/";
usertc := 0;
if((optsw & Prompting) == 0){
if(optsw & UseLocalFS){
sys->print("Option: use local file system\n");
if(lfs() == 0){
fsready = 1;
mountpt = "/n/remote";
}
}
if(optsw & EtherBoot){
sys->print("Attempting remote mount\n");
if(netfs(mountpt) == 0)
fsready = 1;
}
}
if(fsready == 0){
sys->print("\n\n");
stdin := sys->fildes(0);
buf := array[128] of byte;
sources := "fs" :: "net" :: nil;
loop: for(;;) {
sys->print("root from (");
cm := "";
for(l := sources; l != nil; l = tl l){
sys->print("%s%s", cm, hd l);
cm = ",";
}
sys->print(")[%s] ", hd sources);
n := sys->read(stdin, buf, len buf);
if(n <= 0)
continue;
if(buf[n-1] == byte '\n')
n--;
(nil, choice) := sys->tokenize(string buf[0:n], "\t ");
if(choice == nil)
choice = sources;
opt := hd choice;
case opt {
* =>
sys->print("\ninvalid boot option: '%s'\n", opt);
break;
"fs" or "" =>
if(lfs() == 0){
usertc = 1;
break loop;
}
"net" =>
if(netfs("/") == 0)
break loop;
}
}
}
#
# default namespace
#
sys->unmount(nil, "/dev");
sys->bind("#c", "/dev", sys->MBEFORE); # console
sys->bind("#l", "/net", sys->MBEFORE); # ethernet
sys->bind("#I", "/net", sys->MBEFORE); # TCP/IP
sys->bind("#p", "/prog", sys->MREPL); # prog device
sys->bind("#d", "/fd", Sys->MREPL);
setsysname();
sys->print("clock...\n");
setclock(usertc, mountpt);
sys->print("Console...\n");
shell := load Shell "/dis/sh.dis";
if(shell == nil) {
sys->print("init: load /dis/sh.dis: %r");
exit;
}
dc: ref Draw->Context;
shell->init(dc, nil);
}
setclock(usertc: int, timedir: string)
{
now := 0;
if(usertc){
fd := sys->open("#r/rtc", Sys->OREAD);
if(fd != nil){
b := array[64] of byte;
n := sys->read(fd, b, len b-1);
if(n > 0){
b[n] = byte 0;
now = int string b;
if(now <= 16r20000000)
now = 0; # rtc itself is not initialised
}
}
}
if(now == 0){
(ok, dir) := sys->stat(timedir);
if (ok < 0) {
sys->print("init: stat %s: %r", timedir);
return;
}
now = dir.atime;
}
fd := sys->open("/dev/time", sys->OWRITE);
if (fd == nil) {
sys->print("init: can't open /dev/time: %r");
return;
}
# Time is kept as microsecs, atime is in secs
b := array of byte sys->sprint("%ud000000", now);
if (sys->write(fd, b, len b) != len b)
sys->print("init: can't write /dev/time: %r");
}
#
# Set system name from nvram
#
setsysname()
{
fd := sys->open("/nvfs/ID", sys->OREAD);
if(fd == nil)
return;
fds := sys->open("/dev/sysname", sys->OWRITE);
if(fds == nil)
return;
buf := array[128] of byte;
nr := sys->read(fd, buf, len buf);
if(nr <= 0)
return;
sys->write(fds, buf, nr);
}
#
# fetch options from switch DS2
#
options(): int
{
fd := sys->open("#r/switch", Sys->OREAD);
if(fd == nil){
sys->print("can't open #r/switch: %r\n");
return 0;
}
b := array[20] of byte;
n := sys->read(fd, b, len b);
s := string b[0:n];
return int s;
}
bootp(): string
{
fd := sys->open("/net/bootp", sys->OREAD);
if(fd == nil) {
sys->print("init: can't open /net/bootp: %r");
return nil;
}
buf := array[Bootpreadlen] of byte;
nr := sys->read(fd, buf, len buf);
fd = nil;
if(nr <= 0) {
sys->print("init: read /net/bootp: %r");
return nil;
}
(ntok, ls) := sys->tokenize(string buf, " \t\n");
while(ls != nil) {
if(hd ls == "fsip"){
ls = tl ls;
break;
}
ls = tl ls;
}
if(ls == nil) {
sys->print("init: server address not in bootp read");
return nil;
}
srv := hd ls;
sys->print("%s\n", srv);
return srv;
}
#
# set up flash translation layer
#
ftldone := 0;
ftlinit(flashmem: string, offset: int, length: int): int
{
if(ftldone)
return 1;
sys->print("Set flash translation of %s at offset %d (%d bytes)\n", flashmem, offset, length);
fd := sys->open("#X/ftlctl", Sys->OWRITE);
if(fd == nil){
sys->print("can't open #X/ftlctl: %r\n");
return 0;
}
if(sys->fprint(fd, "init %s %ud %ud", flashmem, offset, length) <= 0){
sys->print("can't init flash translation: %r");
return 0;
}
ftldone = 1;
return 1;
}
#
# Mount kfs filesystem
#
mountkfs(devname: string, fsname: string, options: string): int
{
fd := sys->open("#Kcons/kfsctl", sys->OWRITE);
if(fd == nil) {
sys->print("could not open #Kcons/kfsctl: %r\n");
return -1;
}
if(sys->fprint(fd, "filsys %s %s %s", fsname, devname, options) <= 0){
sys->print("could not write #Kcons/kfsctl: %r\n");
return -1;
}
if(options == "ro")
sys->fprint(fd, "cons flashwrite");
return 0;
}