diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-07-25 08:19:12 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-07-25 08:19:12 +0200 |
commit | 4983adfa2cd403eda22d862917c2ff5ed35b48b3 (patch) | |
tree | b95d5270b5c77f47932ddb9c9ccdd7419fd5f186 /sys/src | |
parent | a6a1806c17c6dbb6c657ac676fc97fd6c5207da7 (diff) |
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.
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/bcm/bootargs.c | 196 | ||||
-rw-r--r-- | sys/src/9/bcm/fns.h | 2 | ||||
-rw-r--r-- | sys/src/9/bcm/main.c | 2 | ||||
-rw-r--r-- | sys/src/9/bcm64/fns.h | 2 | ||||
-rw-r--r-- | sys/src/9/bcm64/l.s | 8 | ||||
-rw-r--r-- | sys/src/9/bcm64/main.c | 30 | ||||
-rw-r--r-- | sys/src/9/bcm64/rebootcode.s | 5 |
7 files changed, 188 insertions, 57 deletions
diff --git a/sys/src/9/bcm/bootargs.c b/sys/src/9/bcm/bootargs.c index 830e9bc65..d2304af0f 100644 --- a/sys/src/9/bcm/bootargs.c +++ b/sys/src/9/bcm/bootargs.c @@ -11,29 +11,7 @@ static char *confname[MAXCONF]; static char *confval[MAXCONF]; static int nconf; - -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 char maxmem[11]; static int findconf(char *k) @@ -85,22 +63,150 @@ plan9iniinit(char *s, int cmdline) } } -void -bootargsinit(void) +typedef struct Devtree Devtree; +struct Devtree { - static char maxmem[11]; - char x, *e; - Atag *a; + uchar *base; + uchar *end; + char *stab; + char path[1024]; +}; - e = BOOTARGS; - a = (Atag*)e; - if(a->tag != AtagCore){ - plan9iniinit(e, 0); +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) +{ + 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; + } + 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){ 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; switch(a->tag){ case AtagMem: @@ -116,10 +222,32 @@ bootargsinit(void) *e = x; break; } - if(e > &BOOTARGS[BOOTARGSLEN-8]) + if(e+8 > base+len) break; 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* diff --git a/sys/src/9/bcm/fns.h b/sys/src/9/bcm/fns.h index 564201605..6e35a2401 100644 --- a/sys/src/9/bcm/fns.h +++ b/sys/src/9/bcm/fns.h @@ -5,7 +5,7 @@ Dirtab* addarchfile(char*, int, long(*)(Chan*, void*, long, vlong), extern void archreboot(void); extern void archreset(void); extern void armtimerset(int); -extern void bootargsinit(void); +extern void bootargsinit(uintptr); extern void cachedwbinv(void); extern void cachedwbse(void*, int); extern void cachedwbinvse(void*, int); diff --git a/sys/src/9/bcm/main.c b/sys/src/9/bcm/main.c index 3cc30034f..4099d67f2 100644 --- a/sys/src/9/bcm/main.c +++ b/sys/src/9/bcm/main.c @@ -85,7 +85,7 @@ main(void) memset(edata, 0, end - edata); /* clear bss */ mach0init(); quotefmtinstall(); - bootargsinit(); + bootargsinit(0); confinit(); /* figures out amount of memory */ xinit(); uartconsinit(); diff --git a/sys/src/9/bcm64/fns.h b/sys/src/9/bcm64/fns.h index 25345043a..280e74821 100644 --- a/sys/src/9/bcm64/fns.h +++ b/sys/src/9/bcm64/fns.h @@ -163,7 +163,7 @@ extern void vgpinit(void); extern void vgpset(uint port, int on); /* bootargs */ -extern void bootargsinit(void); +extern void bootargsinit(uintptr); extern char *getconf(char *name); extern void setconfenv(void); extern void writeconf(void); diff --git a/sys/src/9/bcm64/l.s b/sys/src/9/bcm64/l.s index 9a776a4b9..2e7e9ebc1 100644 --- a/sys/src/9/bcm64/l.s +++ b/sys/src/9/bcm64/l.s @@ -5,6 +5,8 @@ #define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5)) TEXT _start(SB), 1, $-4 + MOV R0, R26 /* save */ + MOV $setSB-KZERO(SB), R28 BL svcmode<>(SB) @@ -55,6 +57,7 @@ _startup: WFE BL mmuenable<>(SB) + MOV R26, R0 MOV $0, R26 ORR $KZERO, R27 MSR R27, TPIDR_EL1 @@ -72,11 +75,6 @@ TEXT sev(SB), 1, $-4 WFE RETURN -TEXT PUTC(SB), 1, $-4 - MOVWU $(0x3F000000+0x215040), R14 - MOVB R0, (R14) - RETURN - TEXT svcmode<>(SB), 1, $-4 MSR $0xF, DAIFSet MRS CurrentEL, R0 diff --git a/sys/src/9/bcm64/main.c b/sys/src/9/bcm64/main.c index eab88466b..cb553f397 100644 --- a/sys/src/9/bcm64/main.c +++ b/sys/src/9/bcm64/main.c @@ -151,14 +151,16 @@ confinit(void) if(p = getconf("*maxmem")) memsize = strtoul(p, 0, 0) - PHYSDRAM; - if (memsize < 16*MB) /* sanity */ - memsize = 16*MB; + if (memsize < 512*MB) /* sanity */ + memsize = 512*MB; getramsize(&conf.mem[0]); if(conf.mem[0].limit == 0){ conf.mem[0].base = PHYSDRAM; conf.mem[0].limit = PHYSDRAM + memsize; }else if(p != nil) 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; pa = PADDR(PGROUND((uintptr)end)); @@ -239,21 +241,18 @@ mpinit(void) extern void _start(void); int i; - for(i = 0; i < MAXMACH; i++) - ((uintptr*)SPINTABLE)[i] = 0; - - for(i = 1; i < conf.nmach; i++) + for(i = 1; i < conf.nmach; i++){ MACHP(i)->machno = i; - - coherence(); - - for(i = 1; i < conf.nmach; i++) - ((uintptr*)SPINTABLE)[i] = PADDR(_start); - + cachedwbinvse(MACHP(i), MACHSIZE); + } + for(i = 0; i < MAXMACH; i++) + ((uintptr*)SPINTABLE)[i] = i < conf.nmach ? PADDR(_start) : 0; cachedwbinvse((void*)SPINTABLE, MAXMACH*8); + sev(); delay(100); sev(); + synccycles(); for(i = 0; i < MAXMACH; i++) @@ -261,7 +260,7 @@ mpinit(void) } void -main(void) +main(uintptr arg0) { machinit(); if(m->machno){ @@ -278,7 +277,7 @@ main(void) return; } quotefmtinstall(); - bootargsinit(); + bootargsinit(arg0); confinit(); xinit(); printinit(); @@ -313,7 +312,6 @@ rebootjump(void *entry, void *code, ulong size) { void (*f)(void*, void*, ulong); - intrsoff(); intrcpushutdown(); /* redo identity map */ @@ -322,6 +320,7 @@ rebootjump(void *entry, void *code, ulong size) /* setup reboot trampoline function */ f = (void*)REBOOTADDR; memmove(f, rebootcode, sizeof(rebootcode)); + cachedwbinvse(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) */ clockshutdown(); wdogoff(); + intrsoff(); /* off we go - never to return */ rebootjump(entry, code, size); diff --git a/sys/src/9/bcm64/rebootcode.s b/sys/src/9/bcm64/rebootcode.s index b3eb307ac..8b4986473 100644 --- a/sys/src/9/bcm64/rebootcode.s +++ b/sys/src/9/bcm64/rebootcode.s @@ -44,6 +44,11 @@ _mmuoff: BL cachedwbinv(SB) BL cacheiinv(SB) + + MOVWU $0, R0 + MOVWU $0, R1 + MOVWU $0, R2 + MOVWU $0, R3 _wait: WFE MOV (R27), LR |