main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "init.h"
  15. #include "io.h"
  16. #include "encoding.h"
  17. #include "ureg.h"
  18. #include <tos.h>
  19. int cpuserver = 1;
  20. extern void (*consuartputs)(char*, int);
  21. void query_mem(const char *config_string, uintptr_t *base, size_t *size);
  22. void query_rtc(const char *config_string, uintptr_t *mtime);
  23. void query_uint(const char *config_string, char *name, uintptr_t *val);
  24. void putchar(uint8_t c);
  25. void msg(char *s)
  26. {
  27. while (*s)
  28. putchar(*s++);
  29. }
  30. void die(char *s)
  31. {
  32. msg(s);
  33. while (1);
  34. }
  35. void
  36. ndnr(void)
  37. {
  38. die("ndnr");
  39. }
  40. static void puts(char * s, int n)
  41. {
  42. while (n--)
  43. putchar(*s++);
  44. }
  45. /* mach info for hart 0. */
  46. /* in many plan 9 implementations this stuff is all reserved in early assembly.
  47. * we don't have to do that. */
  48. uint64_t m0stack[4096];
  49. Mach m0;
  50. Sys asys, *sys=&asys;
  51. Conf conf;
  52. uintptr_t kseg0 = KZERO;
  53. char *cputype = "riscv";
  54. int64_t hz;
  55. uintptr_t rtc;
  56. /* I forget where this comes from and I don't care just now. */
  57. uint32_t kerndate;
  58. int maxcores = 1;
  59. int nosmp = 1;
  60. uint64_t mtimepa, mtimecmppa, uartpa;
  61. uint64_t *mtime, *mtimecmp;
  62. uint64_t *uart;
  63. /*
  64. * kseg2 is the base of the virtual address space.
  65. * it is not a constant as in amd64; in riscv there are many possible
  66. * values, even on the same SOC. It is determined by firmware.
  67. */
  68. void *kseg2;
  69. char *configstring; /* from coreboot, first arg to main */
  70. static uintptr_t sp; /* XXX - must go - user stack of init proc */
  71. /* general purpose hart startup. We call this via startmach.
  72. * When we enter here, the machp() function is usable.
  73. */
  74. void hart(void)
  75. {
  76. //Mach *mach = machp();
  77. die("not yet");
  78. }
  79. uint64_t
  80. rdtsc(void)
  81. {
  82. uint64_t cycles;
  83. // msg("rdtsc\n");
  84. cycles = read_csr(/*s*/cycle);
  85. //print("cycles in rdtsc is 0x%llx\n", cycles);
  86. // msg("done rdts\n");
  87. return cycles;
  88. }
  89. void
  90. loadenv(int argc, char* argv[])
  91. {
  92. char *env[2];
  93. /*
  94. * Process command line env options
  95. */
  96. while(--argc > 0){
  97. char* next = *++argv;
  98. if(next[0] !='-'){
  99. if (gettokens(next, env, 2, "=") == 2){;
  100. ksetenv(env[0], env[1], 0);
  101. }else{
  102. print("Ignoring parameter with no value: %s\n", env[0]);
  103. }
  104. }
  105. }
  106. }
  107. void
  108. init0(void)
  109. {
  110. Proc *up = externup();
  111. char buf[2*KNAMELEN];
  112. Ureg u;
  113. up->nerrlab = 0;
  114. /*
  115. * if(consuart == nil)
  116. * i8250console("0");
  117. */
  118. spllo();
  119. /*
  120. * These are o.k. because rootinit is null.
  121. * Then early kproc's will have a root and dot.
  122. */
  123. print("init0: up is %p\n", up);
  124. up->slash = namec("#/", Atodir, 0, 0);
  125. print("1\n");
  126. pathclose(up->slash->path);
  127. print("1\n");
  128. up->slash->path = newpath("/");
  129. print("1\n");
  130. up->dot = cclone(up->slash);
  131. print("1\n");
  132. devtabinit();
  133. print("1\n");
  134. if(!waserror()){
  135. //snprint(buf, sizeof(buf), "%s %s", "AMD64", conffile);
  136. //loadenv(oargc, oargv);
  137. ksetenv("terminal", buf, 0);
  138. ksetenv("cputype", cputype, 0);
  139. ksetenv("pgsz", "2097152", 0);
  140. // no longer. confsetenv();
  141. poperror();
  142. }
  143. kproc("alarm", alarmkproc, 0);
  144. //nixprepage(-1);
  145. print("TOUSER: kstack is %p\n", up->kstack);
  146. //debugtouser((void *)UTZERO);
  147. memset(&u, 0, sizeof(u));
  148. u.ip = (uintptr_t)init_main;
  149. u.sp = sp;
  150. u.a2 = USTKTOP-sizeof(Tos);
  151. print("sstatus is 0x%x, sip is 0x%x, sie is 0x%x\n", read_csr(sstatus),
  152. read_csr(sip), read_csr(sie));
  153. print("*mtimecmp is 0x%llx *mtime is 0x%llx\n", *mtimecmp, *mtime);
  154. touser(&u);
  155. }
  156. /*
  157. * Option arguments from the command line.
  158. * oargv[0] is the boot file.
  159. * TODO: do it.
  160. */
  161. static int64_t oargc;
  162. static char* oargv[20];
  163. static char oargb[1024];
  164. static int oargblen;
  165. void
  166. bootargs(uintptr_t base)
  167. {
  168. int i;
  169. uint32_t ssize;
  170. char **av, *p;
  171. /*
  172. * Push the boot args onto the stack.
  173. * Make sure the validaddr check in syscall won't fail
  174. * because there are fewer than the maximum number of
  175. * args by subtracting sizeof(up->arg).
  176. */
  177. i = oargblen+1;
  178. p = UINT2PTR(STACKALIGN(base + BIGPGSZ - sizeof(((Proc*)0)->arg) - i));
  179. memmove(p, oargb, i);
  180. /*
  181. * Now push argc and the argv pointers.
  182. * This isn't strictly correct as the code jumped to by
  183. * touser in init9.[cs] calls startboot (port/initcode.c) which
  184. * expects arguments
  185. * startboot(char* argv0, char* argv[])
  186. * not the usual (int argc, char* argv[]), but argv0 is
  187. * unused so it doesn't matter (at the moment...).
  188. */
  189. av = (char**)(p - (oargc+2)*sizeof(char*));
  190. ssize = base + BIGPGSZ - PTR2UINT(av);
  191. print("Stack size in boot args is %p\n", ssize);
  192. *av++ = (char*)oargc;
  193. for(i = 0; i < oargc; i++)
  194. *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BIGPGSZ);
  195. *av = nil;
  196. sp = USTKTOP - ssize;
  197. print("New sp in bootargs is %p\n", sp);
  198. }
  199. void
  200. userinit(void)
  201. {
  202. Proc *up = externup();
  203. Proc *p;
  204. Segment *s;
  205. KMap *k;
  206. Page *pg;
  207. int sno;
  208. p = newproc();
  209. p->pgrp = newpgrp();
  210. p->egrp = smalloc(sizeof(Egrp));
  211. p->egrp->r.ref = 1;
  212. p->fgrp = dupfgrp(nil);
  213. p->rgrp = newrgrp();
  214. p->procmode = 0640;
  215. kstrdup(&eve, "");
  216. kstrdup(&p->text, "*init*");
  217. kstrdup(&p->user, eve);
  218. /*
  219. * Kernel Stack
  220. *
  221. * N.B. make sure there's enough space for syscall to check
  222. * for valid args and
  223. * space for gotolabel's return PC
  224. * AMD64 stack must be quad-aligned.
  225. */
  226. p->sched.pc = PTR2UINT(init0);
  227. p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr_t));
  228. p->sched.sp = STACKALIGN(p->sched.sp);
  229. /*
  230. * User Stack
  231. *
  232. * Technically, newpage can't be called here because it
  233. * should only be called when in a user context as it may
  234. * try to sleep if there are no pages available, but that
  235. * shouldn't be the case here.
  236. */
  237. sno = 0;
  238. print("newseg(0x%x, %p, 0x%llx)\n", SG_STACK|SG_READ|SG_WRITE, (void *)USTKTOP-USTKSIZE, USTKSIZE/ BIGPGSZ);
  239. s = newseg(SG_STACK|SG_READ|SG_WRITE, USTKTOP-USTKSIZE, USTKSIZE/ BIGPGSZ);
  240. p->seg[sno++] = s;
  241. pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1);
  242. segpage(s, pg);
  243. k = kmap(pg);
  244. bootargs(VA(k));
  245. kunmap(k);
  246. /*
  247. * Text
  248. */
  249. s = newseg(SG_TEXT|SG_READ|SG_EXEC, UTZERO, 1);
  250. s->flushme++;
  251. p->seg[sno++] = s;
  252. pg = newpage(1, 0, UTZERO, BIGPGSZ, -1);
  253. memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
  254. segpage(s, pg);
  255. k = kmap(s->map[0]->pages[0]);
  256. /* UTZERO is only needed until we make init not have 2M block of zeros at the front. */
  257. memmove(UINT2PTR(VA(k) + init_code_start - UTZERO), init_code_out, sizeof(init_code_out));
  258. kunmap(k);
  259. /*
  260. * Data
  261. */
  262. s = newseg(SG_DATA|SG_READ|SG_WRITE, UTZERO + BIGPGSZ, 1);
  263. s->flushme++;
  264. p->seg[sno++] = s;
  265. pg = newpage(1, 0, UTZERO + BIGPGSZ, BIGPGSZ, -1);
  266. memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
  267. segpage(s, pg);
  268. k = kmap(s->map[0]->pages[0]);
  269. /* This depends on init having a text segment < 2M. */
  270. memmove(UINT2PTR(VA(k) + init_data_start - (UTZERO + BIGPGSZ)), init_data_out, sizeof(init_data_out));
  271. kunmap(k);
  272. ready(p);
  273. }
  274. void
  275. confinit(void)
  276. {
  277. int i;
  278. conf.npage = 0;
  279. for(i=0; i<nelem(conf.mem); i++)
  280. conf.npage += conf.mem[i].npage;
  281. conf.nproc = 1000;
  282. conf.nimage = 200;
  283. }
  284. /* check checks simple atomics and anything else that is critical to correct operation.
  285. * You can make the prints optional on errors cases, not have it print all tests,
  286. * but you should never remove check or the call to it. It found some nasty problems. */
  287. static void
  288. check(void)
  289. {
  290. uint64_t f2ns;
  291. // cas test
  292. uint32_t t = 0;
  293. int fail = 0;
  294. int _42 = 42;
  295. int a = _42, b;
  296. int x = cas32(&t, 0, 1);
  297. print("cas32 done x %d (want 1) t %d (want 1)\n", x, t);
  298. if ((t != 1) || (x != 1))
  299. fail++;
  300. x = cas32(&t, 0, 1);
  301. print("cas32 done x %d (want 0) t %d (want 1)\n", x, t);
  302. if ((t != 1) || (x != 0))
  303. fail++;
  304. print("t is now %d before final cas32\n", t);
  305. x = cas32(&t, 1, 2);
  306. print("cas32 done x %d (want 1) t %d (want 2)\n", x, t);
  307. if ((t != 2) || (x != 1))
  308. fail++;
  309. t = 0;
  310. x = tas32(&t);
  311. print("tas done x %d (want 0) t %d (want 1)\n", x, t);
  312. if ((t != 1) || (x != 0))
  313. fail++;
  314. x = tas32(&t);
  315. print("tas done x %d (want 1) t %d (want 1)\n", x, t);
  316. if ((t != 1) || (x != 1))
  317. fail++;
  318. t = 0;
  319. x = tas32(&t);
  320. print("tas done x %d (want ) t %d (want 1)\n", x, t);
  321. if ((t != 1) || (x != 0))
  322. fail++;
  323. b = ainc(&a);
  324. print("after ainc a is %d (want 43) b is %d (want 43)\n", a, b);
  325. if ((b != _42 + 1) || (a != _42 + 1))
  326. fail++;
  327. b = ainc(&a);
  328. print("after ainc a is %d (want 44) b is %d (want 44)\n", a, b);
  329. if ((b != _42 + 2) || (a != _42 + 2))
  330. fail++;
  331. b = adec(&a);
  332. print("after ainc a is %d (want 43) b is %d (want 43)\n", a, b);
  333. if ((b != _42 + 1) || (a != _42 + 1))
  334. fail++;
  335. if (fail) {
  336. print("%d failures in check();\n", fail);
  337. panic("FIX ME");
  338. }
  339. f2ns = fastticks2ns(10);
  340. if ((f2ns < 1) || (f2ns > 10)) {
  341. print("fastticks2ns(1) is nuts: %d\n", f2ns);
  342. panic("Should be in the range 1 to 10, realistically");
  343. }
  344. f2ns = ns2fastticks(1);
  345. if ((f2ns < 2) || (f2ns > 100)) {
  346. print("ns2fastticks(1) is nuts: %d\n", f2ns);
  347. panic("Should be in the range 2 to 100, realistically");
  348. }
  349. }
  350. // Note: any message you try to print before the uart is determined from
  351. // the configstring will go nowhere. You can hack around if you hit
  352. // serious problems by, e.g., setting uart to 0xffffffff40001000
  353. // in this function. Hence, I've left some messages in that won't
  354. // print as an example of debugging.
  355. void bsp(void *stack, uintptr_t _configstring)
  356. {
  357. msg("BSP starting\n");
  358. kseg2 = findKSeg2();
  359. configstring = KADDR(_configstring);
  360. Mach *mach = machp();
  361. if (mach != &m0)
  362. die("MACH NOT MATCH");
  363. msg("memset mach\n");
  364. memset(mach, 0, sizeof(Mach));
  365. msg("done that\n");
  366. MACHP(0) = mach;
  367. msg(configstring);
  368. mach->self = (uintptr_t)mach;
  369. msg("SET SELF OK\n");
  370. mach->machno = 0;
  371. mach->online = 1;
  372. mach->NIX.nixtype = NIXTC;
  373. mach->stack = PTR2UINT(stack);
  374. *(uintptr_t*)mach->stack = STACKGUARD;
  375. msg(configstring);
  376. mach->externup = nil;
  377. active.nonline = 1;
  378. active.exiting = 0;
  379. active.nbooting = 0;
  380. consuartputs = puts;
  381. msg("call asminit\n");
  382. msg("==============================================\n");
  383. asminit();
  384. msg(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\n");
  385. asmmapinit(0x81000000, 0x3f000000, 1);
  386. msg(configstring);
  387. /*
  388. * Need something for initial delays
  389. * until a timebase is worked out.
  390. */
  391. mach->cpuhz = 2000000000ll;
  392. mach->cpumhz = 2000;
  393. sys->cyclefreq = mach->cpuhz;
  394. sys->nmach = 1;
  395. msg(configstring);
  396. fmtinit();
  397. mach->perf.period = 1;
  398. if((hz = archhz()) != 0ll){
  399. mach->cpuhz = hz;
  400. mach->cyclefreq = hz;
  401. sys->cyclefreq = hz;
  402. mach->cpumhz = hz/1000000ll;
  403. }
  404. /*
  405. * Mmuinit before meminit because it
  406. * flushes the TLB via machp()->pml4->pa.
  407. */
  408. mmuinit();
  409. ioinit(); print("ioinit\n");
  410. print("IOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIO\n");
  411. meminit();print("meminit\n");
  412. print("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n");
  413. confinit();print("confinit\n");
  414. print("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n");
  415. archinit();print("archinit\n");
  416. print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
  417. mallocinit();print("mallocinit\n");
  418. /* test malloc. It's easier to find out it's broken here,
  419. * not deep in some call chain.
  420. * See next note.
  421. *
  422. */
  423. if (1) {
  424. void *v = malloc(1234);
  425. msg("allocated\n ");
  426. free(v);
  427. msg("free ok\n");
  428. }
  429. query_uint(configstring, "uart{addr", (uintptr_t*)&uartpa);
  430. uart = KADDR(uartpa);
  431. print("\nHarvey\n");
  432. /* you're going to love this. Print does not print the whole
  433. * string. msg does. Bug. */
  434. print("Config string:%p '%s'\n", configstring, configstring);
  435. msg("Config string via msg\n");
  436. msg(configstring);
  437. msg("\n");
  438. query_rtc(configstring, &rtc);
  439. print("rtc: %p\n", rtc);
  440. query_uint(configstring, "rtc{addr", (uintptr_t*)&mtimepa);
  441. mtime = KADDR(mtimepa);
  442. query_uint(configstring, "core{0{0{timecmp", (uintptr_t*)&mtimecmppa);
  443. mtimecmp = KADDR(mtimecmppa);
  444. print("mtime is %p and mtimecmp is %p\n", mtime, mtimecmp);
  445. umeminit();
  446. procinit0();
  447. print("before mpacpi, maxcores %d\n", maxcores);
  448. trapinit();
  449. print("trapinit done\n");
  450. /* Forcing to single core if desired */
  451. if(!nosmp) {
  452. // smp startup
  453. }
  454. //working.
  455. // not needed. teardownidmap(mach);
  456. timersinit();print(" timersinit();\n");
  457. // ? fpuinit();
  458. psinit(conf.nproc);print(" psinit(conf.nproc);\n");
  459. initimage();print(" initimage();\n");
  460. links();
  461. devtabreset();print(" devtabreset();\n");
  462. pageinit();print(" pageinit();\n");
  463. swapinit();print(" swapinit();\n");
  464. userinit();print(" userinit();\n");
  465. /* Forcing to single core if desired */
  466. if(!nosmp) {
  467. //nixsquids();
  468. //testiccs();
  469. }
  470. print("NO profiling until you set upa alloc_cpu_buffers()\n");
  471. //alloc_cpu_buffers();
  472. print("CPU Freq. %dMHz\n", mach->cpumhz);
  473. // set the trap vector
  474. void *supervisor_trap_entry(void);
  475. write_csr(/*stvec*/0x105, supervisor_trap_entry);
  476. // enable all interrupt sources.
  477. uint64_t ints = read_csr(sie);
  478. ints |= 0x666;
  479. write_csr(sie, ints);
  480. dumpmmuwalk(0xfffffffffffff000ULL);
  481. check();
  482. void consread(void);
  483. addclock0link(consread, 0);
  484. print("schedinit...\n");
  485. schedinit();
  486. die("Completed hart for bsp OK!\n");
  487. }
  488. /* stubs until we implement in assembly */
  489. int corecolor(int _)
  490. {
  491. return -1;
  492. }
  493. Proc *externup(void)
  494. {
  495. if (! machp())
  496. return nil;
  497. return machp()->externup;
  498. }
  499. void errstr(char *s, int i) {
  500. panic("errstr");
  501. }
  502. void
  503. hardhalt(void)
  504. {
  505. panic((char *)__func__);
  506. }
  507. void
  508. ureg2gdb(Ureg *u, uintptr_t *g)
  509. {
  510. panic((char *)__func__);
  511. }
  512. int
  513. userureg(Ureg*u)
  514. {
  515. int64_t ip = (int64_t)u->ip;
  516. if (ip < 0) {
  517. //print("RETURNING 0 for userureg\n");
  518. return 0;
  519. }
  520. //print("Returning 1 for userureg; need a better test\n");
  521. return 1;
  522. }
  523. void exit(int _)
  524. {
  525. panic((char *)__func__);
  526. }
  527. void fpunoted(void)
  528. {
  529. print((char *)__func__);
  530. print("NOT DOING IT. IT WILL HURT LATER\n");
  531. }
  532. void fpunotify(Ureg*_)
  533. {
  534. print("fpunotify: doing nothing since FPU is disabled\n");
  535. }
  536. void fpusysrfork(Ureg*_)
  537. {
  538. print((char *)__func__);
  539. print("IGNORING\n");
  540. }
  541. void sysrforkret(void)
  542. {
  543. void *stack(void);
  544. void *sp = stack();
  545. if(0) print("sysrforkret: stack is %p\n", sp);
  546. if(0) dumpgpr((Ureg *)sp);
  547. void _sysrforkret();
  548. _sysrforkret();
  549. }
  550. void
  551. reboot(void*_, void*__, int32_t ___)
  552. {
  553. panic("reboot");
  554. }
  555. void fpusysprocsetup(Proc *_)
  556. {
  557. print((char *)__func__);
  558. print("THIS IS GONNA SCREW YOU IF YOU DO NOT FIX IT\n");
  559. }
  560. void fpusysrforkchild(Proc*_, Proc*__)
  561. {
  562. print((char *)__func__);
  563. print("THIS IS GONNA SCREW YOU IF YOU DO NOT FIX IT\n");
  564. }
  565. int
  566. fpudevprocio(Proc*p, void*v, int32_t _, uintptr_t __, int ___)
  567. {
  568. panic((char *)__func__);
  569. return -1;
  570. }
  571. void cycles(uint64_t *p)
  572. {
  573. *p = rdtsc();
  574. }
  575. int islo(void)
  576. {
  577. // msg("isloc\n");
  578. uint64_t ms = read_csr(sstatus);
  579. // msg("read it\n");
  580. return ms & MSTATUS_SIE;
  581. }
  582. void
  583. stacksnippet(void)
  584. {
  585. //Stackframe *stkfr;
  586. kmprint(" stack:");
  587. // for(stkfr = stackframe(); stkfr != nil; stkfr = stkfr->next)
  588. // kmprint(" %c:%p", ktextaddr(stkfr->pc) ? 'k' : '?', ktextaddr(stkfr->pc) ? (stkfr->pc & 0xfffffff) : stkfr->pc);
  589. kmprint("\n");
  590. }
  591. /* crap. */
  592. /* this should come from build but it's intimately tied in to VGA. Crap. */
  593. Physseg physseg[8];
  594. int nphysseg = 8;
  595. /* bringup -- remove asap. */
  596. void
  597. DONE(void)
  598. {
  599. print("DONE\n");
  600. //prflush();
  601. delay(10000);
  602. ndnr();
  603. }
  604. void
  605. HERE(void)
  606. {
  607. print("here\n");
  608. //prflush();
  609. delay(5000);
  610. }
  611. /* The old plan 9 standby ... wave ... */
  612. /* Keep to debug trap.c */
  613. void wave(int c)
  614. {
  615. putchar(c);
  616. }
  617. void hi(char *s)
  618. {
  619. if (! s)
  620. s = "<NULL>";
  621. while (*s)
  622. wave(*s++);
  623. }