Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/fs/pc/pc.c

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


#include	"all.h"
#include	"mem.h"
#include	"io.h"
#include	"ureg.h"

/*
 * Where configuration info is left for the loaded programme.
 * This will turn into a structure as more is done by the boot loader
 * (e.g. why parse the .ini file twice?).
 * There are 1024 bytes available at CONFADDR.
 */
#define BOOTLINE	((char*)CONFADDR)
#define BOOTLINELEN	64
#define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
#define	BOOTARGSLEN	(1024-BOOTLINELEN)
#define	MAXCONF		32

char bootdisk[NAMELEN];
char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;

int
getcfields(char* lp, char** fields, int n, char* sep)
{
	int i;

	for(i = 0; lp && *lp && i < n; i++){
		while(*lp && strchr(sep, *lp) != 0)
			*lp++ = 0;
		if(*lp == 0)
			break;
		fields[i] = lp;
		while(*lp && strchr(sep, *lp) == 0){
			if(*lp == '\\' && *(lp+1) == '\n')
				*lp++ = ' ';
			lp++;
		}
	}

	return i;
}

static void
options(void)
{
	long i, n;
	char *cp, *line[MAXCONF], *p, *q;

	/*
	 *  parse configuration args from dos file plan9.ini
	 */
	cp = BOOTARGS;	/* where b.com leaves its config */
	cp[BOOTARGSLEN-1] = 0;

	/*
	 * Strip out '\r', change '\t' -> ' '.
	 */
	p = cp;
	for(q = cp; *q; q++){
		if(*q == '\r')
			continue;
		if(*q == '\t')
			*q = ' ';
		*p++ = *q;
	}
	*p = 0;

	n = getcfields(cp, line, MAXCONF, "\n");
	for(i = 0; i < n; i++){
		if(*line[i] == '#')
			continue;
		cp = strchr(line[i], '=');
		if(cp == 0)
			continue;
		*cp++ = 0;
		if(cp - line[i] >= NAMELEN+1)
			*(line[i]+NAMELEN-1) = 0;
		confname[nconf] = line[i];
		confval[nconf] = cp;
		nconf++;
	}
}


/*
 * Vecinit is the first hook we have into configuring the machine,
 * so we do it all here. A pox on special fileserver code.
 * We do more in meminit below.
 */
void
vecinit(void)
{
	options();
}

char*
getconf(char *name)
{
	int i;

	for(i = 0; i < nconf; i++)
		if(cistrcmp(confname[i], name) == 0)
			return confval[i];
	return 0;
}

/*
 * old memory scan.  if no e820 information is available,
 * this kernel will see MAXMEG megabytes of RAM at most.
 * maxmeg is limited due the the fact the page table might be too large
 * for our temporary mapping to hold and depends on the size of 
 * our kernel.
 */
#ifndef MAXMEG
#define MAXMEG 2015
#endif

char mmap[MAXMEG+2];
Mconf mconf;

static void
mconfscan(void)
{
	ulong x, i, j, ktop;
	Mbank *b;

	/*
	 *  size memory above 4 meg. Kernel sits at 1 meg.  We
	 *  only recognize MB size chunks.
	 */
	x = 0x12345678;
	for(i = 4; i <= MAXMEG; i++){
		/*
		 *  write the first & last word in a megabyte of memory
		 */
		*mapaddr(i*MB) = x;
		*mapaddr((i+1)*MB-BY2WD) = x;

		/*
		 *  write the first and last word in all previous megs to
		 *  handle address wrap around
		 */
		for(j = 4; j < i; j++){
			*mapaddr(j*MB) = ~x;
			*mapaddr((j+1)*MB-BY2WD) = ~x;
		}

		/*
		 *  check for correct value
		 */
		if(*mapaddr(i*MB) == x && *mapaddr((i+1)*MB-BY2WD) == x)
			mmap[i] = 'x';
		x += 0x3141526;
	}

	b = mconf.bank;
	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	b->base = ktop;
	/* careful with that ax, eugene */
	for(i = 4; mmap[i] == 'x'; i++)
		;
	b->limit = i*MB;
	mconf.topofmem = b->limit;
	b++;

	/*
	 * Look for any other chunks of memory.
	 */
	for(; i <= MAXMEG; i++){
		if(mmap[i] == 'x'){
			b->base = i*MB;
			for(j = i+1; mmap[j] == 'x'; j++)
				;
			b->limit = j*MB;
			mconf.topofmem = j*MB;
			b++;

			if(b - mconf.bank == MAXBANK)
				break;
		}
	}

	mconf.nbank = b - mconf.bank;
}

