mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
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:
parent
23f34184d6
commit
1fe150f1ed
6 changed files with 266 additions and 120 deletions
249
sys/src/9/arm64/bootargs.c
Normal file
249
sys/src/9/arm64/bootargs.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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 *)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -51,6 +51,7 @@ OBJ=\
|
|||
sysreg.$O\
|
||||
random.$O\
|
||||
trap.$O\
|
||||
bootargs.$O\
|
||||
$CONF.root.$O\
|
||||
$CONF.rootc.$O\
|
||||
$DEVS\
|
||||
|
|
Loading…
Reference in a new issue