Add NVMM - for NetBSD Virtual Machine Monitor -, a kernel driver that

provides support for hardware-accelerated virtualization on NetBSD.

It is made of an MI frontend, to which MD backends can be plugged. One
MD backend is implemented, x86-SVM, for x86 AMD CPUs.

We install

	/usr/include/dev/nvmm/nvmm.h
	/usr/include/dev/nvmm/nvmm_ioctl.h
	/usr/include/dev/nvmm/{arch}/nvmm_{arch}.h

And the kernel module. For now, the only architecture where we do that
is amd64 (arch=x86).

NVMM is not enabled by default in amd64-GENERIC, but is instead easily
modloadable.

Sent to tech-kern@ a month ago. Validated with kASan, and optimized
with tprof.
This commit is contained in:
maxv 2018-11-07 07:43:07 +00:00
parent 8c426f1bc1
commit f3a4baf748
19 changed files with 3732 additions and 8 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: md.amd64,v 1.259 2018/07/17 18:55:24 joerg Exp $
# $NetBSD: md.amd64,v 1.260 2018/11/07 07:43:07 maxv Exp $
./usr/include/amd64 comp-c-include
./usr/include/amd64/ansi.h comp-c-include
@ -677,6 +677,11 @@
./usr/include/ieeefp.h comp-c-include
./usr/include/mm_malloc.h comp-obsolete obsolete
./usr/include/mmintrin.h comp-obsolete obsolete
./usr/include/dev/nvmm comp-c-include
./usr/include/dev/nvmm/nvmm.h comp-c-include
./usr/include/dev/nvmm/nvmm_ioctl.h comp-c-include
./usr/include/dev/nvmm/x86 comp-c-include
./usr/include/dev/nvmm/x86/nvmm_x86.h comp-c-include
./usr/include/pmmintrin.h comp-obsolete obsolete
./usr/include/x64_64 comp-obsolete obsolete
./usr/include/x64_64/ansi.h comp-obsolete obsolete

View File

@ -1,4 +1,4 @@
# $NetBSD: md.amd64,v 1.77 2018/08/28 09:42:10 martin Exp $
# $NetBSD: md.amd64,v 1.78 2018/11/07 07:43:07 maxv Exp $
#
# NOTE that there are two sets of files here:
# @MODULEDIR@ and amd64-xen
@ -141,6 +141,8 @@
./@MODULEDIR@/mt2131/mt2131.kmod base-kernel-modules kmod
./@MODULEDIR@/nvme base-obsolete obsolete
./@MODULEDIR@/nvme/nvme.kmod base-obsolete obsolete
./@MODULEDIR@/nvmm base-kernel-modules kmod
./@MODULEDIR@/nvmm/nvmm.kmod base-kernel-modules kmod
./@MODULEDIR@/nxt2k base-kernel-modules kmod
./@MODULEDIR@/nxt2k/nxt2k.kmod base-kernel-modules kmod
./@MODULEDIR@/odcm base-kernel-modules kmod

View File

@ -1,5 +1,5 @@
#!/bin/sh -
# $NetBSD: MAKEDEV.tmpl,v 1.195 2018/11/04 12:48:01 maxv Exp $
# $NetBSD: MAKEDEV.tmpl,v 1.196 2018/11/07 07:43:07 maxv Exp $
#
# Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc.
# All rights reserved.
@ -258,6 +258,7 @@
# nsmb* SMB requester
# nvme* Non-Volatile Memory Host Controller Interface device driver
# nvme*ns* Non-Volatile Memory namespace
# nvmm NetBSD Virtual Machine Monitor
# openfirm OpenFirmware accessor
# pad* Pseudo-audio device driver
# pci* PCI bus access devices
@ -277,7 +278,7 @@
# stic* PixelStamp interface chip
# sysmon System Monitoring hardware
# tap* virtual Ethernet device
# tprof task profiler
# tprof task profiler
# tun* network tunnel driver
# twa 3ware Apache control interface
# twe 3ware Escalade control interface
@ -2205,6 +2206,10 @@ nvme[0-9]*)
mkdev nvme$unit c %nvme_chr% $(($unit * 65536))
;;
nvmm)
mkdev nvmm c %nvmm_chr% 0
;;
autofs)
mkdev autofs c %autofs_chr% 0 600
;;

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.1215 2018/10/19 21:09:10 jakllsch Exp $
# $NetBSD: files,v 1.1216 2018/11/07 07:43:07 maxv Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20171118
@ -1548,6 +1548,11 @@ include "lib/libx86emu/files.x86emu"
#
include "dev/tprof/files.tprof"
#
# NetBSD Virtual Machine Monitor.
#
include "dev/nvmm/files.nvmm"
#
# alternate memory device
#

View File

@ -1,4 +1,4 @@
# $NetBSD: majors,v 1.79 2018/05/20 14:08:33 thorpej Exp $
# $NetBSD: majors,v 1.80 2018/11/07 07:43:07 maxv Exp $
#
# Device majors for Machine-Independent drivers.
#
@ -78,3 +78,4 @@ device-major nvme char 341 nvme
device-major qemufwcfg char 342 qemufwcfg
device-major autofs char 343 autofs
device-major gpiopps char 344 gpiopps
device-major nvmm char 345 nvmm

View File

@ -1,10 +1,14 @@
# $NetBSD: Makefile,v 1.39 2017/12/10 20:38:14 bouyer Exp $
# $NetBSD: Makefile,v 1.40 2018/11/07 07:43:08 maxv Exp $
SUBDIR= apm ata bluetooth dec dm dmover dtv filemon hdaudio hdmicec hid hpc \
i2c i2o ic ieee1394 ir isa \
microcode ofw pci pckbport pcmcia pud putter raidframe sbus scsipi \
sun tc usb vme wscons
.if ${MACHINE_ARCH} == "x86_64"
SUBDIR+= nvmm
.endif
.include <bsd.own.mk>
.if ${MKISCSI} != "no"

