Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/devarch.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname pc/devarch.c 1999/0820
## diff -e /dev/null /n/emeliedump/1999/0820/sys/src/brazil/pc/devarch.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"


typedef struct IOMap IOMap;
struct IOMap
{
	IOMap	*next;
	char	tag[13];
	ulong	start;
	ulong	end;
};

static struct
{
	Lock;
	IOMap	*m;
	IOMap	*free;
	IOMap	maps[32];		// some initial free maps

	QLock	ql;			// lock for reading map
} iomap;

enum {
	Qdir,
	Qcputype,
	Qioalloc,
	Qiob,
	Qiow,
	Qiol,
	Qirqalloc,
};

static Dirtab ioallocdir[] = {
	"cputype",	{ Qcputype, 0 },	0,	0444,
	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
	"iob",		{ Qiob, 0 },		0,	0660,
	"iow",		{ Qiow, 0 },		0,	0660,
	"iol",		{ Qiol, 0 },		0,	0660,
	"irqalloc",	{ Qirqalloc, 0},	0,	0444,
};

void
ioinit(void)
{
	int i;

	for(i = 0; i < nelem(iomap.maps)-1; i++)
		iomap.maps[i].next = &iomap.maps[i+1];
	iomap.maps[i].next = nil;
	iomap.free = iomap.maps;

	// a dummy entry at 2^16
	ioalloc(0x1000000, 1, 0, "dummy");
}

static long cputyperead(char*, int, ulong);

//
//	alloc some io port space and remember who it was
//	alloced to.  if port < 0, find a free region.
//
int
ioalloc(int port, int size, int align, char *tag)
{
	IOMap *m, **l;
	int i;

	lock(&iomap);
	if(port < 0){
		// find a free port above 0x400 and below 0x1000
		port = 0x400;
		for(l = &iomap.m; *l; l = &(*l)->next){
			m = *l;
			i = m->start - port;
			if(i > size)
				break;
			if(align > 0)
				port = ((port+align-1)/align)*align;
			else
				port = m->end;
		}
		if(*l == nil){
			unlock(&iomap);
			return -1;
		}
	} else {
		// see if the space clashes with previously alllocated ports
		for(l = &iomap.m; *l; l = &(*l)->next){
			m = *l;
			if(m->end <= port)
				continue;
			if(m->start >= port+size)
				break;
			unlock(&iomap);
			return -1;
		}
	}
	m = iomap.free;
	if(m == nil){
		print("ioalloc: out of maps");
		unlock(&iomap);
		return port;
	}
	iomap.free = m->next;
	m->next = *l;
	m->start = port;
	m->end = port + size;
	strncpy(m->tag, tag, sizeof(m->tag));
	m->tag[sizeof(m->tag)-1] = 0;
	*l = m;

	ioallocdir[0].qid.vers++;

	unlock(&iomap);
	return m->start;
}

void
iofree(int port)
{
	IOMap *m, **l;

	lock(&iomap);
	for(l = &iomap.m; *l; l = &(*l)->next){
		if((*l)->start == port){
			m = *l;
			*l = m->next;
			m->next = iomap.free;
			iomap.free = m;
			break;
		}
		if((*l)->start > port)
			break;
	}
	ioallocdir[0].qid.vers++;
	unlock(&iomap);
}

int
iounused(int start, int end)
{
	IOMap *m;

	for(m = iomap.m; m; m = m->next){
		if(start >= m->start && start < m->end
		|| start <= m->start && end > m->start)
			return 0; 
	}
	return 1;
}

static void
checkport(int start, int end)
{
	/* standard vga regs are OK */
	if(start >= 0x2b0 && end <= 0x2df+1)
		return;
	if(start >= 0x3c0 && end <= 0x3da+1)
		return;

	if(iounused(start, end))
		return;
	error(Eperm);
}

static Chan*
archattach(char* spec)
{
	return devattach('P', spec);
}

int
archwalk(Chan* c, char* name)
{
	return devwalk(c, name, ioallocdir, nelem(ioallocdir), devgen);
}

static void
archstat(Chan* c, char* dp)
{
	devstat(c, dp, ioallocdir, nelem(ioallocdir), devgen);
}

static Chan*
archopen(Chan* c, int omode)
{
	return devopen(c, omode, ioallocdir, nelem(ioallocdir), devgen);
}

static void
archclose(Chan*)
{
}

enum
{
	Linelen= 31,
};

static long
archread(Chan *c, void *a, long n, vlong offset)
{
	char *p;
	IOMap *m;
	char buf[Linelen+1];
	int port;
	ushort *sp;
	ulong *lp;

	switch(c->qid.path & ~CHDIR){

	case Qdir:
		return devdirread(c, a, n, ioallocdir, nelem(ioallocdir), devgen);

	case Qiob:
		port = offset;
		checkport(offset, offset+n);
		for(p = a; port < offset+n; port++)
			*p++ = inb(port);
		return n;

	case Qiow:
		if((n & 0x01) || (offset & 0x01))
			error(Ebadarg);
		checkport(offset, offset+n+1);
		n /= 2;
		sp = a;
		for(port = offset; port < offset+n; port += 2)
			*sp++ = ins(port);
		return n*2;

	case Qiol:
		if((n & 0x03) || (offset & 0x03))
			error(Ebadarg);
		checkport(offset, offset+n+3);
		n /= 4;
		lp = a;
		for(port = offset; port < offset+n; port += 4)
			*lp++ = inl(port);
		return n*4;

	case Qioalloc:
		break;

	case Qirqalloc:
		return irqallocread(a, n, offset);

	case Qcputype:
		return cputyperead(a, n, offset);

	default:
		error(Eperm);
		break;
	}

	offset = offset/Linelen;
	n = n/Linelen;
	p = a;
	lock(&iomap);
	for(m = iomap.m; n > 0 && m != nil; m = m->next){
		if(offset-- > 0)
			continue;
		if(strcmp(m->tag, "dummy") == 0)
			break;
		sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
		memmove(p, buf, Linelen);
		p += Linelen;
		n--;
	}
	unlock(&iomap);

	return p - (char*)a;
}

