diff options
Diffstat (limited to 'os/init/mpcinit.b')
| -rw-r--r-- | os/init/mpcinit.b | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/os/init/mpcinit.b b/os/init/mpcinit.b new file mode 100644 index 00000000..bef89fa2 --- /dev/null +++ b/os/init/mpcinit.b @@ -0,0 +1,383 @@ +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; +} |
