xref: /inferno-os/os/init/ipaqinit.b (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1#
2# ipaq
3#
4# TO DO: read params from params flash
5#
6
7implement Init;
8
9include "sys.m";
10	sys:	Sys;
11
12include "draw.m";
13
14include "keyring.m";
15	kr: Keyring;
16
17include "security.m";
18	auth: Auth;
19
20include "dhcp.m";
21	dhcpclient: Dhcpclient;
22	Bootconf: import dhcpclient;
23
24include "keyboard.m";
25
26include "sh.m";
27
28Init: module
29{
30	init:	fn();
31};
32
33Bootpreadlen: con 128;
34
35ethername := "ether0";
36
37# standard Inferno flash partitions
38
39flashparts := array[] of {
40	# bootstrap at 0x0 to 0x40000, don't touch
41	"add params 0x40000 0x80000",
42	"add kernel 0x80000 0x140000",
43	"add fs 0x140000 end",
44};
45
46#
47# initialise flash translation
48# mount flash file system
49# add devices
50# start a shell or window manager
51#
52
53init()
54{
55	sys = load Sys Sys->PATH;
56	kr = load Keyring Keyring->PATH;
57	auth = load Auth Auth->PATH;
58	if(auth != nil)
59		auth->init();
60
61	sys->bind("/", "/", Sys->MREPL);
62
63	lightup();
64
65	localok := 0;
66	if(lfs() >= 0){
67		# let's just take a closer look
68		sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
69		(rc, nil) := sys->stat("/n/local/dis/sh.dis");
70		if(rc >= 0)
71			localok = 1;
72		else
73			err("local file system unusable");
74	}
75	netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
76	if(!netok){
77		netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
78		if(netok)
79			ethername = "ether1";
80	}
81	if(netok)
82		configether();
83
84	dobind("#I", "/net", sys->MAFTER);	# IP
85	dobind("#p", "/prog", sys->MREPL);	# prog
86	dobind("#c", "/dev", sys->MREPL); 	# console
87	sys->bind("#d", "/fd", Sys->MREPL);
88	dobind("#t", "/dev", sys->MAFTER);	# serial line
89	dobind("#i", "/dev", sys->MAFTER); 	# draw
90	dobind("#m", "/dev", Sys->MAFTER);	# pointer
91	sys->bind("#e", "/env", sys->MREPL|sys->MCREATE);	# environment
92	sys->bind("#A", "/dev", Sys->MAFTER);	# optional audio
93	dobind("#T","/dev",sys->MAFTER);	# touch screen and other ipaq devices
94
95	timefile: string;
96	rootsource: string;
97	cfd := sys->open("/dev/consctl", Sys->OWRITE);
98	if(cfd != nil)
99		sys->fprint(cfd, "rawon");
100	for(;;){
101		(rootsource, timefile) = askrootsource(localok, netok);
102		if(rootsource == nil)
103			break;	# internal
104		(rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
105		if(rc < 0)
106			err("%s has no shell");
107		else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
108			sys->print("can't bind %s on /: %r\n", rootsource);
109		else{
110			sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
111			break;
112		}
113	}
114	cfd = nil;
115
116	setsysname("ipaq");			# set system name
117
118	now := getclock(timefile, rootsource);
119	setclock("/dev/time", now);
120	if(timefile != "#r/rtc")
121		setclock("#r/rtc", now/big 1000000);
122
123	sys->chdir("/");
124	if(netok){
125		start("ndb/dns", nil);
126		start("ndb/cs", nil);
127	}
128	calibrate();
129	startup := "/nvfs/startup";
130	if(sys->open(startup, Sys->OREAD) != nil){
131		shell := load Command Sh->PATH;
132		if(shell != nil){
133			sys->print("Running %s\n", startup);
134			shell->init(nil, "sh" :: startup :: nil);
135		}
136	}
137	user := rdenv("user", "inferno");
138	(ok, nil) := sys->stat("/dis/wm/wm.dis");
139	if(ok >= 0)
140		(ok, nil) = sys->stat("/dis/wm/logon.dis");
141	if(ok >= 0 && userok(user)){
142		wm := load Command "/dis/wm/wm.dis";
143		if(wm != nil){
144			fd := sys->open("/nvfs/user", Sys->OWRITE);
145			if(fd != nil){
146				sys->fprint(fd, "%s", user);
147				fd = nil;
148			}
149			spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-n", "lib/ipaqns", "-u", user});
150			exit;
151		}
152		sys->print("init: can't load wm/logon: %r");
153	}
154	sh := load Command Sh->PATH;
155	if(sh == nil){
156		err(sys->sprint("can't load %s: %r", Sh->PATH));
157		hang();
158	}
159	spawn sh->init(nil, "sh" :: nil);
160}
161
162start(cmd: string, args: list of string)
163{
164	disfile := cmd;
165	if(disfile[0] != '/')
166		disfile = "/dis/"+disfile+".dis";
167	(ok, nil) := sys->stat(disfile);
168	if(ok >= 0){
169		dis := load Command disfile;
170		if(dis == nil)
171			sys->print("init: can't load %s: %r\n", disfile);
172		else
173			spawn dis->init(nil, cmd :: args);
174	}
175}
176
177dobind(f, t: string, flags: int)
178{
179	if(sys->bind(f, t, flags) < 0)
180		err(sys->sprint("can't bind %s on %s: %r", f, t));
181}
182
183lightup()
184{
185	# backlight
186	fd := sys->open("#T/ipaqctl", Sys->OWRITE);
187	if(fd != nil)
188		sys->fprint(fd, "light 1 1 0x80");
189}
190
191#
192# Set system name from nvram if possible
193#
194setsysname(def: string)
195{
196	v := array of byte def;
197	fd := sys->open("/nvfs/ID", sys->OREAD);
198	if(fd == nil)
199		fd = sys->open("/env/sysname", sys->OREAD);
200	if(fd != nil){
201		buf := array[Sys->NAMEMAX] of byte;
202		nr := sys->read(fd, buf, len buf);
203		while(nr > 0 && buf[nr-1] == byte '\n')
204			nr--;
205		if(nr > 0)
206			v = buf[0:nr];
207	}
208	fd = sys->open("/dev/sysname", sys->OWRITE);
209	if(fd != nil)
210		sys->write(fd, v, len v);
211}
212
213getclock(timefile: string, timedir: string): big
214{
215	now := big 0;
216	if(timefile != nil){
217		fd := sys->open(timefile, Sys->OREAD);
218		if(fd != nil){
219			b := array[64] of byte;
220			n := sys->read(fd, b, len b-1);
221			if(n > 0){
222				now = big string b[0:n];
223				if(now <= big 16r20000000)
224					now = big 0;	# remote itself is not initialised
225			}
226		}
227	}
228	if(now == big 0){
229		if(timedir != nil){
230			(ok, dir) := sys->stat(timedir);
231			if(ok < 0) {
232				sys->print("init: stat %s: %r", timedir);
233				return big 0;
234			}
235			now = big dir.atime;
236		}else{
237			now = big 993826747000000;
238			sys->print("time warped\n");
239		}
240	}
241	return now;
242}
243
244setclock(timefile: string, now: big)
245{
246	fd := sys->open(timefile, sys->OWRITE);
247	if (fd == nil) {
248		sys->print("init: can't open %s: %r", timefile);
249		return;
250	}
251
252	b := sys->aprint("%ubd", now);
253	if (sys->write(fd, b, len b) != len b)
254		sys->print("init: can't write to %s: %r", timefile);
255}
256
257srv()
258{
259	sys->print("remote debug srv...");
260	fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
261	if(fd != nil)
262		sys->fprint(fd, "b115200");
263
264	fd = sys->open("/dev/eia0", Sys->ORDWR);
265	if (fd == nil){
266		err(sys->sprint("can't open /dev/eia0: %r"));
267		return;
268	}
269	if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
270		err(sys->sprint("can't export on serial port: %r"));
271		return;
272	}
273}
274
275err(s: string)
276{
277	sys->fprint(sys->fildes(2), "init: %s\n", s);
278}
279
280hang()
281{
282	<-(chan of int);
283}
284
285tried := 0;
286
287askrootsource(localok: int, netok: int): (string, string)
288{
289	stdin := sys->fildes(0);
290	sources := "kernel" :: nil;
291	if(netok)
292		sources = "remote" :: sources;
293	if(localok){
294		sources = "local" :: sources;
295		if(netok)
296			sources = "local+remote" :: sources;
297	}
298Query:
299	for(;;) {
300		s := "";
301		if (tried == 0 && (s = rdenv("rootsource", nil)) != nil) {
302			tried = 1;
303			if (s[len s - 1] == '\n')
304				s = s[:len s - 1];
305			sys->print("/nvfs/rootsource: root from %s\n", s);
306		} else {
307			sys->print("root from (");
308			cm := "";
309			for(l := sources; l != nil; l = tl l){
310				sys->print("%s%s", cm, hd l);
311				cm = ",";
312			}
313			sys->print(")[%s] ", hd sources);
314
315			s = getline(stdin, hd sources);	# default
316		}
317		case s[0] {
318		Keyboard->Right or Keyboard->Left =>
319			sources = append(hd sources, tl sources);
320			sys->print("\n");
321			continue Query;
322		Keyboard->Down =>
323			s = hd sources;
324			sys->print(" %s\n", s);
325		}
326		(nil, choice) := sys->tokenize(s, "\t ");
327		if(choice == nil)
328			choice = sources;
329		opt := hd choice;
330		case opt {
331		* =>
332			sys->print("\ninvalid boot option: '%s'\n", opt);
333		"kernel" =>
334			return (nil, "#r/rtc");
335		"local" =>
336			return ("/n/local", "#r/rtc");
337		"local+remote" =>
338			if(netfs("/n/remote") >= 0)
339				return ("/n/local", "/n/remote/dev/time");
340		"remote" =>
341			if(netfs("/n/remote") >= 0)
342				return ("/n/remote", "/n/remote/dev/time");
343		}
344	}
345}
346
347getline(fd: ref Sys->FD, default: string): string
348{
349	result := "";
350	buf := array[10] of byte;
351	i := 0;
352	for(;;) {
353		n := sys->read(fd, buf[i:], len buf - i);
354		if(n < 1)
355			break;
356		i += n;
357		while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
358			s := string buf[0:nutf];
359			for (j := 0; j < len s; j++)
360				case s[j] {
361				'\b' =>
362					if(result != nil)
363						result = result[0:len result-1];
364				'u'&16r1F =>
365					sys->print("^U\n");
366					result = "";
367				'\r' =>
368					;
369				* =>
370					sys->print("%c", s[j]);
371					if(s[j] == '\n' || s[j] >= 16r80){
372						if(s[j] != '\n')
373							result[len result] = s[j];
374						if(result == nil)
375							return default;
376						return result;
377					}
378					result[len result] = s[j];
379				}
380			buf[0:] = buf[nutf:i];
381			i -= nutf;
382		}
383	}
384	return default;
385}
386
387append(v: string, l: list of string): list of string
388{
389	if(l == nil)
390		return v :: nil;
391	return hd l :: append(v, tl l);
392}
393
394#
395# serve local DOS or kfs file system using flash translation layer
396#
397lfs(): int
398{
399	if(!flashpart("#F/flash/flashctl", flashparts))
400		return -1;
401	if(!ftlinit("#F/flash/fs"))
402		return -1;
403	if(iskfs("#X/ftldata"))
404		return lkfs("#X/ftldata");
405	c := chan of string;
406	spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil, nil);
407	if(<-c != nil)
408		return -1;
409	return 0;
410}
411
412wmagic := "kfs wren device\n";
413
414iskfs(file: string): int
415{
416	fd := sys->open(file, Sys->OREAD);
417	if(fd == nil)
418		return 0;
419	buf := array[512] of byte;
420	n := sys->read(fd, buf, len buf);
421	if(n < len buf)
422		return 0;
423	if(string buf[256:256+len wmagic] != wmagic)
424		return 0;
425	RBUFSIZE := int string buf[256+len wmagic:256+len wmagic+12];
426	if(RBUFSIZE % 512)
427		return 0;	# bad block size
428	return 1;
429}
430
431lkfs(file: string): int
432{
433	p := array[2] of ref Sys->FD;
434	if(sys->pipe(p) < 0)
435		return -1;
436	c := chan of string;
437	spawn startfs(c, "/dis/disk/kfs.dis", "disk/kfs" :: "-A" :: "-n" :: "main" :: file :: nil, p[0]);
438	if(<-c != nil)
439		return -1;
440	p[0] = nil;
441	return sys->mount(p[1], nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil);
442}
443
444startfs(c: chan of string, file: string, args: list of string, fd: ref Sys->FD)
445{
446	if(fd != nil){
447		sys->pctl(Sys->NEWFD, fd.fd :: 1 :: 2 :: nil);
448		sys->dup(fd.fd, 0);
449	}
450	fs := load Command file;
451	if(fs == nil){
452		sys->print("can't load %s: %r\n", file);
453		c <-= "load failed";
454	}
455	{
456		fs->init(nil, args);
457		c <-= nil;
458	}exception {
459	"*" =>
460		c <-= "failed";
461	* =>
462		c <-= "unknown exception";
463	}
464}
465
466#
467# partition flash
468#
469flashdone := 0;
470
471flashpart(ctl: string, parts: array of string): int
472{
473	if(flashdone)
474		return 1;
475	cfd := sys->open(ctl, Sys->ORDWR);
476	if(cfd == nil){
477		sys->print("can't open %s: %r\n", ctl);
478		return 0;
479	}
480	for(i := 0; i < len parts; i++)
481		if(sys->fprint(cfd, "%s", parts[i]) < 0){
482			sys->print("can't %q to %s: %r\n", parts[i], ctl);
483			return 0;
484		}
485	flashdone = 1;
486	return 1;
487}
488
489#
490# set up flash translation layer
491#
492ftldone := 0;
493
494ftlinit(flashmem: string): int
495{
496	if(ftldone)
497		return 1;
498	sys->print("Set flash translation of %s...\n", flashmem);
499	fd := sys->open("#X/ftlctl", Sys->OWRITE);
500	if(fd == nil){
501		sys->print("can't open #X/ftlctl: %r\n");
502		return 0;
503	}
504	if(sys->fprint(fd, "init %s", flashmem) <= 0){
505		sys->print("can't init flash translation: %r\n");
506		return 0;
507	}
508	ftldone = 1;
509	return 1;
510}
511
512configether()
513{
514	if(ethername == nil)
515		return;
516	fd := sys->open("/nvfs/etherparams", Sys->OREAD);
517	if(fd == nil)
518		return;
519	ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
520	if(ctl == nil){
521		sys->print("init: can't open %s's clone: %r\n", ethername);
522		return;
523	}
524	b := array[1024] of byte;
525	n := sys->read(fd, b, len b);
526	if(n <= 0)
527		return;
528	for(i := 0; i < n;){
529		for(e := i; e < n && b[e] != byte '\n'; e++)
530			;
531		s := string b[i:e];
532		if(sys->fprint(ctl, "%s", s) < 0)
533			sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
534		i = e+1;
535	}
536}
537
538donebind := 0;
539
540#
541# set up network mount
542#
543netfs(mountpt: string): int
544{
545	fd: ref Sys->FD;
546	if(!donebind){
547		fd = sys->open("/net/ipifc/clone", sys->OWRITE);
548		if(fd == nil) {
549			sys->print("init: open /net/ipifc/clone: %r\n");
550			return -1;
551		}
552		if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
553			sys->print("could not bind ether0 interface: %r\n");
554			return -1;
555		}
556		donebind = 1;
557	}else{
558		fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
559		if(fd == nil){
560			sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
561			return -1;
562		}
563	}
564	server := rdenv("fsip", nil);
565	if((ip := rdenv("ip", nil)) != nil) {
566		sys->print("**using %s\n", ip);
567		sys->fprint(fd, "bind ether /net/ether0");
568		sys->fprint(fd, "add %s ", ip);
569		if((ipgw := rdenv("ipgw", nil)) != nil){
570			rfd := sys->open("/net/iproute", Sys->OWRITE);
571			if(rfd != nil){
572				sys->fprint(rfd, "add 0 0 %s", ipgw);
573				sys->print("**using ipgw=%s\n", ipgw);
574			}
575		}
576	}else if(server == nil){
577		sys->print("dhcp...");
578		dhcpclient = load Dhcpclient Dhcpclient->PATH;
579		if(dhcpclient == nil){
580			sys->print("can't load dhcpclient: %r\n");
581			return -1;
582		}
583		dhcpclient->init();
584		(cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil);
585		if(e != nil){
586			sys->print("dhcp: %s\n", e);
587			return -1;
588		}
589		if(server == nil)
590			server = cfg.getip(Dhcpclient->OP9fs);
591		dhcpclient = nil;
592	}
593	if(server == nil || server == "0.0.0.0"){
594		sys->print("no file server address\n");
595		return -1;
596	}
597	sys->print("fs=%s\n", server);
598
599	net := "tcp";	# how to specify il?
600	svcname := net + "!" + server + "!6666";
601
602	sys->print("dial %s...", svcname);
603
604	(ok, c) := sys->dial(svcname, nil);
605	if(ok < 0){
606		sys->print("can't dial %s: %r\n", svcname);
607		return -1;
608	}
609
610	sys->print("\nConnected ...\n");
611	if(kr != nil){
612		err: string;
613		sys->print("Authenticate ...");
614		ai := kr->readauthinfo("/nvfs/default");
615		if(ai == nil){
616			sys->print("readauthinfo /nvfs/default failed: %r\n");
617			sys->print("trying mount as `nobody'\n");
618		}
619		(c.dfd, err) = auth->client("none", ai, c.dfd);
620		if(c.dfd == nil){
621			sys->print("authentication failed: %s\n", err);
622			return -1;
623		}
624	}
625
626	sys->print("mount %s...", mountpt);
627
628	c.cfd = nil;
629	n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
630	if(n > 0)
631		return 0;
632	if(n < 0)
633		sys->print("%r");
634	return -1;
635}
636
637calibrate()
638{
639	val := rf("/nvfs/calibrate", nil);
640	if(val != nil){
641		fd := sys->open("/dev/touchctl", Sys->OWRITE);
642		if(fd != nil && sys->fprint(fd, "%s", val) >= 0)
643			return;
644	}
645	done := chan of int;
646	spawn docal(done);
647	<-done;
648}
649
650docal(done: chan of int)
651{
652	sys->pctl(Sys->FORKFD, nil);
653	ofd := sys->create("/nvfs/calibrate", Sys->OWRITE, 8r644);
654	if(ofd != nil)
655		sys->dup(ofd.fd, 1);
656	cal := load Command "/dis/touchcal.dis";
657	if(cal != nil){
658		{
659			cal->init(nil, "touchcal" :: nil);
660		}exception{
661		"fail:*" =>
662			;
663		}
664	}
665	done <-= 1;
666}
667
668userok(user: string): int
669{
670	(ok, d) := sys->stat("/usr/"+user);
671	return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
672}
673
674rdenv(name: string, def: string): string
675{
676	s := rf("#e/"+name, nil);
677	if(s != nil)
678		return s;
679	s = rf("/nvfs/"+name, def);
680	while(s != nil && ((c := s[len s-1]) == '\n' || c == '\r'))
681		s = s[0: len s-1];
682	if(s != nil)
683		return s;
684	return def;
685}
686
687rf(file: string, default: string): string
688{
689	fd := sys->open(file, Sys->OREAD);
690	if(fd != nil){
691		buf := array[128] of byte;
692		nr := sys->read(fd, buf, len buf);
693		if(nr > 0)
694			return string buf[0:nr];
695	}
696	return default;
697}
698