xref: /inferno-os/os/pc/main.c (revision a60fa48ce2f27a689f276bea9538b5db2b74ff86)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"ureg.h"
8 
9 extern int main_pool_pcnt;
10 extern int heap_pool_pcnt;
11 extern int image_pool_pcnt;
12 int	pckdebug;
13 
14 Mach *m;
15 
16 static  uchar *sp;	/* stack pointer for /boot */
17 
18 /*
19  * Where configuration info is left for the loaded programme.
20  * This will turn into a structure as more is done by the boot loader
21  * (e.g. why parse the .ini file twice?).
22  * There are 3584 bytes available at CONFADDR.
23  */
24 #define BOOTLINE	((char*)CONFADDR)
25 #define BOOTLINELEN	64
26 #define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
27 #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
28 #define	MAXCONF		64
29 
30 char bootdisk[KNAMELEN];
31 char *confname[MAXCONF];
32 char *confval[MAXCONF];
33 int nconf;
34 
35 static void
36 options(void)
37 {
38 	long i, n;
39 	char *cp, *line[MAXCONF], *p, *q;
40 
41 	/*
42 	 *  parse configuration args from dos file plan9.ini
43 	 */
44 	cp = BOOTARGS;	/* where b.com leaves its config */
45 	cp[BOOTARGSLEN-1] = 0;
46 
47 	/*
48 	 * Strip out '\r', change '\t' -> ' '.
49 	 */
50 	p = cp;
51 	for(q = cp; *q; q++){
52 		if(*q == '\r')
53 			continue;
54 		if(*q == '\t')
55 			*q = ' ';
56 		*p++ = *q;
57 	}
58 	*p = 0;
59 
60 	n = getfields(cp, line, MAXCONF, 1, "\n");
61 	for(i = 0; i < n; i++){
62 		if(*line[i] == '#')
63 			continue;
64 		cp = strchr(line[i], '=');
65 		if(cp == nil)
66 			continue;
67 		*cp++ = '\0';
68 		confname[nconf] = line[i];
69 		confval[nconf] = cp;
70 		nconf++;
71 	}
72 }
73 
74 static void
75 doc(char *m)
76 {
77 	int i;
78 	print("%s...\n", m);
79 	for(i = 0; i < 100*1024*1024; i++)
80 		i++;
81 }
82 
83 void
84 main(void)
85 {
86 	outb(0x3F2, 0x00);			/* botch: turn off the floppy motor */
87 
88 	mach0init();
89 	options();
90 	ioinit();
91 	i8250console();
92 	quotefmtinstall();
93 	kbdinit();
94 	i8253init();
95 	cpuidentify();
96 	confinit();
97 	archinit();
98 	xinit();
99 	poolsizeinit();
100 	trapinit();
101 	printinit();
102 	screeninit();
103 	cpuidprint();
104 	mmuinit();
105 	eve = strdup("inferno");
106 	if(arch->intrinit){	/* launches other processors on an mp */
107 		doc("intrinit");
108 		arch->intrinit();
109 	}
110 	doc("timersinit");
111 	timersinit();
112 	doc("mathinit");
113 	mathinit();
114 	doc("kbdenable");
115 	kbdenable();
116 	if(arch->clockenable){
117 		doc("clockinit");
118 		arch->clockenable();
119 	}
120 	doc("procinit");
121 	procinit();
122 	doc("links");
123 	links();
124 	doc("chandevreset");
125 	chandevreset();
126 	doc("userinit");
127 	userinit();
128 	doc("schedinit");
129 	active.thunderbirdsarego = 1;
130 	schedinit();
131 
132 }
133 
134 void
135 mach0init(void)
136 {
137 	conf.nmach = 1;
138 	MACHP(0) = (Mach*)CPU0MACH;
139 	m->pdb = (ulong*)CPU0PDB;
140 	m->gdt = (Segdesc*)CPU0GDT;
141 
142 	machinit();
143 
144 	active.machs = 1;
145 	active.exiting = 0;
146 }
147 
148 void
149 machinit(void)
150 {
151 	int machno;
152 	ulong *pdb;
153 	Segdesc *gdt;
154 
155 	machno = m->machno;
156 	pdb = m->pdb;
157 	gdt = m->gdt;
158 	memset(m, 0, sizeof(Mach));
159 	m->machno = machno;
160 	m->pdb = pdb;
161 	m->gdt = gdt;
162 
163 	/*
164 	 * For polled uart output at boot, need
165 	 * a default delay constant. 100000 should
166 	 * be enough for a while. Cpuidentify will
167 	 * calculate the real value later.
168 	 */
169 	m->loopconst = 100000;
170 }
171 
172 void
173 init0(void)
174 {
175 	Osenv *o;
176 	int i;
177 	char buf[2*KNAMELEN];
178 
179 	up->nerrlab = 0;
180 
181 	spllo();
182 	if(waserror())
183 		panic("init0: %r");
184 	/*
185 	 * These are o.k. because rootinit is null.
186 	 * Then early kproc's will have a root and dot.
187 	 */
188 	o = up->env;
189 	o->pgrp->slash = namec("#/", Atodir, 0, 0);
190 	cnameclose(o->pgrp->slash->name);
191 	o->pgrp->slash->name = newcname("/");
192 	o->pgrp->dot = cclone(o->pgrp->slash);
193 
194 	chandevinit();
195 
196 	if(!waserror()){
197 		ksetenv("cputype", "386", 0);
198 		snprint(buf, sizeof(buf), "386 %s", conffile);
199 		ksetenv("terminal", buf, 0);
200 		for(i = 0; i < nconf; i++){
201 			if(confname[i][0] != '*')
202 				ksetenv(confname[i], confval[i], 0);
203 			ksetenv(confname[i], confval[i], 1);
204 		}
205 		poperror();
206 	}
207 
208 	poperror();
209 
210 	disinit("/osinit.dis");
211 }
212 
213 void
214 userinit(void)
215 {
216 	Proc *p;
217 	Osenv *o;
218 
219 	p = newproc();
220 	o = p->env;
221 
222 	o->fgrp = newfgrp(nil);
223 
224 	o->pgrp = newpgrp();
225 	kstrdup(&o->user, eve);
226 
227 	strcpy(p->text, "interp");
228 
229 	p->fpstate = FPINIT;
230 	fpoff();
231 
232 	/*
233 	 * Kernel Stack
234 	 *
235 	 * N.B. make sure there's
236 	 *	4 bytes for gotolabel's return PC
237 	 */
238 	p->sched.pc = (ulong)init0;
239 	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
240 
241 	ready(p);
242 }
243 
244 Conf	conf;
245 
246 char*
247 getconf(char *name)
248 {
249 	int i;
250 
251 	for(i = 0; i < nconf; i++)
252 		if(cistrcmp(confname[i], name) == 0)
253 			return confval[i];
254 	return 0;
255 }
256 
257 void
258 confinit(void)
259 {
260 	char *p;
261 	int pcnt;
262 	ulong maxmem;
263 
264 	if(p = getconf("*maxmem"))
265 		maxmem = strtoul(p, 0, 0);
266 	else
267 		maxmem = 0;
268 	if(p = getconf("*kernelpercent"))
269 		pcnt = 100 - strtol(p, 0, 0);
270 	else
271 		pcnt = 0;
272 
273 	meminit(maxmem);
274 
275 	conf.npage = conf.npage0 + conf.npage1;
276 	if(pcnt < 10)
277 		pcnt = 70;
278 	conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG;
279 
280 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
281 }
282 
283 void
284 poolsizeinit(void)
285 {
286 	ulong nb;
287 
288 	nb = conf.npage*BY2PG;
289 	poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
290 	poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
291 	poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
292 }
293 
294 static char *mathmsg[] =
295 {
296 	"invalid operation",
297 	"denormalized operand",
298 	"division by zero",
299 	"numeric overflow",
300 	"numeric underflow",
301 	"precision loss",
302 	"stack",
303 	"error",
304 };
305 
306 /*
307  *  math coprocessor error
308  */
309 void
310 matherror(Ureg* ureg, void* arg)
311 {
312 	ulong status;
313 	int i;
314 	char *msg;
315 	char note[ERRMAX];
316 
317 	USED(arg);
318 
319 	/*
320 	 *  a write cycle to port 0xF0 clears the interrupt latch attached
321 	 *  to the error# line from the 387
322 	 */
323 	if(!(m->cpuiddx & 0x01))
324 		outb(0xF0, 0xFF);
325 
326 	/*
327 	 *  save floating point state to check out error
328 	 */
329 	FPsave(&up->fpsave.env);
330 	status = up->fpsave.env.status;
331 
332 	msg = 0;
333 	for(i = 0; i < 8; i++)
334 		if((1<<i) & status){
335 			msg = mathmsg[i];
336 			sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->fpsave.env.pc);
337 			error(note);
338 			break;
339 		}
340 	if(msg == 0){
341 		sprint(note, "sys: fp: unknown fppc=0x%lux", up->fpsave.env.pc);
342 		error(note);
343 	}
344 	if(ureg->pc & KZERO)
345 		panic("fp: status %lux fppc=0x%lux pc=0x%lux", status,
346 			up->fpsave.env.pc, ureg->pc);
347 }
348 
349 /*
350  *  math coprocessor emulation fault
351  */
352 void
353 mathemu(Ureg* ureg, void* arg)
354 {
355 	USED(ureg, arg);
356 	switch(up->fpstate){
357 	case FPINIT:
358 		fpinit();
359 		up->fpstate = FPACTIVE;
360 		break;
361 	case FPINACTIVE:
362 		fprestore(&up->fpsave);
363 		up->fpstate = FPACTIVE;
364 		break;
365 	case FPACTIVE:
366 		panic("math emu");
367 		break;
368 	}
369 }
370 
371 /*
372  *  math coprocessor segment overrun
373  */
374 void
375 mathover(Ureg* ureg, void* arg)
376 {
377 	USED(arg);
378 	print("sys: fp: math overrun pc 0x%lux pid %ld\n", ureg->pc, up->pid);
379 	pexit("math overrun", 0);
380 }
381 
382 void
383 mathinit(void)
384 {
385 	trapenable(VectorCERR, matherror, 0, "matherror");
386 	if(X86FAMILY(m->cpuidax) == 3)
387 		intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
388 	trapenable(VectorCNA, mathemu, 0, "mathemu");
389 	trapenable(VectorCSO, mathover, 0, "mathover");
390 }
391 
392 /*
393  *  Save the mach dependent part of the process state.
394  */
395 void
396 procsave(Proc *p)
397 {
398 	if(p->fpstate == FPACTIVE){
399 		if(p->state == Moribund)
400 			fpoff();
401 		else
402 			fpsave(&up->fpsave);
403 		p->fpstate = FPINACTIVE;
404 	}
405 }
406 
407 void
408 exit(int ispanic)
409 {
410 	USED(ispanic);
411 
412 	up = 0;
413 	print("exiting\n");
414 
415 	/* Shutdown running devices */
416 	chandevshutdown();
417 
418 	arch->reset();
419 }
420 
421 void
422 reboot(void)
423 {
424 	exit(0);
425 }
426 
427 int
428 isaconfig(char *class, int ctlrno, ISAConf *isa)
429 {
430 	char cc[32], *p;
431 	int i;
432 
433 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
434 	p = getconf(cc);
435 	if(p == nil)
436 		return 0;
437 
438 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
439 	for(i = 0; i < isa->nopt; i++){
440 		p = isa->opt[i];
441 		if(cistrncmp(p, "type=", 5) == 0)
442 			isa->type = p + 5;
443 		else if(cistrncmp(p, "port=", 5) == 0)
444 			isa->port = strtoul(p+5, &p, 0);
445 		else if(cistrncmp(p, "irq=", 4) == 0)
446 			isa->irq = strtoul(p+4, &p, 0);
447 		else if(cistrncmp(p, "dma=", 4) == 0)
448 			isa->dma = strtoul(p+4, &p, 0);
449 		else if(cistrncmp(p, "mem=", 4) == 0)
450 			isa->mem = strtoul(p+4, &p, 0);
451 		else if(cistrncmp(p, "size=", 5) == 0)
452 			isa->size = strtoul(p+5, &p, 0);
453 		else if(cistrncmp(p, "freq=", 5) == 0)
454 			isa->freq = strtoul(p+5, &p, 0);
455 	}
456 	return 1;
457 }
458 
459 /*
460  *  put the processor in the halt state if we've no processes to run.
461  *  an interrupt will get us going again.
462  */
463 void
464 idlehands(void)
465 {
466 	if(conf.nmach == 1)
467 		halt();
468 }
469