changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: bcm: fix /dev/reboot text/data corruption (thanks richard miller)

changeset 6855: 01468da33a6e
parent 6854: ede4bb3c885e
child 6856: 0df717a3b0a1
author: cinap_lenrek@felloff.net
date: Wed, 31 Oct 2018 19:48:16 +0100
files: sys/src/9/bcm/archbcm2.c sys/src/9/bcm/armv7.s sys/src/9/bcm/main.c sys/src/9/bcm/mkfile sys/src/9/bcm/rebootcode.s
description: bcm: fix /dev/reboot text/data corruption (thanks richard miller)

- clean dcache before turning off caches and mmu (rebootcode.s)
- use WFE and inter-core mailboxes for cpu startup (rebootcode.s)
- disable SMP during dcache invalidation before enabling caches and mmu (in armv7.s)
     1.1--- a/sys/src/9/bcm/archbcm2.c
     1.2+++ b/sys/src/9/bcm/archbcm2.c
     1.3@@ -145,7 +145,6 @@ getncpus(void)
     1.4 {
     1.5 	int n, max;
     1.6 	char *p;
     1.7-
     1.8 	n = 4;
     1.9 	if(n > MAXMACH)
    1.10 		n = MAXMACH;
     2.1--- a/sys/src/9/bcm/armv7.s
     2.2+++ b/sys/src/9/bcm/armv7.s
     2.3@@ -46,34 +46,34 @@ TEXT armstart(SB), 1, $-4
     2.4 	BARRIERS
     2.5 
     2.6 	/*
     2.7-	 * turn SMP on
     2.8-	 * invalidate tlb
     2.9+	 * turn SMP off
    2.10 	 */
    2.11 	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.12-	ORR	$CpACsmp, R1		/* turn SMP on */
    2.13+	BIC	$CpACsmp, R1
    2.14 	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.15 	BARRIERS
    2.16-	MCR	CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
    2.17-	BARRIERS
    2.18 
    2.19 	/*
    2.20 	 * clear mach and page tables
    2.21 	 */
    2.22 	MOVW	$PADDR(MACHADDR), R1
    2.23 	MOVW	$PADDR(KTZERO), R2
    2.24+	MOVW	$0, R0
    2.25 _ramZ:
    2.26 	MOVW	R0, (R1)
    2.27 	ADD	$4, R1
    2.28 	CMP	R1, R2
    2.29-	BNE	_ramZ
    2.30+	BNE	_ramZ	
    2.31 
    2.32 	/*
    2.33 	 * start stack at top of mach (physical addr)
    2.34 	 * set up page tables for kernel
    2.35 	 */
    2.36 	MOVW	$PADDR(MACHADDR+MACHSIZE-4), R13
    2.37+
    2.38 	MOVW	$PADDR(L1), R0
    2.39 	BL	mmuinit(SB)
    2.40+	BL	mmuinvalidate(SB)
    2.41 
    2.42 	/*
    2.43 	 * set up domain access control and page table base
    2.44@@ -94,6 +94,14 @@ TEXT armstart(SB), 1, $-4
    2.45 	BARRIERS
    2.46 
    2.47 	/*
    2.48+	 * turn SMP on
    2.49+	 */
    2.50+	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.51+	ORR	$CpACsmp, R1
    2.52+	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.53+	BARRIERS
    2.54+
    2.55+	/*
    2.56 	 * enable caches, mmu, and high vectors
    2.57 	 */
    2.58 	MRC	CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
    2.59@@ -133,12 +141,10 @@ TEXT cpureset(SB), 1, $-4
    2.60 reset:
    2.61 	/*
    2.62 	 * load physical base for SB addressing while mmu is off
    2.63-	 * keep a handy zero in R0 until first function call
    2.64 	 */
    2.65 	MOVW	$setR12(SB), R12
    2.66 	SUB	$KZERO, R12
    2.67 	ADD	$PHYSDRAM, R12
    2.68-	MOVW	$0, R0
    2.69 
    2.70 	/*
    2.71 	 * SVC mode, interrupts disabled
    2.72@@ -156,15 +162,12 @@ reset:
    2.73 	BARRIERS
    2.74 
    2.75 	/*
    2.76-	 * turn SMP on
    2.77-	 * invalidate tlb
    2.78+	 * turn SMP off
    2.79 	 */
    2.80 	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.81-	ORR	$CpACsmp, R1		/* turn SMP on */
    2.82+	BIC	$CpACsmp, R1
    2.83 	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    2.84 	BARRIERS
    2.85-	MCR	CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
    2.86-	BARRIERS
    2.87 
    2.88 	/*
    2.89 	 * find Mach for this cpu
    2.90@@ -173,6 +176,8 @@ reset:
    2.91 	AND	$(MAXMACH-1), R2	/* mask out non-cpu-id bits */
    2.92 	SLL	$2, R2			/* convert to word index */
    2.93 	MOVW	$machaddr(SB), R0
    2.94+	BIC	$KSEGM, R0
    2.95+	ORR	$PHYSDRAM, R0
    2.96 	ADD	R2, R0			/* R0 = &machaddr[cpuid] */
    2.97 	MOVW	(R0), R0		/* R0 = machaddr[cpuid] */
    2.98 	CMP	$0, R0
    2.99@@ -184,6 +189,8 @@ reset:
   2.100 	 */
   2.101 	ADD	$(MACHSIZE-4), R(MACH), R13
   2.102 
   2.103+	BL	mmuinvalidate(SB)
   2.104+
   2.105 	/*
   2.106 	 * set up domain access control and page table base
   2.107 	 */
   2.108@@ -203,6 +210,14 @@ reset:
   2.109 	BARRIERS
   2.110 
   2.111 	/*
   2.112+	 * turn SMP on
   2.113+	 */
   2.114+	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
   2.115+	ORR	$CpACsmp, R1
   2.116+	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
   2.117+	BARRIERS
   2.118+
   2.119+	/*
   2.120 	 * enable caches, mmu, and high vectors
   2.121 	 */
   2.122 	MRC	CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
     3.1--- a/sys/src/9/bcm/main.c
     3.2+++ b/sys/src/9/bcm/main.c
     3.3@@ -242,7 +242,7 @@ launchinit(void)
     3.4 	}
     3.5 	cachedwbse(machaddr, sizeof machaddr);
     3.6 	if((mach = startcpus(conf.nmach)) < conf.nmach)
     3.7-			print("only %d cpu%s started\n", mach, mach == 1? "" : "s");
     3.8+		print("only %d cpu%s started\n", mach, mach == 1? "" : "s");
     3.9 }
    3.10 
    3.11 static void
    3.12@@ -551,10 +551,9 @@ confinit(void)
    3.13 }
    3.14 
    3.15 static void
    3.16-rebootjump(ulong entry, ulong code, ulong size)
    3.17+rebootjump(void *entry, void *code, ulong size)
    3.18 {
    3.19-	static void (*f)(ulong, ulong, ulong);
    3.20-	static Lock lk;
    3.21+	void (*f)(void*, void*, ulong);
    3.22 
    3.23 	intrsoff();
    3.24 	intrcpushutdown();
    3.25@@ -562,17 +561,10 @@ rebootjump(ulong entry, ulong code, ulon
    3.26 	/* redo identity map */
    3.27 	mmuinit1(1);
    3.28 
    3.29-	lock(&lk);
    3.30-	if(f == nil){
    3.31-		/* setup reboot trampoline function */
    3.32-		f = (void*)REBOOTADDR;
    3.33-		memmove(f, rebootcode, sizeof(rebootcode));
    3.34-		cachedwbse(f, sizeof(rebootcode));
    3.35-	}
    3.36-	unlock(&lk);
    3.37-
    3.38+	/* setup reboot trampoline function */
    3.39+	f = (void*)REBOOTADDR;
    3.40+	memmove(f, rebootcode, sizeof(rebootcode));
    3.41 	cacheuwbinv();
    3.42-	l2cacheuwbinv();
    3.43 
    3.44 	(*f)(entry, code, size);
    3.45 
    3.46@@ -587,9 +579,9 @@ exit(int)
    3.47 {
    3.48 	cpushutdown();
    3.49 	splfhi();
    3.50-	if(m->machno != 0)
    3.51-		rebootjump(0, 0, 0);
    3.52-	archreboot();
    3.53+	if(m->machno == 0)
    3.54+		archreboot();
    3.55+	rebootjump(0, 0, 0);
    3.56 }
    3.57 
    3.58 /*
    3.59@@ -609,13 +601,13 @@ void
    3.60 reboot(void *entry, void *code, ulong size)
    3.61 {
    3.62 	writeconf();
    3.63-	if (m->machno != 0) {
    3.64+	while(m->machno != 0){
    3.65 		procwired(up, 0);
    3.66 		sched();
    3.67 	}
    3.68 
    3.69 	cpushutdown();
    3.70-	delay(1000);
    3.71+	delay(2000);
    3.72 
    3.73 	splfhi();
    3.74 
    3.75@@ -630,7 +622,7 @@ reboot(void *entry, void *code, ulong si
    3.76 	wdogoff();
    3.77 
    3.78 	/* off we go - never to return */
    3.79-	rebootjump(PADDR(entry), PADDR(code), size);
    3.80+	rebootjump(entry, code, size);
    3.81 }
    3.82 
    3.83 void
     4.1--- a/sys/src/9/bcm/mkfile
     4.2+++ b/sys/src/9/bcm/mkfile
     4.3@@ -70,8 +70,6 @@ LIB=\
     4.4 	/$objtype/lib/libmp.a\
     4.5 	/$objtype/lib/libc.a\
     4.6 
     4.7-9:V: $p$CONF s$p$CONF
     4.8-
     4.9 $p$CONF:DQ:	$CONF.c $OBJ $LIB mkfile
    4.10 	$CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c
    4.11 	echo '# linking raw kernel'	# H6: no headers, data segment aligned
    4.12@@ -123,8 +121,8 @@ init.h:D:	../port/initcode.c init9.s
    4.13 
    4.14 reboot.h:D:	rebootcode.s arm.s arm.h mem.h
    4.15 	$AS rebootcode.s
    4.16-	# -lc is only for memmove.  -T arg is REBOOTADDR
    4.17-	$LD -l -s -T0x1c00 -R4 -o reboot.out rebootcode.$O -lc
    4.18+	# -T arg is REBOOTADDR
    4.19+	$LD -l -s -T0x1c00 -R4 -o reboot.out rebootcode.$O
    4.20 	{echo 'uchar rebootcode[]={'
    4.21 	 xd -1x reboot.out |
    4.22 		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
     5.1--- a/sys/src/9/bcm/rebootcode.s
     5.2+++ b/sys/src/9/bcm/rebootcode.s
     5.3@@ -6,25 +6,46 @@
     5.4 #define WFI	WORD	$0xe320f003	/* wait for interrupt */
     5.5 #define WFE	WORD	$0xe320f002	/* wait for event */
     5.6 
     5.7-/*
     5.8- * Turn off MMU, then copy the new kernel to its correct location
     5.9- * in physical memory.  Then jump to the start of the kernel.
    5.10- */
    5.11-
    5.12-/* main(PADDR(entry), PADDR(code), size); */
    5.13 TEXT	main(SB), 1, $-4
    5.14 	MOVW	$setR12(SB), R12
    5.15 
    5.16-	/* copy in arguments before stack gets unmapped */
    5.17-	MOVW	R0, R8			/* entry point */
    5.18-	MOVW	p2+4(FP), R9		/* source */
    5.19-	MOVW	n+8(FP), R6		/* byte count */
    5.20+	MOVW	R0, entry+0(FP)
    5.21+	CMP	$0, R0
    5.22+	BEQ	shutdown
    5.23+
    5.24+	MOVW	entry+0(FP), R8
    5.25+	MOVW	code+4(FP), R9
    5.26+	MOVW	size+8(FP), R6	
    5.27+
    5.28+	/* round to words */
    5.29+	BIC	$3, R8
    5.30+	BIC	$3, R9
    5.31+	ADD	$3, R6
    5.32+	BIC	$3, R6
    5.33 
    5.34-	/* SVC mode, interrupts disabled */
    5.35-	MOVW	$(PsrDirq|PsrDfiq|PsrMsvc), R1
    5.36-	MOVW	R1, CPSR
    5.37+memloop:
    5.38+	MOVM.IA.W	(R9), [R1]
    5.39+	MOVM.IA.W	[R1], (R8)
    5.40+	SUB.S	$4, R6
    5.41+	BNE	memloop
    5.42 
    5.43-	/* turn caches off */
    5.44+shutdown:
    5.45+	/* clean dcache using appropriate code for armv6 or armv7 */
    5.46+	MRC	CpSC, 0, R1, C(CpID), C(CpIDfeat), 7	/* Memory Model Feature Register 3 */
    5.47+	TST	$0xF, R1	/* hierarchical cache maintenance? */
    5.48+	BNE	l2wb
    5.49+	DSB
    5.50+	MOVW	$0, R0
    5.51+	MCR	CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEall
    5.52+	B	l2wbx
    5.53+l2wb:
    5.54+	BL	cachedwb(SB)
    5.55+	BL	l2cacheuwb(SB)
    5.56+l2wbx:
    5.57+	/* load entry before turning off mmu */
    5.58+	MOVW	entry+0(FP), R8
    5.59+
    5.60+	/* disable caches */
    5.61 	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.62 	BIC	$(CpCdcache|CpCicache|CpCpredict), R1
    5.63 	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.64@@ -39,42 +60,34 @@ TEXT	main(SB), 1, $-4
    5.65 	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.66 	BIC	$CpCmmu, R1
    5.67 	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.68+	BARRIERS
    5.69 
    5.70-	/* continue with reboot only on cpu0 */
    5.71-	CPUID(R2)
    5.72-	BEQ	bootcpu
    5.73+	/* turn SMP off */
    5.74+	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    5.75+	BIC	$CpACsmp, R1
    5.76+	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
    5.77+	ISB
    5.78+	DSB
    5.79 
    5.80-	/* other cpus wait for inter processor interrupt from cpu0 */
    5.81-	/* turn icache back on */
    5.82-	MRC	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.83-	ORR	$(CpCicache), R1
    5.84-	MCR	CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
    5.85-	BARRIERS
    5.86+	/* have entry? */
    5.87+	CMP	$0, R8
    5.88+	BNE	bootcpu
    5.89+
    5.90+	/* other cpus wait for inter processor interrupt */
    5.91+	CPUID(R2)
    5.92 dowfi:
    5.93-	WFI
    5.94-	MOVW	$0x40000060, R1
    5.95-	ADD		R2<<2, R1
    5.96-	MOVW	0(R1), R0
    5.97-	AND	$0x10, R0
    5.98-	BEQ		dowfi
    5.99-	MOVW	$0x8000, R1
   5.100-	BL		(R1)
   5.101-	B		dowfi
   5.102+	WFE			/* wait for event signal */
   5.103+	MOVW	$0x400000CC, R1	/* inter-core .startcpu mailboxes */
   5.104+	ADD	R2<<4, R1	/* mailbox for this core */
   5.105+	MOVW	0(R1), R8	/* content of mailbox */
   5.106+	CMP	$0, R8		
   5.107+	BEQ	dowfi		/* if zero, wait again */
   5.108 
   5.109 bootcpu:
   5.110-	/* set up a tiny stack for local vars and memmove args */
   5.111-	MOVW	R8, SP			/* stack top just before kernel dest */
   5.112-	SUB	$20, SP			/* allocate stack frame */
   5.113+	BIC	$KSEGM, R8	/* entry to physical */
   5.114+	ORR	$PHYSDRAM, R8
   5.115+	BL	(R8)
   5.116+	B	dowfi
   5.117 
   5.118-	/* copy the kernel to final destination */
   5.119-	MOVW	R8, 16(SP)		/* save dest (entry point) */
   5.120-	MOVW	R8, R0			/* first arg is dest */
   5.121-	MOVW	R9, 8(SP)		/* push src */
   5.122-	MOVW	R6, 12(SP)		/* push size */
   5.123-	BL	memmove(SB)
   5.124-	MOVW	16(SP), R8		/* restore entry point */
   5.125-
   5.126-	/* jump to kernel physical entry point */
   5.127-	ORR	R8,R8
   5.128-	B	(R8)
   5.129-	B	0(PC)
   5.130+#define ICACHELINESZ	32
   5.131+#include "cache.v7.s"