aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/extable.c
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2010-12-24 08:47:23 +0000
committerKeir Fraser <keir@xen.org>2010-12-24 08:47:23 +0000
commit0c4ff0fb92533aff947945f3562221a83bbfb941 (patch)
tree6c87342b77718bc05e02e23841051c8aa01d6abe /xen/arch/x86/extable.c
parentabf60d361232f53ad3c51fab74ff3b6f084d7f8e (diff)
downloadxen-0c4ff0fb92533aff947945f3562221a83bbfb941.tar.gz
xen-0c4ff0fb92533aff947945f3562221a83bbfb941.tar.bz2
xen-0c4ff0fb92533aff947945f3562221a83bbfb941.zip
x86-64: use PC-relative exception table entries
... thus allowing to make the entries half their current size. Rather than adjusting all instances to the new layout, abstract the construction the table entries via a macro (paralleling a similar one in recent Linux). Also change the name of the section (to allow easier detection of missed cases) and merge the final resulting output sections into .data.read_mostly. Signed-off-by: Jan Beulich <jbeulich@novell.com>
Diffstat (limited to 'xen/arch/x86/extable.c')
-rw-r--r--xen/arch/x86/extable.c68
1 files changed, 49 insertions, 19 deletions
diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c
index da822d34af..8c64585483 100644
--- a/xen/arch/x86/extable.c
+++ b/xen/arch/x86/extable.c
@@ -2,6 +2,7 @@
#include <xen/config.h>
#include <xen/init.h>
#include <xen/perfc.h>
+#include <xen/sort.h>
#include <xen/spinlock.h>
#include <asm/uaccess.h>
@@ -10,29 +11,58 @@ extern struct exception_table_entry __stop___ex_table[];
extern struct exception_table_entry __start___pre_ex_table[];
extern struct exception_table_entry __stop___pre_ex_table[];
-static void __init sort_exception_table(struct exception_table_entry *start,
- struct exception_table_entry *end)
+#ifdef __i386__
+#define EX_FIELD(ptr, field) (ptr)->field
+#define swap_ex NULL
+#else
+#define EX_FIELD(ptr, field) ((unsigned long)&(ptr)->field + (ptr)->field)
+#endif
+
+static inline unsigned long ex_addr(const struct exception_table_entry *x)
{
- struct exception_table_entry *p, *q, tmp;
+ return EX_FIELD(x, addr);
+}
- for ( p = start; p < end; p++ )
- {
- for ( q = p-1; q > start; q-- )
- if ( p->insn > q->insn )
- break;
- if ( ++q != p )
- {
- tmp = *p;
- memmove(q+1, q, (p-q)*sizeof(*p));
- *q = tmp;
- }
- }
+static inline unsigned long ex_cont(const struct exception_table_entry *x)
+{
+ return EX_FIELD(x, cont);
+}
+
+static int __init cmp_ex(const void *a, const void *b)
+{
+ const struct exception_table_entry *l = a, *r = b;
+ unsigned long lip = ex_addr(l);
+ unsigned long rip = ex_addr(r);
+
+ /* avoid overflow */
+ if (lip > rip)
+ return 1;
+ if (lip < rip)
+ return -1;
+ return 0;
+}
+
+#ifndef swap_ex
+static void __init swap_ex(void *a, void *b, int size)
+{
+ struct exception_table_entry *l = a, *r = b, tmp;
+ long delta = b - a;
+
+ tmp = *l;
+ l->addr = r->addr + delta;
+ l->cont = r->cont + delta;
+ r->addr = tmp.addr - delta;
+ r->cont = tmp.cont - delta;
}
+#endif
void __init sort_exception_tables(void)
{
- sort_exception_table(__start___ex_table, __stop___ex_table);
- sort_exception_table(__start___pre_ex_table, __stop___pre_ex_table);
+ sort(__start___ex_table, __stop___ex_table - __start___ex_table,
+ sizeof(struct exception_table_entry), cmp_ex, swap_ex);
+ sort(__start___pre_ex_table,
+ __stop___pre_ex_table - __start___pre_ex_table,
+ sizeof(struct exception_table_entry), cmp_ex, swap_ex);
}
static inline unsigned long
@@ -46,9 +76,9 @@ search_one_table(const struct exception_table_entry *first,
while ( first <= last )
{
mid = (last - first) / 2 + first;
- diff = mid->insn - value;
+ diff = ex_addr(mid) - value;
if (diff == 0)
- return mid->fixup;
+ return ex_cont(mid);
else if (diff < 0)
first = mid+1;
else