## diffname gnot/fault.c 1990/03091
## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/fault.c
0a
#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;
int zeroed = 0, head = 1;
int i, user, read, insyscall;
if(u == 0)
panic("fault");
insyscall = u->p->insyscall;
u->p->insyscall = 1;
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");
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);
s = seg(u->p, addr);
if(s == 0){
if(addr>USTKTOP){
cant:
u->p->state = MMUing;
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);
}
dumpregs(ur);
panic("fault");
exit();
}
s = &u->p->seg[SSEG];
if(s->o==0 || addr<s->maxva-4*1024*1024 || addr>=s->maxva)
goto cant;
/* grow stack */
o = s->o;
n = o->npte;
growpte(o, (s->maxva-addr)>>PGSHIFT);
/* stacks grown down, sigh */
lock(o);
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);
qlock(o->chan);
if(waserror()){
print("demand load i/o error %d\n", u->error.code);
qunlock(o->chan);
pg->o = 0;
pg->ref--;
goto cant;
}
o->chan->offset = (addr-o->va) + o->minca;
l = (char*)(pg->pa|KZERO);
if((*devtab[o->chan->type].read)(o->chan, l, n) != n)
error(0, Eioload);
qunlock(o->chan);
poperror();
/* BUG: if was first page of bss, move to data */
if(n<BY2PG)
memset(l+n, 0, BY2PG-n);
lock(o);
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--;
}
}
}
/*
* Copy on reference
*/
if((o->flag & OWRPERM)
&& ((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);
memcpy((void*)(pte->page->pa|KZERO), (void*)(pg->pa|KZERO), BY2PG);
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)
{
Seg *s;
if((long)len < 0)
panic("validaddr len %lux\n", len);
s = seg(u->p, addr);
if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){
pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
postnote(u->p, 1, "bad address", NDebug);
error(0, Ebadarg);
}
}
/*
* &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;
}
.
## diffname gnot/fault.c 1990/0312
## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/fault.c /n/bootesdump/1990/0312/sys/src/9/68020/fault.c
277a
Err:
.
275c
goto Err;
.
85a
/* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/
.
## diffname gnot/fault.c 1990/0315
## diff -e /n/bootesdump/1990/0312/sys/src/9/68020/fault.c /n/bootesdump/1990/0315/sys/src/9/68020/fault.c
97a
u->p->state = MMUing;
.
92d
## diffname gnot/fault.c 1990/06021
## diff -e /n/bootesdump/1990/0315/sys/src/9/68020/fault.c /n/bootesdump/1990/06021/sys/src/9/68020/fault.c
234c
k = kmap(pte->page);
k1 = kmap(pg);
memcpy((void*)k->va, (void*)k1->va, BY2PG);
kunmap(k);
kunmap(k1);
.
169a
kunmap(k);
poperror();
.
165d
161c
l = (char*)k->va;
.
154a
kunmap(k);
.
151a
k = kmap(pg);
.
58c
panic("fault u==0 pc=%lux", ur->pc);
.
53a
KMap *k, *k1;
.
## diffname gnot/fault.c 1990/0603
## diff -e /n/bootesdump/1990/06021/sys/src/9/68020/fault.c /n/bootesdump/1990/0603/sys/src/9/68020/fault.c
59a
}
.
58c
if(u == 0){
dumpregs(ur);
.
## diffname gnot/fault.c 1990/0614
## diff -e /n/bootesdump/1990/0603/sys/src/9/68020/fault.c /n/bootesdump/1990/0614/sys/src/9/68020/fault.c
242c
memcpy((void*)VA(k), (void*)VA(k1), BY2PG);
.
166c
l = (char*)VA(k);
.
## diffname gnot/fault.c 1990/0617
## diff -e /n/bootesdump/1990/0614/sys/src/9/68020/fault.c /n/bootesdump/1990/0617/sys/src/9/68020/fault.c
295d
293a
Again:
s = seg(u->p, addr);
if(s==0)
goto Err;
if(write && (s->o->flag&OWRPERM)==0)
goto Err;
if(addr+len > s->maxva){
len -= s->maxva - addr;
addr = s->maxva;
goto Again;
}
.
285,288c
if((long)len < 0){
.
283c
Seg *s, *ns;
.
## diffname gnot/fault.c 1990/0724
## diff -e /n/bootesdump/1990/0617/sys/src/9/68020/fault.c /n/bootesdump/1990/0724/sys/src/9/68020/fault.c
190c
if((o->flag & OWRPERM) && !read
.
188c
* Copy on write
.
## diffname gnot/fault.c 1990/0802
## diff -e /n/bootesdump/1990/0724/sys/src/9/68020/fault.c /n/bootesdump/1990/0802/sys/src/9/68020/fault.c
113d
111a
poperror();
.
110a
lock(o);
if(waserror()){
unlock(o);
pprint("can't allocate stack page\n");
goto cant;
}
.
## diffname gnot/fault.c 1990/08101
## diff -e /n/bootesdump/1990/0802/sys/src/9/68020/fault.c /n/bootesdump/1990/08101/sys/src/9/68020/fault.c
102c
panic("fault: 0x%lux", badvaddr);
.
81a
addr &= VAMASK;
.
## diffname gnot/fault.c 1990/0814
## diff -e /n/bootesdump/1990/08101/sys/src/9/68020/fault.c /n/bootesdump/1990/0814/sys/src/9/68020/fault.c
120a
lock(o);
.
114d
112d
## diffname gnot/fault.c 1990/0821
## diff -e /n/bootesdump/1990/0814/sys/src/9/68020/fault.c /n/bootesdump/1990/0821/sys/src/9/68020/fault.c
299,300c
if(s==0){
s = &u->p->seg[SSEG];
if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
goto Err;
}
.
107c
if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
.
## diffname gnot/fault.c 1990/0918
## diff -e /n/bootesdump/1990/0821/sys/src/9/68020/fault.c /n/bootesdump/1990/0918/sys/src/9/68020/fault.c
176d
## diffname gnot/fault.c 1990/1110
## diff -e /n/bootesdump/1990/0918/sys/src/9/68020/fault.c /n/bootesdump/1990/1110/sys/src/9/68020/fault.c
293c
postnote(u->p, 1, "sys: bad address", NDebug);
.
168a
if(user)
pexit("Interrupt", 0);
.
## diffname gnot/fault.c 1990/1113
## diff -e /n/bootesdump/1990/1110/sys/src/9/68020/fault.c /n/bootesdump/1990/1113/sys/src/9/68020/fault.c
169,171c
pexit("load i/o error", 0);
.
## diffname gnot/fault.c 1990/11211
## diff -e /n/bootesdump/1990/1113/sys/src/9/68020/fault.c /n/bootesdump/1990/11211/sys/src/9/68020/fault.c
294c
error(Ebadarg);
.
174c
error(Eioload);
.
164c
print("demand load i/o error %s\n", u->error);
.
## diffname gnot/fault.c 1990/1126
## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/fault.c /n/bootesdump/1990/1126/sys/src/9/68020/fault.c
63a
addr = 0; /* set */
.
## diffname gnot/fault.c 1990/1202
## diff -e /n/bootesdump/1990/1126/sys/src/9/68020/fault.c /n/bootesdump/1990/1202/sys/src/9/68020/fault.c
165d
## diffname gnot/fault.c 1990/1212 # deleted
## diff -e /n/bootesdump/1990/1202/sys/src/9/68020/fault.c /n/bootesdump/1990/1212/sys/src/9/68020/fault.c
1,347d
|