|
|
Plan 9 NeXT
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "ureg.h"
#include "../port/error.h"
#define FORMAT(ur) ((((ur)->vo)>>12)&0xF)
#define OFFSET(ur) (((ur)->vo)&0xFFF)
struct FFrame
{
ulong ea; /* effective address */
ushort ssw; /* special status word */
ushort wb3s; /* write back 3 status */
ushort wb2s; /* write back 2 status */
ushort wb1s; /* write back 1 status */
ulong fa; /* fault address */
ulong wb3a; /* write back 3 address */
ulong wb3d; /* write back 3 data */
ulong wb2a; /* write back 2 address */
ulong wb2d; /* write back 2 data */
ulong wb1a; /* write back 1 address */
ulong wb1d; /* write back 3 data */
ulong pd1; /* push data lw1 */
ulong pd2; /* push data lw2 */
ulong pd3; /* push data lw3 */
};
static uchar tsz[4] = { 4, 1, 2, 0 };
/*
* SSW bits
*/
#define READ 0x0100
#define TM 0x0007
/*
* Writeback bits
*/
#define WBVALID (1<<7)
#define WBSIZE (3<<5)
#define WBSZSH 5
#define WBTT (3<<3)
#define WBTM (7<<0)
int wbfault(ulong, int, ushort, int, ulong);
ulong normalize(ulong, ulong, ulong);
extern struct{
ulong addr;
ulong baddr;
Lock;
}kmapalloc;
void
fault68040(Ureg *ur, FFrame *f)
{
ulong addr, badvaddr;
int user, read, insyscall;
char buf[ERRLEN];
flushatc();
if(u == 0){
dumpregs(ur);
print("ssw=%ux ea=%lux fa=%lux\n", f->ssw, f->ea, f->fa);
panic("fault u==0 pc=%lux fa=%lux ssw=%lux", ur->pc, f->fa, f->ssw);
}
insyscall = u->p->insyscall;
u->p->insyscall = 1;
addr = f->fa;
addr &= VAMASK;
badvaddr = addr;
addr &= ~(BY2PG-1);
read = 0;
if(f->ssw & READ)
read = 1;
user = !(ur->sr&SUPER);
if(user)
u->dbgreg = ur;
if((f->ssw&TM) == 0)
panic("cache push pc %lux addr %lux ssw %lux\n", ur->pc, f->fa, f->ssw);
/* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/
/*
* original fault plus 3 writeback buffers
*/
if(fault(addr, read) < 0
|| wbfault(f->wb1a, user, f->wb1s, 1, normalize(f->wb1s, f->wb1a, f->wb1d)) < 0
|| wbfault(f->wb2a, user, f->wb2s, 2, f->wb2d) < 0
|| wbfault(f->wb3a, user, f->wb3s, 3, f->wb3d) < 0){
if(user){
sprint(buf, "sys: trap: fault %s addr=0x%lux",
read? "read" : "write", badvaddr);
postnote(u->p, 1, buf, NDebug);
notify(ur);
return;
}
dumpregs(ur);
print("wb1a %lux wb1s %lux wb1d %lux\n", f->wb1a, f->wb1s, f->wb1d);
print("wb2a %lux wb2s %lux wb2d %lux\n", f->wb2a, f->wb2s, f->wb2d);
print("wb3a %lux wb3s %lux wb3d %lux\n", f->wb3a, f->wb3s, f->wb3d);
panic("fault: 0x%lux 0x%lux", badvaddr, addr);
}
u->p->insyscall = insyscall;
if(user)
notify(ur);
}
/*
* get relevant data into the right hand side of the long
*/
ulong
normalize(ulong stat, ulong addr, ulong val)
{
int thecase, size;
size = (stat&WBSIZE) >> WBSZSH;
thecase = (size<<2) | (addr&3);
switch(thecase){
/* long write */
case 0: return val;
case 1: return (val<<8) | ((val>>24)&0xff);
case 2: return (val<<16) | ((val>>16)&0xffff);
case 3: return (val<<24) | ((val>>8)&0xffffff);
/* byte write */
case 4: return val>>24;
case 5: return val>>16;
case 6: return val>>8;
case 7: return val;
/* short write */
case 8: return val>>16;
case 9: return val>>8;
case 10: return val;
case 11: return (val<<8) | ((val>>24)&0xff);
}
}
/*
* Check fault status before doing writeback
*/
int
wbfault(ulong fa, int user, ushort wbs, int wbn, ulong d)
{
int s;
ulong addr;
if(!(wbs & WBVALID))
return 0;
if(wbs & WBTT)
panic("writeback%d status %ux", wbn, wbs);
addr = fa & ~(BY2PG-1);
s = tsz[(wbs&WBSIZE) >> WBSZSH];
if(user || !kernaddr(addr)){
if(fault(fa, 0) < 0){
print("wbfault: %lux, 0\n", fa);
return -1;
}
if(addr != ((fa+s-1)&~(BY2PG-1)))
if(fault(fa+s-1, 0) < 0){
print("wbfault: %lux, %lux\n", fa, fa+s-1);
return -1;
}
}
switch(s){
case 4:
*(ulong*)fa = d;
break;
case 1:
*(uchar*)fa = d;
break;
case 2:
*(ushort*)fa = d;
break;
default:
panic("writeback%d %d\n", wbn, s);
}
return 0;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.