13
sys/dev/nvmm/Makefile Normal file
View File

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.1 2018/11/07 07:43:08 maxv Exp $
.if ${MACHINE_ARCH} == "x86_64"
SUBDIR= x86
.endif
.include <bsd.own.mk>
INCSDIR= /usr/include/dev/nvmm
INCS= nvmm.h nvmm_ioctl.h
.include <bsd.kinc.mk>

11
sys/dev/nvmm/files.nvmm Normal file
View File

@ -0,0 +1,11 @@
# $NetBSD: files.nvmm,v 1.1 2018/11/07 07:43:08 maxv Exp $
defpseudo nvmm
file dev/nvmm/nvmm.c nvmm
ifdef amd64
file dev/nvmm/x86/nvmm_x86_svm.c nvmm
file dev/nvmm/x86/nvmm_x86_svmfunc.S nvmm
endif

788
sys/dev/nvmm/nvmm.c Normal file
View File

@ -0,0 +1,788 @@
/* $NetBSD: nvmm.c,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.1 2018/11/07 07:43:08 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/cpu.h>
#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <uvm/uvm.h>
#include <uvm/uvm_page.h>
#include "ioconf.h"
#include <dev/nvmm/nvmm.h>
#include <dev/nvmm/nvmm_internal.h>
#include <dev/nvmm/nvmm_ioctl.h>
static struct nvmm_machine machines[NVMM_MAX_MACHINES];
static const struct nvmm_impl *nvmm_impl_list[] = {
&nvmm_x86_svm /* x86 AMD SVM */
};
static const struct nvmm_impl *nvmm_impl = NULL;
/* -------------------------------------------------------------------------- */
static int
nvmm_machine_alloc(struct nvmm_machine **ret)
{
struct nvmm_machine *mach;
size_t i;
for (i = 0; i < NVMM_MAX_MACHINES; i++) {
mach = &machines[i];
rw_enter(&mach->lock, RW_WRITER);
if (mach->present) {
rw_exit(&mach->lock);
continue;
}
mach->present = true;
*ret = mach;
return 0;
}
return ENOBUFS;
}
static void
nvmm_machine_free(struct nvmm_machine *mach)
{
KASSERT(rw_write_held(&mach->lock));
KASSERT(mach->present);
mach->present = false;
}
static int
nvmm_machine_get(nvmm_machid_t machid, struct nvmm_machine **ret, bool writer)
{
struct nvmm_machine *mach;
krw_t op = writer ? RW_WRITER : RW_READER;
if (machid >= NVMM_MAX_MACHINES) {
return EINVAL;
}
mach = &machines[machid];
rw_enter(&mach->lock, op);
if (!mach->present) {
rw_exit(&mach->lock);
return ENOENT;
}
if (mach->procid != curproc->p_pid) {
rw_exit(&mach->lock);
return EPERM;
}
*ret = mach;
return 0;
}
static void
nvmm_machine_put(struct nvmm_machine *mach)
{
rw_exit(&mach->lock);
}
/* -------------------------------------------------------------------------- */
static int
nvmm_vcpu_alloc(struct nvmm_machine *mach, struct nvmm_cpu **ret)
{
struct nvmm_cpu *vcpu;
size_t i;
for (i = 0; i < NVMM_MAX_VCPUS; i++) {
vcpu = &mach->cpus[i];
mutex_enter(&vcpu->lock);
if (vcpu->present) {
mutex_exit(&vcpu->lock);
continue;
}
vcpu->present = true;
vcpu->cpuid = i;
*ret = vcpu;
return 0;
}
return ENOBUFS;
}
static void
nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
{
KASSERT(mutex_owned(&vcpu->lock));
vcpu->present = false;
vcpu->hcpu_last = -1;
}
int
nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
struct nvmm_cpu **ret)
{
struct nvmm_cpu *vcpu;
if (cpuid >= NVMM_MAX_VCPUS) {
return EINVAL;
}
vcpu = &mach->cpus[cpuid];
mutex_enter(&vcpu->lock);
if (!vcpu->present) {
mutex_exit(&vcpu->lock);
return ENOENT;
}
*ret = vcpu;
return 0;
}
void
nvmm_vcpu_put(struct nvmm_cpu *vcpu)
{
mutex_exit(&vcpu->lock);
}
/* -------------------------------------------------------------------------- */
static void
nvmm_kill_machines(pid_t pid)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
size_t i, j;
int error;
for (i = 0; i < NVMM_MAX_MACHINES; i++) {
mach = &machines[i];
rw_enter(&mach->lock, RW_WRITER);
if (!mach->present || mach->procid != pid) {
rw_exit(&mach->lock);
continue;
}
/* Kill it. */
for (j = 0; j < NVMM_MAX_VCPUS; j++) {
error = nvmm_vcpu_get(mach, j, &vcpu);
if (error)
continue;
(*nvmm_impl->vcpu_destroy)(mach, vcpu);
nvmm_vcpu_free(mach, vcpu);
nvmm_vcpu_put(vcpu);
}
uvmspace_free(mach->vm);
uao_detach(mach->uobj);
nvmm_machine_free(mach);
rw_exit(&mach->lock);
}
}
/* -------------------------------------------------------------------------- */
static int
nvmm_capability(struct nvmm_ioc_capability *args)
{
args->cap.version = NVMM_CAPABILITY_VERSION;
args->cap.state_size = nvmm_impl->state_size;
args->cap.max_machines = NVMM_MAX_MACHINES;
args->cap.max_vcpus = NVMM_MAX_VCPUS;
args->cap.max_ram = NVMM_MAX_RAM;
(*nvmm_impl->capability)(&args->cap);
return 0;
}
static int
nvmm_machine_create(struct nvmm_ioc_machine_create *args)
{
struct nvmm_machine *mach;
int error;
error = nvmm_machine_alloc(&mach);
if (error)
return error;
/* Curproc owns the machine. */
mach->procid = curproc->p_pid;
/* Create the machine vmspace. */
mach->gpa_begin = 0;
mach->gpa_end = NVMM_MAX_RAM;
mach->vm = uvmspace_alloc(0, mach->gpa_end - mach->gpa_begin, false);
mach->uobj = uao_create(mach->gpa_end - mach->gpa_begin, 0);
/* Grab a reference for the machine. */
uao_reference(mach->uobj);
(*nvmm_impl->machine_create)(mach);
args->machid = mach->machid;
nvmm_machine_put(mach);
return 0;
}
static int
nvmm_machine_destroy(struct nvmm_ioc_machine_destroy *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
int error;
size_t i;
error = nvmm_machine_get(args->machid, &mach, true);
if (error)
return error;
for (i = 0; i < NVMM_MAX_VCPUS; i++) {
error = nvmm_vcpu_get(mach, i, &vcpu);
if (error)
continue;
(*nvmm_impl->vcpu_destroy)(mach, vcpu);
nvmm_vcpu_free(mach, vcpu);
nvmm_vcpu_put(vcpu);
}
(*nvmm_impl->machine_destroy)(mach);
/* Free the machine vmspace. */
uvmspace_free(mach->vm);
uao_detach(mach->uobj);
nvmm_machine_free(mach);
nvmm_machine_put(mach);
return 0;
}
static int
nvmm_machine_configure(struct nvmm_ioc_machine_configure *args)
{
struct nvmm_machine *mach;
size_t allocsz;
void *data;
int error;
if (__predict_false(args->op >= nvmm_impl->conf_max)) {
return EINVAL;
}
allocsz = nvmm_impl->conf_sizes[args->op];
data = kmem_alloc(allocsz, KM_SLEEP);
error = nvmm_machine_get(args->machid, &mach, true);
if (error) {
kmem_free(data, allocsz);
return error;
}
error = copyin(args->conf, data, allocsz);
if (error) {
goto out;
}
error = (*nvmm_impl->machine_configure)(mach, args->op, data);
out:
nvmm_machine_put(mach);
kmem_free(data, allocsz);
return error;
}
static int
nvmm_vcpu_create(struct nvmm_ioc_vcpu_create *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
error = nvmm_vcpu_alloc(mach, &vcpu);
if (error)
goto out;
error = (*nvmm_impl->vcpu_create)(mach, vcpu);
if (error) {
nvmm_vcpu_free(mach, vcpu);
nvmm_vcpu_put(vcpu);
goto out;
}
nvmm_vcpu_put(vcpu);
out:
nvmm_machine_put(mach);
return error;
}
static int
nvmm_vcpu_destroy(struct nvmm_ioc_vcpu_destroy *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
if (error)
goto out;
(*nvmm_impl->vcpu_destroy)(mach, vcpu);
nvmm_vcpu_free(mach, vcpu);
nvmm_vcpu_put(vcpu);
out:
nvmm_machine_put(mach);
return error;
}
static int
nvmm_vcpu_setstate(struct nvmm_ioc_vcpu_setstate *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
void *data;
int error;
data = kmem_alloc(nvmm_impl->state_size, KM_SLEEP);
error = nvmm_machine_get(args->machid, &mach, false);
if (error) {
kmem_free(data, nvmm_impl->state_size);
return error;
}
error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
if (error)
goto out;
error = copyin(args->state, data, nvmm_impl->state_size);
if (error) {
nvmm_vcpu_put(vcpu);
goto out;
}
(*nvmm_impl->vcpu_setstate)(vcpu, data, args->flags);
nvmm_vcpu_put(vcpu);
out:
nvmm_machine_put(mach);
kmem_free(data, nvmm_impl->state_size);
return error;
}
static int
nvmm_vcpu_getstate(struct nvmm_ioc_vcpu_getstate *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
void *data;
int error;
data = kmem_alloc(nvmm_impl->state_size, KM_SLEEP);
error = nvmm_machine_get(args->machid, &mach, false);
if (error) {
kmem_free(data, nvmm_impl->state_size);
return error;
}
error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
if (error)
goto out;
(*nvmm_impl->vcpu_getstate)(vcpu, data, args->flags);
nvmm_vcpu_put(vcpu);
error = copyout(data, args->state, nvmm_impl->state_size);
out:
nvmm_machine_put(mach);
kmem_free(data, nvmm_impl->state_size);
return error;
}
static int
nvmm_vcpu_inject(struct nvmm_ioc_vcpu_inject *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
if (error)
goto out;
error = (*nvmm_impl->vcpu_inject)(mach, vcpu, &args->event);
nvmm_vcpu_put(vcpu);
out:
nvmm_machine_put(mach);
return error;
}
static int
nvmm_vcpu_run(struct nvmm_ioc_vcpu_run *args)
{
struct nvmm_machine *mach;
struct nvmm_cpu *vcpu;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
if (error)
goto out;
(*nvmm_impl->vcpu_run)(mach, vcpu, &args->exit);
nvmm_vcpu_put(vcpu);
out:
nvmm_machine_put(mach);
return error;
}
/* -------------------------------------------------------------------------- */
static int
nvmm_gpa_map(struct nvmm_ioc_gpa_map *args)
{
struct proc *p = curproc;
struct nvmm_machine *mach;
struct vmspace *vmspace;
gpaddr_t gpa;
vaddr_t uva;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
vmspace = p->p_vmspace;
if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
(args->hva % PAGE_SIZE) != 0) {
error = EINVAL;
goto out;
}
if (args->hva == 0) {
error = EINVAL;
goto out;
}
if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
error = EINVAL;
goto out;
}
if (args->gpa + args->size <= args->gpa) {
error = EINVAL;
goto out;
}
if (args->gpa + args->size >= mach->gpa_end) {
error = EINVAL;
goto out;
}
gpa = args->gpa;
/* Take a reference for the kernel. */
uao_reference(mach->uobj);
/* Map the uobj into the machine address space, as pageable. */
error = uvm_map(&mach->vm->vm_map, &gpa, args->size, mach->uobj,
args->gpa, 0, UVM_MAPFLAG(UVM_PROT_RWX, UVM_PROT_RWX,
UVM_INH_NONE, UVM_ADV_NORMAL, UVM_FLAG_FIXED));
if (error) {
uao_detach(mach->uobj);
goto out;
}
if (gpa != args->gpa) {
uao_detach(mach->uobj);
printf("[!] uvm_map problem\n");
error = EINVAL;
goto out;
}
uva = (vaddr_t)args->hva;
/* Take a reference for the user. */
uao_reference(mach->uobj);
/* Map the uobj into the user address space, as pageable. */
error = uvm_map(&vmspace->vm_map, &uva, args->size, mach->uobj,
args->gpa, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
UVM_INH_SHARE, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
if (error) {
uao_detach(mach->uobj);
goto out;
}
out:
nvmm_machine_put(mach);
return error;
}
static int
nvmm_gpa_unmap(struct nvmm_ioc_gpa_unmap *args)
{
struct nvmm_machine *mach;
gpaddr_t gpa;
int error;
error = nvmm_machine_get(args->machid, &mach, false);
if (error)
return error;
if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
error = EINVAL;
goto out;
}
if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
error = EINVAL;
goto out;
}
if (args->gpa + args->size <= args->gpa) {
error = EINVAL;
goto out;
}
if (args->gpa + args->size >= mach->gpa_end) {
error = EINVAL;
goto out;
}
gpa = args->gpa;
/* Unmap the memory from the machine. */
uvm_unmap(&mach->vm->vm_map, gpa, gpa + args->size);
out:
nvmm_machine_put(mach);
return error;
}
/* -------------------------------------------------------------------------- */
static int
nvmm_init(void)
{
size_t i, n;
for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
if (!(*nvmm_impl_list[i]->ident)()) {
continue;
}
nvmm_impl = nvmm_impl_list[i];
break;
}
if (nvmm_impl == NULL) {
printf("[!] No implementation found\n");
return ENOTSUP;
}
for (i = 0; i < NVMM_MAX_MACHINES; i++) {
machines[i].machid = i;
rw_init(&machines[i].lock);
for (n = 0; n < NVMM_MAX_VCPUS; n++) {
mutex_init(&machines[i].cpus[n].lock, MUTEX_DEFAULT,
IPL_NONE);
machines[i].cpus[n].hcpu_last = -1;
}
}
(*nvmm_impl->init)();
return 0;
}
static void
nvmm_fini(void)
{
size_t i, n;
for (i = 0; i < NVMM_MAX_MACHINES; i++) {
rw_destroy(&machines[i].lock);
for (n = 0; n < NVMM_MAX_VCPUS; n++) {
mutex_destroy(&machines[i].cpus[n].lock);
}
/* TODO need to free stuff, etc */
}
(*nvmm_impl->fini)();
}
/* -------------------------------------------------------------------------- */
static int
nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
{
if (minor(dev) != 0) {
return EXDEV;
}
return 0;
}
static int
nvmm_close(dev_t dev, int flags, int type, struct lwp *l)
{
KASSERT(minor(dev) == 0);
nvmm_kill_machines(l->l_proc->p_pid);
return 0;
}
static int
nvmm_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
{
KASSERT(minor(dev) == 0);
switch (cmd) {
case NVMM_IOC_CAPABILITY:
return nvmm_capability(data);
case NVMM_IOC_MACHINE_CREATE:
return nvmm_machine_create(data);
case NVMM_IOC_MACHINE_DESTROY:
return nvmm_machine_destroy(data);
case NVMM_IOC_MACHINE_CONFIGURE:
return nvmm_machine_configure(data);
case NVMM_IOC_VCPU_CREATE:
return nvmm_vcpu_create(data);
case NVMM_IOC_VCPU_DESTROY:
return nvmm_vcpu_destroy(data);
case NVMM_IOC_VCPU_SETSTATE:
return nvmm_vcpu_setstate(data);
case NVMM_IOC_VCPU_GETSTATE:
return nvmm_vcpu_getstate(data);
case NVMM_IOC_VCPU_INJECT:
return nvmm_vcpu_inject(data);
case NVMM_IOC_VCPU_RUN:
return nvmm_vcpu_run(data);
case NVMM_IOC_GPA_MAP:
return nvmm_gpa_map(data);
case NVMM_IOC_GPA_UNMAP:
return nvmm_gpa_unmap(data);
default:
return EINVAL;
}
}
const struct cdevsw nvmm_cdevsw = {
.d_open = nvmm_open,
.d_close = nvmm_close,
.d_read = noread,
.d_write = nowrite,
.d_ioctl = nvmm_ioctl,
.d_stop = nostop,
.d_tty = notty,
.d_poll = nopoll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
.d_flag = D_OTHER | D_MPSAFE
};
void
nvmmattach(int nunits)
{
/* nothing */
}
MODULE(MODULE_CLASS_DRIVER, nvmm, NULL);
static int
nvmm_modcmd(modcmd_t cmd, void *arg)
{
int error;
switch (cmd) {
case MODULE_CMD_INIT:
error = nvmm_init();
if (error)
return error;
#if defined(_MODULE)
{
devmajor_t bmajor = NODEVMAJOR;
devmajor_t cmajor = 345;
/* mknod /dev/nvmm c 345 0 */
error = devsw_attach("nvmm", NULL, &bmajor,
&nvmm_cdevsw, &cmajor);
if (error) {
nvmm_fini();
return error;
}
}
#endif
return 0;
case MODULE_CMD_FINI:
#if defined(_MODULE)
{
error = devsw_detach(NULL, &nvmm_cdevsw);
if (error) {
return error;
}
}
#endif
nvmm_fini();
return 0;
default:
return ENOTTY;
}
}

