shithub: riscv

Download patch

ref: 4983adfa2cd403eda22d862917c2ff5ed35b48b3
parent: a6a1806c17c6dbb6c657ac676fc97fd6c5207da7
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Jul 25 04:19:12 EDT 2019

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.

--- a/sys/src/9/bcm/bootargs.c
+++ b/sys/src/9/bcm/bootargs.c
@@ -11,30 +11,8 @@
 static char *confname[MAXCONF];
 static char *confval[MAXCONF];
 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
 findconf(char *k)
 {
@@ -85,22 +63,150 @@
 	}
 }
 
-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 @@
 			*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*
--- a/sys/src/9/bcm/fns.h
+++ b/sys/src/9/bcm/fns.h
@@ -5,7 +5,7 @@
 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);
--- a/sys/src/9/bcm/main.c
+++ b/sys/src/9/bcm/main.c
@@ -85,7 +85,7 @@
 	memset(edata, 0, end - edata);	/* clear bss */
 	mach0init();
 	quotefmtinstall();
-	bootargsinit();
+	bootargsinit(0);
 	confinit();		/* figures out amount of memory */
 	xinit();
 	uartconsinit();
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -163,7 +163,7 @@
 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);
--- 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 @@
 	WFE
 	BL	mmuenable<>(SB)
 
+	MOV	R26, R0
 	MOV	$0, R26
 	ORR	$KZERO, R27
 	MSR	R27, TPIDR_EL1
@@ -70,11 +73,6 @@
 TEXT sev(SB), 1, $-4
 	SEV
 	WFE
-	RETURN
-
-TEXT PUTC(SB), 1, $-4
-	MOVWU $(0x3F000000+0x215040), R14
-	MOVB R0, (R14)
 	RETURN
 
 TEXT svcmode<>(SB), 1, $-4
--- a/sys/src/9/bcm64/main.c
+++ b/sys/src/9/bcm64/main.c
@@ -151,8 +151,8 @@
 
 	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;
@@ -159,6 +159,8 @@
 		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 @@
 	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 @@
 }
 
 void
-main(void)
+main(uintptr arg0)
 {
 	machinit();
 	if(m->machno){
@@ -278,7 +277,7 @@
 		return;
 	}
 	quotefmtinstall();
-	bootargsinit();
+	bootargsinit(arg0);
 	confinit();
 	xinit();
 	printinit();
@@ -313,7 +312,6 @@
 {
 	void (*f)(void*, void*, ulong);
 
-	intrsoff();
 	intrcpushutdown();
 
 	/* redo identity map */
@@ -322,6 +320,7 @@
 	/* setup reboot trampoline function */
 	f = (void*)REBOOTADDR;
 	memmove(f, rebootcode, sizeof(rebootcode));
+
 	cachedwbinvse(f, sizeof(rebootcode));
 	cacheiinvse(f, sizeof(rebootcode));
 
@@ -363,6 +362,7 @@
 	/* stop the clock (and watchdog if any) */
 	clockshutdown();
 	wdogoff();
+	intrsoff();
 
 	/* off we go - never to return */
 	rebootjump(entry, code, size);
--- a/sys/src/9/bcm64/rebootcode.s
+++ b/sys/src/9/bcm64/rebootcode.s
@@ -44,6 +44,11 @@
 
 	BL	cachedwbinv(SB)
 	BL	cacheiinv(SB)
+
+	MOVWU	$0, R0
+	MOVWU	$0, R1
+	MOVWU	$0, R2
+	MOVWU	$0, R3
 _wait:
 	WFE
 	MOV	(R27), LR