[U-Boot] [PATCH v4] MIPS: Hang if run on a secondary CPU

Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com
---
Changes in v4: - Presume Config5 is present for MIPSr6, as the arch says it will be
Changes in v3: - Fix branch target for MIPSr6 case... Oops!
Changes in v2: - Rebase atop u-boot-mips/next - Execute a wait instruction in the loop - Fill delay slots with NOPs
arch/mips/cpu/start.S | 21 ++++++++++++++++++++- arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 8f85ede..5eca829 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -108,9 +108,28 @@ ENTRY(_start)
.align 4 reset: +#if __mips_isa_rev >= 6 + mfc0 t0, CP0_CONFIG, 5 + and t0, t0, MIPS_CONF5_VP + beqz t0, 1f + nop + + b 2f + mfc0 t0, CP0_GLOBALNUMBER +#endif + +1: mfc0 t0, CP0_EBASE + and t0, t0, EBASE_CPUNUM + + /* Hang if this isn't the first CPU in the system */ +2: beqz t0, 4f + nop +3: wait + b 3b + nop
/* Clear watch registers */ - MTC0 zero, CP0_WATCHLO +4: MTC0 zero, CP0_WATCHLO mtc0 zero, CP0_WATCHHI
/* WP(Watch Pending), SW0/1 should be cleared */ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b4c2dff..9ab5063 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@ #define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3 +#define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6 @@ -361,6 +362,11 @@ #define CAUSEF_BD (_ULCAST_(1) << 31)
/* + * Bits in the coprocessor 0 EBase register. + */ +#define EBASE_CPUNUM 0x3ff + +/* * Bits in the coprocessor 0 config register. */ /* Generic bits. */ @@ -553,6 +559,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_L2C (_ULCAST_(1) << 10)

Am 21.09.2016 um 15:59 schrieb Paul Burton:
Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com
Changes in v4:
- Presume Config5 is present for MIPSr6, as the arch says it will be
Changes in v3:
- Fix branch target for MIPSr6 case... Oops!
Changes in v2:
- Rebase atop u-boot-mips/next
- Execute a wait instruction in the loop
- Fill delay slots with NOPs
arch/mips/cpu/start.S | 21 ++++++++++++++++++++- arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 8f85ede..5eca829 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -108,9 +108,28 @@ ENTRY(_start)
.align 4 reset: +#if __mips_isa_rev >= 6
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
nop
- b 2f
mfc0 t0, CP0_GLOBALNUMBER
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
just nit-picking but actually you're creating dead code for MIPS r6 by the permanent branch to label 2. Maybe it's better to move these two lines to the #else branch of "#if __mips_isa_rev >= 6" and save the branch to label 2?
- /* Hang if this isn't the first CPU in the system */
+2: beqz t0, 4f
nop
+3: wait
b 3b
nop
/* Clear watch registers */
- MTC0 zero, CP0_WATCHLO
+4: MTC0 zero, CP0_WATCHLO mtc0 zero, CP0_WATCHHI
/* WP(Watch Pending), SW0/1 should be cleared */ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b4c2dff..9ab5063 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@ #define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3 +#define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6 @@ -361,6 +362,11 @@ #define CAUSEF_BD (_ULCAST_(1) << 31)
/*
- Bits in the coprocessor 0 EBase register.
- */
+#define EBASE_CPUNUM 0x3ff
+/*
- Bits in the coprocessor 0 config register.
*/ /* Generic bits. */ @@ -553,6 +559,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_L2C (_ULCAST_(1) << 10)

On Wednesday, 21 September 2016 16:19:58 BST Daniel Schwierzeck wrote:
Am 21.09.2016 um 15:59 schrieb Paul Burton:
Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com
Changes in v4:
- Presume Config5 is present for MIPSr6, as the arch says it will be
Changes in v3:
- Fix branch target for MIPSr6 case... Oops!
Changes in v2:
- Rebase atop u-boot-mips/next
- Execute a wait instruction in the loop
- Fill delay slots with NOPs
arch/mips/cpu/start.S | 21 ++++++++++++++++++++- arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 8f85ede..5eca829 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -108,9 +108,28 @@ ENTRY(_start)
.align 4
reset: +#if __mips_isa_rev >= 6
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
nop
- b 2f
mfc0 t0, CP0_GLOBALNUMBER
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
just nit-picking but actually you're creating dead code for MIPS r6 by the permanent branch to label 2. Maybe it's better to move these two lines to the #else branch of "#if __mips_isa_rev >= 6" and save the branch to label 2?
Hi Daniel,
That's not the case because the Config5.VP bit may be 0, in which case the branch to the "1" label will be taken & we'll read EBase.CPUNum. Sadly we can't rely on the GlobalNumber register being implemented on all MIPSr6 systems since the architecture only requires it when VPs are implemented.
Thanks, Paul
- /* Hang if this isn't the first CPU in the system */
+2: beqz t0, 4f
nop
+3: wait
b 3b
nop
/* Clear watch registers */
- MTC0 zero, CP0_WATCHLO
+4: MTC0 zero, CP0_WATCHLO
mtc0 zero, CP0_WATCHHI
/* WP(Watch Pending), SW0/1 should be cleared */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b4c2dff..9ab5063 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@
#define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3
+#define CP0_GLOBALNUMBER $3, 1
#define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6
@@ -361,6 +362,11 @@
#define CAUSEF_BD (_ULCAST_(1) << 31)
/*
- Bits in the coprocessor 0 EBase register.
- */
+#define EBASE_CPUNUM 0x3ff
+/*
- Bits in the coprocessor 0 config register.
*/
/* Generic bits. */
@@ -553,6 +559,7 @@
#define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5)
+#define MIPS_CONF5_VP (_ULCAST_(1) << 7)
#define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_L2C (_ULCAST_(1) << 10)
participants (2)
-
Daniel Schwierzeck
-
Paul Burton