1885 lines · 32.0 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <aml.h> typedef struct Interp Interp;typedef struct Frame Frame;typedef struct Heap Heap; typedef struct Package Package;typedef struct Method Method;typedef struct Region Region;typedef struct Field Field; typedef struct Name Name;typedef struct Ref Ref;typedef struct Env Env;typedef struct Op Op; struct Heap {	Heap	*link;	short	size;	uchar	mark;	char	tag;}; #define H2D(h)	(((Heap*)(h))+1)#define D2H(d)	(((Heap*)(d))-1)#define TAG(d)	D2H(d)->tag#define SIZE(d)	D2H(d)->size enum {	MemSpace	= 0x00,	IoSpace		= 0x01,	PcicfgSpace	= 0x02,	EbctlSpace	= 0x03,	SmbusSpace	= 0x04,	CmosSpace	= 0x05,	PcibarSpace	= 0x06,	IpmiSpace	= 0x07,}; static char *spacename[] = {	"Mem", 	"Io",	"Pcicfg",	"Ebctl",	"Smbus",	"Cmos",	"Pcibar",	"Ipmi"}; /* field flags */enum {	AnyAcc		= 0x00,	ByteAcc		= 0x01,	WordAcc		= 0x02,	DWordAcc	= 0x03,	QWordAcc	= 0x04,	BufferAcc	= 0x05,	AccMask		= 0x07, 	NoLock		= 0x10, 	Preserve	= 0x00,	WriteAsOnes	= 0x20,	WriteAsZeros	= 0x40,	UpdateMask	= 0x60,}; struct Package {	int	n;	void	*a[];}; struct Method {	Name	*name;	int	narg;	void*	(*eval)(void);	uchar	*start;	uchar	*end;}; struct Region {	Name	*name;	int	space;	uvlong	off;	uvlong	len;	uchar	*va;}; struct Field {	void	*reg;	/* Buffer or Region */	Field	*index;	void	*indexv;	int	flags;	int	bitoff;	int	bitlen;}; struct Name {	void	*v; 	Name	*up;	Name	*next;	Name	*fork;	Name	*down; 	char	seg[4];}; struct Ref {	void	*ref;	void	**ptr;}; struct Env {	void	*loc[8];	void	*arg[8];}; struct Op {	char	*name;	char	*sequence;	void*	(*eval)(void);}; struct Frame {	int	tag;	char	*phase;	uchar	*start;	uchar	*end;	Op	*op;	Env	*env;	Name	*dot;	void	*ref;	void	*aux;	int	narg;	void	*arg[8];}; struct Interp {	uchar	*pc;	Frame	*fp;	int	cond;}; static	Interp	interp;static	Frame	stack[32];	void*	amlroot;	int	amldebug; #define PC	interp.pc#define	FP	interp.fp#define FB	stack#define FT	&stack[nelem(stack)] static Heap *hp; enum {	Obad, Onop, Odebug,	Ostr, Obyte, Oword, Odword, Oqword, Oconst,	Onamec, Oname, Oscope, Oalias,	Oreg, Ofld, Oxfld, Opkg, Ovpkg, Oenv, Obuf, Omet, 	Odev, Ocpu, Othz, Oprc,	Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor,	Onor, Oxor, Onot, Oinc, Odec,	Oland, Olor, Olnot, Oleq, Olgt, Ollt,	Oindex, Omutex, Oevent,	Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,	Oif, Oelse, Owhile, Obreak, Oret, Ocall, 	Ostore, Oderef, Osize, Oref, Ocref,	Oacq, Orel,}; static Op optab[];static uchar octab1[];static uchar octab2[]; static Name*rootname(Name *dot){	while(dot != dot->up)		dot = dot->up;	return dot;} static voidgcmark(void *p){	int i;	Env *e;	Field *f;	Heap *h;	Name *n, *d;	Package *a; 	if(p == nil)		return;	h = D2H(p);	if(h->mark)		return;	h->mark = 1;	switch(h->tag){	case 'E':		e = p;		for(i=0; i<nelem(e->loc); i++)			gcmark(e->loc[i]);		for(i=0; i<nelem(e->arg); i++)			gcmark(e->arg[i]);		break;	case 'R':	case 'A':	case 'L':		gcmark(((Ref*)p)->ref);		break;	case 'N':		n = p;		gcmark(n->v);		for(d = n->down; d; d = d->next)			gcmark(d);		gcmark(n->fork);		gcmark(n->up);		break;	case 'p':		a = p;		for(i=0; i<a->n; i++)			gcmark(a->a[i]);		break;	case 'r':		gcmark(((Region*)p)->name);		break;	case 'm':		gcmark(((Method*)p)->name);		break;	case 'f':	case 'u':		f = p;		gcmark(f->reg);		gcmark(f->index);		gcmark(f->indexv);		break;	}} static intgc(void){	int i;	Heap *h, **hh;	Frame *f; 	for(h = hp; h; h = h->link)		h->mark = 0; 	for(f = FP; f >= FB; f--){		for(i=0; i<f->narg; i++)			gcmark(f->arg[i]);		gcmark(f->env);		gcmark(f->dot);		gcmark(f->ref);	} 	gcmark(amlroot); 	i = 0;	hh = &hp;	while(h = *hh){		if(h->mark){			hh = &h->link;			continue;		}		*hh = h->link;		memset(h, ~0, sizeof(Heap)+h->size);		amlfree(h);		i++;	} 	return i;} static void*mk(int tag, int size){	Heap *h;	int a; 	a = sizeof(Heap) + size;	h = amlalloc(a);	h->size = size;	h->tag = tag;	h->link = hp;	hp = h;	return h+1;} static uvlong*mki(uvlong i){	uvlong *v; 	v = mk('i', sizeof(uvlong));	*v = i;	return v;} static char*mks(char *s){	char *r = mk('s', strlen(s)+1);	strcpy(r, s);	return r;} static intpkglen(uchar *p, uchar *e, uchar **np){	ulong n;	uchar b; 	if(p >= e)		return -1;	b = *p++;	if(b <= 0x3F)		n = b;	else {		n = b & 0xF;		if(p >= e)			return -1;		n += *p++ << 4;		if(b >= 0x80){			if(p >= e)				return -1;			n += *p++ << 12;		}		if(b >= 0xC0){			if(p >= e)				return -1;			n += *p++ << 20;		}	}	if(np)		*np = p;	return n;} static Name*forkname(Name *dot){	Name *n; 	n = mk('N', sizeof(Name));	*n = *dot;	n->fork = dot;	n->next = n->down = nil;	if(dot->v == dot)		n->v = n;	if(dot->up == dot)		n->up = n;	else {		if(n->up = forkname(dot->up))			n->up->down = n;	}	return n;} static Name*getseg(Name *dot, void *seg, int new){	Name *n, *l; 	for(n = l = nil; dot; dot = dot->fork){		for(n = dot->down; n; n = n->next){			if(memcmp(seg, n->seg, 4) == 0)				return n;			l = n;		}		if(new){			n = mk('N', sizeof(Name));			memmove(n->seg, seg, sizeof(n->seg));			n->up = dot;			if(l == nil)				dot->down = n;			else				l->next = n;			n->v = n;			break;		}	}	return n;} Name*getname(Name *dot, char *path, int new){	char seg[4];	int i, s;	Name *x; 	s = !new;	if(*path == '\\'){		path++;		dot = rootname(dot);		s = 0;	}	while(*path == '^'){		path++;		dot = dot->up;		s = 0;	}	do {		for(i=0; i<4; i++){			if(*path == 0 || *path == '.')				break;			seg[i] = *path++;		}		if(i == 0)			break;		while(i < 4)			seg[i++] = '_';		if(s && *path == 0){			for(;;){				if(x = getseg(dot, seg, 0))					break;				if(dot == dot->up)					break;				dot = dot->up;			}			return x;		}		s = 0;		dot = getseg(dot, seg, new);	} while(*path++ == '.'); 	return dot;} static uvlongival(void *p){	if(p)		switch(TAG(p)){		case 'i':			return *((uvlong*)p);		case 's':			return strtoull((char*)p, 0, 0);		}	return 0;} static uvlongrwreg(void *reg, int off, int len, uvlong v, int write){	Region *r;	uchar *p;	int i; 	switch(TAG(reg)){	case 'b':		p = reg;		if((off+len) > SIZE(p))			break;		if(write){			/* putle(p, v, 8); */			for(i=0; i<len; i++){				p[off+i] = v & 0xFF;				v >>= 8;			}		} else {			/* v |= getle(p, 8); */			for(i=0; i<len; i++)				v |= ((u64int)p[off+i]) << i*8;		}		return v;	case 'r':		r = reg;		if((off+len) > r->len)			break;		if(amldebug){			print("rwreg: %s %-8s [%llux+%x]/%d %llux\n", 				write ? "W" : "R", 				spacename[r->space],				r->off, off, len, v);		}		break;	} 	return ~0;} static void *deref(void *p);static void *store(void *s, void *d); static intfieldalign(int flags){	switch(flags & AccMask){	default:	case AnyAcc:	case ByteAcc:	case BufferAcc:

Lines 1–500 of 1885.