libnvmm_x86.c revision 1.1 1 1.1 maxv /* $NetBSD: libnvmm_x86.c,v 1.1 2018/11/10 09:28:56 maxv Exp $ */
2 1.1 maxv
3 1.1 maxv /*
4 1.1 maxv * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 1.1 maxv * All rights reserved.
6 1.1 maxv *
7 1.1 maxv * This code is derived from software contributed to The NetBSD Foundation
8 1.1 maxv * by Maxime Villard.
9 1.1 maxv *
10 1.1 maxv * Redistribution and use in source and binary forms, with or without
11 1.1 maxv * modification, are permitted provided that the following conditions
12 1.1 maxv * are met:
13 1.1 maxv * 1. Redistributions of source code must retain the above copyright
14 1.1 maxv * notice, this list of conditions and the following disclaimer.
15 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 maxv * notice, this list of conditions and the following disclaimer in the
17 1.1 maxv * documentation and/or other materials provided with the distribution.
18 1.1 maxv *
19 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 maxv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 maxv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 maxv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 maxv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 maxv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 maxv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 maxv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 maxv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 maxv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 maxv * POSSIBILITY OF SUCH DAMAGE.
30 1.1 maxv */
31 1.1 maxv
32 1.1 maxv #include <sys/cdefs.h>
33 1.1 maxv
34 1.1 maxv #include <stdio.h>
35 1.1 maxv #include <stdlib.h>
36 1.1 maxv #include <string.h>
37 1.1 maxv #include <unistd.h>
38 1.1 maxv #include <fcntl.h>
39 1.1 maxv #include <errno.h>
40 1.1 maxv #include <sys/ioctl.h>
41 1.1 maxv #include <sys/mman.h>
42 1.1 maxv #include <machine/vmparam.h>
43 1.1 maxv #include <machine/pte.h>
44 1.1 maxv #include <machine/psl.h>
45 1.1 maxv
46 1.1 maxv #include "nvmm.h"
47 1.1 maxv
48 1.1 maxv #include <x86/specialreg.h>
49 1.1 maxv
50 1.1 maxv /* -------------------------------------------------------------------------- */
51 1.1 maxv
52 1.1 maxv #define PTE32_L1_SHIFT 12
53 1.1 maxv #define PTE32_L2_SHIFT 22
54 1.1 maxv
55 1.1 maxv #define PTE32_L2_MASK 0xffc00000
56 1.1 maxv #define PTE32_L1_MASK 0x003ff000
57 1.1 maxv
58 1.1 maxv #define PTE32_L2_FRAME (PTE32_L2_MASK)
59 1.1 maxv #define PTE32_L1_FRAME (PTE32_L2_FRAME|PTE32_L1_MASK)
60 1.1 maxv
61 1.1 maxv #define pte32_l1idx(va) (((va) & PTE32_L1_MASK) >> PTE32_L1_SHIFT)
62 1.1 maxv #define pte32_l2idx(va) (((va) & PTE32_L2_MASK) >> PTE32_L2_SHIFT)
63 1.1 maxv
64 1.1 maxv typedef uint32_t pte_32bit_t;
65 1.1 maxv
66 1.1 maxv static int
67 1.1 maxv x86_gva_to_gpa_32bit(struct nvmm_machine *mach, uint64_t cr3,
68 1.1 maxv gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot)
69 1.1 maxv {
70 1.1 maxv gpaddr_t L2gpa, L1gpa;
71 1.1 maxv uintptr_t L2hva, L1hva;
72 1.1 maxv pte_32bit_t *pdir, pte;
73 1.1 maxv
74 1.1 maxv /* We begin with an RWXU access. */
75 1.1 maxv *prot = NVMM_PROT_ALL;
76 1.1 maxv
77 1.1 maxv /* Parse L2. */
78 1.1 maxv L2gpa = (cr3 & PG_FRAME);
79 1.1 maxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva) == -1)
80 1.1 maxv return -1;
81 1.1 maxv pdir = (pte_32bit_t *)L2hva;
82 1.1 maxv pte = pdir[pte32_l2idx(gva)];
83 1.1 maxv if ((pte & PG_V) == 0)
84 1.1 maxv return -1;
85 1.1 maxv if ((pte & PG_u) == 0)
86 1.1 maxv *prot &= ~NVMM_PROT_USER;
87 1.1 maxv if ((pte & PG_KW) == 0)
88 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
89 1.1 maxv if ((pte & PG_PS) && !has_pse)
90 1.1 maxv return -1;
91 1.1 maxv if (pte & PG_PS) {
92 1.1 maxv *gpa = (pte & PTE32_L2_FRAME);
93 1.1 maxv return 0;
94 1.1 maxv }
95 1.1 maxv
96 1.1 maxv /* Parse L1. */
97 1.1 maxv L1gpa = (pte & PG_FRAME);
98 1.1 maxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva) == -1)
99 1.1 maxv return -1;
100 1.1 maxv pdir = (pte_32bit_t *)L1hva;
101 1.1 maxv pte = pdir[pte32_l1idx(gva)];
102 1.1 maxv if ((pte & PG_V) == 0)
103 1.1 maxv return -1;
104 1.1 maxv if ((pte & PG_u) == 0)
105 1.1 maxv *prot &= ~NVMM_PROT_USER;
106 1.1 maxv if ((pte & PG_KW) == 0)
107 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
108 1.1 maxv if (pte & PG_PS)
109 1.1 maxv return -1;
110 1.1 maxv
111 1.1 maxv *gpa = (pte & PG_FRAME);
112 1.1 maxv return 0;
113 1.1 maxv }
114 1.1 maxv
115 1.1 maxv /* -------------------------------------------------------------------------- */
116 1.1 maxv
117 1.1 maxv #define PTE32_PAE_L1_SHIFT 12
118 1.1 maxv #define PTE32_PAE_L2_SHIFT 21
119 1.1 maxv #define PTE32_PAE_L3_SHIFT 30
120 1.1 maxv
121 1.1 maxv #define PTE32_PAE_L3_MASK 0xc0000000
122 1.1 maxv #define PTE32_PAE_L2_MASK 0x3fe00000
123 1.1 maxv #define PTE32_PAE_L1_MASK 0x001ff000
124 1.1 maxv
125 1.1 maxv #define PTE32_PAE_L3_FRAME (PTE32_PAE_L3_MASK)
126 1.1 maxv #define PTE32_PAE_L2_FRAME (PTE32_PAE_L3_FRAME|PTE32_PAE_L2_MASK)
127 1.1 maxv #define PTE32_PAE_L1_FRAME (PTE32_PAE_L2_FRAME|PTE32_PAE_L1_MASK)
128 1.1 maxv
129 1.1 maxv #define pte32_pae_l1idx(va) (((va) & PTE32_PAE_L1_MASK) >> PTE32_PAE_L1_SHIFT)
130 1.1 maxv #define pte32_pae_l2idx(va) (((va) & PTE32_PAE_L2_MASK) >> PTE32_PAE_L2_SHIFT)
131 1.1 maxv #define pte32_pae_l3idx(va) (((va) & PTE32_PAE_L3_MASK) >> PTE32_PAE_L3_SHIFT)
132 1.1 maxv
133 1.1 maxv typedef uint64_t pte_32bit_pae_t;
134 1.1 maxv
135 1.1 maxv static int
136 1.1 maxv x86_gva_to_gpa_32bit_pae(struct nvmm_machine *mach, uint64_t cr3,
137 1.1 maxv gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot)
138 1.1 maxv {
139 1.1 maxv gpaddr_t L3gpa, L2gpa, L1gpa;
140 1.1 maxv uintptr_t L3hva, L2hva, L1hva;
141 1.1 maxv pte_32bit_pae_t *pdir, pte;
142 1.1 maxv
143 1.1 maxv /* We begin with an RWXU access. */
144 1.1 maxv *prot = NVMM_PROT_ALL;
145 1.1 maxv
146 1.1 maxv /* Parse L3. */
147 1.1 maxv L3gpa = (cr3 & PG_FRAME);
148 1.1 maxv if (nvmm_gpa_to_hva(mach, L3gpa, &L3hva) == -1)
149 1.1 maxv return -1;
150 1.1 maxv pdir = (pte_32bit_pae_t *)L3hva;
151 1.1 maxv pte = pdir[pte32_pae_l3idx(gva)];
152 1.1 maxv if ((pte & PG_V) == 0)
153 1.1 maxv return -1;
154 1.1 maxv if (pte & PG_NX)
155 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
156 1.1 maxv if (pte & PG_PS)
157 1.1 maxv return -1;
158 1.1 maxv
159 1.1 maxv /* Parse L2. */
160 1.1 maxv L2gpa = (pte & PG_FRAME);
161 1.1 maxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva) == -1)
162 1.1 maxv return -1;
163 1.1 maxv pdir = (pte_32bit_pae_t *)L2hva;
164 1.1 maxv pte = pdir[pte32_pae_l2idx(gva)];
165 1.1 maxv if ((pte & PG_V) == 0)
166 1.1 maxv return -1;
167 1.1 maxv if ((pte & PG_u) == 0)
168 1.1 maxv *prot &= ~NVMM_PROT_USER;
169 1.1 maxv if ((pte & PG_KW) == 0)
170 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
171 1.1 maxv if (pte & PG_NX)
172 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
173 1.1 maxv if ((pte & PG_PS) && !has_pse)
174 1.1 maxv return -1;
175 1.1 maxv if (pte & PG_PS) {
176 1.1 maxv *gpa = (pte & PTE32_PAE_L2_FRAME);
177 1.1 maxv return 0;
178 1.1 maxv }
179 1.1 maxv
180 1.1 maxv /* Parse L1. */
181 1.1 maxv L1gpa = (pte & PG_FRAME);
182 1.1 maxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva) == -1)
183 1.1 maxv return -1;
184 1.1 maxv pdir = (pte_32bit_pae_t *)L1hva;
185 1.1 maxv pte = pdir[pte32_pae_l1idx(gva)];
186 1.1 maxv if ((pte & PG_V) == 0)
187 1.1 maxv return -1;
188 1.1 maxv if ((pte & PG_u) == 0)
189 1.1 maxv *prot &= ~NVMM_PROT_USER;
190 1.1 maxv if ((pte & PG_KW) == 0)
191 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
192 1.1 maxv if (pte & PG_NX)
193 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
194 1.1 maxv if (pte & PG_PS)
195 1.1 maxv return -1;
196 1.1 maxv
197 1.1 maxv *gpa = (pte & PG_FRAME);
198 1.1 maxv return 0;
199 1.1 maxv }
200 1.1 maxv
201 1.1 maxv /* -------------------------------------------------------------------------- */
202 1.1 maxv
203 1.1 maxv #define PTE64_L1_SHIFT 12
204 1.1 maxv #define PTE64_L2_SHIFT 21
205 1.1 maxv #define PTE64_L3_SHIFT 30
206 1.1 maxv #define PTE64_L4_SHIFT 39
207 1.1 maxv
208 1.1 maxv #define PTE64_L4_MASK 0x0000ff8000000000
209 1.1 maxv #define PTE64_L3_MASK 0x0000007fc0000000
210 1.1 maxv #define PTE64_L2_MASK 0x000000003fe00000
211 1.1 maxv #define PTE64_L1_MASK 0x00000000001ff000
212 1.1 maxv
213 1.1 maxv #define PTE64_L4_FRAME PTE64_L4_MASK
214 1.1 maxv #define PTE64_L3_FRAME (PTE64_L4_FRAME|PTE64_L3_MASK)
215 1.1 maxv #define PTE64_L2_FRAME (PTE64_L3_FRAME|PTE64_L2_MASK)
216 1.1 maxv #define PTE64_L1_FRAME (PTE64_L2_FRAME|PTE64_L1_MASK)
217 1.1 maxv
218 1.1 maxv #define pte64_l1idx(va) (((va) & PTE64_L1_MASK) >> PTE64_L1_SHIFT)
219 1.1 maxv #define pte64_l2idx(va) (((va) & PTE64_L2_MASK) >> PTE64_L2_SHIFT)
220 1.1 maxv #define pte64_l3idx(va) (((va) & PTE64_L3_MASK) >> PTE64_L3_SHIFT)
221 1.1 maxv #define pte64_l4idx(va) (((va) & PTE64_L4_MASK) >> PTE64_L4_SHIFT)
222 1.1 maxv
223 1.1 maxv typedef uint64_t pte_64bit_t;
224 1.1 maxv
225 1.1 maxv static inline bool
226 1.1 maxv x86_gva_64bit_canonical(gvaddr_t gva)
227 1.1 maxv {
228 1.1 maxv /* Bits 63:47 must have the same value. */
229 1.1 maxv #define SIGN_EXTEND 0xffff800000000000ULL
230 1.1 maxv return (gva & SIGN_EXTEND) == 0 || (gva & SIGN_EXTEND) == SIGN_EXTEND;
231 1.1 maxv }
232 1.1 maxv
233 1.1 maxv static int
234 1.1 maxv x86_gva_to_gpa_64bit(struct nvmm_machine *mach, uint64_t cr3,
235 1.1 maxv gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot)
236 1.1 maxv {
237 1.1 maxv gpaddr_t L4gpa, L3gpa, L2gpa, L1gpa;
238 1.1 maxv uintptr_t L4hva, L3hva, L2hva, L1hva;
239 1.1 maxv pte_64bit_t *pdir, pte;
240 1.1 maxv
241 1.1 maxv /* We begin with an RWXU access. */
242 1.1 maxv *prot = NVMM_PROT_ALL;
243 1.1 maxv
244 1.1 maxv if (!x86_gva_64bit_canonical(gva))
245 1.1 maxv return -1;
246 1.1 maxv
247 1.1 maxv /* Parse L4. */
248 1.1 maxv L4gpa = (cr3 & PG_FRAME);
249 1.1 maxv if (nvmm_gpa_to_hva(mach, L4gpa, &L4hva) == -1)
250 1.1 maxv return -1;
251 1.1 maxv pdir = (pte_64bit_t *)L4hva;
252 1.1 maxv pte = pdir[pte64_l4idx(gva)];
253 1.1 maxv if ((pte & PG_V) == 0)
254 1.1 maxv return -1;
255 1.1 maxv if ((pte & PG_u) == 0)
256 1.1 maxv *prot &= ~NVMM_PROT_USER;
257 1.1 maxv if ((pte & PG_KW) == 0)
258 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
259 1.1 maxv if (pte & PG_NX)
260 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
261 1.1 maxv if (pte & PG_PS)
262 1.1 maxv return -1;
263 1.1 maxv
264 1.1 maxv /* Parse L3. */
265 1.1 maxv L3gpa = (pte & PG_FRAME);
266 1.1 maxv if (nvmm_gpa_to_hva(mach, L3gpa, &L3hva) == -1)
267 1.1 maxv return -1;
268 1.1 maxv pdir = (pte_64bit_t *)L3hva;
269 1.1 maxv pte = pdir[pte64_l3idx(gva)];
270 1.1 maxv if ((pte & PG_V) == 0)
271 1.1 maxv return -1;
272 1.1 maxv if ((pte & PG_u) == 0)
273 1.1 maxv *prot &= ~NVMM_PROT_USER;
274 1.1 maxv if ((pte & PG_KW) == 0)
275 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
276 1.1 maxv if (pte & PG_NX)
277 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
278 1.1 maxv if ((pte & PG_PS) && !has_pse)
279 1.1 maxv return -1;
280 1.1 maxv if (pte & PG_PS) {
281 1.1 maxv *gpa = (pte & PTE64_L3_FRAME);
282 1.1 maxv return 0;
283 1.1 maxv }
284 1.1 maxv
285 1.1 maxv /* Parse L2. */
286 1.1 maxv L2gpa = (pte & PG_FRAME);
287 1.1 maxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva) == -1)
288 1.1 maxv return -1;
289 1.1 maxv pdir = (pte_64bit_t *)L2hva;
290 1.1 maxv pte = pdir[pte64_l2idx(gva)];
291 1.1 maxv if ((pte & PG_V) == 0)
292 1.1 maxv return -1;
293 1.1 maxv if ((pte & PG_u) == 0)
294 1.1 maxv *prot &= ~NVMM_PROT_USER;
295 1.1 maxv if ((pte & PG_KW) == 0)
296 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
297 1.1 maxv if (pte & PG_NX)
298 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
299 1.1 maxv if ((pte & PG_PS) && !has_pse)
300 1.1 maxv return -1;
301 1.1 maxv if (pte & PG_PS) {
302 1.1 maxv *gpa = (pte & PTE64_L2_FRAME);
303 1.1 maxv return 0;
304 1.1 maxv }
305 1.1 maxv
306 1.1 maxv /* Parse L1. */
307 1.1 maxv L1gpa = (pte & PG_FRAME);
308 1.1 maxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva) == -1)
309 1.1 maxv return -1;
310 1.1 maxv pdir = (pte_64bit_t *)L1hva;
311 1.1 maxv pte = pdir[pte64_l1idx(gva)];
312 1.1 maxv if ((pte & PG_V) == 0)
313 1.1 maxv return -1;
314 1.1 maxv if ((pte & PG_u) == 0)
315 1.1 maxv *prot &= ~NVMM_PROT_USER;
316 1.1 maxv if ((pte & PG_KW) == 0)
317 1.1 maxv *prot &= ~NVMM_PROT_WRITE;
318 1.1 maxv if (pte & PG_NX)
319 1.1 maxv *prot &= ~NVMM_PROT_EXEC;
320 1.1 maxv if (pte & PG_PS)
321 1.1 maxv return -1;
322 1.1 maxv
323 1.1 maxv *gpa = (pte & PG_FRAME);
324 1.1 maxv return 0;
325 1.1 maxv }
326 1.1 maxv
327 1.1 maxv static inline int
328 1.1 maxv x86_gva_to_gpa(struct nvmm_machine *mach, struct nvmm_x64_state *state,
329 1.1 maxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
330 1.1 maxv {
331 1.1 maxv bool is_pae, is_lng, has_pse;
332 1.1 maxv uint64_t cr3;
333 1.1 maxv int ret;
334 1.1 maxv
335 1.1 maxv if ((state->crs[NVMM_X64_CR_CR0] & CR0_PG) == 0) {
336 1.1 maxv /* No paging. */
337 1.1 maxv *gpa = gva;
338 1.1 maxv return 0;
339 1.1 maxv }
340 1.1 maxv
341 1.1 maxv is_pae = (state->crs[NVMM_X64_CR_CR4] & CR4_PAE) != 0;
342 1.1 maxv is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0;
343 1.1 maxv has_pse = (state->crs[NVMM_X64_CR_CR4] & CR4_PSE) != 0;
344 1.1 maxv cr3 = state->crs[NVMM_X64_CR_CR3];
345 1.1 maxv
346 1.1 maxv if (is_pae && is_lng) {
347 1.1 maxv /* 64bit */
348 1.1 maxv ret = x86_gva_to_gpa_64bit(mach, cr3, gva, gpa, has_pse, prot);
349 1.1 maxv } else if (is_pae && !is_lng) {
350 1.1 maxv /* 32bit PAE */
351 1.1 maxv ret = x86_gva_to_gpa_32bit_pae(mach, cr3, gva, gpa, has_pse,
352 1.1 maxv prot);
353 1.1 maxv } else if (!is_pae && !is_lng) {
354 1.1 maxv /* 32bit */
355 1.1 maxv ret = x86_gva_to_gpa_32bit(mach, cr3, gva, gpa, has_pse, prot);
356 1.1 maxv } else {
357 1.1 maxv ret = -1;
358 1.1 maxv }
359 1.1 maxv
360 1.1 maxv if (ret == -1) {
361 1.1 maxv errno = EFAULT;
362 1.1 maxv }
363 1.1 maxv
364 1.1 maxv return ret;
365 1.1 maxv }
366 1.1 maxv
367 1.1 maxv int
368 1.1 maxv nvmm_gva_to_gpa(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
369 1.1 maxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
370 1.1 maxv {
371 1.1 maxv struct nvmm_x64_state state;
372 1.1 maxv int ret;
373 1.1 maxv
374 1.1 maxv if (gva & PAGE_MASK) {
375 1.1 maxv errno = EINVAL;
376 1.1 maxv return -1;
377 1.1 maxv }
378 1.1 maxv
379 1.1 maxv ret = nvmm_vcpu_getstate(mach, cpuid, &state,
380 1.1 maxv NVMM_X64_STATE_CRS | NVMM_X64_STATE_MSRS);
381 1.1 maxv if (ret == -1)
382 1.1 maxv return -1;
383 1.1 maxv
384 1.1 maxv return x86_gva_to_gpa(mach, &state, gva, gpa, prot);
385 1.1 maxv }
386 1.1 maxv
387 1.1 maxv /* -------------------------------------------------------------------------- */
388 1.1 maxv
389 1.1 maxv static inline bool
390 1.1 maxv is_long_mode(struct nvmm_x64_state *state)
391 1.1 maxv {
392 1.1 maxv return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0;
393 1.1 maxv }
394 1.1 maxv
395 1.1 maxv static inline bool
396 1.1 maxv is_illegal(struct nvmm_io *io, nvmm_prot_t prot)
397 1.1 maxv {
398 1.1 maxv return (io->in && !(prot & NVMM_PROT_WRITE));
399 1.1 maxv }
400 1.1 maxv
401 1.1 maxv static int
402 1.1 maxv segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva, size_t size)
403 1.1 maxv {
404 1.1 maxv uint64_t limit;
405 1.1 maxv
406 1.1 maxv /*
407 1.1 maxv * This is incomplete. We should check topdown, etc, really that's
408 1.1 maxv * tiring.
409 1.1 maxv */
410 1.1 maxv if (__predict_false(!seg->attrib.p)) {
411 1.1 maxv goto error;
412 1.1 maxv }
413 1.1 maxv
414 1.1 maxv limit = (seg->limit + 1);
415 1.1 maxv if (__predict_true(seg->attrib.gran)) {
416 1.1 maxv limit *= PAGE_SIZE;
417 1.1 maxv }
418 1.1 maxv
419 1.1 maxv if (__predict_false(*gva + seg->base + size > limit)) {
420 1.1 maxv goto error;
421 1.1 maxv }
422 1.1 maxv
423 1.1 maxv *gva += seg->base;
424 1.1 maxv return 0;
425 1.1 maxv
426 1.1 maxv error:
427 1.1 maxv errno = EFAULT;
428 1.1 maxv return -1;
429 1.1 maxv }
430 1.1 maxv
431 1.1 maxv int
432 1.1 maxv nvmm_assist_io(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
433 1.1 maxv struct nvmm_exit *exit, void (*cb)(struct nvmm_io *))
434 1.1 maxv {
435 1.1 maxv struct nvmm_x64_state state;
436 1.1 maxv struct nvmm_io io;
437 1.1 maxv nvmm_prot_t prot;
438 1.1 maxv size_t remain, done;
439 1.1 maxv uintptr_t hva;
440 1.1 maxv gvaddr_t gva, off;
441 1.1 maxv gpaddr_t gpa;
442 1.1 maxv uint64_t rsi;
443 1.1 maxv uint8_t tmp[8];
444 1.1 maxv uint8_t *ptr, *ptr2;
445 1.1 maxv bool cross;
446 1.1 maxv int ret;
447 1.1 maxv
448 1.1 maxv if (__predict_false(exit->reason != NVMM_EXIT_IO)) {
449 1.1 maxv errno = EINVAL;
450 1.1 maxv return -1;
451 1.1 maxv }
452 1.1 maxv
453 1.1 maxv io.port = exit->u.io.port;
454 1.1 maxv io.in = (exit->u.io.type == NVMM_EXIT_IO_IN);
455 1.1 maxv io.size = exit->u.io.operand_size;
456 1.1 maxv
457 1.1 maxv ret = nvmm_vcpu_getstate(mach, cpuid, &state,
458 1.1 maxv NVMM_X64_STATE_GPRS | NVMM_X64_STATE_SEGS |
459 1.1 maxv NVMM_X64_STATE_CRS | NVMM_X64_STATE_MSRS);
460 1.1 maxv if (ret == -1)
461 1.1 maxv return -1;
462 1.1 maxv
463 1.1 maxv cross = false;
464 1.1 maxv
465 1.1 maxv if (!exit->u.io.str) {
466 1.1 maxv ptr = (uint8_t *)&state.gprs[NVMM_X64_GPR_RAX];
467 1.1 maxv } else {
468 1.1 maxv rsi = state.gprs[NVMM_X64_GPR_RSI];
469 1.1 maxv
470 1.1 maxv switch (exit->u.io.address_size) {
471 1.1 maxv case 8:
472 1.1 maxv gva = rsi;
473 1.1 maxv break;
474 1.1 maxv case 4:
475 1.1 maxv gva = (rsi & 0x00000000FFFFFFFF);
476 1.1 maxv break;
477 1.1 maxv case 2:
478 1.1 maxv default: /* impossible */
479 1.1 maxv gva = (rsi & 0x000000000000FFFF);
480 1.1 maxv break;
481 1.1 maxv }
482 1.1 maxv
483 1.1 maxv if (!is_long_mode(&state)) {
484 1.1 maxv ret = segment_apply(&state.segs[exit->u.io.seg], &gva,
485 1.1 maxv io.size);
486 1.1 maxv if (ret == -1)
487 1.1 maxv return -1;
488 1.1 maxv }
489 1.1 maxv
490 1.1 maxv off = (gva & PAGE_MASK);
491 1.1 maxv gva &= ~PAGE_MASK;
492 1.1 maxv
493 1.1 maxv ret = x86_gva_to_gpa(mach, &state, gva, &gpa, &prot);
494 1.1 maxv if (ret == -1)
495 1.1 maxv return -1;
496 1.1 maxv if (__predict_false(is_illegal(&io, prot))) {
497 1.1 maxv errno = EFAULT;
498 1.1 maxv return -1;
499 1.1 maxv }
500 1.1 maxv ret = nvmm_gpa_to_hva(mach, gpa, &hva);
501 1.1 maxv if (ret == -1)
502 1.1 maxv return -1;
503 1.1 maxv
504 1.1 maxv ptr = (uint8_t *)hva + off;
505 1.1 maxv
506 1.1 maxv /*
507 1.1 maxv * Special case. If the buffer is in between two pages, we
508 1.1 maxv * need to retrieve data from the next page.
509 1.1 maxv */
510 1.1 maxv if (__predict_false(off + io.size > PAGE_SIZE)) {
511 1.1 maxv cross = true;
512 1.1 maxv remain = off + io.size - PAGE_SIZE;
513 1.1 maxv done = PAGE_SIZE - off;
514 1.1 maxv
515 1.1 maxv memcpy(tmp, ptr, done);
516 1.1 maxv
517 1.1 maxv ret = x86_gva_to_gpa(mach, &state, gva + PAGE_SIZE,
518 1.1 maxv &gpa, &prot);
519 1.1 maxv if (ret == -1)
520 1.1 maxv return -1;
521 1.1 maxv if (__predict_false(is_illegal(&io, prot))) {
522 1.1 maxv errno = EFAULT;
523 1.1 maxv return -1;
524 1.1 maxv }
525 1.1 maxv ret = nvmm_gpa_to_hva(mach, gpa, &hva);
526 1.1 maxv if (ret == -1)
527 1.1 maxv return -1;
528 1.1 maxv
529 1.1 maxv memcpy(&tmp[done], (uint8_t *)hva, remain);
530 1.1 maxv ptr2 = &tmp[done];
531 1.1 maxv }
532 1.1 maxv }
533 1.1 maxv
534 1.1 maxv if (io.in) {
535 1.1 maxv /* nothing to do */
536 1.1 maxv } else {
537 1.1 maxv memcpy(io.data, ptr, io.size);
538 1.1 maxv }
539 1.1 maxv
540 1.1 maxv (*cb)(&io);
541 1.1 maxv
542 1.1 maxv if (io.in) {
543 1.1 maxv if (!exit->u.io.str)
544 1.1 maxv state.gprs[NVMM_X64_GPR_RAX] = 0;
545 1.1 maxv if (__predict_false(cross)) {
546 1.1 maxv memcpy(ptr, io.data, done);
547 1.1 maxv memcpy(ptr2, &io.data[done], remain);
548 1.1 maxv } else {
549 1.1 maxv memcpy(ptr, io.data, io.size);
550 1.1 maxv }
551 1.1 maxv } else {
552 1.1 maxv /* nothing to do */
553 1.1 maxv }
554 1.1 maxv
555 1.1 maxv if (exit->u.io.rep) {
556 1.1 maxv state.gprs[NVMM_X64_GPR_RCX] -= 1;
557 1.1 maxv if (state.gprs[NVMM_X64_GPR_RCX] == 0) {
558 1.1 maxv state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
559 1.1 maxv }
560 1.1 maxv if (exit->u.io.str) {
561 1.1 maxv if (state.gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
562 1.1 maxv state.gprs[NVMM_X64_GPR_RSI] -= io.size;
563 1.1 maxv } else {
564 1.1 maxv state.gprs[NVMM_X64_GPR_RSI] += io.size;
565 1.1 maxv }
566 1.1 maxv }
567 1.1 maxv } else {
568 1.1 maxv state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
569 1.1 maxv }
570 1.1 maxv
571 1.1 maxv ret = nvmm_vcpu_setstate(mach, cpuid, &state, NVMM_X64_STATE_GPRS);
572 1.1 maxv if (ret == -1)
573 1.1 maxv return -1;
574 1.1 maxv
575 1.1 maxv return 0;
576 1.1 maxv }
577 1.1 maxv
578 1.1 maxv /* -------------------------------------------------------------------------- */
579 1.1 maxv
580 1.1 maxv int
581 1.1 maxv nvmm_assist_mem(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
582 1.1 maxv struct nvmm_exit *exit, void (*cb)(struct nvmm_mem *))
583 1.1 maxv {
584 1.1 maxv if (__predict_false(exit->reason != NVMM_EXIT_MEMORY)) {
585 1.1 maxv errno = EINVAL;
586 1.1 maxv return -1;
587 1.1 maxv }
588 1.1 maxv
589 1.1 maxv // TODO
590 1.1 maxv errno = ENOSYS;
591 1.1 maxv return -1;
592 1.1 maxv }
593