static long
archwrite(Chan *c, void *a, long n, vlong offset)
{
	int port;
	ushort *sp;
	ulong *lp;
	char *p;

	switch(c->qid.path & ~CHDIR){

	case Qiob:
		p = a;
		checkport(offset, offset+n);
		for(port = offset; port < offset+n; port++)
			outb(port, *p++);
		return n;

	case Qiow:
		if((n & 01) || (offset & 01))
			error(Ebadarg);
		checkport(offset, offset+n+1);
		n /= 2;
		sp = a;
		for(port = offset; port < offset+n; port += 2)
			outs(port, *sp++);
		return n*2;

	case Qiol:
		if((n & 0x03) || (offset & 0x03))
			error(Ebadarg);
		checkport(offset, offset+n+3);
		n /= 4;
		lp = a;
		for(port = offset; port < offset+n; port += 4)
			outl(port, *lp++);
		return n*4;

	default:
		error(Eperm);
		break;
	}
	return 0;
}

Dev archdevtab = {
	'P',
	"arch",

	devreset,
	devinit,
	archattach,
	devclone,
	archwalk,
	archstat,
	archopen,
	devcreate,
	archclose,
	archread,
	devbread,
	archwrite,
	devbwrite,
	devremove,
	devwstat,
};

/*
 *  the following is a generic version of the
 *  architecture specific stuff
 */

static int
unimplemented(int)
{
	return 0;
}

static void
nop(void)
{
}

void (*coherence)(void) = nop;
void cycletimerinit(void);
uvlong cycletimer(uvlong*);

PCArch* arch;
extern PCArch* knownarch[];

PCArch archgeneric = {
	"generic",				/* id */
	0,					/* ident */
	i8042reset,				/* reset */
	unimplemented,				/* serialpower */
	unimplemented,				/* modempower */

	i8259init,				/* intrinit */
	i8259enable,				/* intrenable */

	i8253enable,				/* clockenable */

	i8253read,				/* read the standard timer */
};

typedef struct {
	int	family;
	int	model;
	int	aalcycles;
	char*	name;
} X86type;

static X86type x86intel[] =
{
	{ 4,	0,	22,	"486DX", },	/* known chips */
	{ 4,	1,	22,	"486DX50", },
	{ 4,	2,	22,	"486SX", },
	{ 4,	3,	22,	"486DX2", },
	{ 4,	4,	22,	"486SL", },
	{ 4,	5,	22,	"486SX2", },
	{ 4,	7,	22,	"DX2WB", },	/* P24D */
	{ 4,	8,	22,	"DX4", },	/* P24C */
	{ 4,	9,	22,	"DX4WB", },	/* P24CT */
	{ 5,	0,	23,	"P5", },
	{ 5,	1,	23,	"P5", },
	{ 5,	2,	23,	"P54C", },
	{ 5,	3,	23,	"P24T", },
	{ 5,	4,	23,	"P55C MMX", },
	{ 5,	7,	23,	"P54C VRT", },
	{ 6,	1,	16,	"PentiumPro", },/* determined by trial and error */
	{ 6,	3,	16,	"PentiumII", },
	{ 6,	5,	16,	"PentiumII/Xeon", },

	{ 3,	-1,	32,	"386", },	/* family defaults */
	{ 4,	-1,	22,	"486", },
	{ 5,	-1,	23,	"P5", },
	{ 6,	-1,	16,	"P6", },

	{ -1,	-1,	23,	"unknown", },	/* total default */
};

/*
 * The AMD processors all implement the CPUID instruction.
 * The later ones also return the processor name via functions
 * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
 * and DX:
 *	K5	"AMD-K5(tm) Processor"
 *	K6	"AMD-K6tm w/ multimedia extensions"
 *	K6 3D	"AMD-K6(tm) 3D processor"
 *	K6 3D+	?
 */
static X86type x86amd[] =
{
	{ 5,	0,	23,	"AMD-K5", },	/* guesswork */
	{ 5,	1,	23,	"AMD-K5", },	/* guesswork */
	{ 5,	2,	23,	"AMD-K5", },	/* guesswork */
	{ 5,	3,	23,	"AMD-K5", },	/* guesswork */
	{ 5,	6,	11,	"AMD-K6", },	/* determined by trial and error */
	{ 5,	7,	11,	"AMD-K6", },	/* determined by trial and error */
	{ 5,	8,	11,	"AMD-K6 3D", },	/* guesswork */
	{ 5,	9,	11,	"AMD-K6 3D+", },/* guesswork */

	{ 4,	-1,	22,	"Am486", },	/* guesswork */
	{ 5,	-1,	23,	"AMD-K5/K6", },	/* guesswork */

	{ -1,	-1,	23,	"unknown", },	/* total default */
};

