code: plan9front

Download patch

ref: 1fe150f1ed46a8c1a65187b3088274e067493639
parent: 23f34184d60b393579a4de20f03da7befc6ceafc
author: Keegan Saunders <keegan@undefinedbehaviour.org>
date: Sun Jan 7 14:57:50 EST 2024

arm64/qemu: detect VM configuration

Now, *maxmem and *ncpu are not required to be provided.
They will be detected automatically from the QEMU device
tree. Further, >4GB memory configurations are also supported.
The maximum number of CPUs is 16 for now, and the maximum
supported memory is 16GB

--- /dev/null
+++ b/sys/src/9/arm64/bootargs.c
@@ -1,0 +1,249 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+
+#define	MAXCONF 64
+static char *confname[MAXCONF];
+static char *confval[MAXCONF];
+static int nconf;
+static char maxmem[256];
+static int cpus;
+static char ncpu[256];
+
+static int
+findconf(char *k)
+{
+	int i;
+
+	for(i = 0; i < nconf; i++)
+		if(cistrcmp(confname[i], k) == 0)
+			return i;
+	return -1;
+}
+
+static void
+addconf(char *k, char *v)
+{
+	int i;
+
+	i = findconf(k);
+	if(i < 0){
+		if(nconf >= MAXCONF)
+			return;
+		i = nconf++;
+		confname[i] = k;
+	}
+	confval[i] = v;
+}
+
+static void
+plan9iniinit(char *s, int cmdline)
+{
+	char *toks[MAXCONF];
+	int i, c, n;
+	char *v;
+
+	if((c = *s) < ' ' || c >= 0x80)
+		return;
+	if(cmdline)
+		n = tokenize(s, toks, MAXCONF);
+	else
+		n = getfields(s, toks, MAXCONF, 1, "\n");
+	for(i = 0; i < n; i++){
+		if(toks[i][0] == '#')
+			continue;
+		v = strchr(toks[i], '=');
+		if(v == nil)
+			continue;
+		*v++ = '\0';
+		addconf(toks[i], v);
+	}
+}
+
+typedef struct Devtree Devtree;
+struct Devtree
+{
+	uchar	*base;
+	uchar	*end;
+	char	*stab;
+	char	path[1024];
+};
+
+enum {
+	DtHeader	= 0xd00dfeed,
+	DtBeginNode	= 1,
+	DtEndNode	= 2,
+	DtProp		= 3,
+	DtEnd		= 9,
+};
+
+static u32int
+beget4(uchar *p)
+{
+	return (u32int)p[0]<<24 | (u32int)p[1]<<16 | (u32int)p[2]<<8 | (u32int)p[3];
+}
+
+static void
+devtreeprop(char *path, char *key, void *val, int len)
+{
+	uvlong addr;
+	uchar *p = val;
+
+	if((strncmp(path, "/memory", 7) == 0 || strncmp(path, "/memory@0", 9) == 0)
+	&& strcmp(key, "reg") == 0){
+		if(findconf("*maxmem") < 0 && len == 16){
+			p += 4;	/* ignore */
+			addr = (uvlong)beget4(p+4)<<32 | beget4(p);
+			addr += beget4(p+8);
+			snprint(maxmem, sizeof(maxmem), "%#llux", addr);
+			addconf("*maxmem", maxmem);
+		}
+		return;
+	}
+	if(strncmp(path, "/cpus/cpu", 9) == 0 && strcmp(key, "reg") == 0){
+		cpus++;
+		return;
+	}
+	if(strncmp(path, "/chosen", 7) == 0 && strcmp(key, "bootargs") == 0){
+		if(len > BOOTARGSLEN)
+			len = BOOTARGSLEN;
+		memmove(BOOTARGS, val, len);
+		plan9iniinit(BOOTARGS, 1);
+		return;
+	}
+}
+
+static uchar*
+devtreenode(Devtree *t, uchar *p, char *cp)
+{
+	uchar *e = (uchar*)t->stab;
+	char *s;
+	int n;
+
+	if(p+4 > e || beget4(p) != DtBeginNode)
+		return nil;
+	p += 4;
+	if((s = memchr((char*)p, 0, e - p)) == nil)
+		return nil;
+	n = s - (char*)p;
+	cp += n;
+	if(cp >= &t->path[sizeof(t->path)])
+		return nil;
+	memmove(cp - n, (char*)p, n);
+	*cp = 0;
+	p += (n + 4) & ~3;
+	while(p+12 <= e && beget4(p) == DtProp){
+		n = beget4(p+4);
+		if(p + 12 + n > e)
+			return nil;
+		s = t->stab + beget4(p+8);
+		if(s < t->stab || s >= (char*)t->end
+		|| memchr(s, 0, (char*)t->end - s) == nil)
+			return nil;
+		devtreeprop(t->path, s, p+12, n);
+		p += 12 + ((n + 3) & ~3);
+	}
+	while(p+4 <= e && beget4(p) == DtBeginNode){
+		*cp = '/';
+		p = devtreenode(t, p, cp+1);
+		if(p == nil)
+			return nil;
+	}
+	if(p+4 > e || beget4(p) != DtEndNode)
+		return nil;
+	return p+4;
+}
+
+static int
+parsedevtree(uchar *base, uintptr len)
+{
+	Devtree t[1];
+	u32int total;
+
+	if(len < 28 || beget4(base) != DtHeader)
+		return -1;
+	total = beget4(base+4);
+	if(total < 28 || total > len)
+		return -1;
+	t->base = base;
+	t->end = t->base + total;
+	t->stab = (char*)base + beget4(base+12);
+	if(t->stab >= (char*)t->end)
+		return -1;
+	devtreenode(t, base + beget4(base+8), t->path);
+	return  0;
+}
+
+void
+bootargsinit(void)
+{
+	void *va = KADDR(DTBADDR);
+	uintptr len = cankaddr(DTBADDR);
+
+	plan9iniinit(BOOTARGS, 0);
+	if(parsedevtree(va, len) == 0){
+		/* user can provide fewer ncpu */
+		if(findconf("*ncpu") < 0){
+			snprint(ncpu, sizeof(ncpu), "%d", cpus);
+			addconf("*ncpu", ncpu);
+		}
+	}
+}
+
+char*
+getconf(char *name)
+{
+	int i;
+
+	if((i = findconf(name)) < 0)
+		return nil;
+	return confval[i];
+}
+
+void
+setconfenv(void)
+{
+	int i;
+
+	if(nconf < 0){
+		/* use defaults when there was no configuration */
+		ksetenv("console", "0", 1);
+		return;
+	}
+
+	for(i = 0; i < nconf; i++){
+		if(confname[i][0] != '*')
+			ksetenv(confname[i], confval[i], 0);
+		ksetenv(confname[i], confval[i], 1);
+	}
+}
+
+void
+writeconf(void)
+{
+	char *p, *q;
+	int n;
+
+	p = getconfenv();
+	if(waserror()) {
+		free(p);
+		nexterror();
+	}
+
+	/* convert to name=value\n format */
+	for(q=p; *q; q++) {
+		q += strlen(q);
+		*q = '=';
+		q += strlen(q);
+		*q = '\n';
+	}
+	n = q - p + 1;
+	if(n >= BOOTARGSLEN)
+		error("kernel configuration too large");
+	memmove(BOOTARGS, p, n);
+	memset(BOOTARGS+n, 0, BOOTARGSLEN-n);
+	poperror();
+	free(p);
+}
--- a/sys/src/9/arm64/fns.h
+++ b/sys/src/9/arm64/fns.h
@@ -168,3 +168,6 @@
 extern int pcicfgrw32(int tbdf, int rno, int data, int read);
 extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
 extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
