Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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 }