mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
xtensa: rearrange unaligned exception handler
- extract initialization part of the exception handler into a separate function. - use single label for invalid instruction instead of two labels, one for load and one for store, at one place. - use sext instruction for sign extension when available. - store SAR on the stack instead of in a0. - replace numeric labels for load and store writeback with .Lload_w and .Lstore_w respectively. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
@@ -157,58 +157,7 @@
|
|||||||
.literal_position
|
.literal_position
|
||||||
ENTRY(fast_unaligned)
|
ENTRY(fast_unaligned)
|
||||||
|
|
||||||
/* Note: We don't expect the address to be aligned on a word
|
call0 .Lsave_and_load_instruction
|
||||||
* boundary. After all, the processor generated that exception
|
|
||||||
* and it would be a hardware fault.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Save some working register */
|
|
||||||
|
|
||||||
s32i a4, a2, PT_AREG4
|
|
||||||
s32i a5, a2, PT_AREG5
|
|
||||||
s32i a6, a2, PT_AREG6
|
|
||||||
s32i a7, a2, PT_AREG7
|
|
||||||
s32i a8, a2, PT_AREG8
|
|
||||||
|
|
||||||
rsr a0, depc
|
|
||||||
s32i a0, a2, PT_AREG2
|
|
||||||
s32i a3, a2, PT_AREG3
|
|
||||||
|
|
||||||
rsr a3, excsave1
|
|
||||||
movi a4, fast_unaligned_fixup
|
|
||||||
s32i a4, a3, EXC_TABLE_FIXUP
|
|
||||||
|
|
||||||
/* Keep value of SAR in a0 */
|
|
||||||
|
|
||||||
rsr a0, sar
|
|
||||||
rsr a8, excvaddr # load unaligned memory address
|
|
||||||
|
|
||||||
/* Now, identify one of the following load/store instructions.
|
|
||||||
*
|
|
||||||
* The only possible danger of a double exception on the
|
|
||||||
* following l32i instructions is kernel code in vmalloc
|
|
||||||
* memory. The processor was just executing at the EPC_1
|
|
||||||
* address, and indeed, already fetched the instruction. That
|
|
||||||
* guarantees a TLB mapping, which hasn't been replaced by
|
|
||||||
* this unaligned exception handler that uses only static TLB
|
|
||||||
* mappings. However, high-level interrupt handlers might
|
|
||||||
* modify TLB entries, so for the generic case, we register a
|
|
||||||
* TABLE_FIXUP handler here, too.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* a3...a6 saved on stack, a2 = SP */
|
|
||||||
|
|
||||||
/* Extract the instruction that caused the unaligned access. */
|
|
||||||
|
|
||||||
rsr a7, epc1 # load exception address
|
|
||||||
movi a3, ~3
|
|
||||||
and a3, a3, a7 # mask lower bits
|
|
||||||
|
|
||||||
l32i a4, a3, 0 # load 2 words
|
|
||||||
l32i a5, a3, 4
|
|
||||||
|
|
||||||
__ssa8 a7
|
|
||||||
__src_b a4, a4, a5 # a4 has the instruction
|
|
||||||
|
|
||||||
/* Analyze the instruction (load or store?). */
|
/* Analyze the instruction (load or store?). */
|
||||||
|
|
||||||
@@ -249,7 +198,7 @@ ENTRY(fast_unaligned)
|
|||||||
addi a7, a7, 2 # increment PC (assume 16-bit insn)
|
addi a7, a7, 2 # increment PC (assume 16-bit insn)
|
||||||
|
|
||||||
extui a5, a4, INSN_OP0, 4
|
extui a5, a4, INSN_OP0, 4
|
||||||
_beqi a5, OP0_L32I_N, 1f # l32i.n: jump
|
_beqi a5, OP0_L32I_N, .Lload_w# l32i.n: jump
|
||||||
|
|
||||||
addi a7, a7, 1
|
addi a7, a7, 1
|
||||||
#else
|
#else
|
||||||
@@ -257,21 +206,24 @@ ENTRY(fast_unaligned)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extui a5, a4, INSN_OP1, 4
|
extui a5, a4, INSN_OP1, 4
|
||||||
_beqi a5, OP1_L32I, 1f # l32i: jump
|
_beqi a5, OP1_L32I, .Lload_w # l32i: jump
|
||||||
|
|
||||||
extui a3, a3, 0, 16 # extract lower 16 bits
|
extui a3, a3, 0, 16 # extract lower 16 bits
|
||||||
_beqi a5, OP1_L16UI, 1f
|
_beqi a5, OP1_L16UI, .Lload_w
|
||||||
addi a5, a5, -OP1_L16SI
|
addi a5, a5, -OP1_L16SI
|
||||||
_bnez a5, .Linvalid_instruction_load
|
_bnez a5, .Linvalid_instruction
|
||||||
|
|
||||||
/* sign extend value */
|
/* sign extend value */
|
||||||
|
#if XCHAL_HAVE_SEXT
|
||||||
|
sext a3, a3, 15
|
||||||
|
#else
|
||||||
slli a3, a3, 16
|
slli a3, a3, 16
|
||||||
srai a3, a3, 16
|
srai a3, a3, 16
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set target register. */
|
/* Set target register. */
|
||||||
|
|
||||||
1:
|
.Lload_w:
|
||||||
extui a4, a4, INSN_T, 4 # extract target register
|
extui a4, a4, INSN_T, 4 # extract target register
|
||||||
movi a5, .Lload_table
|
movi a5, .Lload_table
|
||||||
addx8 a4, a4, a5
|
addx8 a4, a4, a5
|
||||||
@@ -297,28 +249,27 @@ ENTRY(fast_unaligned)
|
|||||||
mov a15, a3 ; _j .Lexit; .align 8
|
mov a15, a3 ; _j .Lexit; .align 8
|
||||||
|
|
||||||
.Lstore_table:
|
.Lstore_table:
|
||||||
l32i a3, a2, PT_AREG0; _j 1f; .align 8
|
l32i a3, a2, PT_AREG0; _j .Lstore_w; .align 8
|
||||||
mov a3, a1; _j 1f; .align 8 # fishy??
|
mov a3, a1; _j .Lstore_w; .align 8 # fishy??
|
||||||
l32i a3, a2, PT_AREG2; _j 1f; .align 8
|
l32i a3, a2, PT_AREG2; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG3; _j 1f; .align 8
|
l32i a3, a2, PT_AREG3; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG4; _j 1f; .align 8
|
l32i a3, a2, PT_AREG4; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG5; _j 1f; .align 8
|
l32i a3, a2, PT_AREG5; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG6; _j 1f; .align 8
|
l32i a3, a2, PT_AREG6; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG7; _j 1f; .align 8
|
l32i a3, a2, PT_AREG7; _j .Lstore_w; .align 8
|
||||||
l32i a3, a2, PT_AREG8; _j 1f; .align 8
|
l32i a3, a2, PT_AREG8; _j .Lstore_w; .align 8
|
||||||
mov a3, a9 ; _j 1f; .align 8
|
mov a3, a9 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a10 ; _j 1f; .align 8
|
mov a3, a10 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a11 ; _j 1f; .align 8
|
mov a3, a11 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a12 ; _j 1f; .align 8
|
mov a3, a12 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a13 ; _j 1f; .align 8
|
mov a3, a13 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a14 ; _j 1f; .align 8
|
mov a3, a14 ; _j .Lstore_w; .align 8
|
||||||
mov a3, a15 ; _j 1f; .align 8
|
mov a3, a15 ; _j .Lstore_w; .align 8
|
||||||
|
|
||||||
/* We cannot handle this exception. */
|
/* We cannot handle this exception. */
|
||||||
|
|
||||||
.extern _kernel_exception
|
.extern _kernel_exception
|
||||||
.Linvalid_instruction_load:
|
.Linvalid_instruction:
|
||||||
.Linvalid_instruction_store:
|
|
||||||
|
|
||||||
movi a4, 0
|
movi a4, 0
|
||||||
rsr a3, excsave1
|
rsr a3, excsave1
|
||||||
@@ -326,6 +277,7 @@ ENTRY(fast_unaligned)
|
|||||||
|
|
||||||
/* Restore a4...a8 and SAR, set SP, and jump to default exception. */
|
/* Restore a4...a8 and SAR, set SP, and jump to default exception. */
|
||||||
|
|
||||||
|
l32i a0, a2, PT_SAR
|
||||||
l32i a8, a2, PT_AREG8
|
l32i a8, a2, PT_AREG8
|
||||||
l32i a7, a2, PT_AREG7
|
l32i a7, a2, PT_AREG7
|
||||||
l32i a6, a2, PT_AREG6
|
l32i a6, a2, PT_AREG6
|
||||||
@@ -343,8 +295,8 @@ ENTRY(fast_unaligned)
|
|||||||
2: movi a0, _user_exception
|
2: movi a0, _user_exception
|
||||||
jx a0
|
jx a0
|
||||||
|
|
||||||
1: # a7: instruction pointer, a4: instruction, a3: value
|
# a7: instruction pointer, a4: instruction, a3: value
|
||||||
|
.Lstore_w:
|
||||||
movi a6, 0 # mask: ffffffff:00000000
|
movi a6, 0 # mask: ffffffff:00000000
|
||||||
|
|
||||||
#if XCHAL_HAVE_DENSITY
|
#if XCHAL_HAVE_DENSITY
|
||||||
@@ -361,7 +313,7 @@ ENTRY(fast_unaligned)
|
|||||||
|
|
||||||
extui a5, a4, INSN_OP1, 4 # extract OP1
|
extui a5, a4, INSN_OP1, 4 # extract OP1
|
||||||
_beqi a5, OP1_S32I, 1f # jump if 32 bit store
|
_beqi a5, OP1_S32I, 1f # jump if 32 bit store
|
||||||
_bnei a5, OP1_S16I, .Linvalid_instruction_store
|
_bnei a5, OP1_S16I, .Linvalid_instruction
|
||||||
|
|
||||||
movi a5, -1
|
movi a5, -1
|
||||||
__extl a3, a3 # get 16-bit value
|
__extl a3, a3 # get 16-bit value
|
||||||
@@ -434,6 +386,7 @@ ENTRY(fast_unaligned)
|
|||||||
|
|
||||||
/* Restore working register */
|
/* Restore working register */
|
||||||
|
|
||||||
|
l32i a0, a2, PT_SAR
|
||||||
l32i a8, a2, PT_AREG8
|
l32i a8, a2, PT_AREG8
|
||||||
l32i a7, a2, PT_AREG7
|
l32i a7, a2, PT_AREG7
|
||||||
l32i a6, a2, PT_AREG6
|
l32i a6, a2, PT_AREG6
|
||||||
@@ -448,6 +401,59 @@ ENTRY(fast_unaligned)
|
|||||||
l32i a2, a2, PT_AREG2
|
l32i a2, a2, PT_AREG2
|
||||||
rfe
|
rfe
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.Lsave_and_load_instruction:
|
||||||
|
|
||||||
|
/* Save some working register */
|
||||||
|
|
||||||
|
s32i a3, a2, PT_AREG3
|
||||||
|
s32i a4, a2, PT_AREG4
|
||||||
|
s32i a5, a2, PT_AREG5
|
||||||
|
s32i a6, a2, PT_AREG6
|
||||||
|
s32i a7, a2, PT_AREG7
|
||||||
|
s32i a8, a2, PT_AREG8
|
||||||
|
|
||||||
|
rsr a4, depc
|
||||||
|
s32i a4, a2, PT_AREG2
|
||||||
|
|
||||||
|
rsr a5, sar
|
||||||
|
s32i a5, a2, PT_SAR
|
||||||
|
|
||||||
|
rsr a3, excsave1
|
||||||
|
movi a4, fast_unaligned_fixup
|
||||||
|
s32i a4, a3, EXC_TABLE_FIXUP
|
||||||
|
|
||||||
|
rsr a8, excvaddr # load unaligned memory address
|
||||||
|
|
||||||
|
/* Now, identify one of the following load/store instructions.
|
||||||
|
*
|
||||||
|
* The only possible danger of a double exception on the
|
||||||
|
* following l32i instructions is kernel code in vmalloc
|
||||||
|
* memory. The processor was just executing at the EPC_1
|
||||||
|
* address, and indeed, already fetched the instruction. That
|
||||||
|
* guarantees a TLB mapping, which hasn't been replaced by
|
||||||
|
* this unaligned exception handler that uses only static TLB
|
||||||
|
* mappings. However, high-level interrupt handlers might
|
||||||
|
* modify TLB entries, so for the generic case, we register a
|
||||||
|
* TABLE_FIXUP handler here, too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* a3...a6 saved on stack, a2 = SP */
|
||||||
|
|
||||||
|
/* Extract the instruction that caused the unaligned access. */
|
||||||
|
|
||||||
|
rsr a7, epc1 # load exception address
|
||||||
|
movi a3, ~3
|
||||||
|
and a3, a3, a7 # mask lower bits
|
||||||
|
|
||||||
|
l32i a4, a3, 0 # load 2 words
|
||||||
|
l32i a5, a3, 4
|
||||||
|
|
||||||
|
__ssa8 a7
|
||||||
|
__src_b a4, a4, a5 # a4 has the instruction
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
ENDPROC(fast_unaligned)
|
ENDPROC(fast_unaligned)
|
||||||
|
|
||||||
ENTRY(fast_unaligned_fixup)
|
ENTRY(fast_unaligned_fixup)
|
||||||
@@ -459,10 +465,11 @@ ENTRY(fast_unaligned_fixup)
|
|||||||
l32i a7, a2, PT_AREG7
|
l32i a7, a2, PT_AREG7
|
||||||
l32i a6, a2, PT_AREG6
|
l32i a6, a2, PT_AREG6
|
||||||
l32i a5, a2, PT_AREG5
|
l32i a5, a2, PT_AREG5
|
||||||
l32i a4, a2, PT_AREG4
|
l32i a4, a2, PT_SAR
|
||||||
l32i a0, a2, PT_AREG2
|
l32i a0, a2, PT_AREG2
|
||||||
xsr a0, depc # restore depc and a0
|
wsr a4, sar
|
||||||
wsr a0, sar
|
wsr a0, depc # restore depc and a0
|
||||||
|
l32i a4, a2, PT_AREG4
|
||||||
|
|
||||||
rsr a0, exccause
|
rsr a0, exccause
|
||||||
s32i a0, a2, PT_DEPC # mark as a regular exception
|
s32i a0, a2, PT_DEPC # mark as a regular exception
|
||||||
|
Reference in New Issue
Block a user