Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/boot/pc-e820/conf.c

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


#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

#include "fs.h"

/*
 * There are 3584 bytes available at CONFADDR.
 *
 * The low-level boot routines in l.s leave data for us at CONFADDR,
 * which we pick up before reading the plan9.ini file.
 */
enum {
	Maxblocks	= 10,
	Maxitem		= 32,
	Maxconf		= 100,
	Bootlinelen	= 64,
	Bootargslen	= 3584-0x200-Bootlinelen,
};
#define Bootargs	((char*)(CONFADDR+Bootlinelen))

typedef struct Mblock Mblock;
struct Mblock {
	Mblock	*next;
	char	name[28];
	char	v[256];
};

static	Mblock	*blktab[Maxblocks];
static	Mblock	*conftab[Maxconf];
static	Mblock	*curblk;
static	int	nblock;
extern	char	**ini;

	void	parseini(char*);

static Mblock*
lookblock(char *s)
{
	int i;

	for(i = 0; i < nblock; i++)
		if(strcmp(s, blktab[i]->name) == 0)
			return blktab[i];
	return nil;
}

static Mblock*
newblock(char *s)
{
	char buf[28];
	int l;
	Mblock *b;

	if(nblock == Maxblocks)
		return nil;
	if(s[0] != '[' || (l = strlen(++s)) >= 28)
		return nil;
	if(s[--l] != ']' || l < 1)
		return nil;
	memmove(buf, s, l);
	buf[l] = 0;
	if(b = lookblock(buf))
		return curblk = b;
	b = blktab[nblock++] = malloc(sizeof *b);
	memmove(b->name, buf, l + 1);
	return curblk = b;
}

static Mblock*
common(void)
{
	return newblock("[common]");
}

static Mblock*
lookitem(char *s)
{
	Mblock *b;

	for(b = curblk; b; b = b->next)
		if(strcmp(b->name, s) == 0)
			return b;
	return nil;
}

static Mblock*
newitem0(Mblock *m)
{
	Mblock *b;

	for(b = curblk; b->next; b = b->next)
		;
	b->next = m;
	return m;
}

static Mblock*
newitem(char *s)
{
	char *p;
	int l;
	Mblock *m;

	p = strchr(s, '=');
	if(p == nil || (l = p - s) == 0 || l >= 28)
		return nil;
	if(s[l - 1] == ' ' && --l == 0)
		return nil;
	if(*++p && *p == ' ')
		p++;
	m = malloc(sizeof *m);
	memmove(m->name, s, l);
	m->name[l] = 0;
	snprint(m->v, sizeof m->v, "%s", p);
	return newitem0(m);
}

static int
varsep(int c)
{
	return strchr("!/= {}()", c) != nil;
}

static char *legacy[] = {
	"bootpath",
	"bootdev",
};

static int
legacyvar(char *p)
{
	int i;

	for(i = 0; i < nelem(legacy); i++)
		if(strcmp(p, legacy[i]) == 0)
			return 0;
	return -1;
}

static void
dovar(Mblock *b0, Mblock *b, char *p, char *e)
{
	char *p0, *q, buf[28], tok[80];
	int l, dol;
	Mblock *c, *m;

	while(*p){
		p0 = p;
		if(dol = *p == '$')
			p++;
		for(q = p; *q; q++)
			if(varsep(*q))
				break;
		l = snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
		if(0)
			print("dovar %s[%s] %s\n", dol? "$ ": "", buf, q);
		m = nil;
		if(q > p)
		if(dol || legacyvar(buf) == 0)
			for(c = b0; c != nil && c != b; c = c->next)
				if(cistrcmp(c->name, buf) == 0)
					m = c;
		if(m){
			snprint(tok, sizeof tok, "%s%s", m->v, q);
			seprint(p0, e, "%s", tok);
		}else{
			p += l;
			if(varsep(*p))
				p++;
		}
	}
}

static void
varsubst(Mblock *b0)
{
	Mblock *b;

	for(b = b0; b != nil; b = b->next)
		dovar(b0, b, b->v, b->v + sizeof b->v);
}

void
changeconf(char *name, int append, char *fmt, ...)
{
	char *p, *e, buf[128];
	int m;
	va_list arg;
	Mblock *b;

	va_start(arg, fmt);
	vseprint(buf, buf+sizeof buf, fmt, arg);
	va_end(arg);

	for(b = common(); b != nil; b = b->next){
		m = cistrcmp(name, b->name) == 0;
		if(!m && b->next == nil && !append){
			b->next = malloc(sizeof *b);
			memmove(b->next->name, name, strlen(name));
		}else if(m){
			if(!append)
				b->v[0] = 0;
			p = b->v;
			e = p + sizeof b->v;
			p += strlen(b->v);
			seprint(p, e, "%s", buf);
			dovar(common(), b,  p, e);
		}
	}
}

