Commit 6c94f27a authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Catalin Marinas

arm64: switch to relative exception tables

Instead of using absolute addresses for both the exception location
and the fixup, use offsets relative to the exception table entry values.
Not only does this cut the size of the exception table in half, it is
also a prerequisite for KASLR, since absolute exception table entries
are subject to dynamic relocation, which is incompatible with the sorting
of the exception table that occurs at build time.

This patch also introduces the _ASM_EXTABLE preprocessor macro (which
exists on x86 as well) and its _asm_extable assembly counterpart, as
shorthands to emit exception table entries.
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent a272858a
...@@ -157,11 +157,8 @@ void apply_alternatives(void *start, size_t length); ...@@ -157,11 +157,8 @@ void apply_alternatives(void *start, size_t length);
add \addr, \addr, \post_inc; add \addr, \addr, \post_inc;
alternative_endif alternative_endif
.section __ex_table,"a"; _asm_extable 8888b,\l;
.align 3; _asm_extable 8889b,\l;
.quad 8888b,\l;
.quad 8889b,\l;
.previous;
.endm .endm
.macro uao_stp l, reg1, reg2, addr, post_inc .macro uao_stp l, reg1, reg2, addr, post_inc
...@@ -175,11 +172,8 @@ void apply_alternatives(void *start, size_t length); ...@@ -175,11 +172,8 @@ void apply_alternatives(void *start, size_t length);
add \addr, \addr, \post_inc; add \addr, \addr, \post_inc;
alternative_endif alternative_endif
.section __ex_table,"a"; _asm_extable 8888b,\l;
.align 3; _asm_extable 8889b,\l;
.quad 8888b,\l;
.quad 8889b,\l;
.previous
.endm .endm
.macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
...@@ -191,10 +185,7 @@ void apply_alternatives(void *start, size_t length); ...@@ -191,10 +185,7 @@ void apply_alternatives(void *start, size_t length);
add \addr, \addr, \post_inc; add \addr, \addr, \post_inc;
alternative_endif alternative_endif
.section __ex_table,"a"; _asm_extable 8888b,\l;
.align 3;
.quad 8888b,\l;
.previous
.endm .endm
#else #else
.macro uao_ldp l, reg1, reg2, addr, post_inc .macro uao_ldp l, reg1, reg2, addr, post_inc
......
...@@ -94,12 +94,19 @@ ...@@ -94,12 +94,19 @@
dmb \opt dmb \opt
.endm .endm
/*
* Emit an entry into the exception table
*/
.macro _asm_extable, from, to
.pushsection __ex_table, "a"
.align 3
.long (\from - .), (\to - .)
.popsection
.endm
#define USER(l, x...) \ #define USER(l, x...) \
9999: x; \ 9999: x; \
.section __ex_table,"a"; \ _asm_extable 9999b, l
.align 3; \
.quad 9999b,l; \
.previous
/* /*
* Register aliases. * Register aliases.
......
...@@ -42,10 +42,8 @@ ...@@ -42,10 +42,8 @@
"4: mov %w0, %w5\n" \ "4: mov %w0, %w5\n" \
" b 3b\n" \ " b 3b\n" \
" .popsection\n" \ " .popsection\n" \
" .pushsection __ex_table,\"a\"\n" \ _ASM_EXTABLE(1b, 4b) \
" .align 3\n" \ _ASM_EXTABLE(2b, 4b) \
" .quad 1b, 4b, 2b, 4b\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \ CONFIG_ARM64_PAN) \
: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \
...@@ -134,10 +132,8 @@ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN) ...@@ -134,10 +132,8 @@ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
"4: mov %w0, %w6\n" "4: mov %w0, %w6\n"
" b 3b\n" " b 3b\n"
" .popsection\n" " .popsection\n"
" .pushsection __ex_table,\"a\"\n" _ASM_EXTABLE(1b, 4b)
" .align 3\n" _ASM_EXTABLE(2b, 4b)
" .quad 1b, 4b, 2b, 4b\n"
" .popsection\n"
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN) ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp) : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
: "r" (oldval), "r" (newval), "Ir" (-EFAULT) : "r" (oldval), "r" (newval), "Ir" (-EFAULT)
......
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
#define VERIFY_WRITE 1 #define VERIFY_WRITE 1
/* /*
* The exception table consists of pairs of addresses: the first is the * The exception table consists of pairs of relative offsets: the first
* address of an instruction that is allowed to fault, and the second is * is the relative offset to an instruction that is allowed to fault,
* the address at which the program should continue. No registers are * and the second is the relative offset at which the program should
* modified, so it is entirely up to the continuation code to figure out * continue. No registers are modified, so it is entirely up to the
* what to do. * continuation code to figure out what to do.
* *
* All the routines below use bits of fixup code that are out of line * All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well, * with the main instruction path. This means when everything is well,
...@@ -50,9 +50,11 @@ ...@@ -50,9 +50,11 @@
struct exception_table_entry struct exception_table_entry
{ {
unsigned long insn, fixup; int insn, fixup;
}; };
#define ARCH_HAS_RELATIVE_EXTABLE
extern int fixup_exception(struct pt_regs *regs); extern int fixup_exception(struct pt_regs *regs);
#define KERNEL_DS (-1UL) #define KERNEL_DS (-1UL)
...@@ -115,6 +117,12 @@ static inline void set_fs(mm_segment_t fs) ...@@ -115,6 +117,12 @@ static inline void set_fs(mm_segment_t fs)
#define access_ok(type, addr, size) __range_ok(addr, size) #define access_ok(type, addr, size) __range_ok(addr, size)
#define user_addr_max get_fs #define user_addr_max get_fs
#define _ASM_EXTABLE(from, to) \
" .pushsection __ex_table, \"a\"\n" \
" .align 3\n" \
" .long (" #from " - .), (" #to " - .)\n" \
" .popsection\n"
/* /*
* The "__xxx" versions of the user access functions do not verify the address * The "__xxx" versions of the user access functions do not verify the address
* space - it must have been done previously with a separate "access_ok()" * space - it must have been done previously with a separate "access_ok()"
...@@ -134,10 +142,7 @@ static inline void set_fs(mm_segment_t fs) ...@@ -134,10 +142,7 @@ static inline void set_fs(mm_segment_t fs)
" mov %1, #0\n" \ " mov %1, #0\n" \
" b 2b\n" \ " b 2b\n" \
" .previous\n" \ " .previous\n" \
" .section __ex_table,\"a\"\n" \ _ASM_EXTABLE(1b, 3b) \
" .align 3\n" \
" .quad 1b, 3b\n" \
" .previous" \
: "+r" (err), "=&r" (x) \ : "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT)) : "r" (addr), "i" (-EFAULT))
...@@ -206,10 +211,7 @@ do { \ ...@@ -206,10 +211,7 @@ do { \
"3: mov %w0, %3\n" \ "3: mov %w0, %3\n" \
" b 2b\n" \ " b 2b\n" \
" .previous\n" \ " .previous\n" \
" .section __ex_table,\"a\"\n" \ _ASM_EXTABLE(1b, 3b) \
" .align 3\n" \
" .quad 1b, 3b\n" \
" .previous" \
: "+r" (err) \ : "+r" (err) \
: "r" (x), "r" (addr), "i" (-EFAULT)) : "r" (x), "r" (addr), "i" (-EFAULT))
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#ifndef __ASM_WORD_AT_A_TIME_H #ifndef __ASM_WORD_AT_A_TIME_H
#define __ASM_WORD_AT_A_TIME_H #define __ASM_WORD_AT_A_TIME_H
#include <asm/uaccess.h>
#ifndef __AARCH64EB__ #ifndef __AARCH64EB__
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -81,10 +83,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) ...@@ -81,10 +83,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
#endif #endif
" b 2b\n" " b 2b\n"
" .popsection\n" " .popsection\n"
" .pushsection __ex_table,\"a\"\n" _ASM_EXTABLE(1b, 3b)
" .align 3\n"
" .quad 1b, 3b\n"
" .popsection"
: "=&r" (ret), "=&r" (offset) : "=&r" (ret), "=&r" (offset)
: "r" (addr), "Q" (*(unsigned long *)addr)); : "r" (addr), "Q" (*(unsigned long *)addr));
......
...@@ -297,11 +297,8 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table) ...@@ -297,11 +297,8 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
"4: mov %w0, %w5\n" \ "4: mov %w0, %w5\n" \
" b 3b\n" \ " b 3b\n" \
" .popsection" \ " .popsection" \
" .pushsection __ex_table,\"a\"\n" \ _ASM_EXTABLE(0b, 4b) \
" .align 3\n" \ _ASM_EXTABLE(1b, 4b) \
" .quad 0b, 4b\n" \
" .quad 1b, 4b\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \ CONFIG_ARM64_PAN) \
: "=&r" (res), "+r" (data), "=&r" (temp) \ : "=&r" (res), "+r" (data), "=&r" (temp) \
......
...@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs) ...@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs)
fixup = search_exception_tables(instruction_pointer(regs)); fixup = search_exception_tables(instruction_pointer(regs));
if (fixup) if (fixup)
regs->pc = fixup->fixup; regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
return fixup != NULL; return fixup != NULL;
} }
...@@ -282,12 +282,12 @@ do_file(char const *const fname) ...@@ -282,12 +282,12 @@ do_file(char const *const fname)
case EM_386: case EM_386:
case EM_X86_64: case EM_X86_64:
case EM_S390: case EM_S390:
case EM_AARCH64:
custom_sort = sort_relative_table; custom_sort = sort_relative_table;
break; break;
case EM_ARCOMPACT: case EM_ARCOMPACT:
case EM_ARCV2: case EM_ARCV2:
case EM_ARM: case EM_ARM:
case EM_AARCH64:
case EM_MICROBLAZE: case EM_MICROBLAZE:
case EM_MIPS: case EM_MIPS:
case EM_XTENSA: case EM_XTENSA:
......
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