+
+/* bootargs */
+extern void bootargsinit(void);
--- a/sys/src/9/arm64/main.c
+++ b/sys/src/9/arm64/main.c
@@ -14,120 +14,6 @@
 
 Conf conf;
 
-#define	MAXCONF 64
-static char *confname[MAXCONF];
-static char *confval[MAXCONF];
-static int nconf = -1;
-
-void
-bootargsinit(void)
-{
-	int i, j, n;
-	char *cp, *line[MAXCONF], *p, *q;
-
-	/*
-	 *  parse configuration args from dos file plan9.ini
-	 */
-	cp = BOOTARGS;
-	cp[BOOTARGSLEN-1] = 0;
-
-	/*
-	 * Strip out '\r', change '\t' -> ' '.
-	 */
-	p = cp;
-	for(q = cp; *q; q++){
-		if(*q == -1)
-			break;
-		if(*q == '\r')
-			continue;
-		if(*q == '\t')
-			*q = ' ';
-		*p++ = *q;
-	}
-	*p = 0;
-
-	n = getfields(cp, line, MAXCONF, 1, "\n");
-	if(n <= 0){
-		/* empty plan9.ini, no configuration passed */
-		return;
-	}
-
-	nconf = 0;
-	for(i = 0; i < n; i++){
-		if(*line[i] == '#')
-			continue;
-		cp = strchr(line[i], '=');
-		if(cp == nil)
-			continue;
-		*cp++ = '\0';
-		for(j = 0; j < nconf; j++){
-			if(cistrcmp(confname[j], line[i]) == 0)
-				break;
-		}
-		confname[j] = line[i];
-		confval[j] = cp;
-		if(j == nconf)
-			nconf++;
-	}
-}
-
-char*
-getconf(char *name)
-{
-	int i;
-
-	for(i = 0; i < nconf; i++)
-		if(cistrcmp(confname[i], name) == 0)
-			return confval[i];
-	return nil;
-}
-
-void
-setconfenv(void)
-{
-	int i;
-
-	if(nconf < 0){
-		/* use defaults when there was no configuration */
-		ksetenv("console", "0", 1);
-		return;
-	}
-
-	for(i = 0; i < nconf; i++){
-		if(confname[i][0] != '*')
-			ksetenv(confname[i], confval[i], 0);
-		ksetenv(confname[i], confval[i], 1);
-	}
-}
-
-void
-writeconf(void)
-{
-	char *p, *q;
-	int n;
-
-	p = getconfenv();
-	if(waserror()) {
-		free(p);
-		nexterror();
-	}
-
-	/* convert to name=value\n format */
-	for(q=p; *q; q++) {
-		q += strlen(q);
-		*q = '=';
-		q += strlen(q);
-		*q = '\n';
-	}
-	n = q - p + 1;
-	if(n >= BOOTARGSLEN)
-		error("kernel configuration too large");
-	memmove(BOOTARGS, p, n);
-	memset(BOOTARGS+n, 0, BOOTARGSLEN-n);
-	poperror();
-	free(p);
-}
-
 int
 isaconfig(char *, int, ISAConf *)
 {
--- a/sys/src/9/arm64/mem.c
+++ b/sys/src/9/arm64/mem.c
@@ -67,13 +67,16 @@
 meminit(void)
 {
 	char *p;
+	uintptr l = GiB + 128 * MiB;
 
-	conf.mem[0].base = PGROUND((uintptr)end - KZERO);
-	conf.mem[0].limit = GiB + 128 * MiB;
 	if(p = getconf("*maxmem"))
-		conf.mem[0].limit = strtoull(p, 0, 0);
+		l = strtoull(p, 0, 0);
+	conf.mem[0].base = PGROUND((uintptr)end - KZERO);
+	conf.mem[0].limit = l;
 
-	kmapram(conf.mem[0].base, conf.mem[0].limit);
+	if(l > KLIMIT)
+		l = KLIMIT;
+	kmapram(conf.mem[0].base, l);
 
 	conf.mem[0].npage = (conf.mem[0].limit - conf.mem[0].base)/BY2PG;
 }
--- a/sys/src/9/arm64/mem.h
+++ b/sys/src/9/arm64/mem.h
@@ -18,7 +18,7 @@
 #define	PGROUND(s)	ROUND(s, BY2PG)
 
 /* effective virtual address space */
-#define EVASHIFT	34
+#define EVASHIFT	36
 #define EVAMASK		((1ULL<<EVASHIFT)-1)
 
 #define PTSHIFT		(PGSHIFT-3)
@@ -32,7 +32,7 @@
 #define L1TABLE(v, l)	(L1TABLES - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
 #define L1TOPSIZE	(1ULL << (EVASHIFT - PTLEVELS*PTSHIFT))
 
-#define	MAXMACH		24			/* max # cpus system can run */
+#define	MAXMACH		16			/* max # cpus system can run */
 #define	MACHSIZE	(8*KiB)
 
 #define KSTACK		(8*KiB)
@@ -39,6 +39,8 @@
 #define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
 #define TRAPFRAMESIZE	(38*8)
 
+#define DTBADDR		0x40000000
+
 #define VDRAM		(0xFFFFFFFFC0000000ULL)	/* 0x40000000 - 0x80000000 */
 #define	KTZERO		(VDRAM + 0x100000)	/* 0x40100000 - kernel text start */
 
@@ -53,6 +55,8 @@
 
 #define KMAPEND		(0xFFFFFFFF00000000ULL)	/* 0x140000000 */
 #define KMAP		(0xFFFFFFFE00000000ULL)	/*  0x40000000 */
+
+#define KLIMIT		(VDRAM - KZERO + KMAPEND - KMAP)	/* 0x140000000 */
 
 #define KSEG0		(0xFFFFFFFE00000000ULL)
 
--- a/sys/src/9/arm64/mkfile
+++ b/sys/src/9/arm64/mkfile
@@ -51,6 +51,7 @@
 	sysreg.$O\
 	random.$O\
 	trap.$O\
+	bootargs.$O\
 	$CONF.root.$O\
 	$CONF.rootc.$O\
 	$DEVS\