/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 9boot - load next 386 or amd64 kernel from disk and start it * and * 9load - load next 386 or amd64 kernel via pxe (bootp, tftp) and start it * * intel says that pxe can only load into the bottom 640K, and * intel's pxe boot agent takes 128K, leaving only 512K for 9boot. */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "pool.h"#include "reboot.h"#include "ip.h" /* for eipfmt */#include <tos.h> enum { Datamagic = 0xbabeabed,}; Mach *m; ulong* mach0pdb;Mach* mach0m;Segdesc* mach0gdt;u32int memstart;u32int memend;int noclock; extern int pcivga;extern char hellomsg[]; /* * Where configuration info is left for the loaded programme. */char bootdisk[KNAMELEN];Conf conf; uchar *sp; /* user stack of init proc */int delaylink;int debug;int v_flag; static voidsanity(void){ uintptr cr3; cr3 = (uintptr)KADDR(getcr3()); if (cr3 == 0) panic("zero cr3"); if ((uintptr)m->pdb != cr3 || (uintptr)mach0pdb != cr3) panic("not all same: cr3 %#p m->pdb %#p mach0pdb %#p", cr3, m->pdb, mach0pdb); if (m != mach0m) panic("m %#p != mach0m %#p", m, mach0m); if (m->gdt != mach0gdt) panic("m->gdt %#p != mach0gdt %#p", m->gdt, mach0gdt); if (0) iprint("m->pdb %#p m %#p sp %#p m->gdt %#p\n", m->pdb, m, &cr3, m->gdt);} enum { /* system control port a */ Sysctla= 0x92, Sysctlreset= 1<<0, Sysctla20ena= 1<<1,}; static intisa20on(void){ int r; ulong o; ulong *zp, *mb1p; zp = 0; mb1p = (ulong *)MB; o = *zp; *zp = 0x1234; *mb1p = 0x8765; mb586(); wbinvd(); r = *zp != *mb1p; *zp = o; return r;} voida20init(void){ int b; if (isa20on()) return; i8042a20(); /* original method, via kbd ctlr */ if (isa20on()) return; /* newer method, last resort */ b = inb(Sysctla); if (!(b & Sysctla20ena)) outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena); if (!isa20on()) iprint("a20 didn't come on!\n");} voidmain(void){ Proc *savup; static ulong vfy = Datamagic; static char novga[] = "\nno vga; serial console only\n"; savup = up; up = nil; /* m has been set by l32v.s */ /* * disable address wraps at 1MB boundaries. * if we're 9boot, ldecomp.s already did this. */ a20init(); mach0init();// options(); /* we don't get options passed to us */ ioinit(); /* we later call i8250console after plan9.ini has been read */ i8250config("0"); /* configure serial port 0 with defaults */ quotefmtinstall(); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); screeninit(); /* cga setup */ cgapost(0xc); trapinit0(); mmuinit0(); kbdinit(); i8253init(); cpuidentify(); readlsconf(); meminit(); confinit(); archinit(); xinit(); if(i8237alloc != nil) i8237alloc(); /* dma (for floppy) init */ trapinit(); printinit(); sanity(); cgapost(1); /* * soekris servers have no built-in video but each has a serial port. * they must see serial output, if any, before cga output because * otherwise the soekris bios will translate cga output to serial * output, which will garble serial console output. */ pcimatch(nil, 0, 0); /* force scan of pci table */ if (!pcivga) { screenputs = nil; uartputs(novga, sizeof novga - 1); } print(" %s\n\n", hellomsg); if (vfy != Datamagic) panic("data segment incorrectly aligned or loaded"); if (savup) print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n", savup); // xsummary(); cpuidprint(); mmuinit(); if(arch->intrinit) /* launches other processors on an mp */ arch->intrinit(); timersinit(); mathinit(); kbdenable(); /* * 9loadusb runs much faster if we don't use the clock. * perhaps we're competing with the bios for the use of it? */ if(!noclock && arch->clockenable) arch->clockenable(); procinit0(); initseg(); if(delaylink){ bootlinks(); pcimatch(0, 0, 0); }else links(); conf.monitor = 1; cgapost(0xcd); chandevreset(); cgapost(2); pageinit(); /* must follow xinit, and conf.mem must be populated */ i8253link(); userinit(); active.thunderbirdsarego = 1; cgapost(0xb0); schedinit();} voidmach0init(void){ conf.nmach = 1; MACHP(0) = mach0m; m->machno = 0; m->pdb = mach0pdb; m->gdt = mach0gdt; machinit(); active.machs = 1; active.exiting = 0;} voidmachinit(void){ int machno; ulong *pdb; Segdesc *gdt; machno = m->machno; pdb = m->pdb; gdt = m->gdt; memset(m, 0, sizeof(Mach)); m->machno = machno; m->pdb = pdb; m->gdt = gdt; m->perf.period = 1; /* * For polled uart output at boot, need * a default delay constant. 100000 should * be enough for a while. Cpuidentify will * calculate the real value later. */ m->loopconst = 100000;} voidinit0(void){ int i; char buf[2*KNAMELEN]; up->nerrlab = 0; spllo(); /* * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); pathclose(up->slash->path); up->slash->path = newpath("/"); up->dot = cclone(up->slash); chandevinit(); if(0 && !waserror()){ /* not needed by boot */ snprint(buf, sizeof(buf), "%s %s", arch->id, conffile); ksetenv("terminal", buf, 0); ksetenv("cputype", "386", 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); for(i = 0; i < nconf; i++){ if(confname[i][0] != '*') ksetenv(confname[i], confval[i], 0); ksetenv(confname[i], confval[i], 1); } poperror(); } kproc("alarm", alarmkproc, 0); conschan = enamecopen("#c/cons", ORDWR); bootloadproc(0); panic("bootloadproc returned");} voiduserinit(void){ Proc *p; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); p->fpstate = FPinit; fpoff(); /* * Kernel Stack * * N.B. make sure there's enough space for syscall to check * for valid args and * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* NB: no user stack nor text segments are set up */ ready(p);} voidconfinit(void){ int i, userpcnt; ulong kpages; userpcnt = 0; /* bootstrap; no user mode */ conf.npage = 0; for(i=0; i<nelem(conf.mem); i++) conf.npage += conf.mem[i].npage; conf.npage = MemMax / BY2PG; conf.nproc = 20; /* need a few kprocs */ if(cpuserver) conf.nproc *= 3; if(conf.nproc > 2000) conf.nproc = 2000; conf.nimage = 40; conf.nswap = conf.nproc*80; conf.nswppo = 4096; kpages = conf.npage - (conf.npage*userpcnt)/100; /* * can't go past the end of virtual memory * (ulong)-KZERO is 2^32 - KZERO */ if(kpages > ((ulong)-KZERO)/BY2PG) kpages = ((ulong)-KZERO)/BY2PG; conf.upages = conf.npage - kpages; conf.ialloc = (kpages/2)*BY2PG; /* * Guess how much is taken by the large permanent * datastructures. Mntcache and Mntrpc are not accounted for * (probably ~300KB). */ kpages *= BY2PG; kpages -= conf.upages*sizeof(Page) + conf.nproc*sizeof(Proc) + conf.nimage*sizeof(Image) + conf.nswap + conf.nswppo*sizeof(Page); mainmem->maxsize = kpages; if(!cpuserver){ /* * give terminals lots of image memory, too; the dynamic * allocation will balance the load properly, hopefully. * be careful with 32-bit overflow. */ imagmem->maxsize = kpages; }} /* * math coprocessor segment overrun */static voidmathover(Ureg*, void*){ pexit("math overrun", 0);} voidmathinit(void){} /* * set up floating point for a new process */voidprocsetup(Proc*p){ p->fpstate = FPinit; fpoff();} voidprocrestore(Proc *p){ uvlong t; if(p->kp) return; cycles(&t); p->pcycles -= t;} /* * Save the mach dependent part of the process state. */voidprocsave(Proc *p){ uvlong t; cycles(&t); p->pcycles += t; /* * While this processor is in the scheduler, the process could run * on another processor and exit, returning the page tables to * the free list where they could be reallocated and overwritten. * When this processor eventually has to get an entry from the * trashed page tables it will crash. * * If there's only one processor, this can't happen. * You might think it would be a win not to do this in that case, * especially on VMware, but it turns out not to matter. */ mmuflushtlb(PADDR(m->pdb));} static voidshutdown(int ispanic){ int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), * which calls shutdown(0) and arch->reset(), which on mp systems is * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap * processors (to permit a reboot). clearing our bit in machs avoids * calling exit(0) from hzclock() on this processor. */ active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) iprint("cpu%d: exiting\n", m->machno); /* wait for any other processors to shutdown */ spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } if(active.ispanic){ if(!cpuserver) for(;;) halt(); if(getconf("*debug")) delay(5*60*1000); else delay(10000);Lines 1–500 of 696. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 9boot - load next 386 or amd64 kernel from disk and start it * and * 9load - load next 386 or amd64 kernel via pxe (bootp, tftp) and start it * * intel says that pxe can only load into the bottom 640K, and * intel's pxe boot agent takes 128K, leaving only 512K for 9boot. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "pool.h" #include "reboot.h" #include "ip.h" /* for eipfmt */ #include <tos.h> enum { Datamagic = 0xbabeabed, }; Mach *m; ulong* mach0pdb; Mach* mach0m; Segdesc* mach0gdt; u32int memstart; u32int memend; int noclock; extern int pcivga; extern char hellomsg[]; /* * Where configuration info is left for the loaded programme. */ char bootdisk[KNAMELEN]; Conf conf; uchar *sp; /* user stack of init proc */ int delaylink; int debug; int v_flag; static void sanity(void) { uintptr cr3; cr3 = (uintptr)KADDR(getcr3()); if (cr3 == 0) panic("zero cr3"); if ((uintptr)m->pdb != cr3 || (uintptr)mach0pdb != cr3) panic("not all same: cr3 %#p m->pdb %#p mach0pdb %#p", cr3, m->pdb, mach0pdb); if (m != mach0m) panic("m %#p != mach0m %#p", m, mach0m); if (m->gdt != mach0gdt) panic("m->gdt %#p != mach0gdt %#p", m->gdt, mach0gdt); if (0) iprint("m->pdb %#p m %#p sp %#p m->gdt %#p\n", m->pdb, m, &cr3, m->gdt); } enum { /* system control port a */ Sysctla= 0x92, Sysctlreset= 1<<0, Sysctla20ena= 1<<1, }; static int isa20on(void) { int r; ulong o; ulong *zp, *mb1p; zp = 0; mb1p = (ulong *)MB; o = *zp; *zp = 0x1234; *mb1p = 0x8765; mb586(); wbinvd(); r = *zp != *mb1p; *zp = o; return r; } void a20init(void) { int b; if (isa20on()) return; i8042a20(); /* original method, via kbd ctlr */ if (isa20on()) return; /* newer method, last resort */ b = inb(Sysctla); if (!(b & Sysctla20ena)) outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena); if (!isa20on()) iprint("a20 didn't come on!\n"); } void main(void) { Proc *savup; static ulong vfy = Datamagic; static char novga[] = "\nno vga; serial console only\n"; savup = up; up = nil; /* m has been set by l32v.s */ /* * disable address wraps at 1MB boundaries. * if we're 9boot, ldecomp.s already did this. */ a20init(); mach0init(); // options(); /* we don't get options passed to us */ ioinit(); /* we later call i8250console after plan9.ini has been read */ i8250config("0"); /* configure serial port 0 with defaults */ quotefmtinstall(); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); screeninit(); /* cga setup */ cgapost(0xc); trapinit0(); mmuinit0(); kbdinit(); i8253init(); cpuidentify(); readlsconf(); meminit(); confinit(); archinit(); xinit(); if(i8237alloc != nil) i8237alloc(); /* dma (for floppy) init */ trapinit(); printinit(); sanity(); cgapost(1); /* * soekris servers have no built-in video but each has a serial port. * they must see serial output, if any, before cga output because * otherwise the soekris bios will translate cga output to serial * output, which will garble serial console output. */ pcimatch(nil, 0, 0); /* force scan of pci table */ if (!pcivga) { screenputs = nil; uartputs(novga, sizeof novga - 1); } print(" %s\n\n", hellomsg); if (vfy != Datamagic) panic("data segment incorrectly aligned or loaded"); if (savup) print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n", savup); // xsummary(); cpuidprint(); mmuinit(); if(arch->intrinit) /* launches other processors on an mp */ arch->intrinit(); timersinit(); mathinit(); kbdenable(); /* * 9loadusb runs much faster if we don't use the clock. * perhaps we're competing with the bios for the use of it? */ if(!noclock && arch->clockenable) arch->clockenable(); procinit0(); initseg(); if(delaylink){ bootlinks(); pcimatch(0, 0, 0); }else links(); conf.monitor = 1; cgapost(0xcd); chandevreset(); cgapost(2); pageinit(); /* must follow xinit, and conf.mem must be populated */ i8253link(); userinit(); active.thunderbirdsarego = 1; cgapost(0xb0); schedinit(); } void mach0init(void) { conf.nmach = 1; MACHP(0) = mach0m; m->machno = 0; m->pdb = mach0pdb; m->gdt = mach0gdt; machinit(); active.machs = 1; active.exiting = 0; } void machinit(void) { int machno; ulong *pdb; Segdesc *gdt; machno = m->machno; pdb = m->pdb; gdt = m->gdt; memset(m, 0, sizeof(Mach)); m->machno = machno; m->pdb = pdb; m->gdt = gdt; m->perf.period = 1; /* * For polled uart output at boot, need * a default delay constant. 100000 should * be enough for a while. Cpuidentify will * calculate the real value later. */ m->loopconst = 100000; } void init0(void) { int i; char buf[2*KNAMELEN]; up->nerrlab = 0; spllo(); /* * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); pathclose(up->slash->path); up->slash->path = newpath("/"); up->dot = cclone(up->slash); chandevinit(); if(0 && !waserror()){ /* not needed by boot */ snprint(buf, sizeof(buf), "%s %s", arch->id, conffile); ksetenv("terminal", buf, 0); ksetenv("cputype", "386", 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); for(i = 0; i < nconf; i++){ if(confname[i][0] != '*') ksetenv(confname[i], confval[i], 0); ksetenv(confname[i], confval[i], 1); } poperror(); } kproc("alarm", alarmkproc, 0); conschan = enamecopen("#c/cons", ORDWR); bootloadproc(0); panic("bootloadproc returned"); } void userinit(void) { Proc *p; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); p->fpstate = FPinit; fpoff(); /* * Kernel Stack * * N.B. make sure there's enough space for syscall to check * for valid args and * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* NB: no user stack nor text segments are set up */ ready(p); } void confinit(void) { int i, userpcnt; ulong kpages; userpcnt = 0; /* bootstrap; no user mode */ conf.npage = 0; for(i=0; i<nelem(conf.mem); i++) conf.npage += conf.mem[i].npage; conf.npage = MemMax / BY2PG; conf.nproc = 20; /* need a few kprocs */ if(cpuserver) conf.nproc *= 3; if(conf.nproc > 2000) conf.nproc = 2000; conf.nimage = 40; conf.nswap = conf.nproc*80; conf.nswppo = 4096; kpages = conf.npage - (conf.npage*userpcnt)/100; /* * can't go past the end of virtual memory * (ulong)-KZERO is 2^32 - KZERO */ if(kpages > ((ulong)-KZERO)/BY2PG) kpages = ((ulong)-KZERO)/BY2PG; conf.upages = conf.npage - kpages; conf.ialloc = (kpages/2)*BY2PG; /* * Guess how much is taken by the large permanent * datastructures. Mntcache and Mntrpc are not accounted for * (probably ~300KB). */ kpages *= BY2PG; kpages -= conf.upages*sizeof(Page) + conf.nproc*sizeof(Proc) + conf.nimage*sizeof(Image) + conf.nswap + conf.nswppo*sizeof(Page); mainmem->maxsize = kpages; if(!cpuserver){ /* * give terminals lots of image memory, too; the dynamic * allocation will balance the load properly, hopefully. * be careful with 32-bit overflow. */ imagmem->maxsize = kpages; } } /* * math coprocessor segment overrun */ static void mathover(Ureg*, void*) { pexit("math overrun", 0); } void mathinit(void) { } /* * set up floating point for a new process */ void procsetup(Proc*p) { p->fpstate = FPinit; fpoff(); } void procrestore(Proc *p) { uvlong t; if(p->kp) return; cycles(&t); p->pcycles -= t; } /* * Save the mach dependent part of the process state. */ void procsave(Proc *p) { uvlong t; cycles(&t); p->pcycles += t; /* * While this processor is in the scheduler, the process could run * on another processor and exit, returning the page tables to * the free list where they could be reallocated and overwritten. * When this processor eventually has to get an entry from the * trashed page tables it will crash. * * If there's only one processor, this can't happen. * You might think it would be a win not to do this in that case, * especially on VMware, but it turns out not to matter. */ mmuflushtlb(PADDR(m->pdb)); } static void shutdown(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), * which calls shutdown(0) and arch->reset(), which on mp systems is * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap * processors (to permit a reboot). clearing our bit in machs avoids * calling exit(0) from hzclock() on this processor. */ active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) iprint("cpu%d: exiting\n", m->machno); /* wait for any other processors to shutdown */ spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } if(active.ispanic){ if(!cpuserver) for(;;) halt(); if(getconf("*debug")) delay(5*60*1000); else delay(10000);