Commit d70aa010 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: unified extable code.

update extable support in s390 and s390x

this makes use of the unified extable code.
for 31 bit s390, this is slightly more complicated
than the other architectures, but as long as
no one outside /arch uses search_exception_tables,
everything should work nicely
parent 99743175
......@@ -268,9 +268,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
}
#endif
} else {
unsigned long fixup = search_exception_table(regs->psw.addr);
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->psw.addr & 0x7fffffff);
if (fixup)
regs->psw.addr = fixup;
regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE31;
else
die(str, regs, interruption_code);
}
......
......@@ -2,10 +2,8 @@
* arch/s390/mm/extable.c
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Hartmut Penner (hp@de.ibm.com)
*
* Derived from "arch/i386/mm/extable.c"
* identical to arch/i386/mm/extable.c
*/
#include <linux/config.h>
......@@ -13,63 +11,24 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
/* Simple binary search */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
while (first <= last) {
while (first <= last) {
const struct exception_table_entry *mid;
long diff;
mid = (last - first) / 2 + first;
diff = mid->insn - value;
if (diff == 0)
return mid->fixup;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
return 0;
}
extern spinlock_t modlist_lock;
unsigned long
search_exception_table(unsigned long addr)
{
struct list_head *i;
unsigned long ret = 0;
#ifndef CONFIG_MODULES
addr &= 0x7fffffff; /* remove amode bit from address */
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
if (ret) ret = ret | PSW_ADDR_AMODE31;
return ret;
#else
unsigned long flags;
addr &= 0x7fffffff; /* remove amode bit from address */
/* The kernel is the last "module" -- no need to treat it special. */
spin_lock_irqsave(&modlist_lock, flags);
list_for_each(i, &extables) {
struct exception_table *ex
= list_entry(i, struct exception_table, list);
if (ex->num_entries == 0)
continue;
ret = search_one_table(ex->entry,
ex->entry + ex->num_entries - 1, addr);
if (ret) {
ret = ret | PSW_ADDR_AMODE31;
break;
}
if (diff == 0)
return mid;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
spin_unlock_irqrestore(&modlist_lock, flags);
return ret;
#endif
return NULL;
}
......@@ -25,6 +25,7 @@
#include <linux/compatmac.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
......@@ -151,7 +152,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
struct vm_area_struct * vma;
unsigned long address;
int user_address;
unsigned long fixup;
const struct exception_table_entry *fixup;
int si_code = SEGV_MAPERR;
tsk = current;
......@@ -267,8 +268,9 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
no_context:
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
regs->psw.addr = fixup;
fixup = search_exception_tables(regs->psw.addr & 0x7fffffff);
if (fixup) {
regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE31;
return;
}
......
......@@ -269,9 +269,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
}
#endif
} else {
unsigned long fixup = search_exception_table(regs->psw.addr);
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->psw.addr);
if (fixup)
regs->psw.addr = fixup;
regs->psw.addr = fixup->fixup;
else
die(str, regs, interruption_code);
}
......
......@@ -11,58 +11,24 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
/* Simple binary search */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
while (first <= last) {
while (first <= last) {
const struct exception_table_entry *mid;
long diff;
mid = (last - first) / 2 + first;
diff = mid->insn - value;
if (diff == 0)
return mid->fixup;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
return 0;
}
extern spinlock_t modlist_lock;
unsigned long
search_exception_table(unsigned long addr)
{
unsigned long ret = 0;
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
return ret;
#else
unsigned long flags;
struct list_head *i;
/* The kernel is the last "module" -- no need to treat it special. */
spin_lock_irqsave(&modlist_lock, flags);
list_for_each(i, &extables) {
struct exception_table *ex
= list_entry(i, struct exception_table, list);
if (ex->num_entries == 0)
continue;
ret = search_one_table(ex->entry,
ex->entry + ex->num_entries - 1, addr);
if (ret)
break;
if (diff == 0)
return mid;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
spin_unlock_irqrestore(&modlist_lock, flags);
return ret;
#endif
return NULL;
}
......@@ -24,6 +24,7 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
......@@ -151,7 +152,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
struct vm_area_struct * vma;
unsigned long address;
int user_address;
unsigned long fixup;
const struct exception_table_entry *fixup;
int si_code = SEGV_MAPERR;
tsk = current;
......@@ -267,8 +268,9 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
no_context:
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
regs->psw.addr = fixup;
fixup = search_exception_tables(regs->psw.addr);
if (fixup) {
regs->psw.addr = fixup->fixup;
return;
}
......
......@@ -71,10 +71,6 @@ struct exception_table_entry
unsigned long insn, fixup;
};
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
......
......@@ -71,10 +71,6 @@ struct exception_table_entry
unsigned long insn, fixup;
};
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment