xref: /inferno-os/os/init/mpcinit.b (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1implement Init;
2#
3# init program for Motorola 800 series (serial console only)
4#
5include "sys.m";
6	sys: Sys;
7
8include "draw.m";
9	draw: Draw;
10
11include "keyring.m";
12	kr: Keyring;
13
14include "security.m";
15	auth: Auth;
16
17Init: module
18{
19	init:	fn();
20};
21
22Shell: module
23{
24	init:	fn(ctxt: ref Draw->Context, argv: list of string);
25};
26
27Bootpreadlen: con 128;
28
29# option switches
30UseLocalFS: con 1<<0;
31EtherBoot: con 1<<1;
32Prompting: con 1<<3;
33
34lfs(): int
35{
36	if(!ftlinit("#F/flash/flash", 1024*1024, 1024*1024))
37		return -1;
38	if(mountkfs("#X/ftldata", "main", "flash") < 0)
39		return -1;
40	if(sys->bind("#Kmain", "/n/local", sys->MREPL) < 0){
41		sys->print("can't bind #Kmain to /n/local: %r\n");
42		return -1;
43	}
44	if(sys->bind("/n/local", "/", Sys->MCREATE|Sys->MREPL) < 0){
45		sys->print("can't bind /n/local after /: %r\n");
46		return -1;
47	}
48	return 0;
49}
50
51donebind := 0;
52
53#
54# set up network mount
55#
56netfs(mountpt: string): int
57{
58	sys->print("bootp ...");
59
60	fd: ref Sys->FD;
61	if(!donebind){
62		fd = sys->open("/net/ipifc/clone", sys->OWRITE);
63		if(fd == nil) {
64			sys->print("init: open /net/ipifc/clone: %r\n");
65			return -1;
66		}
67		if(sys->fprint(fd, "bind ether %s", "/net/ether0") < 0) {
68			sys->print("could not bind ether0 interface: %r\n");
69			return -1;
70		}
71		donebind = 1;
72	}else{
73		fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
74		if(fd == nil){
75			sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
76			return -1;
77		}
78	}
79	if(sys->fprint(fd, "bootp") < 0){
80		sys->print("init: bootp failed: %r\n");
81		return -1;
82	}
83
84	server := bootp();
85	if(server == nil)
86		return -1;
87
88	net := "tcp";	# how to specify il?
89	svcname := net + "!" + server + "!6666";
90
91	sys->print("dial %s...", svcname);
92
93	(ok, c) := sys->dial(svcname, nil);
94	if(ok < 0){
95		sys->print("can't dial %s: %r\n", svcname);
96		return -1;
97	}
98
99	sys->print("\nConnected ...\n");
100	if(kr != nil){
101		err: string;
102		sys->print("Authenticate ...");
103		ai := kr->readauthinfo("/nvfs/default");
104		if(ai == nil){
105			sys->print("readauthinfo /nvfs/default failed: %r\n");
106			sys->print("trying mount as `nobody'\n");
107		}
108		(c.dfd, err) = auth->client("none", ai, c.dfd);
109		if(c.dfd == nil){
110			sys->print("authentication failed: %s\n", err);
111			return -1;
112		}
113	}
114
115	sys->print("mount %s...", mountpt);
116
117	c.cfd = nil;
118	n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
119	if(n > 0)
120		return 0;
121	if(n < 0)
122		sys->print("%r");
123	return -1;
124}
125
126init()
127{
128	sys = load Sys Sys->PATH;
129	kr = load Keyring Keyring->PATH;
130	auth = load Auth Auth->PATH;
131	if(auth != nil)
132		auth->init();
133
134	sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
135
136	optsw := options();
137	sys->print("Switch options: 0x%ux\n", optsw);
138
139	#
140	# Setup what we need to call a server and
141	# Authenticate
142	#
143	sys->bind("#l", "/net", sys->MREPL);
144	sys->bind("#I", "/net", sys->MAFTER);
145	sys->bind("#c", "/dev", sys->MAFTER);
146
147	fsready := 0;
148	mountpt := "/";
149	usertc := 0;
150
151	if((optsw & Prompting) == 0){
152		if(optsw & UseLocalFS){
153			sys->print("Option: use local file system\n");
154			if(lfs() == 0){
155				fsready = 1;
156				mountpt = "/n/remote";
157			}
158		}
159
160		if(optsw & EtherBoot){
161			sys->print("Attempting remote mount\n");
162			if(netfs(mountpt) == 0)
163				fsready = 1;
164		}
165	}
166
167	if(fsready == 0){
168
169		sys->print("\n\n");
170
171		stdin := sys->fildes(0);
172		buf := array[128] of byte;
173		sources := "fs" :: "net" :: nil;
174
175		loop: for(;;) {
176			sys->print("root from (");
177			cm := "";
178			for(l := sources; l != nil; l = tl l){
179				sys->print("%s%s", cm, hd l);
180				cm = ",";
181			}
182			sys->print(")[%s] ", hd sources);
183
184			n := sys->read(stdin, buf, len buf);
185			if(n <= 0)
186				continue;
187			if(buf[n-1] == byte '\n')
188				n--;
189
190			(nil, choice) := sys->tokenize(string buf[0:n], "\t ");
191
192			if(choice == nil)
193				choice = sources;
194			opt := hd choice;
195			case opt {
196			* =>
197				sys->print("\ninvalid boot option: '%s'\n", opt);
198				break;
199			"fs" or "" =>
200				if(lfs() == 0){
201					usertc = 1;
202					break loop;
203				}
204			"net" =>
205				if(netfs("/") == 0)
206					break loop;
207			}
208		}
209	}
210
211	#
212	# default namespace
213	#
214	sys->unmount(nil, "/dev");
215	sys->bind("#c", "/dev", sys->MBEFORE);			# console
216	sys->bind("#l", "/net", sys->MBEFORE);		# ethernet
217	sys->bind("#I", "/net", sys->MBEFORE);		# TCP/IP
218	sys->bind("#p", "/prog", sys->MREPL);		# prog device
219	sys->bind("#d", "/fd", Sys->MREPL);
220
221	setsysname();
222
223	sys->print("clock...\n");
224	setclock(usertc, mountpt);
225
226	sys->print("Console...\n");
227
228	shell := load Shell "/dis/sh.dis";
229	if(shell == nil) {
230		sys->print("init: load /dis/sh.dis: %r");
231		exit;
232	}
233	dc: ref Draw->Context;
234	shell->init(dc, nil);
235}
236
237setclock(usertc: int, timedir: string)
238{
239	now := 0;
240	if(usertc){
241		fd := sys->open("#r/rtc", Sys->OREAD);
242		if(fd != nil){
243			b := array[64] of byte;
244			n := sys->read(fd, b, len b-1);
245			if(n > 0){
246				b[n] = byte 0;
247				now = int string b;
248				if(now <= 16r20000000)
249					now = 0;	# rtc itself is not initialised
250			}
251		}
252	}
253	if(now == 0){
254		(ok, dir) := sys->stat(timedir);
255		if (ok < 0) {
256			sys->print("init: stat %s: %r", timedir);
257			return;
258		}
259		now = dir.atime;
260	}
261	fd := sys->open("/dev/time", sys->OWRITE);
262	if (fd == nil) {
263		sys->print("init: can't open /dev/time: %r");
264		return;
265	}
266
267	# Time is kept as microsecs, atime is in secs
268	b := array of byte sys->sprint("%ud000000", now);
269	if (sys->write(fd, b, len b) != len b)
270		sys->print("init: can't write /dev/time: %r");
271}
272
273#
274# Set system name from nvram
275#
276setsysname()
277{
278	fd := sys->open("/nvfs/ID", sys->OREAD);
279	if(fd == nil)
280		return;
281	fds := sys->open("/dev/sysname", sys->OWRITE);
282	if(fds == nil)
283		return;
284	buf := array[128] of byte;
285	nr := sys->read(fd, buf, len buf);
286	if(nr <= 0)
287		return;
288	sys->write(fds, buf, nr);
289}
290
291#
292# fetch options from switch DS2
293#
294options(): int
295{
296	fd := sys->open("#r/switch", Sys->OREAD);
297	if(fd == nil){
298		sys->print("can't open #r/switch: %r\n");
299		return 0;
300	}
301	b := array[20] of byte;
302	n := sys->read(fd, b, len b);
303	s := string b[0:n];
304	return int s;
305}
306
307bootp(): string
308{
309	fd := sys->open("/net/bootp", sys->OREAD);
310	if(fd == nil) {
311		sys->print("init: can't open /net/bootp: %r");
312		return nil;
313	}
314
315	buf := array[Bootpreadlen] of byte;
316	nr := sys->read(fd, buf, len buf);
317	fd = nil;
318	if(nr <= 0) {
319		sys->print("init: read /net/bootp: %r");
320		return nil;
321	}
322
323	(ntok, ls) := sys->tokenize(string buf, " \t\n");
324	while(ls != nil) {
325		if(hd ls == "fsip"){
326			ls = tl ls;
327			break;
328		}
329		ls = tl ls;
330	}
331	if(ls == nil) {
332		sys->print("init: server address not in bootp read");
333		return nil;
334	}
335
336	srv := hd ls;
337
338	sys->print("%s\n", srv);
339
340	return srv;
341}
342
343#
344# set up flash translation layer
345#
346ftldone := 0;
347
348ftlinit(flashmem: string, offset: int, length: int): int
349{
350	if(ftldone)
351		return 1;
352	sys->print("Set flash translation of %s at offset %d (%d bytes)\n", flashmem, offset, length);
353	fd := sys->open("#X/ftlctl", Sys->OWRITE);
354	if(fd == nil){
355		sys->print("can't open #X/ftlctl: %r\n");
356		return 0;
357	}
358	if(sys->fprint(fd, "init %s %ud %ud", flashmem, offset, length) <= 0){
359		sys->print("can't init flash translation: %r");
360		return 0;
361	}
362	ftldone = 1;
363	return 1;
364}
365
366#
367# Mount kfs filesystem
368#
369mountkfs(devname: string, fsname: string, options: string): int
370{
371	fd := sys->open("#Kcons/kfsctl", sys->OWRITE);
372	if(fd == nil) {
373		sys->print("could not open #Kcons/kfsctl: %r\n");
374		return -1;
375	}
376	if(sys->fprint(fd, "filsys %s %s %s", fsname, devname, options) <= 0){
377		sys->print("could not write #Kcons/kfsctl: %r\n");
378		return -1;
379	}
380	if(options == "ro")
381		sys->fprint(fd, "cons flashwrite");
382	return 0;
383}
384