Added safe user memory access APIs
[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 <ex_table.h>
14 #include <arch/uaccess.h>
15 #include <sort.h>
16
17 extern struct extable_ip_fixup __start___ex_table;
18 extern struct extable_ip_fixup __stop___ex_table;
19
20 static int fixup_cmp(const void *f1, const void *f2)
21 {
22         return ((const struct extable_ip_fixup *) f1)->insn <
23                 ((const struct extable_ip_fixup *) f2)->insn ? -1 : 1;
24 }
25
26 void exception_table_init(void)
27 {
28         struct extable_ip_fixup *first = &__start___ex_table;
29         struct extable_ip_fixup *last = &__stop___ex_table;
30         uint64_t offset = 0;
31
32         for (struct extable_ip_fixup *fx = first; fx < last; fx++) {
33                 fx->insn += offset;
34                 offset += sizeof(fx->insn);
35                 fx->fixup += offset;
36                 offset += sizeof(fx->fixup);
37         }
38
39         sort(first, last - first, sizeof(*first), fixup_cmp);
40
41         offset = 0;
42         for (struct extable_ip_fixup *fx = first; fx < last; fx++) {
43                 fx->insn -= offset;
44                 offset += sizeof(fx->insn);
45                 fx->fixup -= offset;
46                 offset += sizeof(fx->fixup);
47         }
48
49         /* Avoid undefined __start___ex_table and __stop___ex_table errors when
50          * no code is using the exception table facility.
51          */
52         _ASM_EXTABLE_INIT();
53 }
54
55 uintptr_t get_fixup_ip(uintptr_t xip)
56 {
57         const struct extable_ip_fixup *first = &__start___ex_table;
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         return 0;
73 }