2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "io.h"
|
2011-05-14 17:05:51 +00:00
|
|
|
#include "tos.h"
|
2011-03-30 12:46:40 +00:00
|
|
|
#include "ureg.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "pool.h"
|
|
|
|
#include "reboot.h"
|
|
|
|
|
|
|
|
Mach *m;
|
|
|
|
Conf conf;
|
2017-06-25 20:22:58 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
int delaylink;
|
2013-12-31 03:41:51 +00:00
|
|
|
int idle_spin;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
extern void (*i8237alloc)(void);
|
2014-10-13 21:02:53 +00:00
|
|
|
extern void bootscreeninit(void);
|
2017-06-25 20:22:58 +00:00
|
|
|
extern void multibootdebug(void);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
main(void)
|
|
|
|
{
|
|
|
|
mach0init();
|
2017-06-25 20:22:58 +00:00
|
|
|
bootargsinit();
|
2011-03-30 12:46:40 +00:00
|
|
|
ioinit();
|
|
|
|
i8250console();
|
|
|
|
quotefmtinstall();
|
|
|
|
screeninit();
|
|
|
|
|
|
|
|
print("\nPlan 9\n");
|
2017-06-25 20:22:58 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
trapinit0();
|
|
|
|
i8253init();
|
|
|
|
cpuidentify();
|
|
|
|
meminit();
|
|
|
|
confinit();
|
|
|
|
xinit();
|
2014-10-18 00:01:58 +00:00
|
|
|
archinit();
|
|
|
|
bootscreeninit();
|
2011-03-30 12:46:40 +00:00
|
|
|
if(i8237alloc != nil)
|
|
|
|
i8237alloc();
|
|
|
|
trapinit();
|
|
|
|
printinit();
|
|
|
|
cpuidprint();
|
|
|
|
mmuinit();
|
|
|
|
if(arch->intrinit) /* launches other processors on an mp */
|
|
|
|
arch->intrinit();
|
|
|
|
timersinit();
|
|
|
|
mathinit();
|
|
|
|
if(arch->clockenable)
|
|
|
|
arch->clockenable();
|
|
|
|
procinit0();
|
|
|
|
initseg();
|
|
|
|
if(delaylink){
|
|
|
|
bootlinks();
|
|
|
|
pcimatch(0, 0, 0);
|
|
|
|
}else
|
|
|
|
links();
|
|
|
|
chandevreset();
|
|
|
|
pageinit();
|
|
|
|
userinit();
|
|
|
|
schedinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mach0init(void)
|
|
|
|
{
|
|
|
|
conf.nmach = 1;
|
|
|
|
MACHP(0) = (Mach*)CPU0MACH;
|
|
|
|
m->pdb = (ulong*)CPU0PDB;
|
|
|
|
m->gdt = (Segdesc*)CPU0GDT;
|
|
|
|
|
|
|
|
machinit();
|
|
|
|
|
2016-01-05 04:32:40 +00:00
|
|
|
active.machs[0] = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
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)
|
|
|
|
{
|
2017-06-28 16:56:16 +00:00
|
|
|
char buf[2*KNAMELEN], **sp;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
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(!waserror()){
|
|
|
|
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);
|
2017-06-25 20:22:58 +00:00
|
|
|
setconfenv();
|
2011-03-30 12:46:40 +00:00
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
kproc("alarm", alarmkproc, 0);
|
2017-06-25 20:22:58 +00:00
|
|
|
|
2017-06-28 16:56:16 +00:00
|
|
|
sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
|
|
|
|
sp[3] = sp[2] = nil;
|
|
|
|
strcpy(sp[1] = (char*)&sp[4], "boot");
|
|
|
|
sp[0] = nil;
|
|
|
|
touser(sp);
|
2017-06-25 20:22:58 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
void
|
|
|
|
userinit(void)
|
|
|
|
{
|
|
|
|
void *v;
|
|
|
|
Proc *p;
|
|
|
|
Segment *s;
|
|
|
|
Page *pg;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2011-07-12 13:46:22 +00:00
|
|
|
procsetup(p);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* User Stack
|
|
|
|
*
|
|
|
|
* N.B. cannot call newpage() with clear=1, because pc kmap
|
|
|
|
* requires up != nil. use tmpmap instead.
|
|
|
|
*/
|
|
|
|
s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
|
|
|
|
p->seg[SSEG] = s;
|
|
|
|
pg = newpage(0, 0, USTKTOP-BY2PG);
|
2017-06-28 16:56:16 +00:00
|
|
|
segpage(s, pg);
|
2011-03-30 12:46:40 +00:00
|
|
|
v = tmpmap(pg);
|
|
|
|
memset(v, 0, BY2PG);
|
|
|
|
tmpunmap(v);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Text
|
|
|
|
*/
|
|
|
|
s = newseg(SG_TEXT, UTZERO, 1);
|
|
|
|
s->flushme++;
|
|
|
|
p->seg[TSEG] = s;
|
|
|
|
pg = newpage(0, 0, UTZERO);
|
2015-02-07 01:52:23 +00:00
|
|
|
pg->txtflush = ~0;
|
2011-03-30 12:46:40 +00:00
|
|
|
segpage(s, pg);
|
|
|
|
v = tmpmap(pg);
|
|
|
|
memset(v, 0, BY2PG);
|
|
|
|
memmove(v, initcode, sizeof initcode);
|
|
|
|
tmpunmap(v);
|
|
|
|
|
|
|
|
ready(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
confinit(void)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
int i, userpcnt;
|
|
|
|
ulong kpages;
|
|
|
|
|
2014-03-14 23:55:02 +00:00
|
|
|
if(p = getconf("service")){
|
|
|
|
if(strcmp(p, "cpu") == 0)
|
|
|
|
cpuserver = 1;
|
|
|
|
else if(strcmp(p,"terminal") == 0)
|
|
|
|
cpuserver = 0;
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(p = getconf("*kernelpercent"))
|
|
|
|
userpcnt = 100 - strtol(p, 0, 0);
|
|
|
|
else
|
|
|
|
userpcnt = 0;
|
|
|
|
|
|
|
|
conf.npage = 0;
|
|
|
|
for(i=0; i<nelem(conf.mem); i++)
|
|
|
|
conf.npage += conf.mem[i].npage;
|
|
|
|
|
|
|
|
conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
|
|
|
|
if(cpuserver)
|
|
|
|
conf.nproc *= 3;
|
|
|
|
if(conf.nproc > 2000)
|
|
|
|
conf.nproc = 2000;
|
|
|
|
conf.nimage = 200;
|
|
|
|
conf.nswap = conf.nproc*80;
|
|
|
|
conf.nswppo = 4096;
|
|
|
|
|
|
|
|
if(cpuserver) {
|
|
|
|
if(userpcnt < 10)
|
|
|
|
userpcnt = 70;
|
|
|
|
kpages = conf.npage - (conf.npage*userpcnt)/100;
|
2017-03-11 15:28:11 +00:00
|
|
|
conf.nimage = conf.nproc;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Hack for the big boys. Only good while physmem < 4GB.
|
|
|
|
* Give the kernel fixed max + enough to allocate the
|
|
|
|
* page pool.
|
|
|
|
* This is an overestimate as conf.upages < conf.npages.
|
|
|
|
* The patch of nimage is a band-aid, scanning the whole
|
|
|
|
* page list in imagereclaim just takes too long.
|
|
|
|
*/
|
2013-08-02 15:52:51 +00:00
|
|
|
if(getconf("*imagemaxmb") == 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
|
|
|
|
kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
|
|
|
|
kpages += (conf.nproc*KSTACK)/BY2PG;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(userpcnt < 10) {
|
|
|
|
if(conf.npage*BY2PG < 16*MB)
|
2011-12-13 15:16:01 +00:00
|
|
|
userpcnt = 50;
|
2011-03-30 12:46:40 +00:00
|
|
|
else
|
|
|
|
userpcnt = 60;
|
|
|
|
}
|
|
|
|
kpages = conf.npage - (conf.npage*userpcnt)/100;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure terminals with low memory get at least
|
|
|
|
* 4MB on the first Image chunk allocation.
|
|
|
|
*/
|
|
|
|
if(conf.npage*BY2PG < 16*MB)
|
2012-03-18 19:12:29 +00:00
|
|
|
imagmem->minarena = 4*MB;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2014-12-16 07:11:21 +00:00
|
|
|
* datastructures. Mntcache and Mntrpc are not accounted for.
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
|
|
|
kpages *= BY2PG;
|
|
|
|
kpages -= conf.upages*sizeof(Page)
|
|
|
|
+ conf.nproc*sizeof(Proc)
|
|
|
|
+ conf.nimage*sizeof(Image)
|
|
|
|
+ conf.nswap
|
2011-12-13 23:10:33 +00:00
|
|
|
+ conf.nswppo*sizeof(Page*);
|
2011-03-30 12:46:40 +00:00
|
|
|
mainmem->maxsize = kpages;
|
2012-03-18 19:12:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the dynamic allocation will balance the load properly,
|
|
|
|
* hopefully. be careful with 32-bit overflow.
|
|
|
|
*/
|
2012-10-06 05:05:08 +00:00
|
|
|
imagmem->maxsize = kpages - (kpages/10);
|
2012-03-18 19:12:29 +00:00
|
|
|
if(p = getconf("*imagemaxmb")){
|
|
|
|
imagmem->maxsize = strtol(p, nil, 0)*MB;
|
|
|
|
if(imagmem->maxsize > mainmem->maxsize)
|
|
|
|
imagmem->maxsize = mainmem->maxsize;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-26 20:41:40 +00:00
|
|
|
/*
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
* we keep FPsave structure in SSE format emulating FXSAVE / FXRSTOR
|
2013-05-26 20:41:40 +00:00
|
|
|
* instructions for legacy x87 fpu.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fpx87save(FPsave *fps)
|
|
|
|
{
|
2013-05-30 21:16:22 +00:00
|
|
|
ushort tag;
|
|
|
|
|
2013-05-26 20:41:40 +00:00
|
|
|
fpx87save0(fps);
|
|
|
|
|
2013-05-30 21:16:22 +00:00
|
|
|
/*
|
|
|
|
* convert x87 tag word to fxsave tag byte:
|
|
|
|
* 00, 01, 10 -> 1, 11 -> 0
|
|
|
|
*/
|
|
|
|
tag = ~fps->tag;
|
|
|
|
tag = (tag | (tag >> 1)) & 0x5555;
|
|
|
|
tag = (tag | (tag >> 1)) & 0x3333;
|
|
|
|
tag = (tag | (tag >> 2)) & 0x0F0F;
|
|
|
|
tag = (tag | (tag >> 4)) & 0x00FF;
|
|
|
|
|
2013-05-26 20:41:40 +00:00
|
|
|
/* NOP fps->fcw = fps->control; */
|
|
|
|
fps->fsw = fps->status;
|
2013-05-30 21:16:22 +00:00
|
|
|
fps->ftw = tag;
|
2013-05-26 20:41:40 +00:00
|
|
|
fps->fop = fps->opcode;
|
|
|
|
fps->fpuip = fps->pc;
|
|
|
|
fps->cs = fps->selector;
|
|
|
|
fps->fpudp = fps->operand;
|
|
|
|
fps->ds = fps->oselector;
|
|
|
|
|
|
|
|
#define MOVA(d,s) \
|
|
|
|
*((ushort*)(d+8)) = *((ushort*)(s+8)), \
|
|
|
|
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
|
|
|
|
*((ulong*)(d)) = *((ulong*)(s))
|
|
|
|
|
|
|
|
MOVA(fps->xregs+0x70, fps->regs+70);
|
|
|
|
MOVA(fps->xregs+0x60, fps->regs+60);
|
|
|
|
MOVA(fps->xregs+0x50, fps->regs+50);
|
|
|
|
MOVA(fps->xregs+0x40, fps->regs+40);
|
|
|
|
MOVA(fps->xregs+0x30, fps->regs+30);
|
|
|
|
MOVA(fps->xregs+0x20, fps->regs+20);
|
|
|
|
MOVA(fps->xregs+0x10, fps->regs+10);
|
|
|
|
MOVA(fps->xregs+0x00, fps->regs+00);
|
|
|
|
|
|
|
|
#undef MOVA
|
|
|
|
|
|
|
|
#define CLR6(d) \
|
|
|
|
*((ulong*)(d)) = 0, \
|
|
|
|
*((ushort*)(d+4)) = 0
|
|
|
|
|
|
|
|
CLR6(fps->xregs+0x70+10);
|
|
|
|
CLR6(fps->xregs+0x60+10);
|
|
|
|
CLR6(fps->xregs+0x50+10);
|
|
|
|
CLR6(fps->xregs+0x40+10);
|
|
|
|
CLR6(fps->xregs+0x30+10);
|
|
|
|
CLR6(fps->xregs+0x20+10);
|
|
|
|
CLR6(fps->xregs+0x10+10);
|
|
|
|
CLR6(fps->xregs+0x00+10);
|
|
|
|
|
|
|
|
#undef CLR6
|
|
|
|
|
|
|
|
fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fpx87restore(FPsave *fps)
|
|
|
|
{
|
2013-05-30 21:16:22 +00:00
|
|
|
ushort msk, tos, tag, *reg;
|
|
|
|
|
|
|
|
/* convert fxsave tag byte to x87 tag word */
|
|
|
|
tag = 0;
|
|
|
|
tos = 7 - ((fps->fsw >> 11) & 7);
|
|
|
|
for(msk = 0x80; msk != 0; tos--, msk >>= 1){
|
|
|
|
tag <<= 2;
|
|
|
|
if((fps->ftw & msk) != 0){
|
|
|
|
reg = (ushort*)&fps->xregs[(tos & 7) << 4];
|
|
|
|
switch(reg[4] & 0x7fff){
|
|
|
|
case 0x0000:
|
|
|
|
if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
|
|
|
|
tag |= 1; /* 01 zero */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* no break */
|
|
|
|
case 0x7fff:
|
|
|
|
tag |= 2; /* 10 special */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if((reg[3] & 0x8000) == 0)
|
|
|
|
break; /* 00 valid */
|
|
|
|
tag |= 2; /* 10 special */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
tag |= 3; /* 11 empty */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-26 20:41:40 +00:00
|
|
|
#define MOVA(d,s) \
|
|
|
|
*((ulong*)(d)) = *((ulong*)(s)), \
|
|
|
|
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
|
|
|
|
*((ushort*)(d+8)) = *((ushort*)(s+8))
|
|
|
|
|
|
|
|
MOVA(fps->regs+00, fps->xregs+0x00);
|
|
|
|
MOVA(fps->regs+10, fps->xregs+0x10);
|
|
|
|
MOVA(fps->regs+20, fps->xregs+0x20);
|
|
|
|
MOVA(fps->regs+30, fps->xregs+0x30);
|
|
|
|
MOVA(fps->regs+40, fps->xregs+0x40);
|
|
|
|
MOVA(fps->regs+50, fps->xregs+0x50);
|
|
|
|
MOVA(fps->regs+60, fps->xregs+0x60);
|
|
|
|
MOVA(fps->regs+70, fps->xregs+0x70);
|
|
|
|
|
|
|
|
#undef MOVA
|
|
|
|
|
|
|
|
fps->oselector = fps->ds;
|
|
|
|
fps->operand = fps->fpudp;
|
2013-05-30 21:16:22 +00:00
|
|
|
fps->opcode = fps->fop & 0x7ff;
|
2013-05-26 20:41:40 +00:00
|
|
|
fps->selector = fps->cs;
|
|
|
|
fps->pc = fps->fpuip;
|
2013-05-30 21:16:22 +00:00
|
|
|
fps->tag = tag;
|
2013-05-26 20:41:40 +00:00
|
|
|
fps->status = fps->fsw;
|
|
|
|
/* NOP fps->control = fps->fcw; */
|
|
|
|
|
|
|
|
fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
|
|
|
|
|
|
|
|
fpx87restore0(fps);
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
static char* mathmsg[] =
|
|
|
|
{
|
|
|
|
nil, /* handled below */
|
|
|
|
"denormalized operand",
|
|
|
|
"division by zero",
|
|
|
|
"numeric overflow",
|
|
|
|
"numeric underflow",
|
|
|
|
"precision loss",
|
|
|
|
};
|
|
|
|
|
2013-05-22 18:17:05 +00:00
|
|
|
static void
|
2013-05-25 20:44:19 +00:00
|
|
|
mathnote(ulong status, ulong pc)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
char *msg, note[ERRMAX];
|
2013-05-25 20:44:19 +00:00
|
|
|
int i;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Some attention should probably be paid here to the
|
|
|
|
* exception masks and error summary.
|
|
|
|
*/
|
|
|
|
msg = "unknown exception";
|
|
|
|
for(i = 1; i <= 5; i++){
|
|
|
|
if(!((1<<i) & status))
|
|
|
|
continue;
|
|
|
|
msg = mathmsg[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(status & 0x01){
|
|
|
|
if(status & 0x40){
|
|
|
|
if(status & 0x200)
|
|
|
|
msg = "stack overflow";
|
|
|
|
else
|
|
|
|
msg = "stack underflow";
|
|
|
|
}else
|
|
|
|
msg = "invalid operation";
|
|
|
|
}
|
|
|
|
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
|
2013-05-25 20:44:19 +00:00
|
|
|
msg, pc, status);
|
2011-03-30 12:46:40 +00:00
|
|
|
postnote(up, 1, note, NDebug);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* math coprocessor error
|
|
|
|
*/
|
|
|
|
static void
|
2013-05-25 20:44:19 +00:00
|
|
|
matherror(Ureg*, void*)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* a write cycle to port 0xF0 clears the interrupt latch attached
|
|
|
|
* to the error# line from the 387
|
|
|
|
*/
|
2012-08-17 02:03:51 +00:00
|
|
|
if(!(m->cpuiddx & Fpuonchip))
|
2011-03-30 12:46:40 +00:00
|
|
|
outb(0xF0, 0xFF);
|
|
|
|
|
|
|
|
/*
|
2013-05-25 20:44:19 +00:00
|
|
|
* get floating point state to check out error
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fpsave(up->fpsave);
|
2016-05-01 19:51:15 +00:00
|
|
|
up->fpstate = FPinactive;
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
mathnote(up->fpsave->fsw, up->fpsave->fpuip);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-05-11 03:59:10 +00:00
|
|
|
/*
|
|
|
|
* SIMD error
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
simderror(Ureg *ureg, void*)
|
|
|
|
{
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fpsave(up->fpsave);
|
2014-05-11 03:59:10 +00:00
|
|
|
up->fpstate = FPinactive;
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
|
2014-05-11 03:59:10 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/*
|
|
|
|
* math coprocessor emulation fault
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mathemu(Ureg *ureg, void*)
|
|
|
|
{
|
2013-05-26 20:41:40 +00:00
|
|
|
ulong status, control;
|
2013-05-22 18:17:05 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(up->fpstate & FPillegal){
|
|
|
|
/* someone did floating point in a note handler */
|
|
|
|
postnote(up, 1, "sys: floating point in note handler", NDebug);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch(up->fpstate){
|
|
|
|
case FPinit:
|
|
|
|
fpinit();
|
2014-05-11 03:59:10 +00:00
|
|
|
if(fpsave == fpssesave)
|
2018-01-04 03:38:31 +00:00
|
|
|
ldmxcsr(0x1f80); /* no simd exceptions on 386 */
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
while(up->fpsave == nil)
|
|
|
|
up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
|
2011-03-30 12:46:40 +00:00
|
|
|
up->fpstate = FPactive;
|
|
|
|
break;
|
|
|
|
case FPinactive:
|
|
|
|
/*
|
|
|
|
* Before restoring the state, check for any pending
|
|
|
|
* exceptions, there's no way to restore the state without
|
|
|
|
* generating an unmasked exception.
|
|
|
|
* More attention should probably be paid here to the
|
|
|
|
* exception masks and error summary.
|
|
|
|
*/
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
status = up->fpsave->fsw;
|
|
|
|
control = up->fpsave->fcw;
|
2013-05-22 18:17:05 +00:00
|
|
|
if((status & ~control) & 0x07F){
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
mathnote(status, up->fpsave->fpuip);
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
}
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fprestore(up->fpsave);
|
2011-03-30 12:46:40 +00:00
|
|
|
up->fpstate = FPactive;
|
|
|
|
break;
|
|
|
|
case FPactive:
|
|
|
|
panic("math emu pid %ld %s pc 0x%lux",
|
|
|
|
up->pid, up->text, ureg->pc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* math coprocessor segment overrun
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mathover(Ureg*, void*)
|
|
|
|
{
|
|
|
|
pexit("math overrun", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mathinit(void)
|
|
|
|
{
|
|
|
|
trapenable(VectorCERR, matherror, 0, "matherror");
|
|
|
|
if(X86FAMILY(m->cpuidax) == 3)
|
|
|
|
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
|
|
|
|
trapenable(VectorCNA, mathemu, 0, "mathemu");
|
|
|
|
trapenable(VectorCSO, mathover, 0, "mathover");
|
2014-05-11 03:59:10 +00:00
|
|
|
trapenable(VectorSIMD, simderror, 0, "simderror");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set up floating point for a new process
|
|
|
|
*/
|
|
|
|
void
|
2011-10-25 18:17:39 +00:00
|
|
|
procsetup(Proc *p)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
p->fpstate = FPinit;
|
|
|
|
fpoff();
|
2011-07-12 13:46:22 +00:00
|
|
|
|
2011-10-25 18:17:39 +00:00
|
|
|
cycles(&p->kentry);
|
|
|
|
p->pcycles = -p->kentry;
|
|
|
|
|
2011-07-12 13:46:22 +00:00
|
|
|
memset(p->gdt, 0, sizeof(p->gdt));
|
|
|
|
p->ldt = nil;
|
|
|
|
p->nldt = 0;
|
2017-06-12 19:03:07 +00:00
|
|
|
|
|
|
|
memset(p->dr, 0, sizeof(p->dr));
|
2011-07-12 13:46:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
procfork(Proc *p)
|
|
|
|
{
|
2013-05-30 21:16:22 +00:00
|
|
|
int s;
|
|
|
|
|
2011-10-25 18:17:39 +00:00
|
|
|
p->kentry = up->kentry;
|
|
|
|
p->pcycles = -p->kentry;
|
|
|
|
|
2011-07-12 13:46:22 +00:00
|
|
|
/* inherit user descriptors */
|
|
|
|
memmove(p->gdt, up->gdt, sizeof(p->gdt));
|
|
|
|
|
|
|
|
/* copy local descriptor table */
|
|
|
|
if(up->ldt != nil && up->nldt > 0){
|
2011-12-12 15:55:26 +00:00
|
|
|
p->ldt = smalloc(sizeof(Segdesc) * up->nldt);
|
2011-07-12 13:46:22 +00:00
|
|
|
memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt);
|
|
|
|
p->nldt = up->nldt;
|
|
|
|
}
|
2013-05-30 21:16:22 +00:00
|
|
|
|
|
|
|
/* save floating point state */
|
|
|
|
s = splhi();
|
|
|
|
switch(up->fpstate & ~FPillegal){
|
|
|
|
case FPactive:
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fpsave(up->fpsave);
|
2013-05-30 21:16:22 +00:00
|
|
|
up->fpstate = FPinactive;
|
|
|
|
case FPinactive:
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
while(p->fpsave == nil)
|
|
|
|
p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
|
|
|
|
memmove(p->fpsave, up->fpsave, sizeof(FPsave));
|
2013-05-30 21:16:22 +00:00
|
|
|
p->fpstate = FPinactive;
|
|
|
|
}
|
2017-06-12 19:03:07 +00:00
|
|
|
|
|
|
|
/* clear debug registers */
|
|
|
|
memset(p->dr, 0, sizeof(p->dr));
|
2013-05-30 21:16:22 +00:00
|
|
|
splx(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
procrestore(Proc *p)
|
|
|
|
{
|
|
|
|
uvlong t;
|
2017-06-12 19:03:07 +00:00
|
|
|
|
2017-06-13 00:10:36 +00:00
|
|
|
if(p->dr[7] != 0){
|
|
|
|
m->dr7 = p->dr[7];
|
2017-06-12 19:03:07 +00:00
|
|
|
putdr(p->dr);
|
2017-06-13 00:10:36 +00:00
|
|
|
}
|
2017-08-28 17:27:41 +00:00
|
|
|
|
|
|
|
if(p->vmx != nil)
|
|
|
|
vmxprocrestore(p);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(p->kp)
|
|
|
|
return;
|
2011-10-25 18:17:39 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
cycles(&t);
|
2011-10-25 18:17:39 +00:00
|
|
|
p->kentry += t;
|
2011-03-30 12:46:40 +00:00
|
|
|
p->pcycles -= t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the mach dependent part of the process state.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
procsave(Proc *p)
|
|
|
|
{
|
|
|
|
uvlong t;
|
2017-06-12 19:03:07 +00:00
|
|
|
|
2017-06-13 00:10:36 +00:00
|
|
|
/* we could just always putdr7(0) but accessing DR7 might be slow in a VM */
|
|
|
|
if(m->dr7 != 0){
|
|
|
|
m->dr7 = 0;
|
2017-06-12 19:03:07 +00:00
|
|
|
putdr7(0);
|
2017-06-13 00:10:36 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
cycles(&t);
|
2011-10-25 18:17:39 +00:00
|
|
|
p->kentry -= t;
|
2011-03-30 12:46:40 +00:00
|
|
|
p->pcycles += t;
|
2011-10-25 18:17:39 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(p->fpstate == FPactive){
|
|
|
|
if(p->state == Moribund)
|
|
|
|
fpclear();
|
|
|
|
else{
|
|
|
|
/*
|
|
|
|
* Fpsave() stores without handling pending
|
|
|
|
* unmasked exeptions. Postnote() can't be called
|
|
|
|
* here as sleep() already has up->rlock, so
|
|
|
|
* the handling of pending exceptions is delayed
|
|
|
|
* until the process runs again and generates an
|
|
|
|
* emulation fault to activate the FPU.
|
|
|
|
*/
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fpsave(p->fpsave);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
p->fpstate = FPinactive;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
reboot(void *entry, void *code, ulong size)
|
|
|
|
{
|
|
|
|
void (*f)(ulong, ulong, ulong);
|
|
|
|
ulong *pdb;
|
|
|
|
|
|
|
|
writeconf();
|
2017-09-02 10:43:37 +00:00
|
|
|
vmxshutdown();
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the boot processor is cpu0. execute this function on it
|
|
|
|
* so that the new kernel has the same cpu0. this only matters
|
|
|
|
* because the hardware has a notion of which processor was the
|
|
|
|
* boot processor and we look at it at start up.
|
|
|
|
*/
|
|
|
|
if (m->machno != 0) {
|
|
|
|
procwired(up, 0);
|
|
|
|
sched();
|
|
|
|
}
|
2015-11-30 13:56:00 +00:00
|
|
|
cpushutdown();
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
splhi();
|
|
|
|
|
|
|
|
/* turn off buffered serial console */
|
|
|
|
serialoq = nil;
|
|
|
|
|
|
|
|
/* shutdown devices */
|
|
|
|
chandevshutdown();
|
|
|
|
arch->introff();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Modify the machine page table to directly map the low 4MB of memory
|
|
|
|
* This allows the reboot code to turn off the page mapping
|
|
|
|
*/
|
|
|
|
pdb = m->pdb;
|
|
|
|
pdb[PDX(0)] = pdb[PDX(KZERO)];
|
|
|
|
mmuflushtlb(PADDR(pdb));
|
|
|
|
|
|
|
|
/* setup reboot trampoline function */
|
|
|
|
f = (void*)REBOOTADDR;
|
|
|
|
memmove(f, rebootcode, sizeof(rebootcode));
|
|
|
|
|
|
|
|
/* off we go - never to return */
|
|
|
|
coherence();
|
2014-03-16 19:22:59 +00:00
|
|
|
(*f)((ulong)entry & ~0xF0000000UL, PADDR(code), size);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2015-11-30 13:56:00 +00:00
|
|
|
exit(int)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2015-11-30 13:56:00 +00:00
|
|
|
cpushutdown();
|
2011-03-30 12:46:40 +00:00
|
|
|
arch->reset();
|
|
|
|
}
|