Commit eeb53895 authored by Markos Chandras's avatar Markos Chandras Committed by Ralf Baechle

MIPS: unaligned: Prevent EVA instructions on kernel unaligned accesses

Commit c1771216 ("MIPS: kernel: unaligned: Handle unaligned
accesses for EVA") allowed unaligned accesses to be emulated for
EVA. However, when emulating regular load/store unaligned accesses,
we need to use the appropriate "address space" instructions for that.
Previously, an unaligned load/store instruction in kernel space would
have used the corresponding EVA instructions to emulate it which led to
segmentation faults because of the address translation that happens
with EVA instructions. This is now fixed by using the EVA instruction
only when emulating EVA unaligned accesses.
Signed-off-by: default avatarMarkos Chandras <markos.chandras@imgtec.com>
Fixes: c1771216 ("MIPS: kernel: unaligned: Handle unaligned accesses for EVA")
Cc: <stable@vger.kernel.org> # v3.15+
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9501/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 60cd7e08
......@@ -109,10 +109,10 @@ static u32 unaligned_action;
extern void show_registers(struct pt_regs *regs);
#ifdef __BIG_ENDIAN
#define LoadHW(addr, value, res) \
#define _LoadHW(addr, value, res, type) \
__asm__ __volatile__ (".set\tnoat\n" \
"1:\t"user_lb("%0", "0(%2)")"\n" \
"2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"1:\t"type##_lb("%0", "0(%2)")"\n" \
"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -130,10 +130,10 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadW(addr, value, res) \
#define _LoadW(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "(%2)")"\n" \
"2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"1:\t"type##_lwl("%0", "(%2)")"\n" \
"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
......@@ -149,18 +149,18 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no lwl instruction */
#define LoadW(addr, value, res) \
#define _LoadW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n" \
".set\tnoat\n\t" \
"1:"user_lb("%0", "0(%2)")"\n\t" \
"2:"user_lbu("$1", "1(%2)")"\n\t" \
"1:"type##_lb("%0", "0(%2)")"\n\t" \
"2:"type##_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "2(%2)")"\n\t" \
"3:"type##_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "3(%2)")"\n\t" \
"4:"type##_lbu("$1", "3(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -181,11 +181,11 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define LoadHWU(addr, value, res) \
#define _LoadHWU(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\t"user_lbu("%0", "0(%2)")"\n" \
"2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"1:\t"type##_lbu("%0", "0(%2)")"\n" \
"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -204,10 +204,10 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadWU(addr, value, res) \
#define _LoadWU(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "(%2)")"\n" \
"2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"1:\t"type##_lwl("%0", "(%2)")"\n" \
"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
......@@ -224,7 +224,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
#define _LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tldl\t%0, (%2)\n" \
"2:\tldr\t%0, 7(%2)\n\t" \
......@@ -243,18 +243,18 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has not lwl and ldl instructions */
#define LoadWU(addr, value, res) \
#define _LoadWU(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_lbu("%0", "0(%2)")"\n\t" \
"2:"user_lbu("$1", "1(%2)")"\n\t" \
"1:"type##_lbu("%0", "0(%2)")"\n\t" \
"2:"type##_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "2(%2)")"\n\t" \
"3:"type##_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "3(%2)")"\n\t" \
"4:"type##_lbu("$1", "3(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -274,7 +274,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
#define _LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
......@@ -323,12 +323,12 @@ extern void show_registers(struct pt_regs *regs);
#endif /* CONFIG_CPU_MIPSR6 */
#define StoreHW(addr, value, res) \
#define _StoreHW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\t"user_sb("%1", "1(%2)")"\n" \
"1:\t"type##_sb("%1", "1(%2)")"\n" \
"srl\t$1, %1, 0x8\n" \
"2:\t"user_sb("$1", "0(%2)")"\n" \
"2:\t"type##_sb("$1", "0(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
......@@ -345,10 +345,10 @@ extern void show_registers(struct pt_regs *regs);
: "r" (value), "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define StoreW(addr, value, res) \
#define _StoreW(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_swl("%1", "(%2)")"\n" \
"2:\t"user_swr("%1", "3(%2)")"\n\t" \
"1:\t"type##_swl("%1", "(%2)")"\n" \
"2:\t"type##_swr("%1", "3(%2)")"\n\t"\
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
......@@ -363,7 +363,7 @@ extern void show_registers(struct pt_regs *regs);
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreDW(addr, value, res) \
#define _StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tsdl\t%1,(%2)\n" \
"2:\tsdr\t%1, 7(%2)\n\t" \
......@@ -382,17 +382,17 @@ extern void show_registers(struct pt_regs *regs);
: "r" (value), "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no swl and sdl instructions */
#define StoreW(addr, value, res) \
#define _StoreW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_sb("%1", "3(%2)")"\n\t" \
"1:"type##_sb("%1", "3(%2)")"\n\t" \
"srl\t$1, %1, 0x8\n\t" \
"2:"user_sb("$1", "2(%2)")"\n\t" \
"2:"type##_sb("$1", "2(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"3:"user_sb("$1", "1(%2)")"\n\t" \
"3:"type##_sb("$1", "1(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"4:"user_sb("$1", "0(%2)")"\n\t" \
"4:"type##_sb("$1", "0(%2)")"\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
......@@ -456,10 +456,10 @@ extern void show_registers(struct pt_regs *regs);
#else /* __BIG_ENDIAN */
#define LoadHW(addr, value, res) \
#define _LoadHW(addr, value, res, type) \
__asm__ __volatile__ (".set\tnoat\n" \
"1:\t"user_lb("%0", "1(%2)")"\n" \
"2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"1:\t"type##_lb("%0", "1(%2)")"\n" \
"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -477,10 +477,10 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadW(addr, value, res) \
#define _LoadW(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "3(%2)")"\n" \
"2:\t"user_lwr("%0", "(%2)")"\n\t" \
"1:\t"type##_lwl("%0", "3(%2)")"\n" \
"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
......@@ -496,18 +496,18 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no lwl instruction */
#define LoadW(addr, value, res) \
#define _LoadW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n" \
".set\tnoat\n\t" \
"1:"user_lb("%0", "3(%2)")"\n\t" \
"2:"user_lbu("$1", "2(%2)")"\n\t" \
"1:"type##_lb("%0", "3(%2)")"\n\t" \
"2:"type##_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "1(%2)")"\n\t" \
"3:"type##_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "0(%2)")"\n\t" \
"4:"type##_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -529,11 +529,11 @@ extern void show_registers(struct pt_regs *regs);
#endif /* CONFIG_CPU_MIPSR6 */
#define LoadHWU(addr, value, res) \
#define _LoadHWU(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\t"user_lbu("%0", "1(%2)")"\n" \
"2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"1:\t"type##_lbu("%0", "1(%2)")"\n" \
"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -552,10 +552,10 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadWU(addr, value, res) \
#define _LoadWU(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "3(%2)")"\n" \
"2:\t"user_lwr("%0", "(%2)")"\n\t" \
"1:\t"type##_lwl("%0", "3(%2)")"\n" \
"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
......@@ -572,7 +572,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
#define _LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tldl\t%0, 7(%2)\n" \
"2:\tldr\t%0, (%2)\n\t" \
......@@ -591,18 +591,18 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has not lwl and ldl instructions */
#define LoadWU(addr, value, res) \
#define _LoadWU(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_lbu("%0", "3(%2)")"\n\t" \
"2:"user_lbu("$1", "2(%2)")"\n\t" \
"1:"type##_lbu("%0", "3(%2)")"\n\t" \
"2:"type##_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "1(%2)")"\n\t" \
"3:"type##_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "0(%2)")"\n\t" \
"4:"type##_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
......@@ -622,7 +622,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
#define _LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
......@@ -670,12 +670,12 @@ extern void show_registers(struct pt_regs *regs);
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define StoreHW(addr, value, res) \
#define _StoreHW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\t"user_sb("%1", "0(%2)")"\n" \
"1:\t"type##_sb("%1", "0(%2)")"\n" \
"srl\t$1,%1, 0x8\n" \
"2:\t"user_sb("$1", "1(%2)")"\n" \
"2:\t"type##_sb("$1", "1(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
......@@ -691,10 +691,10 @@ extern void show_registers(struct pt_regs *regs);
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define StoreW(addr, value, res) \
#define _StoreW(addr, value, res, type) \
__asm__ __volatile__ ( \
"1:\t"user_swl("%1", "3(%2)")"\n" \
"2:\t"user_swr("%1", "(%2)")"\n\t" \
"1:\t"type##_swl("%1", "3(%2)")"\n" \
"2:\t"type##_swr("%1", "(%2)")"\n\t"\
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
......@@ -709,7 +709,7 @@ extern void show_registers(struct pt_regs *regs);
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreDW(addr, value, res) \
#define _StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tsdl\t%1, 7(%2)\n" \
"2:\tsdr\t%1, (%2)\n\t" \
......@@ -728,17 +728,17 @@ extern void show_registers(struct pt_regs *regs);
: "r" (value), "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no swl and sdl instructions */
#define StoreW(addr, value, res) \
#define _StoreW(addr, value, res, type) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_sb("%1", "0(%2)")"\n\t" \
"1:"type##_sb("%1", "0(%2)")"\n\t" \
"srl\t$1, %1, 0x8\n\t" \
"2:"user_sb("$1", "1(%2)")"\n\t" \
"2:"type##_sb("$1", "1(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"3:"user_sb("$1", "2(%2)")"\n\t" \
"3:"type##_sb("$1", "2(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"4:"user_sb("$1", "3(%2)")"\n\t" \
"4:"type##_sb("$1", "3(%2)")"\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
......@@ -757,7 +757,7 @@ extern void show_registers(struct pt_regs *regs);
: "r" (value), "r" (addr), "i" (-EFAULT) \
: "memory");
#define StoreDW(addr, value, res) \
#define _StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
......@@ -801,6 +801,22 @@ extern void show_registers(struct pt_regs *regs);
#endif /* CONFIG_CPU_MIPSR6 */
#endif
#define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel)
#define LoadHWUE(addr, value, res) _LoadHWU(addr, value, res, user)
#define LoadWU(addr, value, res) _LoadWU(addr, value, res, kernel)
#define LoadWUE(addr, value, res) _LoadWU(addr, value, res, user)
#define LoadHW(addr, value, res) _LoadHW(addr, value, res, kernel)
#define LoadHWE(addr, value, res) _LoadHW(addr, value, res, user)
#define LoadW(addr, value, res) _LoadW(addr, value, res, kernel)
#define LoadWE(addr, value, res) _LoadW(addr, value, res, user)
#define LoadDW(addr, value, res) _LoadDW(addr, value, res)
#define StoreHW(addr, value, res) _StoreHW(addr, value, res, kernel)
#define StoreHWE(addr, value, res) _StoreHW(addr, value, res, user)
#define StoreW(addr, value, res) _StoreW(addr, value, res, kernel)
#define StoreWE(addr, value, res) _StoreW(addr, value, res, user)
#define StoreDW(addr, value, res) _StoreDW(addr, value, res)
static void emulate_load_store_insn(struct pt_regs *regs,
void __user *addr, unsigned int __user *pc)
{
......@@ -872,7 +888,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
set_fs(seg);
goto sigbus;
}
LoadHW(addr, value, res);
LoadHWE(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
......@@ -885,7 +901,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
set_fs(seg);
goto sigbus;
}
LoadW(addr, value, res);
LoadWE(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
......@@ -898,7 +914,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
set_fs(seg);
goto sigbus;
}
LoadHWU(addr, value, res);
LoadHWUE(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
......@@ -913,7 +929,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
}
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreHW(addr, value, res);
StoreHWE(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
......@@ -926,7 +942,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
}
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreW(addr, value, res);
StoreWE(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment