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