1 #include "u.h" 2 #include "tos.h" 3 #include "../port/lib.h" 4 #include "mem.h" 5 #include "dat.h" 6 #include "fns.h" 7 8 #include "init.h" 9 #include <pool.h> 10 11 #include "reboot.h" 12 13 /* Firmware compatibility */ 14 #define Minfirmrev 326770 15 #define Minfirmdate "22 Jul 2012" 16 17 /* 18 * Where configuration info is left for the loaded programme. 19 */ 20 #define BOOTARGS ((char*)CONFADDR) 21 #define BOOTARGSLEN (MACHADDR-CONFADDR) 22 #define MAXCONF 64 23 #define MAXCONFLINE 160 24 25 uintptr kseg0 = KZERO; 26 Mach* machaddr[MAXMACH]; 27 Conf conf; 28 ulong memsize = 128*1024*1024; 29 30 /* 31 * Option arguments from the command line. 32 * oargv[0] is the boot file. 33 */ 34 static int oargc; 35 static char* oargv[20]; 36 static char oargb[128]; 37 static int oargblen; 38 39 static uintptr sp; /* XXX - must go - user stack of init proc */ 40 41 /* store plan9.ini contents here at least until we stash them in #ec */ 42 static char confname[MAXCONF][KNAMELEN]; 43 static char confval[MAXCONF][MAXCONFLINE]; 44 static int nconf; 45 46 typedef struct Atag Atag; 47 struct Atag { 48 u32int size; /* size of atag in words, including this header */ 49 u32int tag; /* atag type */ 50 union { 51 u32int data[1]; /* actually [size-2] */ 52 /* AtagMem */ 53 struct { 54 u32int size; 55 u32int base; 56 } mem; 57 /* AtagCmdLine */ 58 char cmdline[1]; /* actually [4*(size-2)] */ 59 }; 60 }; 61 62 enum { 63 AtagNone = 0x00000000, 64 AtagCore = 0x54410001, 65 AtagMem = 0x54410002, 66 AtagCmdline = 0x54410009, 67 }; 68 69 static int 70 findconf(char *name) 71 { 72 int i; 73 74 for(i = 0; i < nconf; i++) 75 if(cistrcmp(confname[i], name) == 0) 76 return i; 77 return -1; 78 } 79 80 char* 81 getconf(char *name) 82 { 83 int i; 84 85 i = findconf(name); 86 if(i >= 0) 87 return confval[i]; 88 return nil; 89 } 90 91 void 92 addconf(char *name, char *val) 93 { 94 int i; 95 96 i = findconf(name); 97 if(i < 0){ 98 if(val == nil || nconf >= MAXCONF) 99 return; 100 i = nconf++; 101 strecpy(confname[i], confname[i]+sizeof(confname[i]), name); 102 } 103 strecpy(confval[i], confval[i]+sizeof(confval[i]), val); 104 } 105 106 static void 107 writeconf(void) 108 { 109 char *p, *q; 110 int n; 111 112 p = getconfenv(); 113 114 if(waserror()) { 115 free(p); 116 nexterror(); 117 } 118 119 /* convert to name=value\n format */ 120 for(q=p; *q; q++) { 121 q += strlen(q); 122 *q = '='; 123 q += strlen(q); 124 *q = '\n'; 125 } 126 n = q - p + 1; 127 if(n >= BOOTARGSLEN) 128 error("kernel configuration too large"); 129 memmove(BOOTARGS, p, n); 130 memset(BOOTARGS + n, '\n', BOOTARGSLEN - n); 131 poperror(); 132 free(p); 133 } 134 135 static void 136 plan9iniinit(char *s, int cmdline) 137 { 138 char *toks[MAXCONF]; 139 int i, c, n; 140 char *v; 141 142 if((c = *s) < ' ' || c >= 0x80) 143 return; 144 if(cmdline) 145 n = tokenize(s, toks, MAXCONF); 146 else 147 n = getfields(s, toks, MAXCONF, 1, "\n"); 148 for(i = 0; i < n; i++){ 149 if(toks[i][0] == '#') 150 continue; 151 v = strchr(toks[i], '='); 152 if(v == nil) 153 continue; 154 *v++ = '\0'; 155 addconf(toks[i], v); 156 } 157 } 158 159 static void 160 ataginit(Atag *a) 161 { 162 int n; 163 164 if(a->tag != AtagCore){ 165 plan9iniinit((char*)a, 0); 166 return; 167 } 168 while(a->tag != AtagNone){ 169 switch(a->tag){ 170 case AtagMem: 171 /* use only first bank */ 172 if(conf.mem[0].limit == 0 && a->mem.size != 0){ 173 memsize = a->mem.size; 174 conf.mem[0].base = a->mem.base; 175 conf.mem[0].limit = a->mem.base + memsize; 176 } 177 break; 178 case AtagCmdline: 179 n = (a->size * sizeof(u32int)) - offsetof(Atag, cmdline[0]); 180 if(a->cmdline + n < BOOTARGS + BOOTARGSLEN) 181 a->cmdline[n] = 0; 182 else 183 BOOTARGS[BOOTARGSLEN-1] = 0; 184 plan9iniinit(a->cmdline, 1); 185 break; 186 } 187 a = (Atag*)((u32int*)a + a->size); 188 } 189 } 190 191 void 192 machinit(void) 193 { 194 m->machno = 0; 195 machaddr[m->machno] = m; 196 197 m->ticks = 1; 198 m->perf.period = 1; 199 200 conf.nmach = 1; 201 202 active.machs = 1; 203 active.exiting = 0; 204 205 up = nil; 206 } 207 208 static void 209 optionsinit(char* s) 210 { 211 strecpy(oargb, oargb+sizeof(oargb), s); 212 213 oargblen = strlen(oargb); 214 oargc = tokenize(oargb, oargv, nelem(oargv)-1); 215 oargv[oargc] = nil; 216 } 217 218 void 219 main(void) 220 { 221 extern char edata[], end[]; 222 uint rev; 223 224 okay(1); 225 m = (Mach*)MACHADDR; 226 memset(edata, 0, end - edata); /* clear bss */ 227 machinit(); 228 mmuinit1(); 229 230 optionsinit("/boot/boot boot"); 231 quotefmtinstall(); 232 233 ataginit((Atag*)BOOTARGS); 234 confinit(); /* figures out amount of memory */ 235 xinit(); 236 uartconsinit(); 237 screeninit(); 238 239 print("\nPlan 9 from Bell Labs\n"); 240 rev = getfirmware(); 241 print("firmware: rev %d\n", rev); 242 if(rev < Minfirmrev){ 243 print("Sorry, firmware (start.elf) must be at least rev %d (%s)\n", 244 Minfirmrev, Minfirmdate); 245 for(;;) 246 ; 247 } 248 trapinit(); 249 clockinit(); 250 printinit(); 251 timersinit(); 252 if(conf.monitor) 253 swcursorinit(); 254 cpuidprint(); 255 archreset(); 256 257 procinit0(); 258 initseg(); 259 links(); 260 chandevreset(); /* most devices are discovered here */ 261 pageinit(); 262 swapinit(); 263 userinit(); 264 schedinit(); 265 assert(0); /* shouldn't have returned */ 266 } 267 268 /* 269 * starting place for first process 270 */ 271 void 272 init0(void) 273 { 274 int i; 275 char buf[2*KNAMELEN]; 276 277 up->nerrlab = 0; 278 coherence(); 279 spllo(); 280 281 /* 282 * These are o.k. because rootinit is null. 283 * Then early kproc's will have a root and dot. 284 */ 285 up->slash = namec("#/", Atodir, 0, 0); 286 pathclose(up->slash->path); 287 up->slash->path = newpath("/"); 288 up->dot = cclone(up->slash); 289 290 chandevinit(); 291 292 if(!waserror()){ 293 snprint(buf, sizeof(buf), "%s %s", "ARM", conffile); 294 ksetenv("terminal", buf, 0); 295 ksetenv("cputype", "arm", 0); 296 if(cpuserver) 297 ksetenv("service", "cpu", 0); 298 else 299 ksetenv("service", "terminal", 0); 300 snprint(buf, sizeof(buf), "-a %s", getethermac()); 301 ksetenv("etherargs", buf, 0); 302 303 /* convert plan9.ini variables to #e and #ec */ 304 for(i = 0; i < nconf; i++) { 305 ksetenv(confname[i], confval[i], 0); 306 ksetenv(confname[i], confval[i], 1); 307 } 308 poperror(); 309 } 310 kproc("alarm", alarmkproc, 0); 311 touser(sp); 312 assert(0); /* shouldn't have returned */ 313 } 314 315 static void 316 bootargs(uintptr base) 317 { 318 int i; 319 ulong ssize; 320 char **av, *p; 321 322 /* 323 * Push the boot args onto the stack. 324 * The initial value of the user stack must be such 325 * that the total used is larger than the maximum size 326 * of the argument list checked in syscall. 327 */ 328 i = oargblen+1; 329 p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i)); 330 memmove(p, oargb, i); 331 332 /* 333 * Now push the argv pointers. 334 * The code jumped to by touser in lproc.s expects arguments 335 * main(char* argv0, ...) 336 * and calls 337 * startboot("/boot/boot", &argv0) 338 * not the usual (int argc, char* argv[]) 339 */ 340 av = (char**)(p - (oargc+1)*sizeof(char*)); 341 ssize = base + BY2PG - PTR2UINT(av); 342 for(i = 0; i < oargc; i++) 343 *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG); 344 *av = nil; 345 sp = USTKTOP - ssize; 346 } 347 348 /* 349 * create the first process 350 */ 351 void 352 userinit(void) 353 { 354 Proc *p; 355 Segment *s; 356 KMap *k; 357 Page *pg; 358 359 /* no processes yet */ 360 up = nil; 361 362 p = newproc(); 363 p->pgrp = newpgrp(); 364 p->egrp = smalloc(sizeof(Egrp)); 365 p->egrp->ref = 1; 366 p->fgrp = dupfgrp(nil); 367 p->rgrp = newrgrp(); 368 p->procmode = 0640; 369 370 kstrdup(&eve, ""); 371 kstrdup(&p->text, "*init*"); 372 kstrdup(&p->user, eve); 373 374 /* 375 * Kernel Stack 376 */ 377 p->sched.pc = PTR2UINT(init0); 378 p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr)); 379 p->sched.sp = STACKALIGN(p->sched.sp); 380 381 /* 382 * User Stack 383 * 384 * Technically, newpage can't be called here because it 385 * should only be called when in a user context as it may 386 * try to sleep if there are no pages available, but that 387 * shouldn't be the case here. 388 */ 389 s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); 390 s->flushme++; 391 p->seg[SSEG] = s; 392 pg = newpage(1, 0, USTKTOP-BY2PG); 393 segpage(s, pg); 394 k = kmap(pg); 395 bootargs(VA(k)); 396 kunmap(k); 397 398 /* 399 * Text 400 */ 401 s = newseg(SG_TEXT, UTZERO, 1); 402 p->seg[TSEG] = s; 403 pg = newpage(1, 0, UTZERO); 404 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 405 segpage(s, pg); 406 k = kmap(s->map[0]->pages[0]); 407 memmove(UINT2PTR(VA(k)), initcode, sizeof initcode); 408 kunmap(k); 409 410 ready(p); 411 } 412 413 void 414 confinit(void) 415 { 416 int i; 417 ulong kpages; 418 uintptr pa; 419 char *p; 420 421 if(0 && (p = getconf("service")) != nil){ 422 if(strcmp(p, "cpu") == 0) 423 cpuserver = 1; 424 else if(strcmp(p,"terminal") == 0) 425 cpuserver = 0; 426 } 427 if((p = getconf("*maxmem")) != nil){ 428 memsize = strtoul(p, 0, 0) - PHYSDRAM; 429 if (memsize < 16*MB) /* sanity */ 430 memsize = 16*MB; 431 } 432 433 getramsize(&conf.mem[0]); 434 if(conf.mem[0].limit == 0){ 435 conf.mem[0].base = PHYSDRAM; 436 conf.mem[0].limit = PHYSDRAM + memsize; 437 }else if(p != nil) 438 conf.mem[0].limit = conf.mem[0].base + memsize; 439 440 conf.npage = 0; 441 pa = PADDR(PGROUND(PTR2UINT(end))); 442 443 /* 444 * we assume that the kernel is at the beginning of one of the 445 * contiguous chunks of memory and fits therein. 446 */ 447 for(i=0; i<nelem(conf.mem); i++){ 448 /* take kernel out of allocatable space */ 449 if(pa > conf.mem[i].base && pa < conf.mem[i].limit) 450 conf.mem[i].base = pa; 451 452 conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG; 453 conf.npage += conf.mem[i].npage; 454 } 455 456 conf.upages = (conf.npage*80)/100; 457 conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG; 458 459 /* only one processor */ 460 conf.nmach = 1; 461 462 /* set up other configuration parameters */ 463 conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; 464 if(cpuserver) 465 conf.nproc *= 3; 466 if(conf.nproc > 2000) 467 conf.nproc = 2000; 468 conf.nswap = conf.npage*3; 469 conf.nswppo = 4096; 470 conf.nimage = 200; 471 472 conf.copymode = 0; /* copy on write */ 473 474 /* 475 * Guess how much is taken by the large permanent 476 * datastructures. Mntcache and Mntrpc are not accounted for 477 * (probably ~300KB). 478 */ 479 kpages = conf.npage - conf.upages; 480 kpages *= BY2PG; 481 kpages -= conf.upages*sizeof(Page) 482 + conf.nproc*sizeof(Proc) 483 + conf.nimage*sizeof(Image) 484 + conf.nswap 485 + conf.nswppo*sizeof(Page); 486 mainmem->maxsize = kpages; 487 if(!cpuserver) 488 /* 489 * give terminals lots of image memory, too; the dynamic 490 * allocation will balance the load properly, hopefully. 491 * be careful with 32-bit overflow. 492 */ 493 imagmem->maxsize = kpages; 494 495 } 496 497 static void 498 shutdown(int ispanic) 499 { 500 int ms, once; 501 502 lock(&active); 503 if(ispanic) 504 active.ispanic = ispanic; 505 else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) 506 active.ispanic = 0; 507 once = active.machs & (1<<m->machno); 508 active.machs &= ~(1<<m->machno); 509 active.exiting = 1; 510 unlock(&active); 511 512 if(once) 513 iprint("cpu%d: exiting\n", m->machno); 514 spllo(); 515 for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ 516 delay(TK2MS(2)); 517 if(active.machs == 0 && consactive() == 0) 518 break; 519 } 520 delay(1000); 521 } 522 523 /* 524 * exit kernel either on a panic or user request 525 */ 526 void 527 exit(int code) 528 { 529 shutdown(code); 530 splfhi(); 531 archreboot(); 532 } 533 534 /* 535 * stub for ../omap/devether.c 536 */ 537 int 538 isaconfig(char *class, int ctlrno, ISAConf *isa) 539 { 540 USED(ctlrno); 541 USED(isa); 542 return strcmp(class, "ether") == 0; 543 } 544 545 /* 546 * the new kernel is already loaded at address `code' 547 * of size `size' and entry point `entry'. 548 */ 549 void 550 reboot(void *entry, void *code, ulong size) 551 { 552 void (*f)(ulong, ulong, ulong); 553 554 print("starting reboot..."); 555 writeconf(); 556 shutdown(0); 557 558 /* 559 * should be the only processor running now 560 */ 561 562 print("reboot entry %#lux code %#lux size %ld\n", 563 PADDR(entry), PADDR(code), size); 564 delay(100); 565 566 /* turn off buffered serial console */ 567 serialoq = nil; 568 kprintoq = nil; 569 screenputs = nil; 570 571 /* shutdown devices */ 572 chandevshutdown(); 573 574 /* stop the clock (and watchdog if any) */ 575 clockshutdown(); 576 577 splfhi(); 578 intrsoff(); 579 580 /* setup reboot trampoline function */ 581 f = (void*)REBOOTADDR; 582 memmove(f, rebootcode, sizeof(rebootcode)); 583 cacheuwbinv(); 584 585 /* off we go - never to return */ 586 (*f)(PADDR(entry), PADDR(code), size); 587 588 iprint("loaded kernel returned!\n"); 589 delay(1000); 590 archreboot(); 591 } 592 593 int 594 cmpswap(long *addr, long old, long new) 595 { 596 return cas32(addr, old, new); 597 } 598