typedef struct {
	uvlong base;
	uvlong len;
	ulong type;
}Emap;

static char *etypes[] =
{
	"type=0",
	"memory",
	"reserved",
	"acpi reclaim",
	"acpi nvs",
};

#define	smap		0x534d4150
#define	e820tab		0x2d0
#define	e820sz		20
#define	e820end		(16*e820sz+e820tab)

/* debugging crap */
ulong n820;
ulong n820m;
static Emap emap[16];

int
mconf820(void)
{
	ulong i;
	Emap *e, *t;
	Mbank *b;
	uchar *a;
	vlong sz;

	a = (uchar*)mapaddr(0);
	i = *(ulong*)(a+e820end);
	if(i == 0 || i > 16)
		return -1;
	e = (Emap*)(a+e820tab);
	t = e+i;
	b = mconf.bank;
	mconf.topofmem = MB;		// this is used to calculate pgtable sz; allow pci space.
	for(; e<=t; e++){
		emap[n820].base = e->base;
		emap[n820].len = e->len;
		emap[n820++].type = e->type;

		if(e->type != 1)
			continue;
		if(e->base >= 1ULL<<32 || e->base == 0)
			continue;
		sz = e->len;
		b->base = e->base;
		b->limit = e->base+sz;
		mconf.topofmem += sz;
		if(++b-mconf.bank == MAXBANK)
			break;
	}
	mconf.topofmem &= ~(4*MB-1);

	n820m = b-mconf.bank;
	if(b-mconf.bank < 1)
		return 0;
	mconf.nbank = b-mconf.bank;
	/* careful with that axe, eugene */
	mconf.bank[0].base += PADDR(PGROUND((ulong)end));

	return mconf.nbank;
}

/* debugging aide -- please remove */
void
cmd_e820(int, char **)
{
	ulong n;
	Emap *e, *end;
	vlong sz, ex, lim;

	print("found %uld e820 entries %uld banks\n", n820, n820m);

	e = emap;
	end = e+n820;
	
	n = 0;
	sz = 0;
	ex = 0;
	for(; e<end; e++){
		print("e820: %.8llux %.8llux ", e->base, e->base+e->len);
		if(e->type < nelem(etypes))
			print("%s\n", etypes[e->type]);
		else
			print("type=%lud\n", e->type);

		if(e->type != 1 || e->base == 0)
			continue;
		if(e->base >= 1ULL<<32){
			ex += e->len;
			continue;
		}
		lim = e->base+e->len;
		sz += e->len;
		if(++n == MAXBANK)
			continue;

		print("\t" "bank %ullx %ullx\n", e->base, lim);
	}

	print("found %ld e820 memory banks %ulldMB+%ulldMB\n", n, sz/MB, ex/MB);
	print("	topofmem = %p\n", mconf.topofmem);
	print("	cpuiddx %p; cycles %p\n", MACHP(0)->cpuiddx, cycles);
	if((MACHP(0)->cpuiddx & 0x08) && (getcr4() & 0x10))
		print("	pse: yes\n");
}

ulong
meminit(void)
{
	ulong i, sz;

	conf.nmach = 1;
	if(mconf820() <= 0)
		mconfscan();
	mmuinit();
	trapinit();

	sz = 0;
	for(i = 0; i < mconf.nbank; i++)
		sz += mconf.bank[i].limit-mconf.bank[i].base;
	return sz;
}