155
sys/dev/nvmm/nvmm.h Normal file
View File

@ -0,0 +1,155 @@
/* $NetBSD: nvmm.h,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NVMM_H_
#define _NVMM_H_
#include <sys/types.h>
#ifndef _KERNEL
#include <stdbool.h>
#endif
typedef uint64_t gpaddr_t;
typedef uint64_t gvaddr_t;
typedef uint32_t nvmm_machid_t;
typedef uint32_t nvmm_cpuid_t;
enum nvmm_exit_reason {
NVMM_EXIT_NONE = 0x0000000000000000,
/* General. */
NVMM_EXIT_MEMORY = 0x0000000000000001,
NVMM_EXIT_IO = 0x0000000000000002,
NVMM_EXIT_MSR = 0x0000000000000003,
NVMM_EXIT_INT_READY = 0x0000000000000004,
NVMM_EXIT_NMI_READY = 0x0000000000000005,
NVMM_EXIT_SHUTDOWN = 0x0000000000000006,
/* Instructions (x86). */
NVMM_EXIT_HLT = 0x0000000000001000,
NVMM_EXIT_MONITOR = 0x0000000000001001,
NVMM_EXIT_MWAIT = 0x0000000000001002,
NVMM_EXIT_MWAIT_COND = 0x0000000000001003,
NVMM_EXIT_INVALID = 0xFFFFFFFFFFFFFFFF
};
enum nvmm_exit_memory_perm {
NVMM_EXIT_MEMORY_READ,
NVMM_EXIT_MEMORY_WRITE,
NVMM_EXIT_MEMORY_EXEC
};
struct nvmm_exit_memory {
enum nvmm_exit_memory_perm perm;
gpaddr_t gpa;
uint8_t inst_len;
uint8_t inst_bytes[15];
uint64_t npc;
};
enum nvmm_exit_io_type {
NVMM_EXIT_IO_IN,
NVMM_EXIT_IO_OUT
};
struct nvmm_exit_io {
enum nvmm_exit_io_type type;
uint16_t port;
int seg;
uint8_t address_size;
uint8_t operand_size;
bool rep;
bool str;
uint64_t npc;
};
enum nvmm_exit_msr_type {
NVMM_EXIT_MSR_RDMSR,
NVMM_EXIT_MSR_WRMSR
};
struct nvmm_exit_msr {
enum nvmm_exit_msr_type type;
uint64_t msr;
uint64_t val;
uint64_t npc;
};
struct nvmm_exit {
enum nvmm_exit_reason reason;
union {
struct nvmm_exit_memory mem;
struct nvmm_exit_io io;
struct nvmm_exit_msr msr;
} u;
uint64_t exitstate[8];
};
enum nvmm_event_type {
NVMM_EVENT_INTERRUPT_HW,
NVMM_EVENT_INTERRUPT_SW,
NVMM_EVENT_EXCEPTION
};
struct nvmm_event {
enum nvmm_event_type type;
uint64_t vector;
union {
/* NVMM_EVENT_INTERRUPT_HW */
uint8_t prio;
/* NVMM_EVENT_EXCEPTION */
uint64_t error;
} u;
};
#define NVMM_CAPABILITY_VERSION 1
struct nvmm_capability {
uint64_t version;
uint64_t state_size;
uint64_t max_machines;
uint64_t max_vcpus;
uint64_t max_ram;
union {
struct {
uint64_t xcr0_mask;
uint64_t mxcsr_mask;
uint64_t conf_cpuid_maxops;
} x86;
uint64_t rsvd[8];
} u;
};
#endif

