File: /usr/src/linux/arch/s390/mm/extable.c

1     /*
2      *  arch/s390/mm/extable.c
3      *
4      *  S390 version
5      *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6      *    Author(s): Hartmut Penner (hp@de.ibm.com)
7      *
8      *  Derived from "arch/i386/mm/extable.c"
9      */
10     
11     #include <linux/config.h>
12     #include <linux/module.h>
13     #include <asm/uaccess.h>
14     
15     extern const struct exception_table_entry __start___ex_table[];
16     extern const struct exception_table_entry __stop___ex_table[];
17     
18     static inline unsigned long
19     search_one_table(const struct exception_table_entry *first,
20     		 const struct exception_table_entry *last,
21     		 unsigned long value)
22     {
23             while (first <= last) {
24     		const struct exception_table_entry *mid;
25     		long diff;
26     
27     		mid = (last - first) / 2 + first;
28     		diff = mid->insn - value;
29                     if (diff == 0)
30                             return mid->fixup;
31                     else if (diff < 0)
32                             first = mid+1;
33                     else
34                             last = mid-1;
35             }
36             return 0;
37     }
38     
39     unsigned long
40     search_exception_table(unsigned long addr)
41     {
42     	unsigned long ret;
43     
44     #ifndef CONFIG_MODULES
45             addr &= 0x7fffffff;  /* remove amode bit from address */
46     	/* There is only the kernel to search.  */
47     	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
48     	if (ret) return FIX_PSW(ret);
49     #else
50     	/* The kernel is the last "module" -- no need to treat it special.  */
51     	struct module *mp;
52             addr &= 0x7fffffff;  /* remove amode bit from address */
53     	for (mp = module_list; mp != NULL; mp = mp->next) {
54     		if (mp->ex_table_start == NULL)
55     			continue;
56     		ret = search_one_table(mp->ex_table_start,
57     				       mp->ex_table_end - 1, addr);
58     		if (ret) return FIX_PSW(ret);
59     	}
60     #endif
61     
62     	return 0;
63     }
64