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
options(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
doc(char * m)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
main(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
mach0init(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
machinit(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
init0(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
userinit(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*
getconf(char * name)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
confinit(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
poolsizeinit(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
matherror(Ureg * ureg,void * arg)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
mathemu(Ureg * ureg,void * arg)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
mathover(Ureg * ureg,void * arg)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
mathinit(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
procsave(Proc * p)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
exit(int ispanic)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
reboot(void)422 reboot(void)
423 {
424 exit(0);
425 }
426
427 int
isaconfig(char * class,int ctlrno,ISAConf * isa)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
idlehands(void)464 idlehands(void)
465 {
466 if(conf.nmach == 1)
467 halt();
468 }
469