|
|
|
1990/1202/sys/src/9/gnot/fault.c:1,347 –
1990/1212/sys/src/9/gnot/fault.c:0
(short | long | prev)
|
Deleted.
rsc Mon Mar 7 10:21:44 2005
|
|
1990/03091
| |
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "ureg.h"
#include "errno.h"
#define FORMAT(ur) ((((ur)->vo)>>12)&0xF)
#define OFFSET(ur) (((ur)->vo)&0xFFF)
struct FFrame
{
ushort ireg0; /* internal register */
ushort ssw; /* special status word */
ushort ipsc; /* instr. pipe stage c */
ushort ipsb; /* instr. pipe stage b */
ulong addr; /* data cycle fault address */
ushort ireg1; /* internal register */
ushort ireg2; /* internal register */
ulong dob; /* data output buffer */
ushort ireg3[4]; /* more stuff */
ulong baddr; /* stage b address */
ushort ireg4[26]; /* more more stuff */
};
/*
* SSW bits
*/
#define RW 0x0040 /* read/write for data cycle */
#define FC 0x8000 /* fault on stage C of instruction pipe */
#define FB 0x4000 /* fault on stage B of instruction pipe */
#define RC 0x2000 /* rerun flag for stage C of instruction pipe */
#define RB 0x1000 /* rerun flag for stage B of instruction pipe */
#define DF 0x0100 /* fault/rerun flag for data cycle */
#define RM 0x0080 /* read-modify-write on data cycle */
#define READ 0x0040
#define WRITE 0x0000
#define SIZ 0x0030 /* size code for data cycle */
#define FC2 0x0004 /* address space for data cycle */
#define FC1 0x0002
#define FC0 0x0001
void
fault(Ureg *ur, FFrame *f)
{
ulong addr, mmuvirt, mmuphys, n, badvaddr;
Seg *s;
PTE *opte, *pte, *npte;
Orig *o;
char *l;
Page *pg;
|
|
1990/06021
| |
KMap *k, *k1;
|
|
1990/03091
| |
int zeroed = 0, head = 1;
int i, user, read, insyscall;
|
|
1990/0603
| |
if(u == 0){
dumpregs(ur);
|
|
1990/06021
| |
panic("fault u==0 pc=%lux", ur->pc);
|
|
1990/0603
| |
}
|
|
1990/03091
| |
insyscall = u->p->insyscall;
u->p->insyscall = 1;
|
|
1990/1126
| |
addr = 0; /* set */
|
|
1990/03091
| |
if(f->ssw & DF)
addr = f->addr;
else if(FORMAT(ur) == 0xA){
if(f->ssw & FC)
addr = ur->pc+2;
else if(f->ssw & FB)
addr = ur->pc+4;
else
panic("prefetch pagefault");
}else if(FORMAT(ur) == 0xB){
if(f->ssw & FC)
addr = f->baddr-2;
else if(f->ssw & FB)
addr = f->baddr;
else
panic("prefetch pagefault");
}else
panic("prefetch format");
|
|
1990/08101
| |
addr &= VAMASK;
|
|
1990/03091
| |
badvaddr = addr;
addr &= ~(BY2PG-1);
user = !(ur->sr&SUPER);
if(f->ssw & DF)
read = (f->ssw&READ) && !(f->ssw&RM);
else
read = f->ssw&(FB|FC);
|
|
1990/0312
| |
/* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/
|
|
1990/03091
| |
s = seg(u->p, addr);
if(s == 0){
if(addr>USTKTOP){
cant:
if(user){
pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp);
pexit("Suicide", 0);
}
|
|
1990/0315
| |
u->p->state = MMUing;
|
|
1990/03091
| |
dumpregs(ur);
|
|
1990/08101
| |
panic("fault: 0x%lux", badvaddr);
|
|
1990/03091
| |
exit();
}
s = &u->p->seg[SSEG];
|
|
1990/0821
| |
if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
|
|
1990/03091
| |
goto cant;
/* grow stack */
o = s->o;
n = o->npte;
|
|
1990/0802
| |
if(waserror()){
pprint("can't allocate stack page\n");
goto cant;
}
|
|
1990/03091
| |
growpte(o, (s->maxva-addr)>>PGSHIFT);
|
|
1990/0802
| |
poperror();
|
|
1990/03091
| |
/* stacks grown down, sigh */
|
|
1990/0814
| |
lock(o);
|
|
1990/03091
| |
memcpy(o->pte+(o->npte-n), o->pte, n*sizeof(PTE));
memset(o->pte, 0, (o->npte-n)*sizeof(PTE));
unlock(o);
s->minva = addr;
o->va = addr;
}else
o = s->o;
if(!read && (o->flag&OWRPERM)==0)
goto cant;
lock(o);
opte = &o->pte[(addr-o->va)>>PGSHIFT];
pte = opte;
if(s->mod){
while(pte = pte->nextmod) /* assign = */
if(pte->proc == u->p){
if(pte->page==0 || pte->page->va!=addr)
panic("bad page %lux", pte->page);
head = 0;
break;
}
if(pte == 0)
pte = opte;
}
if(pte->page == 0){
if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){
/*
* Zero fill page. If we are really doing a copy-on-write
* (e.g. into shared bss) we'll move the page later.
*/
pte->page = newpage(0, o, addr);
o->npage++;
zeroed = 1;
}else{
/*
* Demand load. Release o because it could take a while.
*/
unlock(o);
n = (o->va+(o->maxca-o->minca)) - addr;
if(n > BY2PG)
n = BY2PG;
pg = newpage(1, o, addr);
|
|
1990/06021
| |
k = kmap(pg);
|
|
1990/03091
| |
qlock(o->chan);
if(waserror()){
|
|
1990/06021
| |
kunmap(k);
|
|
1990/03091
| |
qunlock(o->chan);
pg->o = 0;
pg->ref--;
|
|
1990/1113
| |
pexit("load i/o error", 0);
|
|
1990/03091
| |
}
o->chan->offset = (addr-o->va) + o->minca;
|
|
1990/0614
| |
l = (char*)VA(k);
|
|
1990/03091
| |
if((*devtab[o->chan->type].read)(o->chan, l, n) != n)
|
|
1990/11211
| |
error(Eioload);
|
|
1990/03091
| |
qunlock(o->chan);
if(n<BY2PG)
memset(l+n, 0, BY2PG-n);
lock(o);
|
|
1990/06021
| |
kunmap(k);
poperror();
|
|
1990/03091
| |
opte = &o->pte[(addr-s->minva)>>PGSHIFT]; /* could move */
pte = opte;
if(pte->page == 0){
pte->page = pg;
o->npage++;
}else{ /* someone beat us to it */
pg->o = 0;
pg->ref--;
}
}
}
/*
|
|
1990/0724
| |
* Copy on write
|
|
1990/03091
| |
*/
|
|
1990/0724
| |
if((o->flag & OWRPERM) && !read
|
|
1990/03091
| |
&& ((head && ((o->flag&OPURE) || o->nproc>1))
|| (!head && pte->page->ref>1))){
/*
* Look for the easy way out: are we the last non-modified?
*/
if(head && !(o->flag&OPURE)){
npte = opte;
for(i=0; npte; i++)
npte = npte->nextmod;
if(i == o->nproc)
goto easy;
}
if(head){
/*
* Add to mod list
*/
pte = newmod();
pte->proc = u->p;
pte->page = opte->page;
pte->page->ref++;
o->npage++;
/*
* Link into opte mod list (same va)
*/
pte->nextmod = opte->nextmod;
opte->nextmod = pte;
/*
* Link into proc mod list (increasing va)
*/
npte = s->mod;
if(npte == 0){
s->mod = pte;
pte->nextva = 0;
}else{
while(npte->nextva && npte->nextva->page->va<addr)
npte = npte->nextva;
pte->nextva = npte->nextva;
npte->nextva = pte;
}
head = 0;
}
pg = pte->page;
if(zeroed){ /* move page */
pg->ref--;
o->npage--;
opte->page = 0;
}else{ /* copy page */
pte->page = newpage(1, o, addr);
|
|
1990/06021
| |
k = kmap(pte->page);
k1 = kmap(pg);
|
|
1990/0614
| |
memcpy((void*)VA(k), (void*)VA(k1), BY2PG);
|
|
1990/06021
| |
kunmap(k);
kunmap(k1);
|
|
1990/03091
| |
if(pg->ref <= 1)
panic("pg->ref <= 1");
pg->ref--;
}
easy:
mmuphys = 0;
}else{
mmuphys = PTERONLY;
if(o->flag & OWRPERM)
if(o->flag & OPURE){
if(!head && pte->page->ref==1)
mmuphys = 0;
}else
if((head && o->nproc==1)
|| (!head && pte->page->ref==1))
mmuphys = 0;
}
mmuvirt = addr;
mmuphys |= PPN(pte->page->pa) | PTEVALID;
usepage(pte->page, 1);
if(pte->page->va != addr)
panic("wrong addr in tail %lux %lux", pte->page->va, addr);
if(pte->proc && pte->proc != u->p){
print("wrong proc in tail %d %s\n", head, u->p->text);
print("u->p %lux pte->proc %lux\n", u->p, pte->proc);
panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg);
}
unlock(o);
putmmu(mmuvirt, mmuphys);
u->p->insyscall = insyscall;
}
/*
* Called only in a system call
*/
void
validaddr(ulong addr, ulong len, int write)
{
|
|
1990/0617
| |
Seg *s, *ns;
|
|
1990/03091
| |
|
|
1990/0617
| |
if((long)len < 0){
|
|
1990/0312
| |
Err:
|
|
1990/03091
| |
pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
|
|
1990/1110
| |
postnote(u->p, 1, "sys: bad address", NDebug);
|
|
1990/11211
| |
error(Ebadarg);
|
|
1990/03091
| |
}
|
|
1990/0617
| |
Again:
s = seg(u->p, addr);
|
|
1990/0821
| |
if(s==0){
s = &u->p->seg[SSEG];
if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
goto Err;
}
|
|
1990/0617
| |
if(write && (s->o->flag&OWRPERM)==0)
goto Err;
if(addr+len > s->maxva){
len -= s->maxva - addr;
addr = s->maxva;
goto Again;
}
|
|
1990/03091
| |
}
/*
* &s[0] is known to be a valid address.
*/
void*
vmemchr(void *s, int c, int n)
{
int m;
char *t;
ulong a;
a = (ulong)s;
m = BY2PG - (a & (BY2PG-1));
if(m < n){
t = vmemchr(s, c, m);
if(t)
return t;
if(!(a & KZERO))
validaddr(a+m, 1, 0);
return vmemchr((void*)(a+m), c, n-m);
}
/*
* All in one page
*/
return memchr(s, c, n);
}
Seg*
seg(Proc *p, ulong addr)
{
int i;
Seg *s;
for(i=0,s=p->seg; i<NSEG; i++,s++)
if(s->o && s->minva<=addr && addr<s->maxva)
return s;
return 0;
}
|