static uvlong fasthz;
static X86type *cputype;

void
cpuidprint(void)
{
	int i;
	char buf[128];

	i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz);
	if(m->cpuidid[0])
		i += sprint(buf+i, "%s ", m->cpuidid);
	sprint(buf+i, "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n",
		m->cpuidtype, m->cpuidax, m->cpuiddx);
	print(buf);
}

int
cpuidentify(void)
{
	int family, model;
	X86type *t;
	ulong cr4;
	vlong mct;

	cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx);
	if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
		t = x86amd;
	else
		t = x86intel;
	family = X86FAMILY(m->cpuidax);
	model = X86MODEL(m->cpuidax);
	while(t->name){
		if((t->family == family && t->model == model)
		|| (t->family == family && t->model == -1)
		|| (t->family == -1))
			break;
		t++;
	}
	m->cpuidtype = t->name;
	i8253init(t->aalcycles, t->family >= 5);

	/*
	 * If machine check exception or page size extensions are supported
	 * enable them in CR4 and clear any other set extensions.
	 * If machine check was enabled clear out any lingering status.
	 */
	if(m->cpuiddx & 0x88){
		cr4 = 0;
		if(m->cpuiddx & 0x08)
			cr4 |= 0x10;		/* page size extensions */
		if(m->cpuiddx & 0x80)
			cr4 |= 0x40;		/* machine check enable */
		putcr4(cr4);
		if(m->cpuiddx & 0x80)
			rdmsr(0x01, &mct);
	}

	cputype = t;
	return t->family;
}

static long
cputyperead(char *a, int n, ulong offset)
{
	char str[32];
	ulong mhz;

	mhz = (m->cpuhz+999999)/1000000;

	snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
	return readstr(offset, a, n, str);
}

void
archinit(void)
{
	PCArch **p;

	arch = 0;
	for(p = knownarch; *p; p++){
		if((*p)->ident && (*p)->ident() == 0){
			arch = *p;
			break;
		}
	}
	if(arch == 0)
		arch = &archgeneric;
	else{
		if(arch->id == 0)
			arch->id = archgeneric.id;
		if(arch->reset == 0)
			arch->reset = archgeneric.reset;
		if(arch->serialpower == 0)
			arch->serialpower = archgeneric.serialpower;
		if(arch->modempower == 0)
			arch->modempower = archgeneric.modempower;
	
		if(arch->intrinit == 0)
			arch->intrinit = archgeneric.intrinit;
		if(arch->intrenable == 0)
			arch->intrenable = archgeneric.intrenable;
	}

	/* pick the better timer */
	if(X86FAMILY(m->cpuidax) >= 5){
		cycletimerinit();
		arch->fastclock = cycletimer;
	}

	/*
	 * Decide whether to use copy-on-reference (386 and mp).
	 */
	if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
		conf.copymode = 1;

	if(X86FAMILY(m->cpuidax) >= 5)
		coherence = wbflush;
}

void
cycletimerinit(void)
{
	wrmsr(0x10, 0);
	fasthz = m->cpuhz;
}

/*
 *  return the most precise clock we have
 */
uvlong
cycletimer(uvlong *hz)
{
	uvlong tsc;

	rdmsr(0x10, (vlong*)&tsc);
	m->fastclock = tsc;
	if(hz != nil)
		*hz = fasthz;
	return tsc;
}

vlong
fastticks(uvlong *hz)
{
	return (*arch->fastclock)(hz);
}
.
## diffname pc/devarch.c 1999/0908
## diff -e /n/emeliedump/1999/0820/sys/src/brazil/pc/devarch.c /n/emeliedump/1999/0908/sys/src/brazil/pc/devarch.c
94c
		// see if the space clashes with previously allocated ports
.
## diffname pc/devarch.c 1999/1001
## diff -e /n/emeliedump/1999/0908/sys/src/brazil/pc/devarch.c /n/emeliedump/1999/1001/sys/src/brazil/pc/devarch.c
411a
	{ 6,	7,	16,	"PentiumIII/Xeon", },
.
## diffname pc/devarch.c 1999/1019
## diff -e /n/emeliedump/1999/1001/sys/src/brazil/pc/devarch.c /n/emeliedump/1999/1019/sys/src/brazil/pc/devarch.c
60c
	ioalloc(0x10000, 1, 0, "dummy");
.
## diffname pc/devarch.c 2000/0208
## diff -e /n/emeliedump/1999/1019/sys/src/brazil/pc/devarch.c /n/emeliedump/2000/0208/sys/src/9/pc/devarch.c
411a
	{ 6,	6,	16,	"Celeron", },
.
## diffname pc/devarch.c 2000/0211
## diff -e /n/emeliedump/2000/0208/sys/src/9/pc/devarch.c /n/emeliedump/2000/0211/sys/src/9/pc/devarch.c
443a
	{ 6,	1,	11,	"AMD-Athlon", },

