125210b06SDavid du Colombier /*
225210b06SDavid du Colombier * 9boot - load next 386 or amd64 kernel from disk and start it
325210b06SDavid du Colombier * and
425210b06SDavid du Colombier * 9load - load next 386 or amd64 kernel via pxe (bootp, tftp) and start it
525210b06SDavid du Colombier *
625210b06SDavid du Colombier * intel says that pxe can only load into the bottom 640K, and
725210b06SDavid du Colombier * intel's pxe boot agent takes 128K, leaving only 512K for 9boot.
825210b06SDavid du Colombier */
925210b06SDavid du Colombier #include "u.h"
1025210b06SDavid du Colombier #include "../port/lib.h"
1125210b06SDavid du Colombier #include "mem.h"
1225210b06SDavid du Colombier #include "dat.h"
1325210b06SDavid du Colombier #include "fns.h"
1425210b06SDavid du Colombier #include "io.h"
1525210b06SDavid du Colombier #include "ureg.h"
1625210b06SDavid du Colombier #include "pool.h"
1725210b06SDavid du Colombier #include "reboot.h"
1825210b06SDavid du Colombier #include "ip.h" /* for eipfmt */
1923a96966SDavid du Colombier #include <tos.h>
2025210b06SDavid du Colombier
2125210b06SDavid du Colombier enum {
2225210b06SDavid du Colombier Datamagic = 0xbabeabed,
2325210b06SDavid du Colombier };
2425210b06SDavid du Colombier
2525210b06SDavid du Colombier Mach *m;
2625210b06SDavid du Colombier
2725210b06SDavid du Colombier ulong* mach0pdb;
2825210b06SDavid du Colombier Mach* mach0m;
2925210b06SDavid du Colombier Segdesc* mach0gdt;
3025210b06SDavid du Colombier u32int memstart;
3125210b06SDavid du Colombier u32int memend;
3225210b06SDavid du Colombier int noclock;
3325210b06SDavid du Colombier
3425210b06SDavid du Colombier extern int pcivga;
3525210b06SDavid du Colombier extern char hellomsg[];
3625210b06SDavid du Colombier
3725210b06SDavid du Colombier /*
3825210b06SDavid du Colombier * Where configuration info is left for the loaded programme.
3925210b06SDavid du Colombier */
4025210b06SDavid du Colombier char bootdisk[KNAMELEN];
4125210b06SDavid du Colombier Conf conf;
4225210b06SDavid du Colombier
4325210b06SDavid du Colombier uchar *sp; /* user stack of init proc */
4425210b06SDavid du Colombier int delaylink;
4525210b06SDavid du Colombier int debug;
4625210b06SDavid du Colombier int v_flag;
4725210b06SDavid du Colombier
4825210b06SDavid du Colombier static void
sanity(void)4925210b06SDavid du Colombier sanity(void)
5025210b06SDavid du Colombier {
5125210b06SDavid du Colombier uintptr cr3;
5225210b06SDavid du Colombier
5325210b06SDavid du Colombier cr3 = (uintptr)KADDR(getcr3());
5425210b06SDavid du Colombier if (cr3 == 0)
5525210b06SDavid du Colombier panic("zero cr3");
5625210b06SDavid du Colombier if ((uintptr)m->pdb != cr3 || (uintptr)mach0pdb != cr3)
5725210b06SDavid du Colombier panic("not all same: cr3 %#p m->pdb %#p mach0pdb %#p",
5825210b06SDavid du Colombier cr3, m->pdb, mach0pdb);
5925210b06SDavid du Colombier if (m != mach0m)
6025210b06SDavid du Colombier panic("m %#p != mach0m %#p", m, mach0m);
6125210b06SDavid du Colombier if (m->gdt != mach0gdt)
6225210b06SDavid du Colombier panic("m->gdt %#p != mach0gdt %#p", m->gdt, mach0gdt);
6325210b06SDavid du Colombier if (0)
6425210b06SDavid du Colombier iprint("m->pdb %#p m %#p sp %#p m->gdt %#p\n",
6525210b06SDavid du Colombier m->pdb, m, &cr3, m->gdt);
6625210b06SDavid du Colombier }
6725210b06SDavid du Colombier
6825210b06SDavid du Colombier enum {
6925210b06SDavid du Colombier /* system control port a */
7025210b06SDavid du Colombier Sysctla= 0x92,
7125210b06SDavid du Colombier Sysctlreset= 1<<0,
7225210b06SDavid du Colombier Sysctla20ena= 1<<1,
7325210b06SDavid du Colombier };
7425210b06SDavid du Colombier
7525210b06SDavid du Colombier static int
isa20on(void)7625210b06SDavid du Colombier isa20on(void)
7725210b06SDavid du Colombier {
7825210b06SDavid du Colombier int r;
7925210b06SDavid du Colombier ulong o;
8025210b06SDavid du Colombier ulong *zp, *mb1p;
8125210b06SDavid du Colombier
8225210b06SDavid du Colombier zp = 0;
8325210b06SDavid du Colombier mb1p = (ulong *)MB;
8425210b06SDavid du Colombier o = *zp;
8525210b06SDavid du Colombier
8625210b06SDavid du Colombier *zp = 0x1234;
8725210b06SDavid du Colombier *mb1p = 0x8765;
8825210b06SDavid du Colombier mb586();
8925210b06SDavid du Colombier wbinvd();
9025210b06SDavid du Colombier r = *zp != *mb1p;
9125210b06SDavid du Colombier
9225210b06SDavid du Colombier *zp = o;
9325210b06SDavid du Colombier return r;
9425210b06SDavid du Colombier }
9525210b06SDavid du Colombier
9625210b06SDavid du Colombier void
a20init(void)9725210b06SDavid du Colombier a20init(void)
9825210b06SDavid du Colombier {
9925210b06SDavid du Colombier int b;
10025210b06SDavid du Colombier
10125210b06SDavid du Colombier if (isa20on())
10225210b06SDavid du Colombier return;
10325210b06SDavid du Colombier
10425210b06SDavid du Colombier i8042a20(); /* original method, via kbd ctlr */
10525210b06SDavid du Colombier if (isa20on())
10625210b06SDavid du Colombier return;
10725210b06SDavid du Colombier
10825210b06SDavid du Colombier /* newer method, last resort */
10925210b06SDavid du Colombier b = inb(Sysctla);
11025210b06SDavid du Colombier if (!(b & Sysctla20ena))
11125210b06SDavid du Colombier outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena);
112*084126e8SDavid du Colombier if (!isa20on()){
11325210b06SDavid du Colombier iprint("a20 didn't come on!\n");
114*084126e8SDavid du Colombier for(;;)
115*084126e8SDavid du Colombier ;
116*084126e8SDavid du Colombier }
11725210b06SDavid du Colombier }
11825210b06SDavid du Colombier
11925210b06SDavid du Colombier void
main(void)12025210b06SDavid du Colombier main(void)
12125210b06SDavid du Colombier {
12225210b06SDavid du Colombier Proc *savup;
12325210b06SDavid du Colombier static ulong vfy = Datamagic;
12425210b06SDavid du Colombier static char novga[] = "\nno vga; serial console only\n";
12525210b06SDavid du Colombier
12625210b06SDavid du Colombier savup = up;
12725210b06SDavid du Colombier up = nil;
12825210b06SDavid du Colombier /* m has been set by l32v.s */
12925210b06SDavid du Colombier
13025210b06SDavid du Colombier /*
13125210b06SDavid du Colombier * disable address wraps at 1MB boundaries.
13225210b06SDavid du Colombier * if we're 9boot, ldecomp.s already did this.
13325210b06SDavid du Colombier */
13425210b06SDavid du Colombier a20init();
13525210b06SDavid du Colombier
13625210b06SDavid du Colombier mach0init();
13725210b06SDavid du Colombier // options(); /* we don't get options passed to us */
13825210b06SDavid du Colombier ioinit();
13925210b06SDavid du Colombier /* we later call i8250console after plan9.ini has been read */
14025210b06SDavid du Colombier i8250config("0"); /* configure serial port 0 with defaults */
14125210b06SDavid du Colombier quotefmtinstall();
14225210b06SDavid du Colombier fmtinstall('i', eipfmt);
14325210b06SDavid du Colombier fmtinstall('I', eipfmt);
14425210b06SDavid du Colombier fmtinstall('E', eipfmt);
14525210b06SDavid du Colombier fmtinstall('V', eipfmt);
14625210b06SDavid du Colombier fmtinstall('M', eipfmt);
14725210b06SDavid du Colombier screeninit(); /* cga setup */
14825210b06SDavid du Colombier cgapost(0xc);
14925210b06SDavid du Colombier
15025210b06SDavid du Colombier trapinit0();
15125210b06SDavid du Colombier mmuinit0();
15225210b06SDavid du Colombier
15325210b06SDavid du Colombier kbdinit();
15425210b06SDavid du Colombier i8253init();
15525210b06SDavid du Colombier cpuidentify();
15625210b06SDavid du Colombier readlsconf();
15725210b06SDavid du Colombier meminit();
15825210b06SDavid du Colombier confinit();
15925210b06SDavid du Colombier archinit();
16025210b06SDavid du Colombier xinit();
16125210b06SDavid du Colombier if(i8237alloc != nil)
16225210b06SDavid du Colombier i8237alloc(); /* dma (for floppy) init */
16325210b06SDavid du Colombier trapinit();
16425210b06SDavid du Colombier printinit();
16525210b06SDavid du Colombier sanity();
16625210b06SDavid du Colombier cgapost(1);
16725210b06SDavid du Colombier
16825210b06SDavid du Colombier /*
16925210b06SDavid du Colombier * soekris servers have no built-in video but each has a serial port.
17025210b06SDavid du Colombier * they must see serial output, if any, before cga output because
17125210b06SDavid du Colombier * otherwise the soekris bios will translate cga output to serial
17225210b06SDavid du Colombier * output, which will garble serial console output.
17325210b06SDavid du Colombier */
17425210b06SDavid du Colombier pcimatch(nil, 0, 0); /* force scan of pci table */
17525210b06SDavid du Colombier if (!pcivga) {
17625210b06SDavid du Colombier screenputs = nil;
17725210b06SDavid du Colombier uartputs(novga, sizeof novga - 1);
17825210b06SDavid du Colombier }
17925210b06SDavid du Colombier print(" %s\n\n", hellomsg);
18025210b06SDavid du Colombier
18125210b06SDavid du Colombier if (vfy != Datamagic)
18225210b06SDavid du Colombier panic("data segment incorrectly aligned or loaded");
18325210b06SDavid du Colombier if (savup)
18425210b06SDavid du Colombier print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n",
18525210b06SDavid du Colombier savup);
18625210b06SDavid du Colombier
18725210b06SDavid du Colombier // xsummary();
18825210b06SDavid du Colombier cpuidprint();
18925210b06SDavid du Colombier mmuinit();
19025210b06SDavid du Colombier if(arch->intrinit) /* launches other processors on an mp */
19125210b06SDavid du Colombier arch->intrinit();
19225210b06SDavid du Colombier timersinit();
19325210b06SDavid du Colombier mathinit();
19425210b06SDavid du Colombier kbdenable();
19525210b06SDavid du Colombier /*
19625210b06SDavid du Colombier * 9loadusb runs much faster if we don't use the clock.
19725210b06SDavid du Colombier * perhaps we're competing with the bios for the use of it?
19825210b06SDavid du Colombier */
19925210b06SDavid du Colombier if(!noclock && arch->clockenable)
20025210b06SDavid du Colombier arch->clockenable();
20125210b06SDavid du Colombier procinit0();
20225210b06SDavid du Colombier initseg();
20325210b06SDavid du Colombier if(delaylink){
20425210b06SDavid du Colombier bootlinks();
20525210b06SDavid du Colombier pcimatch(0, 0, 0);
20625210b06SDavid du Colombier }else
20725210b06SDavid du Colombier links();
20825210b06SDavid du Colombier conf.monitor = 1;
20925210b06SDavid du Colombier cgapost(0xcd);
21025210b06SDavid du Colombier chandevreset();
21125210b06SDavid du Colombier cgapost(2);
21225210b06SDavid du Colombier pageinit(); /* must follow xinit, and conf.mem must be populated */
21325210b06SDavid du Colombier i8253link();
21425210b06SDavid du Colombier userinit();
21525210b06SDavid du Colombier
21625210b06SDavid du Colombier active.thunderbirdsarego = 1;
21725210b06SDavid du Colombier cgapost(0xb0);
21825210b06SDavid du Colombier schedinit();
21925210b06SDavid du Colombier }
22025210b06SDavid du Colombier
22125210b06SDavid du Colombier void
mach0init(void)22225210b06SDavid du Colombier mach0init(void)
22325210b06SDavid du Colombier {
22425210b06SDavid du Colombier conf.nmach = 1;
22525210b06SDavid du Colombier MACHP(0) = mach0m;
22625210b06SDavid du Colombier m->machno = 0;
22725210b06SDavid du Colombier m->pdb = mach0pdb;
22825210b06SDavid du Colombier m->gdt = mach0gdt;
22925210b06SDavid du Colombier
23025210b06SDavid du Colombier machinit();
23125210b06SDavid du Colombier
23225210b06SDavid du Colombier active.machs = 1;
23325210b06SDavid du Colombier active.exiting = 0;
23425210b06SDavid du Colombier }
23525210b06SDavid du Colombier
23625210b06SDavid du Colombier void
machinit(void)23725210b06SDavid du Colombier machinit(void)
23825210b06SDavid du Colombier {
23925210b06SDavid du Colombier int machno;
24025210b06SDavid du Colombier ulong *pdb;
24125210b06SDavid du Colombier Segdesc *gdt;
24225210b06SDavid du Colombier
24325210b06SDavid du Colombier machno = m->machno;
24425210b06SDavid du Colombier pdb = m->pdb;
24525210b06SDavid du Colombier gdt = m->gdt;
24625210b06SDavid du Colombier memset(m, 0, sizeof(Mach));
24725210b06SDavid du Colombier m->machno = machno;
24825210b06SDavid du Colombier m->pdb = pdb;
24925210b06SDavid du Colombier m->gdt = gdt;
25025210b06SDavid du Colombier m->perf.period = 1;
25125210b06SDavid du Colombier
25225210b06SDavid du Colombier /*
25325210b06SDavid du Colombier * For polled uart output at boot, need
25425210b06SDavid du Colombier * a default delay constant. 100000 should
25525210b06SDavid du Colombier * be enough for a while. Cpuidentify will
25625210b06SDavid du Colombier * calculate the real value later.
25725210b06SDavid du Colombier */
25825210b06SDavid du Colombier m->loopconst = 100000;
25925210b06SDavid du Colombier }
26025210b06SDavid du Colombier
26125210b06SDavid du Colombier void
init0(void)26225210b06SDavid du Colombier init0(void)
26325210b06SDavid du Colombier {
26425210b06SDavid du Colombier int i;
26525210b06SDavid du Colombier char buf[2*KNAMELEN];
26625210b06SDavid du Colombier
26725210b06SDavid du Colombier up->nerrlab = 0;
26825210b06SDavid du Colombier
26925210b06SDavid du Colombier spllo();
27025210b06SDavid du Colombier
27125210b06SDavid du Colombier /*
27225210b06SDavid du Colombier * These are o.k. because rootinit is null.
27325210b06SDavid du Colombier * Then early kproc's will have a root and dot.
27425210b06SDavid du Colombier */
27525210b06SDavid du Colombier up->slash = namec("#/", Atodir, 0, 0);
27625210b06SDavid du Colombier pathclose(up->slash->path);
27725210b06SDavid du Colombier up->slash->path = newpath("/");
27825210b06SDavid du Colombier up->dot = cclone(up->slash);
27925210b06SDavid du Colombier
28025210b06SDavid du Colombier chandevinit();
28125210b06SDavid du Colombier
28225210b06SDavid du Colombier if(0 && !waserror()){ /* not needed by boot */
28325210b06SDavid du Colombier snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
28425210b06SDavid du Colombier ksetenv("terminal", buf, 0);
28525210b06SDavid du Colombier ksetenv("cputype", "386", 0);
28625210b06SDavid du Colombier if(cpuserver)
28725210b06SDavid du Colombier ksetenv("service", "cpu", 0);
28825210b06SDavid du Colombier else
28925210b06SDavid du Colombier ksetenv("service", "terminal", 0);
29025210b06SDavid du Colombier for(i = 0; i < nconf; i++){
29125210b06SDavid du Colombier if(confname[i][0] != '*')
29225210b06SDavid du Colombier ksetenv(confname[i], confval[i], 0);
29325210b06SDavid du Colombier ksetenv(confname[i], confval[i], 1);
29425210b06SDavid du Colombier }
29525210b06SDavid du Colombier poperror();
29625210b06SDavid du Colombier }
29725210b06SDavid du Colombier kproc("alarm", alarmkproc, 0);
298c1e5ebd3SDavid du Colombier
299c1e5ebd3SDavid du Colombier conschan = enamecopen("#c/cons", ORDWR);
300e4575fb1SDavid du Colombier bootloadproc(0);
301e4575fb1SDavid du Colombier panic("bootloadproc returned");
30225210b06SDavid du Colombier }
30325210b06SDavid du Colombier
30425210b06SDavid du Colombier void
userinit(void)30525210b06SDavid du Colombier userinit(void)
30625210b06SDavid du Colombier {
30725210b06SDavid du Colombier Proc *p;
30825210b06SDavid du Colombier
30925210b06SDavid du Colombier p = newproc();
31025210b06SDavid du Colombier p->pgrp = newpgrp();
31125210b06SDavid du Colombier p->egrp = smalloc(sizeof(Egrp));
31225210b06SDavid du Colombier p->egrp->ref = 1;
31325210b06SDavid du Colombier p->fgrp = dupfgrp(nil);
31425210b06SDavid du Colombier p->rgrp = newrgrp();
31525210b06SDavid du Colombier p->procmode = 0640;
31625210b06SDavid du Colombier
31725210b06SDavid du Colombier kstrdup(&eve, "");
31825210b06SDavid du Colombier kstrdup(&p->text, "*init*");
31925210b06SDavid du Colombier kstrdup(&p->user, eve);
32025210b06SDavid du Colombier
32125210b06SDavid du Colombier p->fpstate = FPinit;
32225210b06SDavid du Colombier fpoff();
32325210b06SDavid du Colombier
32425210b06SDavid du Colombier /*
32525210b06SDavid du Colombier * Kernel Stack
32625210b06SDavid du Colombier *
32725210b06SDavid du Colombier * N.B. make sure there's enough space for syscall to check
32825210b06SDavid du Colombier * for valid args and
32925210b06SDavid du Colombier * 4 bytes for gotolabel's return PC
33025210b06SDavid du Colombier */
33125210b06SDavid du Colombier p->sched.pc = (ulong)init0;
33225210b06SDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
33325210b06SDavid du Colombier
33425210b06SDavid du Colombier /* NB: no user stack nor text segments are set up */
33525210b06SDavid du Colombier
33625210b06SDavid du Colombier ready(p);
33725210b06SDavid du Colombier }
33825210b06SDavid du Colombier
33925210b06SDavid du Colombier void
confinit(void)34025210b06SDavid du Colombier confinit(void)
34125210b06SDavid du Colombier {
34225210b06SDavid du Colombier int i, userpcnt;
34325210b06SDavid du Colombier ulong kpages;
34425210b06SDavid du Colombier
34525210b06SDavid du Colombier userpcnt = 0; /* bootstrap; no user mode */
34625210b06SDavid du Colombier conf.npage = 0;
34725210b06SDavid du Colombier for(i=0; i<nelem(conf.mem); i++)
34825210b06SDavid du Colombier conf.npage += conf.mem[i].npage;
34925210b06SDavid du Colombier
35025210b06SDavid du Colombier conf.npage = MemMax / BY2PG;
35125210b06SDavid du Colombier conf.nproc = 20; /* need a few kprocs */
35225210b06SDavid du Colombier if(cpuserver)
35325210b06SDavid du Colombier conf.nproc *= 3;
35425210b06SDavid du Colombier if(conf.nproc > 2000)
35525210b06SDavid du Colombier conf.nproc = 2000;
35625210b06SDavid du Colombier conf.nimage = 40;
35725210b06SDavid du Colombier conf.nswap = conf.nproc*80;
35825210b06SDavid du Colombier conf.nswppo = 4096;
35925210b06SDavid du Colombier
36025210b06SDavid du Colombier kpages = conf.npage - (conf.npage*userpcnt)/100;
36125210b06SDavid du Colombier
36225210b06SDavid du Colombier /*
36325210b06SDavid du Colombier * can't go past the end of virtual memory
36425210b06SDavid du Colombier * (ulong)-KZERO is 2^32 - KZERO
36525210b06SDavid du Colombier */
36625210b06SDavid du Colombier if(kpages > ((ulong)-KZERO)/BY2PG)
36725210b06SDavid du Colombier kpages = ((ulong)-KZERO)/BY2PG;
36825210b06SDavid du Colombier
36925210b06SDavid du Colombier conf.upages = conf.npage - kpages;
37025210b06SDavid du Colombier conf.ialloc = (kpages/2)*BY2PG;
37125210b06SDavid du Colombier
37225210b06SDavid du Colombier /*
37325210b06SDavid du Colombier * Guess how much is taken by the large permanent
37425210b06SDavid du Colombier * datastructures. Mntcache and Mntrpc are not accounted for
37525210b06SDavid du Colombier * (probably ~300KB).
37625210b06SDavid du Colombier */
37725210b06SDavid du Colombier kpages *= BY2PG;
37825210b06SDavid du Colombier kpages -= conf.upages*sizeof(Page)
37925210b06SDavid du Colombier + conf.nproc*sizeof(Proc)
38025210b06SDavid du Colombier + conf.nimage*sizeof(Image)
38125210b06SDavid du Colombier + conf.nswap
38225210b06SDavid du Colombier + conf.nswppo*sizeof(Page);
38325210b06SDavid du Colombier mainmem->maxsize = kpages;
38425210b06SDavid du Colombier if(!cpuserver){
38525210b06SDavid du Colombier /*
38625210b06SDavid du Colombier * give terminals lots of image memory, too; the dynamic
38725210b06SDavid du Colombier * allocation will balance the load properly, hopefully.
38825210b06SDavid du Colombier * be careful with 32-bit overflow.
38925210b06SDavid du Colombier */
39025210b06SDavid du Colombier imagmem->maxsize = kpages;
39125210b06SDavid du Colombier }
39225210b06SDavid du Colombier }
39325210b06SDavid du Colombier
39425210b06SDavid du Colombier /*
39525210b06SDavid du Colombier * math coprocessor segment overrun
39625210b06SDavid du Colombier */
39725210b06SDavid du Colombier static void
mathover(Ureg *,void *)39825210b06SDavid du Colombier mathover(Ureg*, void*)
39925210b06SDavid du Colombier {
40025210b06SDavid du Colombier pexit("math overrun", 0);
40125210b06SDavid du Colombier }
40225210b06SDavid du Colombier
40325210b06SDavid du Colombier void
mathinit(void)40425210b06SDavid du Colombier mathinit(void)
40525210b06SDavid du Colombier {
40625210b06SDavid du Colombier }
40725210b06SDavid du Colombier
40825210b06SDavid du Colombier /*
40925210b06SDavid du Colombier * set up floating point for a new process
41025210b06SDavid du Colombier */
41125210b06SDavid du Colombier void
procsetup(Proc * p)41225210b06SDavid du Colombier procsetup(Proc*p)
41325210b06SDavid du Colombier {
41425210b06SDavid du Colombier p->fpstate = FPinit;
41525210b06SDavid du Colombier fpoff();
41625210b06SDavid du Colombier }
41725210b06SDavid du Colombier
41825210b06SDavid du Colombier void
procrestore(Proc * p)41925210b06SDavid du Colombier procrestore(Proc *p)
42025210b06SDavid du Colombier {
42125210b06SDavid du Colombier uvlong t;
42225210b06SDavid du Colombier
42325210b06SDavid du Colombier if(p->kp)
42425210b06SDavid du Colombier return;
42525210b06SDavid du Colombier cycles(&t);
42625210b06SDavid du Colombier p->pcycles -= t;
42725210b06SDavid du Colombier }
42825210b06SDavid du Colombier
42925210b06SDavid du Colombier /*
43025210b06SDavid du Colombier * Save the mach dependent part of the process state.
43125210b06SDavid du Colombier */
43225210b06SDavid du Colombier void
procsave(Proc * p)43325210b06SDavid du Colombier procsave(Proc *p)
43425210b06SDavid du Colombier {
43525210b06SDavid du Colombier uvlong t;
43625210b06SDavid du Colombier
43725210b06SDavid du Colombier cycles(&t);
43825210b06SDavid du Colombier p->pcycles += t;
43925210b06SDavid du Colombier
44025210b06SDavid du Colombier /*
44125210b06SDavid du Colombier * While this processor is in the scheduler, the process could run
44225210b06SDavid du Colombier * on another processor and exit, returning the page tables to
44325210b06SDavid du Colombier * the free list where they could be reallocated and overwritten.
44425210b06SDavid du Colombier * When this processor eventually has to get an entry from the
44525210b06SDavid du Colombier * trashed page tables it will crash.
44625210b06SDavid du Colombier *
44725210b06SDavid du Colombier * If there's only one processor, this can't happen.
44825210b06SDavid du Colombier * You might think it would be a win not to do this in that case,
44925210b06SDavid du Colombier * especially on VMware, but it turns out not to matter.
45025210b06SDavid du Colombier */
45125210b06SDavid du Colombier mmuflushtlb(PADDR(m->pdb));
45225210b06SDavid du Colombier }
45325210b06SDavid du Colombier
45425210b06SDavid du Colombier static void
shutdown(int ispanic)45525210b06SDavid du Colombier shutdown(int ispanic)
45625210b06SDavid du Colombier {
45725210b06SDavid du Colombier int ms, once;
45825210b06SDavid du Colombier
45925210b06SDavid du Colombier lock(&active);
46025210b06SDavid du Colombier if(ispanic)
46125210b06SDavid du Colombier active.ispanic = ispanic;
46225210b06SDavid du Colombier else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
46325210b06SDavid du Colombier active.ispanic = 0;
46425210b06SDavid du Colombier once = active.machs & (1<<m->machno);
46525210b06SDavid du Colombier /*
46625210b06SDavid du Colombier * setting exiting will make hzclock() on each processor call exit(0),
46725210b06SDavid du Colombier * which calls shutdown(0) and arch->reset(), which on mp systems is
46825210b06SDavid du Colombier * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
46925210b06SDavid du Colombier * processors (to permit a reboot). clearing our bit in machs avoids
47025210b06SDavid du Colombier * calling exit(0) from hzclock() on this processor.
47125210b06SDavid du Colombier */
47225210b06SDavid du Colombier active.machs &= ~(1<<m->machno);
47325210b06SDavid du Colombier active.exiting = 1;
47425210b06SDavid du Colombier unlock(&active);
47525210b06SDavid du Colombier
47625210b06SDavid du Colombier if(once)
47725210b06SDavid du Colombier iprint("cpu%d: exiting\n", m->machno);
47825210b06SDavid du Colombier
47925210b06SDavid du Colombier /* wait for any other processors to shutdown */
48025210b06SDavid du Colombier spllo();
48125210b06SDavid du Colombier for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
48225210b06SDavid du Colombier delay(TK2MS(2));
48325210b06SDavid du Colombier if(active.machs == 0 && consactive() == 0)
48425210b06SDavid du Colombier break;
48525210b06SDavid du Colombier }
48625210b06SDavid du Colombier
48725210b06SDavid du Colombier if(active.ispanic){
48825210b06SDavid du Colombier if(!cpuserver)
48925210b06SDavid du Colombier for(;;)
49025210b06SDavid du Colombier halt();
49125210b06SDavid du Colombier if(getconf("*debug"))
49225210b06SDavid du Colombier delay(5*60*1000);
49325210b06SDavid du Colombier else
49425210b06SDavid du Colombier delay(10000);
49525210b06SDavid du Colombier }else
49625210b06SDavid du Colombier delay(1000);
49725210b06SDavid du Colombier }
49825210b06SDavid du Colombier
49925210b06SDavid du Colombier void
reboot(void * entry,void * code,ulong size)50025210b06SDavid du Colombier reboot(void *entry, void *code, ulong size)
50125210b06SDavid du Colombier {
50225210b06SDavid du Colombier int i;
50325210b06SDavid du Colombier void (*f)(ulong, ulong, ulong);
50425210b06SDavid du Colombier ulong *pdb;
50525210b06SDavid du Colombier
50625210b06SDavid du Colombier /* we do pass options to the kernel we loaded, however, at CONFADDR. */
50725210b06SDavid du Colombier // writeconf();
50825210b06SDavid du Colombier
50925210b06SDavid du Colombier /*
51025210b06SDavid du Colombier * the boot processor is cpu0. execute this function on it
51125210b06SDavid du Colombier * so that the new kernel has the same cpu0. this only matters
51225210b06SDavid du Colombier * because the hardware has a notion of which processor was the
51325210b06SDavid du Colombier * boot processor and we look at it at start up.
51425210b06SDavid du Colombier */
51525210b06SDavid du Colombier if (m->machno != 0) {
51625210b06SDavid du Colombier procwired(up, 0);
51725210b06SDavid du Colombier sched();
51825210b06SDavid du Colombier }
51925210b06SDavid du Colombier
52025210b06SDavid du Colombier if(conf.nmach > 1) {
52125210b06SDavid du Colombier /*
52225210b06SDavid du Colombier * the other cpus could be holding locks that will never get
52325210b06SDavid du Colombier * released (e.g., in the print path) if we put them into
52425210b06SDavid du Colombier * reset now, so force them to shutdown gracefully first.
52525210b06SDavid du Colombier */
52625210b06SDavid du Colombier lock(&active);
52725210b06SDavid du Colombier active.rebooting = 1;
52825210b06SDavid du Colombier unlock(&active);
52925210b06SDavid du Colombier shutdown(0);
53025210b06SDavid du Colombier if(arch->resetothers)
53125210b06SDavid du Colombier arch->resetothers();
53225210b06SDavid du Colombier delay(20);
53325210b06SDavid du Colombier }
53425210b06SDavid du Colombier
53525210b06SDavid du Colombier /*
53625210b06SDavid du Colombier * should be the only processor running now
53725210b06SDavid du Colombier */
53825210b06SDavid du Colombier active.machs = 0;
53925210b06SDavid du Colombier if (m->machno != 0)
54025210b06SDavid du Colombier print("on cpu%d (not 0)!\n", m->machno);
54125210b06SDavid du Colombier
54225210b06SDavid du Colombier print("shutting down...\n");
54325210b06SDavid du Colombier delay(200);
54425210b06SDavid du Colombier
54525210b06SDavid du Colombier splhi();
54625210b06SDavid du Colombier
54725210b06SDavid du Colombier /* turn off buffered serial console */
54825210b06SDavid du Colombier serialoq = nil;
54925210b06SDavid du Colombier
55025210b06SDavid du Colombier /* shutdown devices */
55125210b06SDavid du Colombier chandevshutdown();
55225210b06SDavid du Colombier arch->introff();
55325210b06SDavid du Colombier
55425210b06SDavid du Colombier /*
55525210b06SDavid du Colombier * Modify the machine page table to directly map low memory
55625210b06SDavid du Colombier * This allows the reboot code to turn off the page mapping
55725210b06SDavid du Colombier */
55825210b06SDavid du Colombier pdb = m->pdb;
55925210b06SDavid du Colombier for (i = 0; i < LOWPTEPAGES; i++)
56025210b06SDavid du Colombier pdb[PDX(i*4*MB)] = pdb[PDX(KZERO + i*4*MB)];
56125210b06SDavid du Colombier mmuflushtlb(PADDR(pdb));
56225210b06SDavid du Colombier
56325210b06SDavid du Colombier /* setup reboot trampoline function */
56425210b06SDavid du Colombier f = (void*)REBOOTADDR;
56525210b06SDavid du Colombier memmove(f, rebootcode, sizeof(rebootcode));
56625210b06SDavid du Colombier
56725210b06SDavid du Colombier print("rebooting...\n");
56825210b06SDavid du Colombier
56925210b06SDavid du Colombier /* off we go - never to return */
57025210b06SDavid du Colombier coherence();
57125210b06SDavid du Colombier (*f)(PADDR(entry), PADDR(code), size);
57225210b06SDavid du Colombier }
57325210b06SDavid du Colombier
57425210b06SDavid du Colombier
57525210b06SDavid du Colombier void
exit(int ispanic)57625210b06SDavid du Colombier exit(int ispanic)
57725210b06SDavid du Colombier {
57825210b06SDavid du Colombier shutdown(ispanic);
57925210b06SDavid du Colombier spllo();
58025210b06SDavid du Colombier arch->reset();
58125210b06SDavid du Colombier }
58225210b06SDavid du Colombier
58325210b06SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)58425210b06SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
58525210b06SDavid du Colombier {
58625210b06SDavid du Colombier char cc[32], *p;
58725210b06SDavid du Colombier int i;
58825210b06SDavid du Colombier
58925210b06SDavid du Colombier snprint(cc, sizeof cc, "%s%d", class, ctlrno);
59025210b06SDavid du Colombier p = getconf(cc);
59125210b06SDavid du Colombier if(p == nil)
59225210b06SDavid du Colombier return 0;
59325210b06SDavid du Colombier
59425210b06SDavid du Colombier isa->type = "";
59525210b06SDavid du Colombier isa->nopt = tokenize(p, isa->opt, NISAOPT);
59625210b06SDavid du Colombier for(i = 0; i < isa->nopt; i++){
59725210b06SDavid du Colombier p = isa->opt[i];
59825210b06SDavid du Colombier if(cistrncmp(p, "type=", 5) == 0)
59925210b06SDavid du Colombier isa->type = p + 5;
60025210b06SDavid du Colombier else if(cistrncmp(p, "port=", 5) == 0)
60125210b06SDavid du Colombier isa->port = strtoul(p+5, &p, 0);
60225210b06SDavid du Colombier else if(cistrncmp(p, "irq=", 4) == 0)
60325210b06SDavid du Colombier isa->irq = strtoul(p+4, &p, 0);
60425210b06SDavid du Colombier else if(cistrncmp(p, "dma=", 4) == 0)
60525210b06SDavid du Colombier isa->dma = strtoul(p+4, &p, 0);
60625210b06SDavid du Colombier else if(cistrncmp(p, "mem=", 4) == 0)
60725210b06SDavid du Colombier isa->mem = strtoul(p+4, &p, 0);
60825210b06SDavid du Colombier else if(cistrncmp(p, "size=", 5) == 0)
60925210b06SDavid du Colombier isa->size = strtoul(p+5, &p, 0);
61025210b06SDavid du Colombier else if(cistrncmp(p, "freq=", 5) == 0)
61125210b06SDavid du Colombier isa->freq = strtoul(p+5, &p, 0);
61225210b06SDavid du Colombier }
61325210b06SDavid du Colombier return 1;
61425210b06SDavid du Colombier }
61525210b06SDavid du Colombier
61625210b06SDavid du Colombier int
cistrcmp(char * a,char * b)61725210b06SDavid du Colombier cistrcmp(char *a, char *b)
61825210b06SDavid du Colombier {
61925210b06SDavid du Colombier int ac, bc;
62025210b06SDavid du Colombier
62125210b06SDavid du Colombier for(;;){
62225210b06SDavid du Colombier ac = *a++;
62325210b06SDavid du Colombier bc = *b++;
62425210b06SDavid du Colombier
62525210b06SDavid du Colombier if(ac >= 'A' && ac <= 'Z')
62625210b06SDavid du Colombier ac = 'a' + (ac - 'A');
62725210b06SDavid du Colombier if(bc >= 'A' && bc <= 'Z')
62825210b06SDavid du Colombier bc = 'a' + (bc - 'A');
62925210b06SDavid du Colombier ac -= bc;
63025210b06SDavid du Colombier if(ac)
63125210b06SDavid du Colombier return ac;
63225210b06SDavid du Colombier if(bc == 0)
63325210b06SDavid du Colombier break;
63425210b06SDavid du Colombier }
63525210b06SDavid du Colombier return 0;
63625210b06SDavid du Colombier }
63725210b06SDavid du Colombier
63825210b06SDavid du Colombier int
cistrncmp(char * a,char * b,int n)63925210b06SDavid du Colombier cistrncmp(char *a, char *b, int n)
64025210b06SDavid du Colombier {
64125210b06SDavid du Colombier unsigned ac, bc;
64225210b06SDavid du Colombier
64325210b06SDavid du Colombier while(n > 0){
64425210b06SDavid du Colombier ac = *a++;
64525210b06SDavid du Colombier bc = *b++;
64625210b06SDavid du Colombier n--;
64725210b06SDavid du Colombier
64825210b06SDavid du Colombier if(ac >= 'A' && ac <= 'Z')
64925210b06SDavid du Colombier ac = 'a' + (ac - 'A');
65025210b06SDavid du Colombier if(bc >= 'A' && bc <= 'Z')
65125210b06SDavid du Colombier bc = 'a' + (bc - 'A');
65225210b06SDavid du Colombier
65325210b06SDavid du Colombier ac -= bc;
65425210b06SDavid du Colombier if(ac)
65525210b06SDavid du Colombier return ac;
65625210b06SDavid du Colombier if(bc == 0)
65725210b06SDavid du Colombier break;
65825210b06SDavid du Colombier }
65925210b06SDavid du Colombier
66025210b06SDavid du Colombier return 0;
66125210b06SDavid du Colombier }
66225210b06SDavid du Colombier
66325210b06SDavid du Colombier int less_power_slower;
66425210b06SDavid du Colombier
66525210b06SDavid du Colombier /*
66625210b06SDavid du Colombier * put the processor in the halt state if we've no processes to run.
66725210b06SDavid du Colombier * an interrupt will get us going again.
66825210b06SDavid du Colombier */
66925210b06SDavid du Colombier void
idlehands(void)67025210b06SDavid du Colombier idlehands(void)
67125210b06SDavid du Colombier {
67225210b06SDavid du Colombier /*
67325210b06SDavid du Colombier * we used to halt only on single-core setups. halting in an smp system
67425210b06SDavid du Colombier * can result in a startup latency for processes that become ready.
67525210b06SDavid du Colombier * if less_power_slower is true, we care more about saving energy
67625210b06SDavid du Colombier * than reducing this latency.
67725210b06SDavid du Colombier */
67825210b06SDavid du Colombier if(conf.nmach == 1 || less_power_slower)
67925210b06SDavid du Colombier halt();
68025210b06SDavid du Colombier }
68125210b06SDavid du Colombier
68225210b06SDavid du Colombier void
trimnl(char * s)68325210b06SDavid du Colombier trimnl(char *s)
68425210b06SDavid du Colombier {
68525210b06SDavid du Colombier char *nl;
68625210b06SDavid du Colombier
68725210b06SDavid du Colombier nl = strchr(s, '\n');
68825210b06SDavid du Colombier if (nl != nil)
68925210b06SDavid du Colombier *nl = '\0';
69025210b06SDavid du Colombier }
691