Skip to content

Commit 4b22c69

Browse files
mpredfearnralfbaechle
authored andcommitted
MIPS: traps: Ensure full EBase is written
On CPUs which support the EBase WG (write gate) flag, the most significant bits of the exception base can be changed. Firmware running on a VP(E) using MIPS rproc may change EBase to point into the user segment where the firmware is located such that it can service interrupts. When control is transferred back to the kernel the EBase must be switched back into the kernel segment, such that the kernel's exception vectors are used. Similarly when vectored interrupts (vint) or vectored external interrupt controllers (veic) are enabled an exception vector is allocated from bootmem, and written to the EBase register. Due to the WG flag being clear, only bits 29:12 will be written. Asside from the rproc case above this is normally fine (as it will usually be a low allocation within the KSeg0 range, however when Enhanced Virtual Addressing (EVA) is enabled the allocation may be outside of the traditional KSeg0/KSeg1 address range, resulting in the wrong EBase being written. Correct both cases (configure_exception_vector() for the boot CPU, and per_cpu_trap_init() for secondary CPUs) to write EBase with the WG flag first if supported. On the Malta EVA configuration, KSeg0 is mapped to physical address 0, and memory is allocated from the KUSeg segment which is mapped to physical address 0x80000000, which physically aliases the RAM at 0. This only worked due to the exception base address aliasing the same underlying RAM that was written to & cache flushed, and due to flush_icache_range() going beyond the call of duty and flushing from the L2 cache too (due to the differing physical addresses). Signed-off-by: Matt Redfearn <[email protected]> Signed-off-by: James Hogan <[email protected]> Cc: Leonid Yegoshin <[email protected]> Cc: [email protected] Patchwork: https://patchwork.linux-mips.org/patch/14150/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent c195e07 commit 4b22c69

File tree

1 file changed

+18
-1
lines changed

1 file changed

+18
-1
lines changed

arch/mips/kernel/traps.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,14 @@ static void configure_exception_vector(void)
20922092
{
20932093
if (cpu_has_veic || cpu_has_vint) {
20942094
unsigned long sr = set_c0_status(ST0_BEV);
2095+
/* If available, use WG to set top bits of EBASE */
2096+
if (cpu_has_ebase_wg) {
2097+
#ifdef CONFIG_64BIT
2098+
write_c0_ebase_64(ebase | MIPS_EBASE_WG);
2099+
#else
2100+
write_c0_ebase(ebase | MIPS_EBASE_WG);
2101+
#endif
2102+
}
20952103
write_c0_ebase(ebase);
20962104
write_c0_status(sr);
20972105
/* Setting vector spacing enables EI/VI mode */
@@ -2128,8 +2136,17 @@ void per_cpu_trap_init(bool is_boot_cpu)
21282136
* We shouldn't trust a secondary core has a sane EBASE register
21292137
* so use the one calculated by the boot CPU.
21302138
*/
2131-
if (!is_boot_cpu)
2139+
if (!is_boot_cpu) {
2140+
/* If available, use WG to set top bits of EBASE */
2141+
if (cpu_has_ebase_wg) {
2142+
#ifdef CONFIG_64BIT
2143+
write_c0_ebase_64(ebase | MIPS_EBASE_WG);
2144+
#else
2145+
write_c0_ebase(ebase | MIPS_EBASE_WG);
2146+
#endif
2147+
}
21322148
write_c0_ebase(ebase);
2149+
}
21332150

21342151
cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
21352152
cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;

0 commit comments

Comments
 (0)