static Mblock**
buildvtab(Mblock *b0)
{
	int i;
	Mblock *b, **t;

	t = conftab;
	i = 0;
	for(b = b0; b != nil && i < Maxconf-1; b = b->next)
		t[i++] = b;
	t[i] = 0;
	return t;
}

char*
getconf(char *name)
{
	int i, n, nmatch;
	char *r, buf[128], itab[Maxconf];
	Mblock **t, *b;

redux:
	t = buildvtab(common());
	nmatch = 0;
	for(i = 0; t[i] != nil; i++)
		if(cistrcmp(name, t[i]->name) == 0)
			itab[nmatch++] = i;
	n = nmatch;
	if(n > 1){
		print("\n");
		for(i = 0; i < nmatch; i++)
			print("%d. %s\n", i + 1, t[itab[i]]->v);
		print("a. add an item\n");
		do{
			getstr(name, buf, sizeof buf, nil, 0);
			n = strtol(buf, &r, 0);
			if(buf[0] == 'a' && buf[1] == ' '){
				changeconf(" ", 0, buf + 2);
				if(b = lookitem(" "))
					snprint(b->name, sizeof b->name, "%s", name);
				goto redux;
			}
		}while(n < 1 || n > i);
	}
	r = nil;
	if(n != 0)
		r = t[itab[n-1]]->v;
	for(i = 0; i < nmatch; i++)
		if(i != n && i > 0)
			t[itab[i]-1]->next = t[itab[i]+1];
	return r;
}

static int
comma(char *s, char **f)
{
	char *r;
	int i, n;
	static char buf[128];

	f[0] = f[1] = "";
	snprint(buf, sizeof buf, "%s", s);
	n = getfields(buf, f, 2, ',');
	for(i = 0; i < n; i++){
		if(f[i][0] == ' ')
			f[i]++;
		r = f[i] + strlen(f[i]);
		if(r > f[i] && r[-1] == ' ')
			r[-1] = 0;
	}
	return n;
}

static char*
pritem(Mblock *b)
{
	static char buf[128];

	if(b->v[0] == 0)
		snprint(buf, sizeof buf, "[%s]", b->name);
	else
		snprint(buf, sizeof buf, "%s=%s", b->name, b->v);
	return buf;
}
	
static void
menu(void)
{
	char *r, *f[2], buf[80], buf1[10];
	int i, n, tmout, item, dfltno;
	Mblock *m, *b, *p, *dflt, *mtab[Maxblocks], *ptab[Maxblocks];

	if((b = lookblock("menu")) == nil)
		return;
	dflt = nil;
	tmout = 0;
	item = 0;
	for(p = b->next; p != nil; p = p->next){
		n = comma(p->v, f);
		m = lookblock(f[0]);
		if(cistrcmp(p->name, "menuitem") == 0){
			if(n != 2 || m == nil)
				print("invalid block %s\n", f[0]);
			else{
				ptab[item] = p;
				mtab[item++] = m;
			}
		}else if(cistrcmp(p->name, "menudefault") == 0){
			if(m == nil)
				print("invalid menudefault %s\n", f[0]);
			else{
				dflt = m;
				tmout = strtol(f[1], 0, 0);
			}
		}else if(cistrcmp(p->name, "menuconsole") == 0)
			consinit(f[0], f[1]);
		else
			print("invalid line in [menu] %s=%s\n", p->name, p->v);
	}
redux:
	print("\nPlan 9 Startup Menu:\n====================\n");
	dfltno = 0;
	for(i = 0; i < item; i++){
		comma(ptab[i]->v, f);
		print("    %d. %s\n", i + 1, f[1]);
		if(mtab[i] == dflt)
			dfltno = i + 1;
	}
	if(dfltno == 0 && dflt != nil){
		print("bad default [%s]\n", dflt->name);
		tmout = 0;
	}
	for(;;){
		snprint(buf1, sizeof buf1, "%d", dfltno);
		getstr("Selection", buf, sizeof buf, dfltno>0? buf1: nil, tmout);
		tmout = 0;
		i = strtoul(buf, &r, 0);
		if(*r == 'm' && r[1] == 0)
			goto redux;
		print("\n");
		if(*r == 'a' && r[1] == ' ')
			parseini(r + 2);
		else if(*r == 'p' || *r == 'P'){
			for(p = common(); p; p = p->next)
				print("%s\n", pritem(p));
			if(i > 0 && i < item)
				for(p = mtab[i-1]; p; p = p->next)
					print("%s\n", pritem(p));
		}else if(*r == 0 && i <= item){
			m = mtab[i-1];
			common();
			newitem0(m->next);	/* chain 'em up */
			if(b = lookblock("commontail"))
				newitem0(b->next);
			comma(ptab[i-1]->v, f);
			changeconf("menuitem", 0, "%s", f[0]);
			return;
		}
	}
}