View File

@ -0,0 +1,100 @@
/* $NetBSD: nvmm_internal.h,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NVMM_INTERNAL_H_
#define _NVMM_INTERNAL_H_
#define NVMM_MAX_MACHINES 128
#define NVMM_MAX_VCPUS 256
#define NVMM_MAX_RAM (4UL * (1 << 30))
struct nvmm_cpu {
/* Shared. */
bool present;
nvmm_cpuid_t cpuid;
kmutex_t lock;
/* Last host CPU on which the VCPU ran. */
int hcpu_last;
/* Implementation-specific. */
void *cpudata;
};
struct nvmm_machine {
bool present;
nvmm_machid_t machid;
pid_t procid;
krwlock_t lock;
/* Kernel */
struct vmspace *vm;
struct uvm_object *uobj;
gpaddr_t gpa_begin;
gpaddr_t gpa_end;
/* CPU */
struct nvmm_cpu cpus[NVMM_MAX_VCPUS];
/* Implementation-specific */
void *machdata;
};
struct nvmm_impl {
bool (*ident)(void);
void (*init)(void);
void (*fini)(void);
void (*capability)(struct nvmm_capability *);
size_t conf_max;
const size_t *conf_sizes;
size_t state_size;
void (*machine_create)(struct nvmm_machine *);
void (*machine_destroy)(struct nvmm_machine *);
int (*machine_configure)(struct nvmm_machine *, uint64_t, void *);
int (*vcpu_create)(struct nvmm_machine *, struct nvmm_cpu *);
void (*vcpu_destroy)(struct nvmm_machine *, struct nvmm_cpu *);
void (*vcpu_setstate)(struct nvmm_cpu *, void *, uint64_t);
void (*vcpu_getstate)(struct nvmm_cpu *, void *, uint64_t);
int (*vcpu_inject)(struct nvmm_machine *, struct nvmm_cpu *,
struct nvmm_event *);
int (*vcpu_run)(struct nvmm_machine *, struct nvmm_cpu *,
struct nvmm_exit *);
};
int nvmm_vcpu_get(struct nvmm_machine *, nvmm_cpuid_t, struct nvmm_cpu **);
void nvmm_vcpu_put(struct nvmm_cpu *);
extern const struct nvmm_impl nvmm_x86_svm;
#endif /* _NVMM_INTERNAL_H_ */