.
## diffname pc/devarch.c 2000/0222
## diff -e /n/emeliedump/2000/0211/sys/src/9/pc/devarch.c /n/emeliedump/2000/0222/sys/src/9/pc/devarch.c
444c
	{ 6,	1,	11,	"AMD-Athlon", },/* trial and error */
	{ 6,	2,	11,	"AMD-Athlon", },/* trial and error */
.
439,442c
	{ 5,	6,	11,	"AMD-K6", },	/* trial and error */
	{ 5,	7,	11,	"AMD-K6", },	/* trial and error */
	{ 5,	8,	11,	"AMD-K6-2", },	/* trial and error */
	{ 5,	9,	11,	"AMD-K6-III", },/* trial and error */
.
408a
	{ 5,	8,	11,	"AMD-K6 3D", },	/* Kenji Arisawa [email protected] */
	{ 5,	9,	11,	"AMD-K6 3D+", },/* Kenji Arisawa [email protected] */
.
## diffname pc/devarch.c 2000/0421
## diff -e /n/emeliedump/2000/0222/sys/src/9/pc/devarch.c /n/emeliedump/2000/0421/sys/src/9/pc/devarch.c
450a
	{ 6,	-1,	11,	"AMD-Athlon", },/* guesswork */
.
415a
	{ 6,	8,	16,	"PentiumIII/Xeon", },
.
409,411c
	{ 6,	1,	16,	"PentiumPro", },/* trial and error */
.
## diffname pc/devarch.c 2000/0622
## diff -e /n/emeliedump/2000/0421/sys/src/9/pc/devarch.c /n/emeliedump/2000/0622/sys/src/9/pc/devarch.c
593a
	rdmsr(0x10, (vlong*)&tsc);
	m->fastclock = tsc;
.
590,591d
## diffname pc/devarch.c 2000/0907
## diff -e /n/emeliedump/2000/0622/sys/src/9/pc/devarch.c /n/emeliedump/2000/0907/sys/src/9/pc/devarch.c
482a
	else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
		t = x86winchip;
.
454a
/*
 * WinChip 240MHz
 */
static X86type x86winchip[] =
{
	{5,	4,	23,	"Winchip",},	/* guesswork */
	{ -1,	-1,	23,	"unknown", },	/* total default */
};


.
## diffname pc/devarch.c 2000/0922
## diff -e /n/emeliedump/2000/0907/sys/src/9/pc/devarch.c /n/emeliedump/2000/0922/sys/src/9/pc/devarch.c
519a
			if(family == 5){
				rdmsr(0x00, &mca);
				rdmsr(0x01, &mct);
			}
		}
