forked from Minki/linux
sparc32: switch to generic extables
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
c4da8e0dc6
commit
b4edf06c8a
@ -8,7 +8,6 @@
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/extable_64.h>
|
||||
#include <asm/spitfire.h>
|
||||
#include <asm/adi.h>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_EXTABLE64_H
|
||||
#define __ASM_EXTABLE64_H
|
||||
#ifndef __ASM_EXTABLE_H
|
||||
#define __ASM_EXTABLE_H
|
||||
/*
|
||||
* The exception table consists of pairs of addresses: the first is the
|
||||
* address of an instruction that is allowed to fault, and the second is
|
@ -1,6 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef ___ASM_SPARC_UACCESS_H
|
||||
#define ___ASM_SPARC_UACCESS_H
|
||||
|
||||
#include <asm/extable.h>
|
||||
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm/uaccess_64.h>
|
||||
#else
|
||||
|
@ -13,9 +13,6 @@
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
#define ARCH_HAS_SORT_EXTABLE
|
||||
#define ARCH_HAS_SEARCH_EXTABLE
|
||||
|
||||
/* Sparc is not segmented, however we need to be able to fool access_ok()
|
||||
* when doing system calls from kernel mode legitimately.
|
||||
*
|
||||
@ -40,36 +37,6 @@
|
||||
#define __access_ok(addr, size) (__user_ok((addr) & get_fs().seg, (size)))
|
||||
#define access_ok(addr, size) __access_ok((unsigned long)(addr), size)
|
||||
|
||||
/*
|
||||
* The exception table consists of pairs of addresses: the first is the
|
||||
* address of an instruction that is allowed to fault, and the second is
|
||||
* the address at which the program should continue. No registers are
|
||||
* modified, so it is entirely up to the continuation code to figure out
|
||||
* what to do.
|
||||
*
|
||||
* 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,
|
||||
* we don't even have to jump over them. Further, they do not intrude
|
||||
* on our cache or tlb entries.
|
||||
*
|
||||
* There is a special way how to put a range of potentially faulting
|
||||
* insns (like twenty ldd/std's with now intervening other instructions)
|
||||
* You specify address of first in insn and 0 in fixup and in the next
|
||||
* exception_table_entry you specify last potentially faulting insn + 1
|
||||
* and in fixup the routine which should handle the fault.
|
||||
* That fixup code will get
|
||||
* (faulting_insn_address - first_insn_in_the_range_address)/4
|
||||
* in %g2 (ie. index of the faulting instruction in the range).
|
||||
*/
|
||||
|
||||
struct exception_table_entry
|
||||
{
|
||||
unsigned long insn, fixup;
|
||||
};
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
unsigned long search_extables_range(unsigned long addr, unsigned long *g2);
|
||||
|
||||
/* Uh, these should become the main single-value transfer routines..
|
||||
* They automatically use the right size if we just have the right
|
||||
* pointer type..
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/string.h>
|
||||
#include <asm/asi.h>
|
||||
#include <asm/spitfire.h>
|
||||
#include <asm/extable_64.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/extable.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
|
||||
@ -213,10 +214,10 @@ static inline int ok_for_kernel(unsigned int insn)
|
||||
|
||||
static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
|
||||
{
|
||||
unsigned long g2 = regs->u_regs [UREG_G2];
|
||||
unsigned long fixup = search_extables_range(regs->pc, &g2);
|
||||
const struct exception_table_entry *entry;
|
||||
|
||||
if (!fixup) {
|
||||
entry = search_exception_tables(regs->pc);
|
||||
if (!entry) {
|
||||
unsigned long address = compute_effective_address(regs, insn);
|
||||
if(address < PAGE_SIZE) {
|
||||
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
|
||||
@ -232,9 +233,8 @@ static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
|
||||
die_if_kernel("Oops", regs);
|
||||
/* Not reached */
|
||||
}
|
||||
regs->pc = fixup;
|
||||
regs->pc = entry->fixup;
|
||||
regs->npc = regs->pc + 4;
|
||||
regs->u_regs [UREG_G2] = g2;
|
||||
}
|
||||
|
||||
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
|
||||
|
@ -8,7 +8,7 @@ ccflags-y := -Werror
|
||||
obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o
|
||||
obj-y += fault_$(BITS).o
|
||||
obj-y += init_$(BITS).o
|
||||
obj-$(CONFIG_SPARC32) += extable.o srmmu.o iommu.o io-unit.o
|
||||
obj-$(CONFIG_SPARC32) += srmmu.o iommu.o io-unit.o
|
||||
obj-$(CONFIG_SPARC32) += srmmu_access.o
|
||||
obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o
|
||||
obj-$(CONFIG_SPARC32) += leon_mm.o
|
||||
|
@ -1,107 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* linux/arch/sparc/mm/extable.c
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/extable.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
void sort_extable(struct exception_table_entry *start,
|
||||
struct exception_table_entry *finish)
|
||||
{
|
||||
}
|
||||
|
||||
/* Caller knows they are in a range if ret->fixup == 0 */
|
||||
const struct exception_table_entry *
|
||||
search_extable(const struct exception_table_entry *base,
|
||||
const size_t num,
|
||||
unsigned long value)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Single insn entries are encoded as:
|
||||
* word 1: insn address
|
||||
* word 2: fixup code address
|
||||
*
|
||||
* Range entries are encoded as:
|
||||
* word 1: first insn address
|
||||
* word 2: 0
|
||||
* word 3: last insn address + 4 bytes
|
||||
* word 4: fixup code address
|
||||
*
|
||||
* Deleted entries are encoded as:
|
||||
* word 1: unused
|
||||
* word 2: -1
|
||||
*
|
||||
* See asm/uaccess.h for more details.
|
||||
*/
|
||||
|
||||
/* 1. Try to find an exact match. */
|
||||
for (i = 0; i < num; i++) {
|
||||
if (base[i].fixup == 0) {
|
||||
/* A range entry, skip both parts. */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A deleted entry; see trim_init_extable */
|
||||
if (base[i].fixup == -1)
|
||||
continue;
|
||||
|
||||
if (base[i].insn == value)
|
||||
return &base[i];
|
||||
}
|
||||
|
||||
/* 2. Try to find a range match. */
|
||||
for (i = 0; i < (num - 1); i++) {
|
||||
if (base[i].fixup)
|
||||
continue;
|
||||
|
||||
if (base[i].insn <= value && base[i + 1].insn > value)
|
||||
return &base[i];
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
/* We could memmove them around; easier to mark the trimmed ones. */
|
||||
void trim_init_extable(struct module *m)
|
||||
{
|
||||
unsigned int i;
|
||||
bool range;
|
||||
|
||||
for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
|
||||
range = m->extable[i].fixup == 0;
|
||||
|
||||
if (within_module_init(m->extable[i].insn, m)) {
|
||||
m->extable[i].fixup = -1;
|
||||
if (range)
|
||||
m->extable[i+1].fixup = -1;
|
||||
}
|
||||
if (range)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
/* Special extable search, which handles ranges. Returns fixup */
|
||||
unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
|
||||
{
|
||||
const struct exception_table_entry *entry;
|
||||
|
||||
entry = search_exception_tables(addr);
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
/* Inside range? Fix g2 and return correct fixup */
|
||||
if (!entry->fixup) {
|
||||
*g2 = (addr - entry->insn) / 4;
|
||||
return (entry + 1)->fixup;
|
||||
}
|
||||
|
||||
return entry->fixup;
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/extable.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/openprom.h>
|
||||
@ -114,8 +115,6 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
|
||||
struct vm_area_struct *vma;
|
||||
struct task_struct *tsk = current;
|
||||
struct mm_struct *mm = tsk->mm;
|
||||
unsigned int fixup;
|
||||
unsigned long g2;
|
||||
int from_user = !(regs->psr & PSR_PS);
|
||||
int code;
|
||||
vm_fault_t fault;
|
||||
@ -233,23 +232,20 @@ bad_area_nosemaphore:
|
||||
|
||||
/* Is this in ex_table? */
|
||||
no_context:
|
||||
g2 = regs->u_regs[UREG_G2];
|
||||
if (!from_user) {
|
||||
fixup = search_extables_range(regs->pc, &g2);
|
||||
/* Values below 10 are reserved for other things */
|
||||
if (fixup > 10) {
|
||||
const struct exception_table_entry *entry;
|
||||
|
||||
entry = search_exception_tables(regs->pc);
|
||||
#ifdef DEBUG_EXCEPTIONS
|
||||
printk("Exception: PC<%08lx> faddr<%08lx>\n",
|
||||
regs->pc, address);
|
||||
printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
|
||||
regs->pc, fixup, g2);
|
||||
printk("EX_TABLE: insn<%08lx> fixup<%08x>\n",
|
||||
regs->pc, entry->fixup);
|
||||
#endif
|
||||
regs->u_regs[UREG_G2] = g2;
|
||||
regs->pc = fixup;
|
||||
regs->pc = entry->fixup;
|
||||
regs->npc = regs->pc + 4;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unhandled_fault(address, tsk, regs);
|
||||
do_exit(SIGKILL);
|
||||
|
@ -21,7 +21,6 @@ static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ARCH_HAS_SORT_EXTABLE
|
||||
#ifndef ARCH_HAS_RELATIVE_EXTABLE
|
||||
#define swap_ex NULL
|
||||
#else
|
||||
@ -88,9 +87,6 @@ void trim_init_extable(struct module *m)
|
||||
m->num_exentries--;
|
||||
}
|
||||
#endif /* CONFIG_MODULES */
|
||||
#endif /* !ARCH_HAS_SORT_EXTABLE */
|
||||
|
||||
#ifndef ARCH_HAS_SEARCH_EXTABLE
|
||||
|
||||
static int cmp_ex_search(const void *key, const void *elt)
|
||||
{
|
||||
@ -120,4 +116,3 @@ search_extable(const struct exception_table_entry *base,
|
||||
return bsearch(&value, base, num,
|
||||
sizeof(struct exception_table_entry), cmp_ex_search);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user