summaryrefslogtreecommitdiff
path: root/os/init/mpcinit.b
diff options
context:
space:
mode:
Diffstat (limited to 'os/init/mpcinit.b')
-rw-r--r--os/init/mpcinit.b383
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;
+}