Skip to content

Commit f29cf77

Browse files
committed
xtensa: add load/store exception handler
Memory attached to instruction bus of the xtensa CPU is only accessible for a limited subset of opcodes. Other opcodes generate an exception with the load/store error cause code. This property complicates use of such systems. Provide a handler that recognizes and transparently fixes such exceptions. The following opcodes are recognized when used outside of FLIX bundles: l32i, l32i.n, l16ui, l16si, l8ui. Signed-off-by: Max Filippov <[email protected]>
1 parent 651d4af commit f29cf77

File tree

5 files changed

+136
-14
lines changed

5 files changed

+136
-14
lines changed

arch/xtensa/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ config XTENSA_UNALIGNED_USER
203203

204204
Say Y here to enable unaligned memory access in user space.
205205

206+
config XTENSA_LOAD_STORE
207+
bool "Load/store exception handler for memory only readable with l32"
208+
help
209+
The Xtensa architecture only allows reading memory attached to its
210+
instruction bus with l32r and l32i instructions, all other
211+
instructions raise an exception with the LoadStoreErrorCause code.
212+
This makes it hard to use some configurations, e.g. store string
213+
literals in FLASH memory attached to the instruction bus.
214+
215+
Say Y here to enable exception handler that allows transparent
216+
byte and 2-byte access to memory attached to instruction bus.
217+
206218
config HAVE_SMP
207219
bool "System Supports SMP (MX)"
208220
depends on XTENSA_VARIANT_CUSTOM

