New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ukvm: Refactor monitor to support multi-{arch, backend} #171

Merged
merged 11 commits into from Apr 5, 2017

ukvm: Add FreeBSD vmm(4) backend

Add a FreeBSD vmm(4) (a.k.a. bhyve) backend to ukvm.

The "gdb" module is not currently supported and is stubbed out when built
on FreeBSD.

Additional changes:
- ukvm-configure has been rewritten to generate a less convoluted
  Makefile.ukvm, including correct dependencies. I've also added
  user-facing documentation about its invocation.
- the code to ensure that the tap interface is pre-existing in
  tap_attach() has been simplified and ported to FreeBSD.
- the upper sleep limit in test_time has been raised somewhat to account
for behaviour on my (oldish) FreeBSD test hardware.
  • Loading branch information...
mato committed Apr 3, 2017
commit e67a007b75fa3fcee5c082aab04c9fe9e897d779
View
@@ -73,7 +73,7 @@ case $(uname -s) in
for f in ${SRCS}; do cp -f ${INCDIR}/$f ${HOST_INCDIR}; done
HOST_CFLAGS="-nostdlibinc"
BUILD_UKVM=
BUILD_UKVM=yes
BUILD_VIRTIO="yes"
;;
*)
View
@@ -27,5 +27,5 @@ depexts: [
]
available: [
ocaml-version >= "4.02.3" & arch = "x86_64" & os = "linux"
ocaml-version >= "4.02.3" & (arch = "x86_64" | arch = "amd64") & (os = "linux" | os = "freebsd")
]
View
@@ -139,7 +139,18 @@ run_test ()
case ${NAME} in
*.ukvm)
[ -c /dev/kvm -a -w /dev/kvm ] || exit 98
OS="$(uname -s)"
case ${OS} in
Linux)
[ -c /dev/kvm -a -w /dev/kvm ] || exit 98
;;
FreeBSD)
# TODO, just try and run the test anyway
;;
*)
die "Don't know how to run ${NAME} on ${OS}"
;;
esac
UKVM=${TEST_DIR}/ukvm-bin
[ -n "${DISK}" ] && UKVM="${UKVM} --disk=${DISK}"
[ -n "${NET}" ] && UKVM="${UKVM} --net=${NET}"
@@ -61,7 +61,7 @@ int solo5_app_main(char *cmdline __attribute__((unused)))
* Verify that we did not sleep more than requested, within reason
* (scheduling delays, general inaccuracy of the current timing code).
*/
if ((tb - ta) > (NSEC_PER_SEC + 20000000ULL)) {
if ((tb - ta) > (NSEC_PER_SEC + 100000000ULL)) {
puts("ERROR: slept too much\n");
return 1;
}
View
@@ -17,74 +17,124 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
die ()
{
echo "ukvm-configure: error: $@" 1>&2
exit 1
}
if [ "$#" -lt 1 ]; then
echo "Usage: ukvm-configure UKVM_SRC [MODULES]"
echo " UKVM_SRC is /path/to/ukvm"
echo " MODULES can be any combination of: net blk gdb"
cat <<EOM 1<&2
Usage: ukvm-configure SOURCEDIR [ MODULES ... ]
Configures ukvm for your target, enabling the MODULES specified.
Generates a Makefile.ukvm in the current directory. Use the "ukvm-bin" target
to build ukvm.
Options:
SOURCEDIR is the path to the ukvm source
MODULES can be any combination of: net blk gdb
To use a cross-compiler, set the UKVM_CC environment variable.
To build ukvm statically, set the UKVM_STATIC environment variable.
EOM
exit 1
fi
UKVM_CC=${UKVM_CC:-cc}
UKVM_SRC=`readlink -f $1`
UKVM_SRC=$(readlink -f $1)
if [ ! -d ${UKVM_SRC} -o ! -f ${UKVM_SRC}/ukvm_core.c ]; then
echo "Error: Not a ukvm source directory: ${UKVM_SRC}" 1>&2
exit 1
die "Not a ukvm source directory: ${UKVM_SRC}"
fi
shift
UKVM_MODULE_OBJS=
UKVM_MODULE_CFLAGS=
for MODULE in "$@"; do
if [ ! -f ${UKVM_SRC}/ukvm_module_${MODULE}.c ]; then
echo "Error: Invalid module: ${MODULE}" 1>&2
exit 1
add_cflags ()
{
UKVM_CFLAGS="${UKVM_CFLAGS} $@"
}
add_obj ()
{
for i in "$@"; do
UKVM_OBJS="${UKVM_OBJS} _build-ukvm/${i}"
done
}
add_header ()
{
for i in "$@"; do
UKVM_HEADERS="${UKVM_HEADERS} ${UKVM_SRC}/${i}"
done
}
add_module ()
{
if [ ! -f ${UKVM_SRC}/ukvm_module_$1.c ]; then
die "Invalid module: $1"
fi
UKVM_MODULE_OBJS="${UKVM_MODULE_OBJS} ukvm_module_${MODULE}.o"
UKVM_MODULE_CFLAGS="${UKVM_MODULE_CFLAGS} -DUKVM_MODULE_${MODULE}"
enableit="-DUKVM_MODULE_$(echo $1 | tr '[a-z]' '[A-Z]')"
add_obj "ukvm_module_$1.o"
add_cflags "${enableit}"
}
UKVM_CFLAGS=
UKVM_LDFLAGS=
UKVM_LDLIBS=
UKVM_HEADERS=
UKVM_OBJS=
add_obj ukvm_core.o ukvm_elf.o ukvm_main.o
add_header ukvm.h ukvm_guest.h ukvm_cc.h
for module in "$@"; do
[ -z "${module}" ] && continue
add_module ${module}
done
UKVM_MODULE_CFLAGS=$(echo ${UKVM_MODULE_CFLAGS} | tr '[a-z]' '[A-Z]')
[ -n "${UKVM_STATIC}" ] && UKVM_LDFLAGS="-static"
TARGET=$(${UKVM_CC} -dumpmachine)
[ $? -ne 0 ] &&
die "Error running '${UKVM_CC} -dumpmachine', is your compiler working?"
case ${TARGET} in
x86_64-*linux*)
UKVM_SYSDEP_OBJS="ukvm_hv_kvm.o ukvm_hv_kvm_x86_64.o ukvm_cpu_x86_64.o"
UKVM_SYSDEP_HEADERS="ukvm_hv_kvm.h ukvm_cpu_x86_64.h"
add_obj ukvm_hv_kvm.o ukvm_hv_kvm_x86_64.o ukvm_cpu_x86_64.o
add_header ukvm_hv_kvm.h ukvm_cpu_x86_64.h
;;
x86_64-*freebsd1[12]*)
add_obj ukvm_hv_freebsd.o ukvm_hv_freebsd_x86_64.o ukvm_cpu_x86_64.o
add_header ukvm_hv_freebsd.h ukvm_cpu_x86_64.h
;;
*)
echo "Error: Unsupported compiler target: ${TARGET}" 1>&2
echo "Error: Using compiler \"${UKVM_CC}\". Set \$UKVM_CC to change it." 1>&2
exit 1
die "Unsupported compiler target: ${TARGET}"
;;
esac
cat <<EOF> Makefile.ukvm
# Generated by ukvm-configure "$@"
# Using compiler "${UKVM_CC}", target "${TARGET}"
# Generated by 'ukvm-configure $@'
# Using compiler '${UKVM_CC}', target '${TARGET}'
UKVM_CC=${UKVM_CC}
UKVM_CFLAGS=-Wall -Werror -std=c99 -O2 -g ${UKVM_MODULE_CFLAGS}
ifdef UKVM_STATIC
UKVM_LDFLAGS=-static
endif
UKVM_CFLAGS=-Wall -Werror -std=c99 -O2 -g ${UKVM_CFLAGS}
UKVM_LDFLAGS=${UKVM_LDFLAGS}
UKVM_LDLIBS=${UKVM_LDLIBS}
UKVM_OBJS=ukvm_core.o ukvm_elf.o ukvm_main.o ${UKVM_SYSDEP_OBJS} ${UKVM_MODULE_OBJS}
UKVM_HEADERS=ukvm.h ukvm_guest.h ukvm_cc.h ${UKVM_SYSDEP_HEADERS}
UKVM_OBJS=${UKVM_OBJS}
UKVM_HEADERS=${UKVM_HEADERS}
UKVM_BUILD_OBJS=\$(addprefix _build-ukvm/,\$(UKVM_OBJS))
UKVM_SRC_HEADERS=\$(addprefix ${UKVM_SRC}/,\$(UKVM_HEADERS))
\$(UKVM_OBJS): \$(UKVM_HEADERS)
_build-ukvm:
mkdir -p _build-ukvm
_build-ukvm/ukvm_%.o: ${UKVM_SRC}/ukvm_%.c \$(MAKEFILE_LIST) | _build-ukvm
\$(UKVM_CC) \$(UKVM_CFLAGS) -c \$< -o \$@
ukvm-bin: \$(UKVM_BUILD_OBJS) \$(UKVM_SRC_HEADERS) \$(MAKEFILE_LIST)
\$(UKVM_CC) \$(UKVM_LDFLAGS) -o \$@ \$(UKVM_CFLAGS) \$(UKVM_BUILD_OBJS)
ukvm-bin: \$(UKVM_OBJS) \$(MAKEFILE_LIST)
\$(UKVM_CC) \$(UKVM_LDFLAGS) -o \$@ \$(UKVM_OBJS) \$(UKVM_LDLIBS)
.PHONY: ukvm-clean
ukvm-clean:
\$(RM) -r _build-ukvm
\$(RM) ukvm-bin
\$(RM) ukvm-bin
EOF
View
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2015-2017 Contributors as noted in the AUTHORS file
*
* This file is part of ukvm, a unikernel monitor.
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define _WITH_DPRINTF
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <machine/vmm.h>
#include <sys/param.h>
#include <sys/cpuset.h>
#include <machine/vmm_dev.h>
#include "ukvm.h"
#include "ukvm_hv_freebsd.h"
/*
* TODO: To ensure that the VM is correctly destroyed on shutdown (normal or
* not) we currently install an atexit() handler. The top-level API will need
* to be changed to accomodate this, e.g. by introducing a ukvm_hv_shutdown(),
* however this is incompatible with the current "fail fast" approach to
* internal error handling.
*/
static struct ukvm_hv *cleanup_hv;
static void cleanup_vm(void)
{
if (cleanup_hv != NULL)
sysctlbyname("hw.vmm.destroy", NULL, NULL, cleanup_hv->b->vmname,
strlen(cleanup_hv->b->vmname));
}
static void cleanup_vmfd(void)
{
if (cleanup_hv != NULL && cleanup_hv->b->vmfd != -1)
close(cleanup_hv->b->vmfd);
}
struct ukvm_hv *ukvm_hv_init(size_t mem_size)
{
int ret;
struct ukvm_hv *hv = malloc(sizeof (struct ukvm_hv));
if (hv == NULL)
err(1, "malloc");
memset(hv, 0, sizeof (struct ukvm_hv));
struct ukvm_hvb *hvb = malloc(sizeof (struct ukvm_hvb));
if (hvb == NULL)
err(1, "malloc");
memset(hvb, 0, sizeof (struct ukvm_hvb));
hv->b = hvb;
hvb->vmfd = -1;
int namelen = asprintf(&hvb->vmname, "ukvm%d", getpid());
if (namelen == -1)
err(1, "asprintf");
ret = sysctlbyname("hw.vmm.create", NULL, NULL, hvb->vmname, namelen);
if (ret == -1)
err(1, "Cannot create VM '%s'", hvb->vmname);
cleanup_hv = hv;
atexit(cleanup_vm);
char *vmmdevname;
namelen = asprintf(&vmmdevname, "/dev/vmm/%s", hvb->vmname);
if (namelen == -1)
err(1, "asprintf");
hvb->vmfd = open(vmmdevname, O_RDWR, 0);
if (hvb->vmfd == -1)
err(1, "open(%s)", vmmdevname);
atexit(cleanup_vmfd);
struct vm_capability vmcap = {
.cpuid = 0, .captype = VM_CAP_HALT_EXIT, .capval = 1
};
ret = ioctl(hvb->vmfd, VM_SET_CAPABILITY, &vmcap);
if (ret == -1)
err(1, "set VM_CAP_HALT_EXIT");
struct vm_memseg memseg = {
.segid = 0, .len = mem_size
};
ret = ioctl(hvb->vmfd, VM_ALLOC_MEMSEG, &memseg);
if (ret == -1)
err(1, "VM_ALLOC_MEMSEG");
struct vm_memmap memmap = {
.gpa = 0, .len = mem_size, .segid = 0, .segoff = 0,
.prot = PROT_READ | PROT_WRITE | PROT_EXEC, .flags = 0
};
ret = ioctl(hvb->vmfd, VM_MMAP_MEMSEG, &memmap);
if (ret == -1)
err(1, "VM_MMAP_MEMSEG");
hv->mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
hvb->vmfd, 0);
if (hv->mem == MAP_FAILED)
err(1, "mmap");
hv->mem_size = mem_size;
return hv;
}
View
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2015-2017 Contributors as noted in the AUTHORS file
*
* This file is part of ukvm, a unikernel monitor.
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __UKVM_HV_BHYVE_H__
#define __UKVM_HV_BHYVE_H__
struct ukvm_hvb {
char *vmname;
int vmfd;
struct vm_run vmrun;
};
#endif
Oops, something went wrong.