Use the better hash multiplier for __generic_hash
[akaros.git] / kern / src / ex_table.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * See LICENSE for details.
4  *
5  * Part of this code coming from a Linux kernel file:
6  *
7  * linux/arch/x86/mm/extable.c
8  *
9  * Which, even though missing specific copyright, it is supposed to be
10  * ruled by the overall Linux copyright.
11  */
12
13 #include <arch/uaccess.h>
14 #include <compiler.h>
15 #include <sort.h>
16 #include <ex_table.h>
17
18 extern struct extable_ip_fixup __attribute__((weak)) __start___ex_table[];
19 extern struct extable_ip_fixup __attribute__((weak)) __stop___ex_table[];
20
21 static int fixup_cmp(const void *f1, const void *f2)
22 {
23         return ((const struct extable_ip_fixup *) f1)->insn <
24                 ((const struct extable_ip_fixup *) f2)->insn ? -1 : 1;
25 }
26
27 void exception_table_init(void)
28 {
29         if (__start___ex_table) {
30                 struct extable_ip_fixup *first = __start___ex_table;
31                 struct extable_ip_fixup *last = __stop___ex_table;
32                 uint64_t offset = 0;
33
34                 for (struct extable_ip_fixup *fx = first; fx < last; fx++) {
35                         fx->insn += offset;
36                         offset += sizeof(fx->insn);
37                         fx->fixup += offset;
38                         offset += sizeof(fx->fixup);
39                 }
40
41                 sort(first, last - first, sizeof(*first), fixup_cmp);
42
43                 offset = 0;
44                 for (struct extable_ip_fixup *fx = first; fx < last; fx++) {
45                         fx->insn -= offset;
46                         offset += sizeof(fx->insn);
47                         fx->fixup -= offset;
48                         offset += sizeof(fx->fixup);
49                 }
50         }
51 }
52
53 uintptr_t get_fixup_ip(uintptr_t xip)
54 {
55         const struct extable_ip_fixup *first = __start___ex_table;
56
57         if (likely(first)) {
58                 const struct extable_ip_fixup *last = __stop___ex_table;
59
60                 while (first <= last) {
61                         const struct extable_ip_fixup *x = first + ((last - first) >> 1);
62                         uintptr_t insn = ex_insn_addr(x);
63
64                         if (insn < xip)
65                                 first = x + 1;
66                         else if (insn > xip)
67                                 last = x - 1;
68                         else
69                                 return (uintptr_t) ex_fixup_addr(x);
70                 }
71         }
72
73         return 0;
74 }