Home | History | Annotate | Line # | Download | only in libnvmm
libnvmm.c revision 1.1
      1 /*	$NetBSD: libnvmm.c,v 1.1 2018/11/10 09:28:56 maxv Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Maxime Villard.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 #include <fcntl.h>
     39 #include <errno.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/mman.h>
     42 
     43 #include "nvmm.h"
     44 
     45 static int nvmm_fd = -1;
     46 static size_t nvmm_page_size = 0;
     47 
     48 /* -------------------------------------------------------------------------- */
     49 
     50 static int
     51 _nvmm_area_add(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
     52     size_t size)
     53 {
     54 	struct nvmm_area *area;
     55 	void *ptr;
     56 	size_t i;
     57 
     58 	for (i = 0; i < mach->nareas; i++) {
     59 		if (gpa >= mach->areas[i].gpa &&
     60 		    gpa < mach->areas[i].gpa + mach->areas[i].size) {
     61 			goto error;
     62 		}
     63 		if (gpa + size >= mach->areas[i].gpa &&
     64 		    gpa + size < mach->areas[i].gpa + mach->areas[i].size) {
     65 			goto error;
     66 		}
     67 		if (gpa < mach->areas[i].gpa &&
     68 		    gpa + size >= mach->areas[i].gpa + mach->areas[i].size) {
     69 			goto error;
     70 		}
     71 	}
     72 
     73 	mach->nareas++;
     74 	ptr = realloc(mach->areas, mach->nareas * sizeof(struct nvmm_area));
     75 	if (ptr == NULL)
     76 		return -1;
     77 	mach->areas = ptr;
     78 
     79 	area = &mach->areas[mach->nareas-1];
     80 	area->gpa = gpa;
     81 	area->hva = hva;
     82 	area->size = size;
     83 
     84 	return 0;
     85 
     86 error:
     87 	errno = EEXIST;
     88 	return -1;
     89 }
     90 
     91 static int
     92 _nvmm_area_delete(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
     93     size_t size)
     94 {
     95 	size_t i;
     96 
     97 	for (i = 0; i < mach->nareas; i++) {
     98 		if (gpa == mach->areas[i].gpa &&
     99 		    hva == mach->areas[i].hva &&
    100 		    size == mach->areas[i].size) {
    101 			break;
    102 		}
    103 	}
    104 	if (i == mach->nareas) {
    105 		errno = ENOENT;
    106 		return -1;
    107 	}
    108 
    109 	memcpy(&mach->areas[i], &mach->areas[i+1],
    110 	    (mach->nareas - i - 1) * sizeof(struct nvmm_area));
    111 	mach->nareas--;
    112 
    113 	return 0;
    114 }
    115 
    116 /* -------------------------------------------------------------------------- */
    117 
    118 static int
    119 nvmm_init(void)
    120 {
    121 	if (nvmm_fd != -1)
    122 		return 0;
    123 	nvmm_fd = open("/dev/nvmm", O_RDWR);
    124 	if (nvmm_fd == -1)
    125 		return -1;
    126 	nvmm_page_size = sysconf(_SC_PAGESIZE);
    127 	return 0;
    128 }
    129 
    130 int
    131 nvmm_capability(struct nvmm_capability *cap)
    132 {
    133 	struct nvmm_ioc_capability args;
    134 	int ret;
    135 
    136 	if (nvmm_init() == -1) {
    137 		return -1;
    138 	}
    139 
    140 	ret = ioctl(nvmm_fd, NVMM_IOC_CAPABILITY, &args);
    141 	if (ret == -1)
    142 		return -1;
    143 
    144 	memcpy(cap, &args.cap, sizeof(args.cap));
    145 
    146 	return 0;
    147 }
    148 
    149 int
    150 nvmm_machine_create(struct nvmm_machine *mach)
    151 {
    152 	struct nvmm_ioc_machine_create args;
    153 	int ret;
    154 
    155 	if (nvmm_init() == -1) {
    156 		return -1;
    157 	}
    158 
    159 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
    160 	if (ret == -1)
    161 		return -1;
    162 
    163 	memset(mach, 0, sizeof(*mach));
    164 	mach->machid = args.machid;
    165 
    166 	return 0;
    167 }
    168 
    169 int
    170 nvmm_machine_destroy(struct nvmm_machine *mach)
    171 {
    172 	struct nvmm_ioc_machine_destroy args;
    173 	int ret;
    174 
    175 	if (nvmm_init() == -1) {
    176 		return -1;
    177 	}
    178 
    179 	args.machid = mach->machid;
    180 
    181 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_DESTROY, &args);
    182 	if (ret == -1)
    183 		return -1;
    184 
    185 	free(mach->areas);
    186 
    187 	return 0;
    188 }
    189 
    190 int
    191 nvmm_machine_configure(struct nvmm_machine *mach, uint64_t op, void *conf)
    192 {
    193 	struct nvmm_ioc_machine_configure args;
    194 	int ret;
    195 
    196 	if (nvmm_init() == -1) {
    197 		return -1;
    198 	}
    199 
    200 	args.machid = mach->machid;
    201 	args.op = op;
    202 	args.conf = conf;
    203 
    204 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CONFIGURE, &args);
    205 	if (ret == -1)
    206 		return -1;
    207 
    208 	return 0;
    209 }
    210 
    211 int
    212 nvmm_vcpu_create(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
    213 {
    214 	struct nvmm_ioc_vcpu_create args;
    215 	int ret;
    216 
    217 	if (nvmm_init() == -1) {
    218 		return -1;
    219 	}
    220 
    221 	args.machid = mach->machid;
    222 	args.cpuid = cpuid;
    223 
    224 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_CREATE, &args);
    225 	if (ret == -1)
    226 		return -1;
    227 
    228 	return 0;
    229 }
    230 
    231 int
    232 nvmm_vcpu_destroy(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
    233 {
    234 	struct nvmm_ioc_vcpu_destroy args;
    235 	int ret;
    236 
    237 	if (nvmm_init() == -1) {
    238 		return -1;
    239 	}
    240 
    241 	args.machid = mach->machid;
    242 	args.cpuid = cpuid;
    243 
    244 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_DESTROY, &args);
    245 	if (ret == -1)
    246 		return -1;
    247 
    248 	return 0;
    249 }
    250 
    251 int
    252 nvmm_vcpu_setstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    253     void *state, uint64_t flags)
    254 {
    255 	struct nvmm_ioc_vcpu_setstate args;
    256 	int ret;
    257 
    258 	if (nvmm_init() == -1) {
    259 		return -1;
    260 	}
    261 
    262 	args.machid = mach->machid;
    263 	args.cpuid = cpuid;
    264 	args.state = state;
    265 	args.flags = flags;
    266 
    267 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_SETSTATE, &args);
    268 	if (ret == -1)
    269 		return -1;
    270 
    271 	return 0;
    272 }
    273 
    274 int
    275 nvmm_vcpu_getstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    276     void *state, uint64_t flags)
    277 {
    278 	struct nvmm_ioc_vcpu_getstate args;
    279 	int ret;
    280 
    281 	if (nvmm_init() == -1) {
    282 		return -1;
    283 	}
    284 
    285 	args.machid = mach->machid;
    286 	args.cpuid = cpuid;
    287 	args.state = state;
    288 	args.flags = flags;
    289 
    290 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_GETSTATE, &args);
    291 	if (ret == -1)
    292 		return -1;
    293 
    294 	return 0;
    295 }
    296 
    297 int
    298 nvmm_vcpu_inject(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    299     struct nvmm_event *event)
    300 {
    301 	struct nvmm_ioc_vcpu_inject args;
    302 	int ret;
    303 
    304 	if (nvmm_init() == -1) {
    305 		return -1;
    306 	}
    307 
    308 	args.machid = mach->machid;
    309 	args.cpuid = cpuid;
    310 	memcpy(&args.event, event, sizeof(args.event));
    311 
    312 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_INJECT, &args);
    313 	if (ret == -1)
    314 		return -1;
    315 
    316 	return 0;
    317 }
    318 
    319 int
    320 nvmm_vcpu_run(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    321     struct nvmm_exit *exit)
    322 {
    323 	struct nvmm_ioc_vcpu_run args;
    324 	int ret;
    325 
    326 	if (nvmm_init() == -1) {
    327 		return -1;
    328 	}
    329 
    330 	args.machid = mach->machid;
    331 	args.cpuid = cpuid;
    332 	memset(&args.exit, 0, sizeof(args.exit));
    333 
    334 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_RUN, &args);
    335 	if (ret == -1)
    336 		return -1;
    337 
    338 	memcpy(exit, &args.exit, sizeof(args.exit));
    339 
    340 	return 0;
    341 }
    342 
    343 int
    344 nvmm_gpa_map(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
    345     size_t size, int flags)
    346 {
    347 	struct nvmm_ioc_gpa_map args;
    348 	int ret;
    349 
    350 	if (nvmm_init() == -1) {
    351 		return -1;
    352 	}
    353 
    354 	args.machid = mach->machid;
    355 	args.hva = hva;
    356 	args.gpa = gpa;
    357 	args.size = size;
    358 	args.flags = flags;
    359 
    360 	ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args);
    361 	if (ret == -1)
    362 		return -1;
    363 
    364 	ret = _nvmm_area_add(mach, gpa, hva, size);
    365 	if (ret == -1) {
    366 		nvmm_gpa_unmap(mach, hva, gpa, size);
    367 		return -1;
    368 	}
    369 
    370 	return 0;
    371 }
    372 
    373 int
    374 nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
    375     size_t size)
    376 {
    377 	struct nvmm_ioc_gpa_unmap args;
    378 	int ret;
    379 
    380 	if (nvmm_init() == -1) {
    381 		return -1;
    382 	}
    383 
    384 	ret = _nvmm_area_delete(mach, gpa, hva, size);
    385 	if (ret == -1)
    386 		return -1;
    387 
    388 	args.machid = mach->machid;
    389 	args.gpa = gpa;
    390 	args.size = size;
    391 
    392 	ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
    393 	if (ret == -1)
    394 		return -1;
    395 
    396 	ret = munmap((void *)hva, size);
    397 
    398 	return ret;
    399 }
    400 
    401 /*
    402  * nvmm_gva_to_gpa(): architecture-specific.
    403  */
    404 
    405 int
    406 nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva)
    407 {
    408 	size_t i;
    409 
    410 	if (gpa % nvmm_page_size != 0) {
    411 		errno = EINVAL;
    412 		return -1;
    413 	}
    414 
    415 	for (i = 0; i < mach->nareas; i++) {
    416 		if (gpa < mach->areas[i].gpa) {
    417 			continue;
    418 		}
    419 		if (gpa >= mach->areas[i].gpa + mach->areas[i].size) {
    420 			continue;
    421 		}
    422 
    423 		*hva = mach->areas[i].hva + (gpa - mach->areas[i].gpa);
    424 		return 0;
    425 	}
    426 
    427 	errno = ENOENT;
    428 	return -1;
    429 }
    430 
    431 /*
    432  * nvmm_assist_io(): architecture-specific.
    433  */
    434