arch/xtensa/include/asm/traps.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ __init trap_set_handler(int cause, xtensa_exception_handler *handler);
4747
asmlinkage void fast_illegal_instruction_user(void);
4848
asmlinkage void fast_syscall_user(void);
4949
asmlinkage void fast_alloca(void);
50+
asmlinkage void fast_load_store(void);
5051
asmlinkage void fast_unaligned(void);
5152
asmlinkage void fast_second_level_miss(void);
5253
asmlinkage void fast_store_prohibited(void);
@@ -64,6 +65,10 @@ void do_unhandled(struct pt_regs *regs);
6465
static inline void __init early_trap_init(void)
6566
{
6667
static struct exc_table init_exc_table __initdata = {
68+
#ifdef CONFIG_XTENSA_LOAD_STORE
69+
.fast_kernel_handler[EXCCAUSE_LOAD_STORE_ERROR] =
70+
fast_load_store,
71+
#endif
6772
#ifdef CONFIG_MMU
6873
.fast_kernel_handler[EXCCAUSE_DTLB_MISS] =
6974
fast_second_level_miss,

arch/xtensa/kernel/align.S

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,17 @@
2222
#include <asm/asmmacro.h>
2323
#include <asm/processor.h>
2424

25-
#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
25+
#if XCHAL_UNALIGNED_LOAD_EXCEPTION || defined CONFIG_XTENSA_LOAD_STORE
26+
#define LOAD_EXCEPTION_HANDLER
27+
#endif
28+
29+
#if XCHAL_UNALIGNED_STORE_EXCEPTION || defined LOAD_EXCEPTION_HANDLER
30+
#define ANY_EXCEPTION_HANDLER
31+
#endif
32+
33+
#if XCHAL_HAVE_WINDOWED
34+
#define UNALIGNED_USER_EXCEPTION
35+
#endif
2636

2737
/* First-level exception handler for unaligned exceptions.
2838
*
@@ -58,10 +68,6 @@
5868
* BE shift left / mask 0 0 X X
5969
*/
6070

61-
#if XCHAL_HAVE_WINDOWED
62-
#define UNALIGNED_USER_EXCEPTION
63-
#endif
64-
6571
#if XCHAL_HAVE_BE
6672

6773
#define HWORD_START 16
@@ -103,7 +109,7 @@
103109
*
104110
* 23 0
105111
* -----------------------------
106-
* res 0000 0010
112+
* L8UI xxxx xxxx 0000 ssss tttt 0010
107113
* L16UI xxxx xxxx 0001 ssss tttt 0010
108114
* L32I xxxx xxxx 0010 ssss tttt 0010
109115
* XXX 0011 ssss tttt 0010
@@ -128,9 +134,11 @@
128134

129135
#define OP0_L32I_N 0x8 /* load immediate narrow */
130136
#define OP0_S32I_N 0x9 /* store immediate narrow */
137+
#define OP0_LSAI 0x2 /* load/store */
131138
#define OP1_SI_MASK 0x4 /* OP1 bit set for stores */
132139
#define OP1_SI_BIT 2 /* OP1 bit number for stores */
133140

141+
#define OP1_L8UI 0x0
134142
#define OP1_L32I 0x2
135143
#define OP1_L16UI 0x1
136144
#define OP1_L16SI 0x9
@@ -155,8 +163,73 @@
155163
*/
156164

157165
.literal_position
166+
#ifdef CONFIG_XTENSA_LOAD_STORE
167+
ENTRY(fast_load_store)
168+
169+
call0 .Lsave_and_load_instruction
170+
171+
/* Analyze the instruction (load or store?). */
172+
173+
extui a0, a4, INSN_OP0, 4 # get insn.op0 nibble
174+
175+
#if XCHAL_HAVE_DENSITY
176+
_beqi a0, OP0_L32I_N, 1f # L32I.N, jump
177+
#endif
178+
bnei a0, OP0_LSAI, .Linvalid_instruction
179+
/* 'store indicator bit' set, jump */
180+
bbsi.l a4, OP1_SI_BIT + INSN_OP1, .Linvalid_instruction
181+
182+
1:
183+
movi a3, ~3
184+
and a3, a3, a8 # align memory address
185+
186+
__ssa8 a8
187+
188+
#ifdef CONFIG_MMU
189+
/* l32e can't be used here even when it's available. */
190+
/* TODO access_ok(a3) could be used here */
191+
j .Linvalid_instruction
192+
#endif
193+
l32i a5, a3, 0
194+
l32i a6, a3, 4
195+
__src_b a3, a5, a6 # a3 has the data word
196+
197+
#if XCHAL_HAVE_DENSITY
198+
addi a7, a7, 2 # increment PC (assume 16-bit insn)
199+
_beqi a0, OP0_L32I_N, .Lload_w# l32i.n: jump
200+
addi a7, a7, 1
201+
#else
202+
addi a7, a7, 3
203+
#endif
204+
205+
extui a5, a4, INSN_OP1, 4
206+
_beqi a5, OP1_L32I, .Lload_w
207+
bnei a5, OP1_L8UI, .Lload16
208+
extui a3, a3, 0, 8
209+
j .Lload_w
210+
211+
ENDPROC(fast_load_store)
212+
#endif
213+
214+
/*
215+
* Entry condition:
216+
*
217+
* a0: trashed, original value saved on stack (PT_AREG0)
218+
* a1: a1
219+
* a2: new stack pointer, original in DEPC
220+
* a3: a3
221+
* depc: a2, original value saved on stack (PT_DEPC)
222+
* excsave_1: dispatch table
223+
*
224+
* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
225+
* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
226+
*/
227+
228+
#ifdef ANY_EXCEPTION_HANDLER
158229
ENTRY(fast_unaligned)
159230

231+
#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
232+
160233
call0 .Lsave_and_load_instruction
161234

162235
/* Analyze the instruction (load or store?). */
@@ -171,12 +244,17 @@ ENTRY(fast_unaligned)
171244
/* 'store indicator bit' not set, jump */
172245
_bbci.l a4, OP1_SI_BIT + INSN_OP1, .Lload
173246

247+
#endif
248+
#if XCHAL_UNALIGNED_STORE_EXCEPTION
249+
174250
/* Store: Jump to table entry to get the value in the source register.*/
175251

176252
.Lstore:movi a5, .Lstore_table # table
177253
extui a6, a4, INSN_T, 4 # get source register
178254
addx8 a5, a6, a5
179255
jx a5 # jump into table
256+
#endif
257+
#if XCHAL_UNALIGNED_LOAD_EXCEPTION
180258

181259
/* Load: Load memory address. */
182260

@@ -207,7 +285,9 @@ ENTRY(fast_unaligned)
207285

208286
extui a5, a4, INSN_OP1, 4
209287
_beqi a5, OP1_L32I, .Lload_w # l32i: jump
210-
288+
#endif
289+
#ifdef LOAD_EXCEPTION_HANDLER
290+
.Lload16:
211291
extui a3, a3, 0, 16 # extract lower 16 bits
212292
_beqi a5, OP1_L16UI, .Lload_w
213293
addi a5, a5, -OP1_L16SI
@@ -247,7 +327,8 @@ ENTRY(fast_unaligned)
247327
mov a13, a3 ; _j .Lexit; .align 8
248328
mov a14, a3 ; _j .Lexit; .align 8
249329
mov a15, a3 ; _j .Lexit; .align 8
250-
330+
#endif
331+
#if XCHAL_UNALIGNED_STORE_EXCEPTION
251332
.Lstore_table:
252333
l32i a3, a2, PT_AREG0; _j .Lstore_w; .align 8
253334
mov a3, a1; _j .Lstore_w; .align 8 # fishy??
@@ -265,7 +346,9 @@ ENTRY(fast_unaligned)
265346
mov a3, a13 ; _j .Lstore_w; .align 8
266347
mov a3, a14 ; _j .Lstore_w; .align 8
267348
mov a3, a15 ; _j .Lstore_w; .align 8
349+
#endif
268350

351+
#ifdef ANY_EXCEPTION_HANDLER
269352
/* We cannot handle this exception. */
270353

271354
.extern _kernel_exception
@@ -294,6 +377,8 @@ ENTRY(fast_unaligned)
294377

295378
2: movi a0, _user_exception
296379
jx a0
380+
#endif
381+
#if XCHAL_UNALIGNED_STORE_EXCEPTION
297382

298383
# a7: instruction pointer, a4: instruction, a3: value
299384
.Lstore_w:
@@ -358,7 +443,8 @@ ENTRY(fast_unaligned)
358443
#else
359444
s32i a6, a4, 4
360445
#endif
361-
446+
#endif
447+
#ifdef ANY_EXCEPTION_HANDLER
362448
.Lexit:
363449
#if XCHAL_HAVE_LOOPS
364450
rsr a4, lend # check if we reached LEND
@@ -453,7 +539,7 @@ ENTRY(fast_unaligned)
453539
__src_b a4, a4, a5 # a4 has the instruction
454540

455541
ret
456-
542+
#endif
457543
ENDPROC(fast_unaligned)
458544

459545
ENTRY(fast_unaligned_fixup)
@@ -490,5 +576,4 @@ ENTRY(fast_unaligned_fixup)
490576
jx a0
491577

492578
ENDPROC(fast_unaligned_fixup)
493-
494-
#endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
579+
#endif

arch/xtensa/kernel/setup.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ void __init init_arch(bp_tag_t *bp_start)
245245
{
246246
/* Initialize basic exception handling if configuration may need it */
247247

248-
if (IS_ENABLED(CONFIG_KASAN))
248+
if (IS_ENABLED(CONFIG_KASAN) ||
249+
IS_ENABLED(CONFIG_XTENSA_LOAD_STORE))
249250
early_trap_init();
250251

251252
/* Initialize MMU. */

arch/xtensa/kernel/traps.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ static void do_interrupt(struct pt_regs *regs);
5454
#if XTENSA_FAKE_NMI
5555
static void do_nmi(struct pt_regs *regs);
5656
#endif
57+
#ifdef CONFIG_XTENSA_LOAD_STORE
58+
static void do_load_store(struct pt_regs *regs);
59+
#endif
5760
static void do_unaligned_user(struct pt_regs *regs);
5861
static void do_multihit(struct pt_regs *regs);
5962
#if XTENSA_HAVE_COPROCESSORS
@@ -89,7 +92,10 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = {
8992
{ EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user },
9093
{ EXCCAUSE_SYSTEM_CALL, 0, system_call },
9194
/* EXCCAUSE_INSTRUCTION_FETCH unhandled */
92-
/* EXCCAUSE_LOAD_STORE_ERROR unhandled*/
95+
#ifdef CONFIG_XTENSA_LOAD_STORE
96+
{ EXCCAUSE_LOAD_STORE_ERROR, USER|KRNL, fast_load_store },
97+
{ EXCCAUSE_LOAD_STORE_ERROR, 0, do_load_store },
98+
#endif
9399
{ EXCCAUSE_LEVEL1_INTERRUPT, 0, do_interrupt },
94100
#ifdef SUPPORT_WINDOWED
95101
{ EXCCAUSE_ALLOCA, USER|KRNL, fast_alloca },
@@ -347,6 +353,19 @@ static void do_div0(struct pt_regs *regs)
347353
force_sig_fault(SIGFPE, FPE_INTDIV, (void __user *)regs->pc);
348354
}
349355

356+
#ifdef CONFIG_XTENSA_LOAD_STORE
357+
static void do_load_store(struct pt_regs *regs)
358+
{
359+
__die_if_kernel("Unhandled load/store exception in kernel",
360+
regs, SIGKILL);
361+
362+
pr_info_ratelimited("Load/store error to %08lx in '%s' (pid = %d, pc = %#010lx)\n",
363+
regs->excvaddr, current->comm,
364+
task_pid_nr(current), regs->pc);
365+
force_sig_fault(SIGBUS, BUS_ADRERR, (void *)regs->excvaddr);
366+
}
367+
#endif
368+
350369
/*
351370
* Handle unaligned memory accesses from user space. Kill task.
352371
*

0 commit comments

Comments
 (0)