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\