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:
cinap_lenrek 2019-07-25 08:19:12 +02:00
parent a6a1806c17
commit 4983adfa2c
7 changed files with 188 additions and 57 deletions

View file

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

View file

@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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