]> git.neil.brown.name Git - history.git/commitdiff
[SPARC32]: Copy over sparc64 exception table changes.
authorRob Radez <rob@osinvestor.com>
Thu, 9 Jan 2003 15:20:25 +0000 (07:20 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Thu, 9 Jan 2003 15:20:25 +0000 (07:20 -0800)
arch/sparc/kernel/unaligned.c
arch/sparc/mm/extable.c
arch/sparc/mm/fault.c
include/asm-sparc/uaccess.h

index d2f1b3363cb5fc79977a6fa0a705816c64b09a96..194ea9d5b6d8c268ededf586615a7b81b5ea6706 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -342,7 +343,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("ke
 void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
 {
        unsigned long g2 = regs->u_regs [UREG_G2];
-       unsigned long fixup = search_exception_table (regs->pc, &g2);
+       unsigned long fixup = search_extables_range(regs->pc, &g2);
 
        if (!fixup) {
                unsigned long address = compute_effective_address(regs, insn);
index b0d3f297b788b5e8eb7eed407e0bfd399a44b216..3d435860b5aa1cd014b1148455ea6ad12670b795 100644 (file)
@@ -6,13 +6,11 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
-
-static unsigned long
-search_one_table(const struct exception_table_entry *start,
-                const struct exception_table_entry *end,
-                unsigned long value, unsigned long *g2)
+/* Caller knows they are in a range if ret->fixup == 0 */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *start,
+              const struct exception_table_entry *last,
+              unsigned long value)
 {
        const struct exception_table_entry *walk;
 
@@ -30,7 +28,7 @@ search_one_table(const struct exception_table_entry *start,
         */
 
        /* 1. Try to find an exact match. */
-       for (walk = start; walk <= end; walk++) {
+       for (walk = start; walk <= last; walk++) {
                if (walk->fixup == 0) {
                        /* A range entry, skip both parts. */
                        walk++;
@@ -38,55 +36,37 @@ search_one_table(const struct exception_table_entry *start,
                }
 
                if (walk->insn == value)
-                       return walk->fixup;
+                       return walk;
        }
 
        /* 2. Try to find a range match. */
-       for (walk = start; walk <= (end - 1); walk++) {
+       for (walk = start; walk <= (last - 1); walk++) {
                if (walk->fixup)
                        continue;
 
-               if (walk[0].insn <= value &&
-                   walk[1].insn > value) {
-                       *g2 = (value - walk[0].insn) / 4;
-                       return walk[1].fixup;
-               }
+               if (walk[0].insn <= value && walk[1].insn > value)
+                       return walk;
+
                walk++;
        }
 
-        return 0;
+        return NULL;
 }
 
-extern spinlock_t modlist_lock;
-
-unsigned long
-search_exception_table(unsigned long addr, unsigned long *g2)
+/* Special extable search, which handles ranges.  Returns fixup */
+unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
 {
-       unsigned long ret = 0;
+       const struct exception_table_entry *entry;
 
-#ifndef CONFIG_MODULES
-       /* There is only the kernel to search.  */
-       ret = search_one_table(__start___ex_table,
-                              __stop___ex_table-1, addr, g2);
-       return ret;
-#else
-       unsigned long flags;
-       struct list_head *i;
+       entry = search_exception_tables(addr);
+       if (!entry)
+               return 0;
 
-       /* 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, g2);
-               if (ret)
-                       break;
+       /* Inside range?  Fix g2 and return correct fixup */
+       if (!entry->fixup) {
+               *g2 = (addr - entry->insn) / 4;
+               return (entry + 1)->fixup;
        }
-       spin_unlock_irqrestore(&modlist_lock, flags);
-       return ret;
-#endif
+
+       return entry->fixup;
 }
index e07d4d1017a9d1be5c3479c64dd1d7c10d40b351..e8ba587acfff6b39dc4ad1e5a4f7e1f0933cfa52 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -161,7 +162,7 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        unsigned int insn;
        int i;
        
-       i = search_exception_table(ret_pc, &g2);
+       i = search_extables_range(ret_pc, &g2);
        switch (i) {
        case 3:
                /* load & store will be handled by fixup */
@@ -316,7 +317,7 @@ bad_area_nosemaphore:
        /* Is this in ex_table? */
 no_context:
        g2 = regs->u_regs[UREG_G2];
-       if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
+       if (!from_user && (fixup = search_extables_range(regs->pc, &g2))) {
                if (fixup > 10) { /* Values below are reserved for other things */
                        extern const unsigned __memset_start[];
                        extern const unsigned __memset_end[];
index 57a8275b0784a7ce3b8a2ccae280bdd2e30cf40f..cff85b7a987863d7eba543ad748d021f3bdad782 100644 (file)
@@ -78,7 +78,7 @@ struct exception_table_entry
 };
 
 /* Returns 0 if exception not found and fixup otherwise.  */
-extern unsigned long search_exception_table(unsigned long, unsigned long *);
+extern unsigned long search_extables_range(unsigned long addr, unsigned long *g2);
 
 extern void __ret_efault(void);