VMM: Use the I_POKE_CORE IRQ for posted IRQs
[akaros.git] / kern / arch / x86 / uaccess.h
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/include/asm/uaccess.h
8  *
9  * Which, even though missing specific copyright, it is supposed to be
10  * ruled by the overall Linux copyright.
11  */
12
13 #pragma once
14
15 #include <ros/errno.h>
16 #include <compiler.h>
17 #include <stdint.h>
18 #include <umem.h>
19
20 #define ASM_STAC
21 #define ASM_CLAC
22 #define __m(x) *(x)
23
24 struct extable_ip_fixup {
25         uint64_t insn;
26         uint64_t fixup;
27 };
28
29 #define _ASM_EXTABLE(from, to)                                                                  \
30         " .pushsection \"__ex_table\",\"a\"\n"                                          \
31         " .balign 16\n"                                                                                         \
32         " .quad (" #from ") - .\n"                                                                      \
33         " .quad (" #to ") - .\n"                                                                        \
34         " .popsection\n"
35
36 #define __read_msr_asm(eax, edx, addr, err, errret)                                             \
37         asm volatile(ASM_STAC "\n"                                                                                      \
38                                  "1:            rdmsr\n"                                                                        \
39                                  "                      mfence\n"                                                                       \
40                                  "2: " ASM_CLAC "\n"                                                                    \
41                                  ".section .fixup,\"ax\"\n"                                                             \
42                                  "3:            mov %4,%0\n"                                                            \
43                                  "      jmp 2b\n"                                                                                       \
44                                  ".previous\n"                                                                                  \
45                                  _ASM_EXTABLE(1b, 3b)                                                                   \
46                                  : "=r" (err), "=d" (edx), "=a" (eax)                                   \
47                                  : "c" (addr), "i" (errret), "0" (err))
48
49 #define __write_msr_asm(val, addr, err, errret)                                                 \
50         asm volatile(ASM_STAC "\n"                                                                                      \
51                                  "1:            wrmsr\n"                                                                        \
52                                  "2: " ASM_CLAC "\n"                                                                    \
53                                  ".section .fixup,\"ax\"\n"                                                             \
54                                  "3:            mov %4,%0\n"                                                            \
55                                  "      jmp 2b\n"                                                                                       \
56                                  ".previous\n"                                                                                  \
57                                  _ASM_EXTABLE(1b, 3b)                                                                   \
58                                  : "=r" (err)                                                                                   \
59                                  : "d" ((uint32_t) (val >> 32)),                                                \
60                                    "a" ((uint32_t) (val & 0xffffffff)), "c" (addr),             \
61                                    "i" (errret), "0" (err))
62
63 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)               \
64         asm volatile(ASM_STAC "\n"                                                                                      \
65                                  "1:            mov"itype" %"rtype"1,%2\n"                                      \
66                                  "2: " ASM_CLAC "\n"                                                                    \
67                                  ".section .fixup,\"ax\"\n"                                                             \
68                                  "3:            mov %3,%0\n"                                                            \
69                                  "      jmp 2b\n"                                                                                       \
70                                  ".previous\n"                                                                                  \
71                                  _ASM_EXTABLE(1b, 3b)                                                                   \
72                                  : "=r"(err)                                                                                    \
73                                  : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
74
75 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)       \
76         asm volatile(ASM_STAC "\n"                                                                              \
77                                  "1:            mov"itype" %2,%"rtype"1\n"                              \
78                                  "2: " ASM_CLAC "\n"                                                            \
79                                  ".section .fixup,\"ax\"\n"                                                     \
80                                  "3:            mov %3,%0\n"                                                    \
81                                  "      xor"itype" %"rtype"1,%"rtype"1\n"                               \
82                                  "      jmp 2b\n"                                                                               \
83                                  ".previous\n"                                                                          \
84                                  _ASM_EXTABLE(1b, 3b)                                                           \
85                                  : "=r" (err), ltype(x)                                                         \
86                                  : "m" (__m(addr)), "i" (errret), "0" (err))
87
88 #define __user_memcpy(dst, src, count, err, errret)                                             \
89         asm volatile(ASM_STAC "\n"                                                                                      \
90                                  "              cld\n"                                                                          \
91                                  "1:            rep movsb\n"                                                            \
92                                  "2: " ASM_CLAC "\n"                                                                    \
93                                  ".section .fixup,\"ax\"\n"                                                             \
94                                  "3:            mov %4,%0\n"                                                            \
95                                  "      jmp 2b\n"                                                                                       \
96                                  ".previous\n"                                                                                  \
97                                  _ASM_EXTABLE(1b, 3b)                                                                   \
98                                  : "=r"(err), "+D" (dst), "+S" (src), "+c" (count)              \
99                                  : "i" (errret), "0" (err)                                                              \
100                                  : "memory")
101
102 static inline int __put_user(void *dst, const void *src, unsigned int count)
103 {
104         int err = 0;
105
106         switch (count) {
107         case 1:
108                 __put_user_asm(*(const uint8_t *) src, (uint8_t *) dst, err, "b",
109                                            "b", "iq", -EFAULT);
110                 break;
111         case 2:
112                 __put_user_asm(*(const uint16_t *) src, (uint16_t *) dst, err, "w",
113                                            "w", "ir", -EFAULT);
114                 break;
115         case 4:
116                 __put_user_asm(*(const uint32_t *) src, (uint32_t *) dst, err, "l",
117                                            "k", "ir", -EFAULT);
118                 break;
119         case 8:
120                 __put_user_asm(*(const uint64_t *) src, (uint64_t *) dst, err, "q",
121                                            "", "er", -EFAULT);
122                 break;
123         default:
124                 __user_memcpy(dst, src, count, err, -EFAULT);
125         }
126
127         return err;
128 }
129
130 static inline int copy_to_user(void *dst, const void *src, unsigned int count)
131 {
132         int err = 0;
133
134         if (unlikely(!is_user_rwaddr(dst, count))) {
135                 err = -EFAULT;
136         } else if (!__builtin_constant_p(count)) {
137                 __user_memcpy(dst, src, count, err, -EFAULT);
138         } else {
139                 err = __put_user(dst, src, count);
140         }
141
142         return err;
143 }
144
145 static inline int __get_user(void *dst, const void *src, unsigned int count)
146 {
147         int err = 0;
148
149         switch (count) {
150         case 1:
151                 __get_user_asm(*(uint8_t *) dst, (const uint8_t *) src, err, "b",
152                                            "b", "=q", -EFAULT);
153                 break;
154         case 2:
155                 __get_user_asm(*(uint16_t *) dst, (const uint16_t *) src, err, "w",
156                                            "w", "=r", -EFAULT);
157                 break;
158         case 4:
159                 __get_user_asm(*(uint32_t *) dst, (const uint32_t *) src, err, "l",
160                                            "k", "=r", -EFAULT);
161                 break;
162         case 8:
163                 __get_user_asm(*(uint64_t *) dst, (const uint64_t *) src, err, "q",
164                                            "", "=r", -EFAULT);
165                 break;
166         default:
167                 __user_memcpy(dst, src, count, err, -EFAULT);
168         }
169
170         return err;
171 }
172
173 static inline int copy_from_user(void *dst, const void *src,
174                                                                  unsigned int count)
175 {
176         int err = 0;
177
178         if (unlikely(!is_user_raddr((void *) src, count))) {
179                 err = -EFAULT;
180         } else if (!__builtin_constant_p(count)) {
181                 __user_memcpy(dst, src, count, err, -EFAULT);
182         } else {
183                 err = __get_user(dst, src, count);
184         }
185
186         return err;
187 }
188
189 static inline int safe_read_msr(uint32_t addr, uint64_t *value)
190 {
191         int err = 0;
192         uint32_t edx, eax;
193
194         __read_msr_asm(eax, edx, addr, err, -EFAULT);
195         if (likely(err == 0))
196                 *value = ((uint64_t) edx << 32) | eax;
197
198         return err;
199 }
200
201 static inline int safe_write_msr(uint32_t addr, uint64_t value)
202 {
203         int err = 0;
204
205         __write_msr_asm(value, addr, err, -EFAULT);
206
207         return err;
208 }
209
210 static inline uintptr_t ex_insn_addr(const struct extable_ip_fixup *x)
211 {
212         return (uintptr_t) &x->insn + x->insn;
213 }
214
215 static inline uintptr_t ex_fixup_addr(const struct extable_ip_fixup *x)
216 {
217         return (uintptr_t) &x->fixup + x->fixup;
218 }