mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

Remove EX_TABLE_UA_LOAD_MEM exception handling and replace it with EX_TABLE_UA_FAULT. Open code the return code check, and also open code setting of the destination to zero in case of an error. In almost all cases the compiler is able to optimize the open coded checks away, since all users of get_users() must check the return code, and are not supposed to use the result in case of an error. In addition this allows to change the get_user() inline assembly so that the "Q" constraint can be used for the destination, instead of only an "a" constraint. This generates slightly better code. Acked-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
101 lines
2.7 KiB
C
101 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/bitfield.h>
|
|
#include <linux/extable.h>
|
|
#include <linux/string.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/panic.h>
|
|
#include <asm/asm-extable.h>
|
|
#include <asm/extable.h>
|
|
#include <asm/fpu.h>
|
|
|
|
const struct exception_table_entry *s390_search_extables(unsigned long addr)
|
|
{
|
|
const struct exception_table_entry *fixup;
|
|
size_t num;
|
|
|
|
fixup = search_exception_tables(addr);
|
|
if (fixup)
|
|
return fixup;
|
|
num = __stop_amode31_ex_table - __start_amode31_ex_table;
|
|
return search_extable(__start_amode31_ex_table, num, addr);
|
|
}
|
|
|
|
static bool ex_handler_fixup(const struct exception_table_entry *ex, struct pt_regs *regs)
|
|
{
|
|
regs->psw.addr = extable_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
static bool ex_handler_ua_fault(const struct exception_table_entry *ex, struct pt_regs *regs)
|
|
{
|
|
unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
|
|
|
|
regs->gprs[reg_err] = -EFAULT;
|
|
regs->psw.addr = extable_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex,
|
|
bool pair, struct pt_regs *regs)
|
|
{
|
|
unsigned int reg_zero = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
|
|
unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
|
|
|
|
regs->gprs[reg_err] = -EFAULT;
|
|
regs->gprs[reg_zero] = 0;
|
|
if (pair)
|
|
regs->gprs[reg_zero + 1] = 0;
|
|
regs->psw.addr = extable_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
static bool ex_handler_zeropad(const struct exception_table_entry *ex, struct pt_regs *regs)
|
|
{
|
|
unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
|
|
unsigned int reg_data = FIELD_GET(EX_DATA_REG_ERR, ex->data);
|
|
unsigned long data, addr, offset;
|
|
|
|
addr = regs->gprs[reg_addr];
|
|
offset = addr & (sizeof(unsigned long) - 1);
|
|
addr &= ~(sizeof(unsigned long) - 1);
|
|
data = *(unsigned long *)addr;
|
|
data <<= BITS_PER_BYTE * offset;
|
|
regs->gprs[reg_data] = data;
|
|
regs->psw.addr = extable_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
static bool ex_handler_fpc(const struct exception_table_entry *ex, struct pt_regs *regs)
|
|
{
|
|
fpu_sfpc(0);
|
|
regs->psw.addr = extable_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
bool fixup_exception(struct pt_regs *regs)
|
|
{
|
|
const struct exception_table_entry *ex;
|
|
|
|
ex = s390_search_extables(instruction_pointer(regs));
|
|
if (!ex)
|
|
return false;
|
|
switch (ex->type) {
|
|
case EX_TYPE_FIXUP:
|
|
return ex_handler_fixup(ex, regs);
|
|
case EX_TYPE_BPF:
|
|
return ex_handler_bpf(ex, regs);
|
|
case EX_TYPE_UA_FAULT:
|
|
return ex_handler_ua_fault(ex, regs);
|
|
case EX_TYPE_UA_LOAD_REG:
|
|
return ex_handler_ua_load_reg(ex, false, regs);
|
|
case EX_TYPE_UA_LOAD_REGPAIR:
|
|
return ex_handler_ua_load_reg(ex, true, regs);
|
|
case EX_TYPE_ZEROPAD:
|
|
return ex_handler_zeropad(ex, regs);
|
|
case EX_TYPE_FPC:
|
|
return ex_handler_fpc(ex, regs);
|
|
}
|
|
panic("invalid exception table entry");
|
|
}
|