120
sys/dev/nvmm/nvmm_ioctl.h Normal file
View File

@ -0,0 +1,120 @@
/* $NetBSD: nvmm_ioctl.h,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NVMM_IOCTL_H_
#define _NVMM_IOCTL_H_
#include <dev/nvmm/nvmm.h>
struct nvmm_ioc_capability {
struct nvmm_capability cap;
};
struct nvmm_ioc_machine_create {
nvmm_machid_t machid;
};
struct nvmm_ioc_machine_destroy {
nvmm_machid_t machid;
};
struct nvmm_ioc_machine_configure {
nvmm_machid_t machid;
uint64_t op;
void *conf;
};
struct nvmm_ioc_vcpu_create {
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
};
struct nvmm_ioc_vcpu_destroy {
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
};
struct nvmm_ioc_vcpu_setstate {
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
uint64_t flags;
void *state;
};
struct nvmm_ioc_vcpu_getstate {
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
uint64_t flags;
void *state;
};
struct nvmm_ioc_vcpu_inject {
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
struct nvmm_event event;
};
struct nvmm_ioc_vcpu_run {
/* input */
nvmm_machid_t machid;
nvmm_cpuid_t cpuid;
/* output */
struct nvmm_exit exit;
};
struct nvmm_ioc_gpa_map {
nvmm_machid_t machid;
uintptr_t hva;
gpaddr_t gpa;
size_t size;
int flags;
};
struct nvmm_ioc_gpa_unmap {
nvmm_machid_t machid;
gpaddr_t gpa;
size_t size;
};
#define NVMM_IOC_CAPABILITY _IOR ('N', 0, struct nvmm_ioc_capability)
#define NVMM_IOC_MACHINE_CREATE _IOWR('N', 1, struct nvmm_ioc_machine_create)
#define NVMM_IOC_MACHINE_DESTROY _IOW ('N', 2, struct nvmm_ioc_machine_destroy)
#define NVMM_IOC_MACHINE_CONFIGURE _IOW ('N', 3, struct nvmm_ioc_machine_configure)
#define NVMM_IOC_VCPU_CREATE _IOW ('N', 4, struct nvmm_ioc_vcpu_create)
#define NVMM_IOC_VCPU_DESTROY _IOW ('N', 5, struct nvmm_ioc_vcpu_destroy)
#define NVMM_IOC_VCPU_SETSTATE _IOW ('N', 6, struct nvmm_ioc_vcpu_setstate)
#define NVMM_IOC_VCPU_GETSTATE _IOW ('N', 7, struct nvmm_ioc_vcpu_getstate)
#define NVMM_IOC_VCPU_INJECT _IOWR('N', 8, struct nvmm_ioc_vcpu_inject)
#define NVMM_IOC_VCPU_RUN _IOWR('N', 9, struct nvmm_ioc_vcpu_run)
#define NVMM_IOC_GPA_MAP _IOW ('N', 10, struct nvmm_ioc_gpa_map)
#define NVMM_IOC_GPA_UNMAP _IOW ('N', 11, struct nvmm_ioc_gpa_unmap)
#endif /* _NVMM_IOCTL_H_ */