void
buildconf(void)
{
	char *p, *e;
	Mblock *b;

	p = Bootargs;
	e = p + Bootargslen;
	for(b = common()->next; b; b = b->next)
		if(b->v[0])
			p = seprint(p, e, "%s=%s\n", b->name, b->v);
}

static char*
sanitize(char *s)
{
	char *p, *e, *tok[20];
	int m, j, b;
	static char buf[128];

	b = 1;
	for(p = s; *p; p++)
		if(*p == '\t' || *p == '\r')
			*p = ' ';
		else if(b && *p == '#')
			*p = 0;
		else
			b = 0;
	m = getfields(s, tok, nelem(tok), ' ');
	buf[0] = 0;
	if(m > 0){
		j = 0;
		e = buf + sizeof buf;
		for(p = buf;;){
			p = seprint(p, e, "%s", tok[j]);
			if(++j == m)
				break;
			p = seprint(p, e, " ");
		}
	}
	return buf;
}

void
parseini(char *s)
{
	char *p, *line[Maxconf];
	int n, i;

	common();
	n = getfields(s, line, nelem(line), '\n');
	for(i = 0; i < n; i++){
		p = sanitize(line[i]);
		if(*p == '[')
			newblock(p);
		else if(*p)
			newitem(p);
	}
}

int
dotini(Fs *fs, char *name, char *devstr)
{
	char *p;
	int n;
	File rc;

	if(fswalk(fs, *ini, &rc) <= 0)
		return -1;
	p = Bootargs;
	if((n = fsread(&rc, p, Bootargslen-2)) <= 0)
		return -1;
	p[n] = '\n';
	p[n+1] = 0;

//	common();
	changeconf("bootdev", 0, "%s", name);
	changeconf("bootpath", 0, "%s/$bootdev", devstr);
	parseini(p);
	menu();
	varsubst(common());
	return 0;
}

static char*
match(char *s, char *p)
{
	if(cistrncmp(s, p, strlen(p)) == 0)
		return s + strlen(p);
	return nil;
}

static char*
copyto(char *p, char *t, int nt, int term)
{
	char *e;

	e = t + nt;
	for(; *p != 0 && *p != term && t < e;)
		*t++ = *p++;
	*t = 0;
	return p;
}

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

	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
	if((p = getconf(cc)) == nil)
		return 0;
	for(;;){
		if(*p== ' ')
			p++;
		if(*p == 0)
			break;
		if(r = match(p, "type="))
			p = copyto(r, isa->type, sizeof isa->type, ' ');
		else if(r = match(p, "port="))
			isa->port = strtoul(r, &p, 0);
		else if(r = match(p, "irq="))
			isa->irq = strtoul(r, &p, 0);
		else if(r = match(p, "mem="))
			isa->mem = strtoul(r, &p, 0);
		else if(r = match(p, "size="))
			isa->size = strtoul(r, &p, 0);
		else if(r = match(p, "ea=")){
			if(parseether(isa->ea, r) == -1)
				memset(isa->ea, 0, 6);
		}else if(isa->nopt < NISAOPT)
			p = copyto(p, isa->opt[isa->nopt++], ISAOPTLEN, ' ');
		while(*p && *p != ' ')
			p++;
	}
	return 0;	
}

void
readlsconf(void)
{
	ushort *p;
	ulong *l;

	if(strcmp((char*)CONFADDR, "APM") == 0){
		p = (ushort*)CONFADDR;
		l = (ulong*)CONFADDR;
		apm.haveinfo = 1;
		apm.ax = p[2];
		apm.cx = p[3];
		apm.dx = p[4];
		apm.di = p[5];
		apm.ebx = l[3];
		apm.ebx = l[4];
		print("apm ax=%x cx=%x dx=%x di=%x ebx=%x esi=%x\n",
			apm.ax, apm.cx, apm.dx, apm.di, apm.ebx, apm.esi);
	}
	e820();	/* e820(CONFADDR + 20); */
}

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.