.
518c
		if(p = getconf("*nomce"))
			nomce = strtoul(p, 0, 0);
		else
			nomce = 0;
		if((m->cpuiddx & 0x80) && !nomce){
.
488c
	vlong mca, mct;
.
485c
	char *p;
	int family, model, nomce;
.
## diffname pc/devarch.c 2000/1018
## diff -e /n/emeliedump/2000/0922/sys/src/9/pc/devarch.c /n/emeliedump/2000/1018/sys/src/9/pc/devarch.c
594a

	addarchfile("cputype", 0444, cputyperead, nil);
.
540c
cputyperead(Chan*, void *a, long n, vlong offset)
.
319a
		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
			return fn(c, a, n, offset);
.
288c
	Rdwrfn *fn;
.
284a
	char *p;
.
258a
		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
			return fn(c, a, n, offset);
.
252,257d
220c
		return devdirread(c, a, n, archdir, narchdir, devgen);
.
217c
	switch(c->qid.path){
.
215a
	IOMap *m;
	Rdwrfn *fn;
.
210,212c
	char buf[Linelen+1], *p;
.
194c
	return devopen(c, omode, archdir, narchdir, devgen);
.
188c
	devstat(c, dp, archdir, narchdir, devgen);
.
182c
	return devwalk(c, name, archdir, narchdir, devgen);
.
142c
	archdir[0].qid.vers++;
.
119c
	archdir[0].qid.vers++;
.
63,64d
48a
/*
 * Add a file to the #P listing.  Once added, you can't delete it.
 * You can't add a file with the same name as one already there,
 * and you get a pointer to the Dirtab entry so you can do things
 * like change the Qid version.  Changing the Qid path is disallowed.
 */
Dirtab*
addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
{
	int i;
	Dirtab d;
	Dirtab *dp;

	memset(&d, 0, sizeof d);
	strcpy(d.name, name);
	d.perm = perm;

	lock(&archwlock);
	if(narchdir >= Qmax){
		unlock(&archwlock);
		return nil;
	}

	for(i=0; i<narchdir; i++)
		if(strcmp(archdir[i].name, name) == 0){
			unlock(&archwlock);
			return nil;
		}

	d.qid.path = narchdir;
	archdir[narchdir] = d;
	readfn[narchdir] = rdfn;
	writefn[narchdir] = wrfn;
	dp = &archdir[narchdir++];
	unlock(&archwlock);

	return dp;
}

.
47a
Lock archwlock;	/* the lock is only for changing archdir */
int narchdir = Qbase;
.
46d
40,41c
typedef long Rdwrfn(Chan*, void*, long, vlong);

static Rdwrfn *readfn[Qmax];
static Rdwrfn *writefn[Qmax];

static Dirtab archdir[Qmax] = {
.
37c
	Qbase,

	Qmax = 16,
.
31,33c
	Qdir = CHDIR,
	Qioalloc = 0,
.
10d
## diffname pc/devarch.c 2000/1102
## diff -e /n/emeliedump/2000/1018/sys/src/9/pc/devarch.c /n/emeliedump/2000/1102/sys/src/9/pc/devarch.c
351c
		checkport(offset, offset+n);
.
341c
		checkport(offset, offset+n);
.
284c
		checkport(offset, offset+n);
.
274c
		checkport(offset, offset+n);
.
## diffname pc/devarch.c 2001/0510
## diff -e /n/emeliedump/2000/1102/sys/src/9/pc/devarch.c /n/emeliedump/2001/0510/sys/src/9/pc/devarch.c
135a
		// Only 64KB I/O space on the x86.
		if((port+size) >= 0x10000){
			unlock(&iomap);
			return -1;
		}
.
## diffname pc/devarch.c 2001/0527
## diff -e /n/emeliedump/2001/0510/sys/src/9/pc/devarch.c /n/emeliedump/2001/0527/sys/src/9/pc/devarch.c
379d
334c
	switch((ulong)c->qid.path){
.
264c
	switch((ulong)c->qid.path){
.
235c
	return devstat(c, dp, n, archdir, narchdir, devgen);
.
232,233c
static int
archstat(Chan* c, uchar* dp, int n)
.
229c
	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
.
226,227c
Walkqid*
archwalk(Chan* c, Chan *nc, char** name, int nname)
.
45a
	".",	{ Qdir, 0, QTDIR },	0,	0555,
.
30,31c
	Qdir = 0,
	Qioalloc = 1,
.
## diffname pc/devarch.c 2001/0622
## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/devarch.c /n/emeliedump/2001/0622/sys/src/9/pc/devarch.c
146a
			if(m->reserved && m->start == port && m->end == port + size) {
				m->reserved = 0;
				unlock(&iomap);
				return m->start;
			}
.
123a
			if (m->start < 0x400) continue;
.
107a
// Reserve a range to be ioalloced later.  This is in particular useful for exchangable cards, such
// as pcmcia and cardbus cards.
int
ioreserve(int port, int size, int align, char *tag)
{
	IOMap *m, **l;
	int i;

	lock(&iomap);
	// find a free port above 0x400 and below 0x1000
	port = 0x400;
	for(l = &iomap.m; *l; l = &(*l)->next){
		m = *l;
		if (m->start < 0x400) continue;
		i = m->start - port;
		if(i > size)
			break;
		if(align > 0)
			port = ((port+align-1)/align)*align;
		else
			port = m->end;
	}
	if(*l == nil){
		unlock(&iomap);
		return -1;
	}
	m = iomap.free;
	if(m == nil){
		print("ioalloc: out of maps");
		unlock(&iomap);
		return port;
	}
	iomap.free = m->next;
	m->next = *l;
	m->start = port;
	m->end = port + size;
	m->reserved = 1;
	strncpy(m->tag, tag, sizeof(m->tag));
	m->tag[sizeof(m->tag)-1] = 0;
	*l = m;

	archdir[0].qid.vers++;

	unlock(&iomap);
	return m->start;
}

.
105a
	ioalloc(0x1000, 1, 0, "dummy");
.
13a
	int		reserved;
.
## diffname pc/devarch.c 2001/0809
## diff -e /n/emeliedump/2001/0622/sys/src/9/pc/devarch.c /n/emeliedump/2001/0809/sys/src/9/pc/devarch.c
107d
## diffname pc/devarch.c 2001/0905
## diff -e /n/emeliedump/2001/0809/sys/src/9/pc/devarch.c /n/emeliedump/2001/0905/sys/src/9/pc/devarch.c
724a
}

int
pcmspecial(char *idstr, ISAConf *isa)
{
	return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
}

void
pcmspecialclose(int a)
{
	if (_pcmspecialclose != nil)
		_pcmspecialclose(a);
.
478a
	i8259vecno,				/* vector number */
	i8259disable,				/* intrdisable */
.
55a

.
54a
int (*_pcmspecial)(char *, ISAConf *);
void (*_pcmspecialclose)(int);
.
## diffname pc/devarch.c 2001/0925
## diff -e /n/emeliedump/2001/0905/sys/src/9/pc/devarch.c /n/emeliedump/2001/0925/sys/src/9/pc/devarch.c
109a
	ioalloc(0x1000, 1, 0, "dummy");
.
## diffname pc/devarch.c 2001/0926
## diff -e /n/emeliedump/2001/0925/sys/src/9/pc/devarch.c /n/emeliedump/2001/0926/sys/src/9/pc/devarch.c
110c
	ioalloc(0x0fff, 1, 0, "dummy");	// i82557 is at 0x1000, the dummy
							// entry is needed for swappable devs.
.
## diffname pc/devarch.c 2001/1003
## diff -e /n/emeliedump/2001/0926/sys/src/9/pc/devarch.c /n/emeliedump/2001/1003/sys/src/9/pc/devarch.c
111a

	if ((excluded = getconf("ioexclude")) != nil) {
		char *s;

		s = excluded;
		while (s && *s != '\0' && *s != '\n') {
			char *ends;
			int io_s, io_e;

			io_s = (int)strtol(s, &ends, 0);
			if (ends == nil || ends == s || *ends != '-') {
				print("ioinit: cannot parse option string\n");
				break;
			}
			s = ++ends;

			io_e = (int)strtol(s, &ends, 0);
			if (ends && *ends == ',')
				*ends++ = '\0';
			s = ends;

			ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
		}
	}

.
100a
	char *excluded;
.
## diffname pc/devarch.c 2001/1014
## diff -e /n/emeliedump/2001/1003/sys/src/9/pc/devarch.c /n/emeliedump/2001/1014/sys/src/9/pc/devarch.c
373c
		if(n & 3)
.
363c
		if(n & 1)
.
## diffname pc/devarch.c 2001/1130
## diff -e /n/emeliedump/2001/1014/sys/src/9/pc/devarch.c /n/emeliedump/2001/1130/sys/src/9/pc/devarch.c
749c
	rdtsc((vlong*)&tsc);
.
## diffname pc/devarch.c 2002/0109
## diff -e /n/emeliedump/2001/1130/sys/src/9/pc/devarch.c /n/emeliedump/2002/0109/sys/src/9/pc/devarch.c
463a
	devshutdown,
.
## diffname pc/devarch.c 2002/0221
## diff -e /n/emeliedump/2002/0109/sys/src/9/pc/devarch.c /n/emeliedump/2002/0221/sys/src/9/pc/devarch.c
553a
	{ 0xF,	-1,	16,	"P4", },	/* P4 */
.
548a
	{ 0xF,	1,	16,	"P4", },	/* P4 */
.
## diffname pc/devarch.c 2002/0404
## diff -e /n/emeliedump/2002/0221/sys/src/9/pc/devarch.c /n/emeliedump/2002/0404/sys/src/9/pc/devarch.c
447c
		return n;
.
443d
440c
		if(n & 3)
.
437c
		return n;
.
433d
430c
		if(n & 1)
.
380c
		return n;
.
376d
370c
		return n;
.
366d
## diffname pc/devarch.c 2002/0405
## diff -e /n/emeliedump/2002/0404/sys/src/9/pc/devarch.c /n/emeliedump/2002/0405/sys/src/9/pc/devarch.c
764a
/*
 *  call either the pcmcia or pccard device teardown
 */
.
741,758d
739c
 *  call either the pcmcia or pccard device setup
.
731,737d
713,718d
710a
		if(arch->intrenable == 0)
			arch->intrenable = archgeneric.intrenable;
.
706d
642a
	 *  if there is one, set tsc to a known value
	 */
	m->havetsc = t->family >= 5;
	if(m->havetsc)
		wrmsr(0x10, 0);

	/*
 	 *  use i8253 to guess our cpu speed
	 */
	guesscpuhz(t->aalcycles);

	/*
.
640d
613a
/*
 *  figure out:
 *	- cpu type
 *	- whether or not we have a TSC (cycle counter)
 *	- whether or not is supports page size extensions
 *		(if so turn it on)
 *	- whether or not is supports machine check exceptions
 *		(if so turn it on)
 */
.
597d
492,493d
## diffname pc/devarch.c 2002/0409
## diff -e /n/emeliedump/2002/0405/sys/src/9/pc/devarch.c /n/emeliedump/2002/0409/sys/src/9/pc/devarch.c
737c
	if(X86FAMILY(m->cpuidax) >= 5 && conf.nmach > 1)
.
## diffname pc/devarch.c 2002/0410
## diff -e /n/emeliedump/2002/0409/sys/src/9/pc/devarch.c /n/emeliedump/2002/0410/sys/src/9/pc/devarch.c
759a
}

/*
 *  return value and speed of timer set in arch->clockenable
 */
uvlong
fastticks(uvlong *hz)
{
	return (*arch->fastclock)(hz);
}

/*
 *  set next timer interrupt
 */
void
timerset(uvlong x)
{
	(*arch->timerset)(x);
.
727,728d
683a
	if(t->family >= 6){
		cr4 = getcr4();
		cr4 |= 0x80;		/* page global enable bit */
		putcr4(cr4);
	}

.
510a
	i8253timerset,
.
## diffname pc/devarch.c 2002/0411
## diff -e /n/emeliedump/2002/0410/sys/src/9/pc/devarch.c /n/emeliedump/2002/0411/sys/src/9/pc/devarch.c
741,743d
739c
	if(X86FAMILY(m->cpuidax) == 3)
.
737c
	 *  Decide whether to use copy-on-reference (386 and mp).
	 *  We get another chance to set it in mpinit() for a
	 *  multiprocessor.
.
## diffname pc/devarch.c 2002/0412
## diff -e /n/emeliedump/2002/0411/sys/src/9/pc/devarch.c /n/emeliedump/2002/0412/sys/src/9/pc/devarch.c
744a
	addarchfile("pge", 0664, pgeread, pgewrite);
.
706a
static long
pgewrite(Chan*, void *a, long n, vlong)
{
	if(!m->havepge)
		error("processor does not support pge");

	if(n==3 && memcmp(a, "off", 3)==0){
		putcr4(getcr4() & ~0x80);
		return n;
	}
	if(n==2 && memcmp(a, "on", 2)==0){
		putcr4(getcr4() | 0x80);
		return n;
	}
	error("invalid control message");
	return -1;
}

static long
pgeread(Chan*, void *a, long n, vlong offset)
{
	if(n < 16)
		error("need more room");
	if(offset)
		return 0;
	n = snprint(a, n, "%s pge; %s", m->havepge ? "have" : "no", getcr4()&0x80 ? "on" : "off");
	return n;
}

.
688a
		m->havepge = 1;
.
685c
	/*
	 * Detect whether the chip supports the global bit
	 * in page directory and page table entries.  When set
	 * in a particular entry, it means ``don't bother removing
	 * this from the TLB when CR3 changes.''  
	 * 
	 * We flag all kernel pages with this bit.  Doing so lessens the
	 * overhead of switching processes on bare hardware,
	 * even more so on VMware.  See mmu.c:/^memglobal.
	 *
	 * This feature exists on Intel Pentium Pro and later
	 * processors.  Presumably the AMD processors have
	 * a similar notion, but I can't find it in the meager
	 * documentation I've tried.
	 *
	 * For future reference, should we ever need to do a
	 * full TLB flush, it can be accomplished by clearing
	 * the PGE bit in CR4, writing to CR3, and then
	 * restoring the PGE bit.
	 */
	if(tab==x86intel && t->family >= 6){
.
644,645c

.
639c
	for(t=tab; t->name; t++)
.
636c
		tab = x86intel;
	
.
634c
		tab = x86winchip;
.
632c
		tab = x86amd;
.
626c
	X86type *t, *tab;
.
## diffname pc/devarch.c 2002/0413
## diff -e /n/emeliedump/2002/0412/sys/src/9/pc/devarch.c /n/emeliedump/2002/0413/sys/src/9/pc/devarch.c
793a
//	if(X86FAMILY(m->cpuidax) >= 5 && conf.nmach > 1)
		coherence = wbflush;

.
## diffname pc/devarch.c 2002/0531
## diff -e /n/emeliedump/2002/0413/sys/src/9/pc/devarch.c /n/emeliedump/2002/0531/sys/src/9/pc/devarch.c
543a
	{ 6,	0xB,	16,	"PentiumIII/Xeon", },
.
## diffname pc/devarch.c 2002/0703
## diff -e /n/emeliedump/2002/0531/sys/src/9/pc/devarch.c /n/emeliedump/2002/0703/sys/src/9/pc/devarch.c
808c
	return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
.
140c
// Reserve a range to be ioalloced later. 
// This is in particular useful for exchangable cards, such
.
112c
					// entry is needed for swappable devs.
.
55c
int (*_pcmspecial)(char*, ISAConf*);
.
47c
	".",		{ Qdir, 0, QTDIR },	0,	0555,
.
14c
	int	reserved;
.
## diffname pc/devarch.c 2002/1105
## diff -e /n/emeliedump/2002/0703/sys/src/9/pc/devarch.c /n/emeliedump/2002/1105/sys/src/9/pc/devarch.c
509,512c
.clockenable=	i8253enable,
.fastclock=	i8253read,
.timerset=	i8253timerset,
.
504,507c
.intrinit=	i8259init,
.intrenable=	i8259enable,
.intrvecno=	i8259vecno,
.intrdisable=	i8259disable,
.
498,502c
.id=		"generic",
.ident=		0,
.reset=		i8042reset,
.serialpower=	unimplemented,
.modempower=	unimplemented,
.
## diffname pc/devarch.c 2003/0204
## diff -e /n/emeliedump/2002/1105/sys/src/9/pc/devarch.c /n/emeliedump/2003/0204/sys/src/9/pc/devarch.c
407c
	n = p - buf;
	memmove(a, buf, n);
	free(buf);

	return n;
.
400,401c
		sprint(p, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
.
393c
	offset = offset/Linelen;

.
391c
	if((buf = malloc(n)) == nil)
		error(Enomem);
	p = buf;
.
344c
	char *buf, *p;
.
112a
	 */
.
110a
	/*
	 * Someone needs to explain why this was here...
.
## diffname pc/devarch.c 2003/0207
## diff -e /n/emeliedump/2003/0204/sys/src/9/pc/devarch.c /n/emeliedump/2003/0207/sys/src/9/pc/devarch.c
115d
112a
	 */
.
## diffname pc/devarch.c 2003/0208
## diff -e /n/emeliedump/2003/0207/sys/src/9/pc/devarch.c /n/emeliedump/2003/0208/sys/src/9/pc/devarch.c
406c
		snprint(p, Linelen+1, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
.
394c
	/* allocate a buffer to avoid page faults in the loop */
	if((buf = malloc(n+1)) == nil)	/* +1 for the NUL */
.
## diffname pc/devarch.c 2003/0214
## diff -e /n/emeliedump/2003/0208/sys/src/9/pc/devarch.c /n/emeliedump/2003/0214/sys/src/9/pc/devarch.c
694,720d
690a
	
		/*
		 * Detect whether the chip supports the global bit
		 * in page directory and page table entries.  When set
		 * in a particular entry, it means ``don't bother removing
		 * this from the TLB when CR3 changes.''  
		 * 
		 * We flag all kernel pages with this bit.  Doing so lessens the
		 * overhead of switching processes on bare hardware,
		 * even more so on VMware.  See mmu.c:/^memglobal.
		 *
		 * For future reference, should we ever need to do a
		 * full TLB flush, it can be accomplished by clearing
		 * the PGE bit in CR4, writing to CR3, and then
		 * restoring the PGE bit.
		 */
		if(m->cpuiddx & 0x2000){
			cr4 |= 0x80;		/* page global enable bit */
			m->havepge = 1;
		}

.
676c
	if(m->cpuiddx & 0x2088){
.
672,673c
	 * If machine check exception, page size extensions or page global bit
	 * are supported enable them in CR4 and clear any other set extensions.
.
630a
 *	- whether or not it supports the page global flag
 *		(if so turn it on)
.
629c
 *	- whether or not it supports machine check exceptions
.
627c
 *	- whether or not it supports page size extensions
.
407c
		sprint(p, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
.
394,395c
	if((buf = malloc(n)) == nil)
.
115a
	 */
.
113d
## diffname pc/devarch.c 2003/0308
## diff -e /n/emeliedump/2003/0214/sys/src/9/pc/devarch.c /n/emeliedump/2003/0308/sys/src/9/pc/devarch.c
115d
112a
	 */
.
## diffname pc/devarch.c 2003/0326
## diff -e /n/emeliedump/2003/0308/sys/src/9/pc/devarch.c /n/emeliedump/2003/0326/sys/src/9/pc/devarch.c
804c
	addarchfile("archctl", 0664, archctlread, archctlwrite);
.
800,802d
755,759c
	Cmdbuf *cb;
	Cmdtab *ct;

	cb = parsecmd(a, n);
	if(waserror()){
		free(cb);
		nexterror();
	}
	ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
	switch(ct->index){
	case CMpge:
		if(!m->havepge)
			error("processor does not support pge");
		if(strcmp(cb->f[1], "on") == 0)
			putcr4(getcr4() | 0x80);
		else if(strcmp(cb->f[1], "off") == 0)
			putcr4(getcr4() & ~0x80);
		else
			cmderror(cb, "invalid pge ctl");
		break;
	case CMcoherence:
		if(strcmp(cb->f[1], "wbflush") == 0)
			coherence = wbflush;
		else if(strcmp(cb->f[1], "nop") == 0){
			/* only safe on vmware */
			if(conf.nmach > 1)
				error("cannot disable coherence on a multiprocessor");
			coherence = nop;
		}else
			cmderror(cb, "invalid coherence ctl");
		break;
	case CMi8253set:
		if(strcmp(cb->f[1], "on") == 0)
			i8253dotimerset = 1;
		else if(strcmp(cb->f[1], "off") == 0)
			i8253dotimerset = 0;
		else
			cmderror(cb, "invalid i2853set ctl");
		break;
	}
	free(cb);
	poperror();
.
753c
archctlwrite(Chan*, void *a, long n, vlong)
.
751a
enum
{
	CMpge,
	CMcoherence,
	CMi8253set,
};

static Cmdtab archctlmsg[] =
{
	CMpge,		"pge",		2,
	CMcoherence,	"coherence",	2,
	CMi8253set,	"i8253set",	2,
};

.
737,749c
	char buf[256];
	int n;
	
	n = snprint(buf, sizeof buf, "cpu %s %lud%s\n",
		cputype->name, (ulong)(m->cpuhz+999999)/1000000,
		m->havepge ? " pge" : "");
	n += snprint(buf+n, sizeof buf-n, "pge %s\n", getcr4()&0x80 ? "on" : "off");
	n += snprint(buf+n, sizeof buf-n, "coherence %s\n",
		coherence==wbflush ? "wbflush" : "nop");
	buf[n] = 0;
	return readstr(offset, a, nn, buf);
.
735c
archctlread(Chan*, void *a, long nn, vlong offset)
.
501c
/*
 * On a uniprocessor, you'd think that coherence could be nop,
 * but it can't.  We still need wbflush when using coherence() in
 * device drivers.
 *
 * On VMware, it's safe (and a huge win) to set this to nop.
 * Aux/vmware does this via the #P/archctl file.
 */
void (*coherence)(void) = wbflush;
.
115a
	 */
.
113d
57a
extern int i8253dotimerset;
.
## diffname pc/devarch.c 2003/0328
## diff -e /n/emeliedump/2003/0326/sys/src/9/pc/devarch.c /n/emeliedump/2003/0328/sys/src/9/pc/devarch.c
610a
	{6,	7,	23,	"Via C3 Samuel 2 or Ezra",},
	{6,	8,	23,	"Via C3 Ezra-T",},
.
## diffname pc/devarch.c 2003/0401
## diff -e /n/emeliedump/2003/0328/sys/src/9/pc/devarch.c /n/emeliedump/2003/0401/sys/src/9/pc/devarch.c
815a
		break;
	case CMrealmode:
		if(strcmp(cb->f[1], "realmode") == 0)
			realmode();
.
772a
CMrealmode, "realmode", 1,
.
765a
CMrealmode
.
## diffname pc/devarch.c 2003/0402
## diff -e /n/emeliedump/2003/0401/sys/src/9/pc/devarch.c /n/emeliedump/2003/0402/sys/src/9/pc/devarch.c
818,821d
774d
766d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].