View File

@ -0,0 +1,7 @@
# $NetBSD: Makefile,v 1.1 2018/11/07 07:43:08 maxv Exp $
INCSDIR= /usr/include/dev/nvmm/x86
INCS= nvmm_x86.h
.include <bsd.kinc.mk>

172
sys/dev/nvmm/x86/nvmm_x86.h Normal file
View File

@ -0,0 +1,172 @@
/* $NetBSD: nvmm_x86.h,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NVMM_X86_H_
#define _NVMM_X86_H_
/* Segments. */
#define NVMM_X64_SEG_CS 0
#define NVMM_X64_SEG_DS 1
#define NVMM_X64_SEG_ES 2
#define NVMM_X64_SEG_FS 3
#define NVMM_X64_SEG_GS 4
#define NVMM_X64_SEG_SS 5
#define NVMM_X64_SEG_GDT 6
#define NVMM_X64_SEG_IDT 7
#define NVMM_X64_SEG_LDT 8
#define NVMM_X64_SEG_TR 9
#define NVMM_X64_NSEG 10
/* General Purpose Registers. */
#define NVMM_X64_GPR_RAX 0
#define NVMM_X64_GPR_RBX 1
#define NVMM_X64_GPR_RCX 2
#define NVMM_X64_GPR_RDX 3
#define NVMM_X64_GPR_R8 4
#define NVMM_X64_GPR_R9 5
#define NVMM_X64_GPR_R10 6
#define NVMM_X64_GPR_R11 7
#define NVMM_X64_GPR_R12 8
#define NVMM_X64_GPR_R13 9
#define NVMM_X64_GPR_R14 10
#define NVMM_X64_GPR_R15 11
#define NVMM_X64_GPR_RDI 12
#define NVMM_X64_GPR_RSI 13
#define NVMM_X64_GPR_RBP 14
#define NVMM_X64_GPR_RSP 15
#define NVMM_X64_GPR_RIP 16
#define NVMM_X64_GPR_RFLAGS 17
#define NVMM_X64_NGPR 18
/* Control Registers. */
#define NVMM_X64_CR_CR0 0
#define NVMM_X64_CR_CR2 1
#define NVMM_X64_CR_CR3 2
#define NVMM_X64_CR_CR4 3
#define NVMM_X64_CR_CR8 4
#define NVMM_X64_CR_XCR0 5
#define NVMM_X64_NCR 6
/* Debug Registers. */
#define NVMM_X64_DR_DR0 0
#define NVMM_X64_DR_DR1 1
#define NVMM_X64_DR_DR2 2
#define NVMM_X64_DR_DR3 3
#define NVMM_X64_DR_DR6 4
#define NVMM_X64_DR_DR7 5
#define NVMM_X64_NDR 6
/* MSRs. */
#define NVMM_X64_MSR_EFER 0
#define NVMM_X64_MSR_STAR 1
#define NVMM_X64_MSR_LSTAR 2
#define NVMM_X64_MSR_CSTAR 3
#define NVMM_X64_MSR_SFMASK 4
#define NVMM_X64_MSR_KERNELGSBASE 5
#define NVMM_X64_MSR_SYSENTER_CS 6
#define NVMM_X64_MSR_SYSENTER_ESP 7
#define NVMM_X64_MSR_SYSENTER_EIP 8
#define NVMM_X64_MSR_PAT 9
#define NVMM_X64_NMSR 10
/* Misc. */
#define NVMM_X64_MISC_CPL 0
#define NVMM_X64_NMISC 1
#ifndef ASM_NVMM
#include <sys/types.h>
#include <x86/cpu_extended_state.h>
struct nvmm_x64_state_seg {
uint64_t selector;
struct { /* hidden */
uint64_t type:5;
uint64_t dpl:2;
uint64_t p:1;
uint64_t avl:1;
uint64_t lng:1;
uint64_t def32:1;
uint64_t gran:1;
uint64_t rsvd:52;
} attrib;
uint64_t limit; /* hidden */
uint64_t base; /* hidden */
};
/* VM exit state indexes. */
#define NVMM_X64_EXITSTATE_CR8 0
/* Flags. */
#define NVMM_X64_STATE_SEGS 0x01
#define NVMM_X64_STATE_GPRS 0x02
#define NVMM_X64_STATE_CRS 0x04
#define NVMM_X64_STATE_DRS 0x08
#define NVMM_X64_STATE_MSRS 0x10
#define NVMM_X64_STATE_MISC 0x20
#define NVMM_X64_STATE_FPU 0x40
#define NVMM_X64_STATE_ALL \
(NVMM_X64_STATE_SEGS | NVMM_X64_STATE_GPRS | NVMM_X64_STATE_CRS | \
NVMM_X64_STATE_DRS | NVMM_X64_STATE_MSRS | NVMM_X64_STATE_MISC | \
NVMM_X64_STATE_FPU)
struct nvmm_x64_state {
struct nvmm_x64_state_seg segs[NVMM_X64_NSEG];
uint64_t gprs[NVMM_X64_NGPR];
uint64_t crs[NVMM_X64_NCR];
uint64_t drs[NVMM_X64_NDR];
uint64_t msrs[NVMM_X64_NMSR];
uint64_t misc[NVMM_X64_NMISC];
struct fxsave fpu;
};
#define NVMM_X86_CONF_CPUID 0
#define NVMM_X86_NCONF 1
struct nvmm_x86_conf_cpuid {
uint32_t leaf;
struct {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
} set;
struct {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
} del;
};
#endif /* ASM_NVMM */
#endif /* _NVMM_X86_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,218 @@
/* $NetBSD: nvmm_x86_svmfunc.S,v 1.1 2018/11/07 07:43:08 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Override user-land alignment before including asm.h */
#define ALIGN_DATA .align 8
#define ALIGN_TEXT .align 16,0x90
#define _ALIGN_TEXT ALIGN_TEXT
#define _LOCORE
#include "assym.h"
#include <machine/asm.h>
#include <machine/segments.h>
#include <x86/specialreg.h>
#define ASM_NVMM
#include <dev/nvmm/x86/nvmm_x86.h>
.text
#define HOST_SAVE_GPRS \
pushq %rbx ;\
pushq %rbp ;\
pushq %r12 ;\
pushq %r13 ;\
pushq %r14 ;\
pushq %r15
#define HOST_RESTORE_GPRS \
popq %r15 ;\
popq %r14 ;\
popq %r13 ;\
popq %r12 ;\
popq %rbp ;\
popq %rbx
#define HOST_SAVE_MSR(msr) \
movq $msr,%rcx ;\
rdmsr ;\
pushq %rdx ;\
pushq %rax
#define HOST_RESTORE_MSR(msr) \
popq %rax ;\
popq %rdx ;\
movq $msr,%rcx ;\
wrmsr
#define HOST_SAVE_SEGREG(sreg) \
movw sreg,%ax ;\
pushw %ax
#define HOST_RESTORE_SEGREG(sreg)\
popw %ax ;\
movw %ax,sreg
#define HOST_SAVE_TR \
strw %ax ;\
pushw %ax
#define HOST_RESTORE_TR \
popw %ax ;\
movzwq %ax,%rdx ;\
movq CPUVAR(GDT),%rax ;\
andq $~0x0200,4(%rax,%rdx, 1) ;\
ltrw %dx
#define HOST_SAVE_LDT \
sldtw %ax ;\
pushw %ax
#define HOST_RESTORE_LDT \
popw %ax ;\
lldtw %ax
/*
* All GPRs except RAX and RSP, which are taken care of in VMCB.
*/
#define GUEST_SAVE_GPRS(reg) \
movq %rbx,(NVMM_X64_GPR_RBX * 8)(reg) ;\
movq %rcx,(NVMM_X64_GPR_RCX * 8)(reg) ;\
movq %rdx,(NVMM_X64_GPR_RDX * 8)(reg) ;\
movq %r8,(NVMM_X64_GPR_R8 * 8)(reg) ;\
movq %r9,(NVMM_X64_GPR_R9 * 8)(reg) ;\
movq %r10,(NVMM_X64_GPR_R10 * 8)(reg) ;\
movq %r11,(NVMM_X64_GPR_R11 * 8)(reg) ;\
movq %r12,(NVMM_X64_GPR_R12 * 8)(reg) ;\
movq %r13,(NVMM_X64_GPR_R13 * 8)(reg) ;\
movq %r14,(NVMM_X64_GPR_R14 * 8)(reg) ;\
movq %r15,(NVMM_X64_GPR_R15 * 8)(reg) ;\
movq %rbp,(NVMM_X64_GPR_RBP * 8)(reg) ;\
movq %rdi,(NVMM_X64_GPR_RDI * 8)(reg) ;\
movq %rsi,(NVMM_X64_GPR_RSI * 8)(reg)
#define GUEST_RESTORE_GPRS(reg) \
movq (NVMM_X64_GPR_RBX * 8)(reg),%rbx ;\
movq (NVMM_X64_GPR_RCX * 8)(reg),%rcx ;\
movq (NVMM_X64_GPR_RDX * 8)(reg),%rdx ;\
movq (NVMM_X64_GPR_R8 * 8)(reg),%r8 ;\
movq (NVMM_X64_GPR_R9 * 8)(reg),%r9 ;\
movq (NVMM_X64_GPR_R10 * 8)(reg),%r10 ;\
movq (NVMM_X64_GPR_R11 * 8)(reg),%r11 ;\
movq (NVMM_X64_GPR_R12 * 8)(reg),%r12 ;\
movq (NVMM_X64_GPR_R13 * 8)(reg),%r13 ;\
movq (NVMM_X64_GPR_R14 * 8)(reg),%r14 ;\
movq (NVMM_X64_GPR_R15 * 8)(reg),%r15 ;\
movq (NVMM_X64_GPR_RBP * 8)(reg),%rbp ;\
movq (NVMM_X64_GPR_RDI * 8)(reg),%rdi ;\
movq (NVMM_X64_GPR_RSI * 8)(reg),%rsi
/*
* %rdi = PA of VMCB
* %rsi = VA of guest GPR state
*/
ENTRY(svm_vmrun)
/* Save the Host GPRs. */
HOST_SAVE_GPRS
/* Disable Host interrupts. */
clgi
/* Save the Host TR. */
HOST_SAVE_TR
/* Save the variable Host MSRs. */
HOST_SAVE_MSR(MSR_KERNELGSBASE)
HOST_SAVE_MSR(MSR_GSBASE)
HOST_SAVE_MSR(MSR_FSBASE)
/* Reset the Host Segregs. */
movq $GSEL(GUDATA_SEL, SEL_UPL),%rax
movw %ax,%ds
movw %ax,%es
xorq %rax,%rax
movw %ax,%fs
movw %ax,%gs
/* Save some Host Segregs. */
HOST_SAVE_SEGREG(%fs)
HOST_SAVE_SEGREG(%gs)
/* Save the Host LDT. */
HOST_SAVE_LDT
/* Prepare RAX. */
pushq %rsi
pushq %rdi
/* Restore the Guest GPRs. */
movq %rsi,%rax
GUEST_RESTORE_GPRS(%rax)
/* Set RAX. */
popq %rax
/* Run the VM. */
vmload %rax
vmrun %rax
vmsave %rax
/* Get RAX. */
popq %rax
/* Save the Guest GPRs. */
GUEST_SAVE_GPRS(%rax)
/* Restore the Host LDT. */
HOST_RESTORE_LDT
/* Restore the Host Segregs. */
HOST_RESTORE_SEGREG(%gs)
HOST_RESTORE_SEGREG(%fs)
/* Restore the variable Host MSRs. */
HOST_RESTORE_MSR(MSR_FSBASE)
HOST_RESTORE_MSR(MSR_GSBASE)
HOST_RESTORE_MSR(MSR_KERNELGSBASE)
/* Restore the Host TR. */
HOST_RESTORE_TR
/* Enable Host interrupts. */
stgi
/* Restore the Host GPRs. */
HOST_RESTORE_GPRS
xorq %rax,%rax
retq
END(svm_vmrun)

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.209 2018/08/28 03:41:38 riastradh Exp $
# $NetBSD: Makefile,v 1.210 2018/11/07 07:43:08 maxv Exp $
.include <bsd.own.mk>
@ -202,6 +202,10 @@ SUBDIR+= tprof_x86
SUBDIR+= vmt
.endif
.if ${MACHINE_ARCH} == "x86_64"
SUBDIR+= nvmm
.endif
.if ${MACHINE_ARCH} == "i386" || \
${MACHINE_ARCH} == "x86_64"
SUBDIR+= ubsec # Builds on architectures with PCI bus

19
sys/modules/nvmm/Makefile Normal file
View File

@ -0,0 +1,19 @@
# $NetBSD: Makefile,v 1.1 2018/11/07 07:43:08 maxv Exp $
.include "../Makefile.inc"
.include "../Makefile.assym"
CPPFLAGS+=
.PATH: ${S}/dev/nvmm
.PATH: ${S}/dev/nvmm/x86
KMOD= nvmm
IOCONF= nvmm.ioconf
SRCS= nvmm.c
.if ${MACHINE_ARCH} == "x86_64"
SRCS+= nvmm_x86_svm.c nvmm_x86_svmfunc.S
.endif
.include <bsd.kmodule.mk>

View File

@ -0,0 +1,7 @@
# $NetBSD: nvmm.ioconf,v 1.1 2018/11/07 07:43:08 maxv Exp $
ioconf nvmm
include "conf/files"
pseudo-device nvmm