1129 lines · 23.5 KB · C
RawDownload
#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" enum {	Qdir = 0,	Qiob,	Qiow,	Qiol,	Qmsr,	Qbase, 	Qmax = 32,}; enum {				/* cpuid standard function codes */	Highstdfunc = 0,	/* also returns vendor string */	Procsig,	Proctlbcache,	Procserial,		Highextfunc = 0x80000000,	Procextfeat,}; typedef long Rdwrfn(Chan*, void*, long, vlong); static Rdwrfn *readfn[Qmax];static Rdwrfn *writefn[Qmax]; static Dirtab archdir[Qmax] = {	".",		{ Qdir, 0, QTDIR },	0,	0555,	"iob",		{ Qiob, 0 },		0,	0660,	"iow",		{ Qiow, 0 },		0,	0660,	"iol",		{ Qiol, 0 },		0,	0660,	"msr",		{ Qmsr, 0 },		0,	0660,};Lock archwlock;	/* the lock is only for changing archdir */int narchdir = Qbase;int (*_pcmspecial)(char*, ISAConf*);void (*_pcmspecialclose)(int); /* * 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);		print("addarchfile: out of entries for %s\n", name);		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;} voidioinit(void){	char *excluded; 	iomapinit(0xffff); 	/*	 * This is necessary to make the IBM X20 boot.	 * Have not tracked down the reason.	 * i82557 is at 0x1000, the dummy entry is needed for swappable devs.	 */	ioalloc(0x0fff, 1, 0, "dummy"); 	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");		}	}} static voidcheckport(ulong start, ulong end){	if(end < start || end > 0x10000)		error(Ebadarg); 	/* 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);} Walkqid*archwalk(Chan* c, Chan *nc, char** name, int nname){	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);} static intarchstat(Chan* c, uchar* dp, int n){	return devstat(c, dp, n, archdir, narchdir, devgen);} static Chan*archopen(Chan* c, int omode){	return devopen(c, omode, archdir, narchdir, devgen);} static voidarchclose(Chan*){} static longarchread(Chan *c, void *a, long n, vlong offset){	ulong port, end;	uchar *cp;	ushort *sp;	ulong *lp;	vlong *vp;	Rdwrfn *fn; 	port = offset;	end = port+n;	switch((ulong)c->qid.path){	case Qdir:		return devdirread(c, a, n, archdir, narchdir, devgen); 	case Qiob:		checkport(port, end);		for(cp = a; port < end; port++)			*cp++ = inb(port);		return n; 	case Qiow:		if(n & 1)			error(Ebadarg);		checkport(port, end);		for(sp = a; port < end; port += 2)			*sp++ = ins(port);		return n; 	case Qiol:		if(n & 3)			error(Ebadarg);		checkport(port, end);		for(lp = a; port < end; port += 4)			*lp++ = inl(port);		return n; 	case Qmsr:		if(n & 7)			error(Ebadarg);		if((ulong)n/8 > -port)			error(Ebadarg);		end = port+(n/8);		for(vp = a; port != end; port++)			if(rdmsr(port, vp++) < 0)				error(Ebadarg);		return n; 	default:		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))			return fn(c, a, n, offset);		error(Eperm);	}} static longarchwrite(Chan *c, void *a, long n, vlong offset){	ulong port, end;	uchar *cp;	ushort *sp;	ulong *lp;	vlong *vp;	Rdwrfn *fn; 	port = offset;	end = port+n;	switch((ulong)c->qid.path){	case Qiob:		checkport(port, end);		for(cp = a; port < end; port++)			outb(port, *cp++);		return n; 	case Qiow:		if(n & 1)			error(Ebadarg);		checkport(port, end);		for(sp = a; port < end; port += 2)			outs(port, *sp++);		return n; 	case Qiol:		if(n & 3)			error(Ebadarg);		checkport(port, end);		for(lp = a; port < end; port += 4)			outl(port, *lp++);		return n; 	case Qmsr:		if(n & 7)			error(Ebadarg);		if((ulong)n/8 > -port)			error(Ebadarg);		end = port+(n/8);		for(vp = a; port != end; port++)			if(wrmsr(port, *vp++) < 0)				error(Ebadarg);		return n; 	default:		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]) != nil)			return fn(c, a, n, offset);		error(Eperm);		break;	}} Dev archdevtab = {	'P',	"arch", 	devreset,	devinit,	devshutdown,	archattach,	archwalk,	archstat,	archopen,	devcreate,	archclose,	archread,	devbread,	archwrite,	devbwrite,	devremove,	devwstat,}; /* *  the following is a generic version of the *  architecture specific stuff */ static intunimplemented(int){	return 0;} static voidnop(void){} /* * 386 has no compare-and-swap instruction. * Run it with interrupts turned off instead. */static intcmpswap386(long *addr, long old, long new){	int r, s; 	s = splhi();	if(r = (*addr == old))		*addr = new;	splx(s);	return r;} /* * On a uniprocessor, you'd think that coherence could be nop, * but it can't.  We still need a barrier 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) = nop; int (*cmpswap)(long*, long, long) = cmpswap386; PCArch* arch;extern PCArch* knownarch[]; typedef struct X86type X86type;struct X86type {	int	family;	int	model;	int	aalcycles;	char*	name;}; 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", },/* trial and error */	{ 6,	3,	16,	"PentiumII", },	{ 6,	5,	16,	"PentiumII/Xeon", },	{ 6,	6,	16,	"Celeron", },	{ 6,	7,	16,	"PentiumIII/Xeon", },	{ 6,	8,	16,	"PentiumIII/Xeon", },	{ 6,	0xB,	16,	"PentiumIII/Xeon", },	{ 6,	0xF,	16,	"Xeon5000-series", },	{ 6,	0x16,	16,	"Celeron", },	{ 6,	0x17,	16,	"Core 2/Xeon", },	{ 6,	0x1A,	16,	"Core i7/Xeon", },	{ 6,	0x1C,	16,	"Atom", },	{ 6,	0x1D,	16,	"Xeon MP", },	{ 0xF,	1,	16,	"P4", },	/* P4 */	{ 0xF,	2,	16,	"PentiumIV/Xeon", },	{ 0xF,	6,	16,	"PentiumIV/Xeon", }, 	{ 3,	-1,	32,	"386", },	/* family defaults */	{ 4,	-1,	22,	"486", },	{ 5,	-1,	23,	"P5", },	{ 6,	-1,	16,	"P6", },	{ 0xF,	-1,	16,	"P4", },	/* P4 */ 	{ -1,	-1,	16,	"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,	4,	23,	"AMD Geode GX1", },	/* guesswork */	{ 5,	5,	23,	"AMD Geode GX2", },	/* guesswork */	{ 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 */	{ 5,	0xa,	23,	"AMD Geode LX", },	/* guesswork */ 	{ 6,	1,	11,	"AMD-Athlon", },/* trial and error */	{ 6,	2,	11,	"AMD-Athlon", },/* trial and error */ 	{ 0x1F,	9,	11,	"AMD-K10 Opteron G34", },/* guesswork */ 	{ 4,	-1,	22,	"Am486", },	/* guesswork */	{ 5,	-1,	23,	"AMD-K5/K6", },	/* guesswork */	{ 6,	-1,	11,	"AMD-Athlon", },/* guesswork */	{ 0xF,	-1,	11,	"AMD-K8", },	/* guesswork */	{ 0x1F,	-1,	11,	"AMD-K10", },	/* guesswork */	{ 22,	0,	11,	"AMD Jaguar", },	{ 22,	3,	11,	"AMD Puma", },	{ 23,	1,	13,	"AMD Ryzen" }, 	{ -1,	-1,	11,	"unknown", },	/* total default */}; /* * WinChip 240MHz */static X86type x86winchip[] ={	{5,	4,	23,	"Winchip",},	/* guesswork */	{6,	7,	23,	"Via C3 Samuel 2 or Ezra",},	{6,	8,	23,	"Via C3 Ezra-T",},	{6,	9,	23,	"Via C3 Eden-N",},	{6,	0xd,	23,	"Via C7 Eden",},	{ -1,	-1,	23,	"unknown", },	/* total default */}; /* * SiS 55x */static X86type x86sis[] ={	{5,	0,	23,	"SiS 55x",},	/* guesswork */	{ -1,	-1,	23,	"unknown", },	/* total default */}; static void	simplecycles(uvlong*);void	(*cycles)(uvlong*) = simplecycles;void	_cycles(uvlong*);	/* in l.s */ static voidsimplecycles(uvlong*x){	*x = m->ticks;} voidcpuidprint(void){	print("cpu%d: %dMHz %s %s (AX %8.8uX CX %8.8uX DX %8.8uX)\n",		m->machno, m->cpumhz, m->cpuidid, m->cpuidtype,		m->cpuidax, m->cpuidcx, m->cpuiddx);} /* *  figure out: *	- cpu type *	- whether or not we have a TSC (cycle counter) *	- whether or not it supports page size extensions *		(if so turn it on) *	- whether or not it supports machine check exceptions *		(if so turn it on) *	- whether or not it supports the page global flag *		(if so turn it on) *	- detect PAT feature and add write-combining entry *	- detect MTRR support and synchronize state with cpu0 *	- detect NX support and enable it for AMD64 *	- detect watchpoint support *	- detect FPU features and enable the FPU */intcpuidentify(void)

Lines 1–500 of 1129.