bcm, bcm64: add support for device tree parameter passing
the new raspberry pi 4 firmware for arm64 seems to have broken atag support. so we now parse the device tree structure to get the bootargs and memory configuration.
This commit is contained in:
parent
a6a1806c17
commit
4983adfa2c
7 changed files with 188 additions and 57 deletions
|
@ -11,29 +11,7 @@
|
||||||
static char *confname[MAXCONF];
|
static char *confname[MAXCONF];
|
||||||
static char *confval[MAXCONF];
|
static char *confval[MAXCONF];
|
||||||
static int nconf;
|
static int nconf;
|
||||||
|
static char maxmem[11];
|
||||||
typedef struct Atag Atag;
|
|
||||||
struct Atag {
|
|
||||||
u32int size; /* size of atag in words, including this header */
|
|
||||||
u32int tag; /* atag type */
|
|
||||||
union {
|
|
||||||
u32int data[1]; /* actually [size-2] */
|
|
||||||
/* AtagMem */
|
|
||||||
struct {
|
|
||||||
u32int size;
|
|
||||||
u32int base;
|
|
||||||
} mem;
|
|
||||||
/* AtagCmdLine */
|
|
||||||
char cmdline[1]; /* actually [4*(size-2)] */
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
AtagNone = 0x00000000,
|
|
||||||
AtagCore = 0x54410001,
|
|
||||||
AtagMem = 0x54410002,
|
|
||||||
AtagCmdline = 0x54410009,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
findconf(char *k)
|
findconf(char *k)
|
||||||
|
@ -85,22 +63,150 @@ plan9iniinit(char *s, int cmdline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
typedef struct Devtree Devtree;
|
||||||
bootargsinit(void)
|
struct Devtree
|
||||||
{
|
{
|
||||||
static char maxmem[11];
|
uchar *base;
|
||||||
char x, *e;
|
uchar *end;
|
||||||
Atag *a;
|
char *stab;
|
||||||
|
char path[1024];
|
||||||
|
};
|
||||||
|
|
||||||
e = BOOTARGS;
|
enum {
|
||||||
a = (Atag*)e;
|
DtHeader = 0xd00dfeed,
|
||||||
if(a->tag != AtagCore){
|
DtBeginNode = 1,
|
||||||
plan9iniinit(e, 0);
|
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)
|
||||||
|
{
|
||||||
|
if(strcmp(path, "/memory") == 0 && strcmp(key, "reg") == 0 && len == 3*4){
|
||||||
|
if(findconf("*maxmem") < 0){
|
||||||
|
uvlong top;
|
||||||
|
|
||||||
|
top = (uvlong)beget4((uchar*)val)<<32 | beget4((uchar*)val+4);
|
||||||
|
top += beget4((uchar*)val+8);
|
||||||
|
snprint(maxmem, sizeof(maxmem), "%#llux", top);
|
||||||
|
addconf("*maxmem", maxmem);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(strcmp(path, "/chosen") == 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Atag Atag;
|
||||||
|
struct Atag {
|
||||||
|
u32int size; /* size of atag in words, including this header */
|
||||||
|
u32int tag; /* atag type */
|
||||||
|
union {
|
||||||
|
u32int data[1]; /* actually [size-2] */
|
||||||
|
/* AtagMem */
|
||||||
|
struct {
|
||||||
|
u32int size;
|
||||||
|
u32int base;
|
||||||
|
} mem;
|
||||||
|
/* AtagCmdLine */
|
||||||
|
char cmdline[1]; /* actually [4*(size-2)] */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AtagNone = 0x00000000,
|
||||||
|
AtagCore = 0x54410001,
|
||||||
|
AtagMem = 0x54410002,
|
||||||
|
AtagCmdline = 0x54410009,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
parseatags(char *base, uintptr len)
|
||||||
|
{
|
||||||
|
char x, *e = base;
|
||||||
|
Atag *a;
|
||||||
|
|
||||||
|
if(e+8 > base+len)
|
||||||
|
return -1;
|
||||||
|
a = (Atag*)e;
|
||||||
|
if(a->tag != AtagCore)
|
||||||
|
return -1;
|
||||||
while(a->tag != AtagNone){
|
while(a->tag != AtagNone){
|
||||||
e += a->size * sizeof(u32int);
|
e += a->size * sizeof(u32int);
|
||||||
if(a->size < 2 || e < (char*)a || e > &BOOTARGS[BOOTARGSLEN])
|
if(a->size < 2 || e < (char*)a || e > base+len)
|
||||||
break;
|
break;
|
||||||
switch(a->tag){
|
switch(a->tag){
|
||||||
case AtagMem:
|
case AtagMem:
|
||||||
|
@ -116,10 +222,32 @@ bootargsinit(void)
|
||||||
*e = x;
|
*e = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(e > &BOOTARGS[BOOTARGSLEN-8])
|
if(e+8 > base+len)
|
||||||
break;
|
break;
|
||||||
a = (Atag*)e;
|
a = (Atag*)e;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bootargsinit(uintptr pa)
|
||||||
|
{
|
||||||
|
uintptr len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kernel gets DTB/ATAGS pointer in R0 on entry
|
||||||
|
*/
|
||||||
|
if(pa != 0 && (len = cankaddr(pa)) != 0){
|
||||||
|
void *va = KADDR(pa);
|
||||||
|
if(parseatags(va, len) == 0 || parsedevtree(va, len) == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* /dev/reboot case, check CONFADDR
|
||||||
|
*/
|
||||||
|
if(parseatags(BOOTARGS, BOOTARGSLEN) != 0)
|
||||||
|
plan9iniinit(BOOTARGS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char*
|
||||||
|
|
|
@ -5,7 +5,7 @@ Dirtab* addarchfile(char*, int, long(*)(Chan*, void*, long, vlong),
|
||||||
extern void archreboot(void);
|
extern void archreboot(void);
|
||||||
extern void archreset(void);
|
extern void archreset(void);
|
||||||
extern void armtimerset(int);
|
extern void armtimerset(int);
|
||||||
extern void bootargsinit(void);
|
extern void bootargsinit(uintptr);
|
||||||
extern void cachedwbinv(void);
|
extern void cachedwbinv(void);
|
||||||
extern void cachedwbse(void*, int);
|
extern void cachedwbse(void*, int);
|
||||||
extern void cachedwbinvse(void*, int);
|
extern void cachedwbinvse(void*, int);
|
||||||
|
|
|
@ -85,7 +85,7 @@ main(void)
|
||||||
memset(edata, 0, end - edata); /* clear bss */
|
memset(edata, 0, end - edata); /* clear bss */
|
||||||
mach0init();
|
mach0init();
|
||||||
quotefmtinstall();
|
quotefmtinstall();
|
||||||
bootargsinit();
|
bootargsinit(0);
|
||||||
confinit(); /* figures out amount of memory */
|
confinit(); /* figures out amount of memory */
|
||||||
xinit();
|
xinit();
|
||||||
uartconsinit();
|
uartconsinit();
|
||||||
|
|
|
@ -163,7 +163,7 @@ extern void vgpinit(void);
|
||||||
extern void vgpset(uint port, int on);
|
extern void vgpset(uint port, int on);
|
||||||
|
|
||||||
/* bootargs */
|
/* bootargs */
|
||||||
extern void bootargsinit(void);
|
extern void bootargsinit(uintptr);
|
||||||
extern char *getconf(char *name);
|
extern char *getconf(char *name);
|
||||||
extern void setconfenv(void);
|
extern void setconfenv(void);
|
||||||
extern void writeconf(void);
|
extern void writeconf(void);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
|
#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
|
||||||
|
|
||||||
TEXT _start(SB), 1, $-4
|
TEXT _start(SB), 1, $-4
|
||||||
|
MOV R0, R26 /* save */
|
||||||
|
|
||||||
MOV $setSB-KZERO(SB), R28
|
MOV $setSB-KZERO(SB), R28
|
||||||
BL svcmode<>(SB)
|
BL svcmode<>(SB)
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ _startup:
|
||||||
WFE
|
WFE
|
||||||
BL mmuenable<>(SB)
|
BL mmuenable<>(SB)
|
||||||
|
|
||||||
|
MOV R26, R0
|
||||||
MOV $0, R26
|
MOV $0, R26
|
||||||
ORR $KZERO, R27
|
ORR $KZERO, R27
|
||||||
MSR R27, TPIDR_EL1
|
MSR R27, TPIDR_EL1
|
||||||
|
@ -72,11 +75,6 @@ TEXT sev(SB), 1, $-4
|
||||||
WFE
|
WFE
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
TEXT PUTC(SB), 1, $-4
|
|
||||||
MOVWU $(0x3F000000+0x215040), R14
|
|
||||||
MOVB R0, (R14)
|
|
||||||
RETURN
|
|
||||||
|
|
||||||
TEXT svcmode<>(SB), 1, $-4
|
TEXT svcmode<>(SB), 1, $-4
|
||||||
MSR $0xF, DAIFSet
|
MSR $0xF, DAIFSet
|
||||||
MRS CurrentEL, R0
|
MRS CurrentEL, R0
|
||||||
|
|
|
@ -151,14 +151,16 @@ confinit(void)
|
||||||
|
|
||||||
if(p = getconf("*maxmem"))
|
if(p = getconf("*maxmem"))
|
||||||
memsize = strtoul(p, 0, 0) - PHYSDRAM;
|
memsize = strtoul(p, 0, 0) - PHYSDRAM;
|
||||||
if (memsize < 16*MB) /* sanity */
|
if (memsize < 512*MB) /* sanity */
|
||||||
memsize = 16*MB;
|
memsize = 512*MB;
|
||||||
getramsize(&conf.mem[0]);
|
getramsize(&conf.mem[0]);
|
||||||
if(conf.mem[0].limit == 0){
|
if(conf.mem[0].limit == 0){
|
||||||
conf.mem[0].base = PHYSDRAM;
|
conf.mem[0].base = PHYSDRAM;
|
||||||
conf.mem[0].limit = PHYSDRAM + memsize;
|
conf.mem[0].limit = PHYSDRAM + memsize;
|
||||||
}else if(p != nil)
|
}else if(p != nil)
|
||||||
conf.mem[0].limit = conf.mem[0].base + memsize;
|
conf.mem[0].limit = conf.mem[0].base + memsize;
|
||||||
|
if (conf.mem[0].limit > PHYSDRAM + soc.dramsize)
|
||||||
|
conf.mem[0].limit = PHYSDRAM + soc.dramsize;
|
||||||
|
|
||||||
conf.npage = 0;
|
conf.npage = 0;
|
||||||
pa = PADDR(PGROUND((uintptr)end));
|
pa = PADDR(PGROUND((uintptr)end));
|
||||||
|
@ -239,21 +241,18 @@ mpinit(void)
|
||||||
extern void _start(void);
|
extern void _start(void);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < MAXMACH; i++)
|
for(i = 1; i < conf.nmach; i++){
|
||||||
((uintptr*)SPINTABLE)[i] = 0;
|
|
||||||
|
|
||||||
for(i = 1; i < conf.nmach; i++)
|
|
||||||
MACHP(i)->machno = i;
|
MACHP(i)->machno = i;
|
||||||
|
cachedwbinvse(MACHP(i), MACHSIZE);
|
||||||
coherence();
|
}
|
||||||
|
for(i = 0; i < MAXMACH; i++)
|
||||||
for(i = 1; i < conf.nmach; i++)
|
((uintptr*)SPINTABLE)[i] = i < conf.nmach ? PADDR(_start) : 0;
|
||||||
((uintptr*)SPINTABLE)[i] = PADDR(_start);
|
|
||||||
|
|
||||||
cachedwbinvse((void*)SPINTABLE, MAXMACH*8);
|
cachedwbinvse((void*)SPINTABLE, MAXMACH*8);
|
||||||
|
|
||||||
sev();
|
sev();
|
||||||
delay(100);
|
delay(100);
|
||||||
sev();
|
sev();
|
||||||
|
|
||||||
synccycles();
|
synccycles();
|
||||||
|
|
||||||
for(i = 0; i < MAXMACH; i++)
|
for(i = 0; i < MAXMACH; i++)
|
||||||
|
@ -261,7 +260,7 @@ mpinit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
main(void)
|
main(uintptr arg0)
|
||||||
{
|
{
|
||||||
machinit();
|
machinit();
|
||||||
if(m->machno){
|
if(m->machno){
|
||||||
|
@ -278,7 +277,7 @@ main(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
quotefmtinstall();
|
quotefmtinstall();
|
||||||
bootargsinit();
|
bootargsinit(arg0);
|
||||||
confinit();
|
confinit();
|
||||||
xinit();
|
xinit();
|
||||||
printinit();
|
printinit();
|
||||||
|
@ -313,7 +312,6 @@ rebootjump(void *entry, void *code, ulong size)
|
||||||
{
|
{
|
||||||
void (*f)(void*, void*, ulong);
|
void (*f)(void*, void*, ulong);
|
||||||
|
|
||||||
intrsoff();
|
|
||||||
intrcpushutdown();
|
intrcpushutdown();
|
||||||
|
|
||||||
/* redo identity map */
|
/* redo identity map */
|
||||||
|
@ -322,6 +320,7 @@ rebootjump(void *entry, void *code, ulong size)
|
||||||
/* setup reboot trampoline function */
|
/* setup reboot trampoline function */
|
||||||
f = (void*)REBOOTADDR;
|
f = (void*)REBOOTADDR;
|
||||||
memmove(f, rebootcode, sizeof(rebootcode));
|
memmove(f, rebootcode, sizeof(rebootcode));
|
||||||
|
|
||||||
cachedwbinvse(f, sizeof(rebootcode));
|
cachedwbinvse(f, sizeof(rebootcode));
|
||||||
cacheiinvse(f, sizeof(rebootcode));
|
cacheiinvse(f, sizeof(rebootcode));
|
||||||
|
|
||||||
|
@ -363,6 +362,7 @@ reboot(void *entry, void *code, ulong size)
|
||||||
/* stop the clock (and watchdog if any) */
|
/* stop the clock (and watchdog if any) */
|
||||||
clockshutdown();
|
clockshutdown();
|
||||||
wdogoff();
|
wdogoff();
|
||||||
|
intrsoff();
|
||||||
|
|
||||||
/* off we go - never to return */
|
/* off we go - never to return */
|
||||||
rebootjump(entry, code, size);
|
rebootjump(entry, code, size);
|
||||||
|
|
|
@ -44,6 +44,11 @@ _mmuoff:
|
||||||
|
|
||||||
BL cachedwbinv(SB)
|
BL cachedwbinv(SB)
|
||||||
BL cacheiinv(SB)
|
BL cacheiinv(SB)
|
||||||
|
|
||||||
|
MOVWU $0, R0
|
||||||
|
MOVWU $0, R1
|
||||||
|
MOVWU $0, R2
|
||||||
|
MOVWU $0, R3
|
||||||
_wait:
|
_wait:
|
||||||
WFE
|
WFE
|
||||||
MOV (R27), LR
|
MOV (R27), LR
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue