123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- // 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>
- 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_store(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_mem(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_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
- size_t len = FIELD_GET(EX_DATA_LEN, ex->data);
- regs->gprs[reg_err] = -EFAULT;
- memset((void *)regs->gprs[reg_addr], 0, len);
- regs->psw.addr = extable_fixup(ex);
- return true;
- }
- static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex, 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;
- 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_STORE:
- return ex_handler_ua_store(ex, regs);
- case EX_TYPE_UA_LOAD_MEM:
- return ex_handler_ua_load_mem(ex, regs);
- case EX_TYPE_UA_LOAD_REG:
- return ex_handler_ua_load_reg(ex, regs);
- }
- panic("invalid exception table entry");
- }
|