void
userinit(void (*f)(void), void *arg, char *text)
{
	User *p;

	p = newproc();

	/*
	 * Kernel Stack.
	 * The -4 is because the path sched()->gotolabel()->init0()->f()
	 * uses a stack location without creating any local space.
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->stack + sizeof(p->stack) - 4;
	p->start = f;
	p->text = text;
	p->arg = arg;

	dofilter(&p->time);
	ready(p);
}

static int useuart;
static void (*intrputs)(char*, int);

static int
pcgetc(void)
{
	int c;

	if(c = kbdgetc())
		return c;
	if(c = cecgetc())
		return c;
	if(useuart)
		return uartgetc();
	return 0;
}

static void
pcputc(int c)
{
	if(predawn)
		cgaputc(c);
	if(useuart)
		uartputc(c);
}

static void
pcputs(char* s, int n)
{
	if(!predawn){
		cgaputs(s, n);
		cecputs(s, n);
	}
	if(intrputs)
		(*intrputs)(s, n);
}

void
consinit(void (*puts)(char*, int))
{
	char *p;
	int baud, port;

	kbdinit();

	consgetc = pcgetc;
	consputc = pcputc;
	consputs = pcputs;
	intrputs = puts;

	if((p = getconf("console")) == 0 || cistrcmp(p, "cga") == 0)
		return;

	port = strtoul(p, &p, 0);
	if(port < 0 || port > 1)
		return;
	while(*p == ' ' || *p == '\t')
		p++;
	if(*p != 'b' || (baud = strtoul(p+1, 0, 0)) == 0)
		baud = 9600;

	uartspecial(port, kbdchar, conschar, baud);
	useuart = 1;
}

void
consreset(void)
{
}

void
firmware(void)
{
	char *p;

	/*
	 * Always called splhi().
	 */
	if((p = getconf("reset")) && cistrcmp(p, "manual") == 0){
		predawn = 1;
		print("\nHit Reset\n");
		for(;;);
	}
	pcireset();
	i8042reset();
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	char cc[NAMELEN], *p, *q, *r;
	int n;

	sprint(cc, "%s%d", class, ctlrno);
	for(n = 0; n < nconf; n++){
		if(cistrncmp(confname[n], cc, NAMELEN))
			continue;
		isa->nopt = 0;
		p = confval[n];
		while(*p){
			while(*p == ' ' || *p == '\t')
				p++;
			if(*p == '\0')
				break;
			if(cistrncmp(p, "type=", 5) == 0){
				p += 5;
				for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
					if(*p == '\0' || *p == ' ' || *p == '\t')
						break;
					*q = *p++;
				}
				*q = '\0';
			}
			else if(cistrncmp(p, "port=", 5) == 0)
				isa->port = strtoul(p+5, &p, 0);
			else if(cistrncmp(p, "irq=", 4) == 0)
				isa->irq = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "dma=", 4) == 0)
				isa->dma = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "mem=", 4) == 0)
				isa->mem = strtoul(p+4, &p, 0);
			else if(cistrncmp(p, "size=", 5) == 0)
				isa->size = strtoul(p+5, &p, 0);
			else if(cistrncmp(p, "freq=", 5) == 0)
				isa->freq = strtoul(p+5, &p, 0);
			else if(isa->nopt < NISAOPT){
				r = isa->opt[isa->nopt];
				while(*p && *p != ' ' && *p != '\t'){
					*r++ = *p++;
					if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
						break;
				}
				*r = '\0';
				isa->nopt++;
			}
			while(*p && *p != ' ' && *p != '\t')
				p++;
		}
		return 1;
	}
	return 0;
}

void
lockinit(void)
{
}

void
launchinit(void)
{
}

void
lights(int, int)
{
}

/* in assembly language
Float
famd(Float a, int b, int c, int d)
{
	return ((a+b) * c) / d;
}

ulong
fdf(Float a, int b)
{
	return a / b;
}
*/

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.