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
This commit is contained in:
Keegan Saunders 2024-01-07 19:57:50 +00:00
parent 23f34184d6
commit 1fe150f1ed
6 changed files with 266 additions and 120 deletions

249
sys/src/9/arm64/bootargs.c Normal file
View file

@ -0,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);
}

View file

@ -168,3 +168,6 @@ extern int pcicfgrw16(int tbdf, int rno, int data, int read);
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);

View file

@ -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 *)
{

View file

@ -67,13 +67,16 @@ void
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;
}

View file

@ -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,13 +32,15 @@
#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)
#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 */
@ -54,6 +56,8 @@
#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
#define KLIMIT (VDRAM - KZERO + KMAPEND - KMAP) /* 0x140000000 */
#define KSEG0 (0xFFFFFFFE00000000ULL)
/* temporary identity map for TTBR0 (using only top-level) */

View file

@ -51,6 +51,7 @@ OBJ=\
sysreg.$O\
random.$O\
trap.$O\
bootargs.$O\
$CONF.root.$O\
$CONF.rootc.$O\
$DEVS\