0001
0002
0003 #include <linux/bitfield.h>
0004 #include <linux/extable.h>
0005 #include <linux/string.h>
0006 #include <linux/errno.h>
0007 #include <linux/panic.h>
0008 #include <asm/asm-extable.h>
0009 #include <asm/extable.h>
0010
0011 const struct exception_table_entry *s390_search_extables(unsigned long addr)
0012 {
0013 const struct exception_table_entry *fixup;
0014 size_t num;
0015
0016 fixup = search_exception_tables(addr);
0017 if (fixup)
0018 return fixup;
0019 num = __stop_amode31_ex_table - __start_amode31_ex_table;
0020 return search_extable(__start_amode31_ex_table, num, addr);
0021 }
0022
0023 static bool ex_handler_fixup(const struct exception_table_entry *ex, struct pt_regs *regs)
0024 {
0025 regs->psw.addr = extable_fixup(ex);
0026 return true;
0027 }
0028
0029 static bool ex_handler_ua_store(const struct exception_table_entry *ex, struct pt_regs *regs)
0030 {
0031 unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
0032
0033 regs->gprs[reg_err] = -EFAULT;
0034 regs->psw.addr = extable_fixup(ex);
0035 return true;
0036 }
0037
0038 static bool ex_handler_ua_load_mem(const struct exception_table_entry *ex, struct pt_regs *regs)
0039 {
0040 unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
0041 unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
0042 size_t len = FIELD_GET(EX_DATA_LEN, ex->data);
0043
0044 regs->gprs[reg_err] = -EFAULT;
0045 memset((void *)regs->gprs[reg_addr], 0, len);
0046 regs->psw.addr = extable_fixup(ex);
0047 return true;
0048 }
0049
0050 static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex, struct pt_regs *regs)
0051 {
0052 unsigned int reg_zero = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
0053 unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
0054
0055 regs->gprs[reg_err] = -EFAULT;
0056 regs->gprs[reg_zero] = 0;
0057 regs->psw.addr = extable_fixup(ex);
0058 return true;
0059 }
0060
0061 bool fixup_exception(struct pt_regs *regs)
0062 {
0063 const struct exception_table_entry *ex;
0064
0065 ex = s390_search_extables(instruction_pointer(regs));
0066 if (!ex)
0067 return false;
0068 switch (ex->type) {
0069 case EX_TYPE_FIXUP:
0070 return ex_handler_fixup(ex, regs);
0071 case EX_TYPE_BPF:
0072 return ex_handler_bpf(ex, regs);
0073 case EX_TYPE_UA_STORE:
0074 return ex_handler_ua_store(ex, regs);
0075 case EX_TYPE_UA_LOAD_MEM:
0076 return ex_handler_ua_load_mem(ex, regs);
0077 case EX_TYPE_UA_LOAD_REG:
0078 return ex_handler_ua_load_reg(ex, regs);
0079 }
0080 panic("invalid exception table entry");
0081 }