summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile1
-rw-r--r--lib/libc/gen/readpassphrase.c24
-rw-r--r--lib/libc/mips/SYS.h28
-rw-r--r--lib/libdevctl/Makefile8
-rw-r--r--lib/libdevctl/devctl.3254
-rw-r--r--lib/libdevctl/devctl.c110
-rw-r--r--lib/libdevctl/devctl.h40
-rw-r--r--lib/libdpv/dialog_util.c7
-rw-r--r--lib/libdpv/dialog_util.h1
-rw-r--r--lib/libdpv/dpv.35
-rw-r--r--lib/libdpv/dpv.c7
-rw-r--r--lib/libdpv/dpv.h3
-rw-r--r--lib/libdpv/dpv_private.h3
-rw-r--r--lib/libvmmapi/vmmapi.c323
-rw-r--r--lib/libvmmapi/vmmapi.h52
15 files changed, 786 insertions, 80 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 742bd5e..d2cda1e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -37,6 +37,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libcom_err} \
libcompat \
libcrypt \
+ libdevctl \
libdevinfo \
libdevstat \
libdpv \
diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c
index 60051a1..0961fbb 100644
--- a/lib/libc/gen/readpassphrase.c
+++ b/lib/libc/gen/readpassphrase.c
@@ -46,7 +46,7 @@ char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
ssize_t nr;
- int input, output, save_errno, i, need_restart;
+ int input, output, save_errno, i, need_restart, input_is_tty;
char ch, *p, *end;
struct termios term, oterm;
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
@@ -68,12 +68,20 @@ restart:
* Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required.
*/
- if ((flags & RPP_STDIN) ||
- (input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) {
- if (flags & RPP_REQUIRE_TTY) {
- errno = ENOTTY;
- return(NULL);
+ input_is_tty = 0;
+ if (!(flags & RPP_STDIN)) {
+ input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC);
+ if (input == -1) {
+ if (flags & RPP_REQUIRE_TTY) {
+ errno = ENOTTY;
+ return(NULL);
+ }
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ } else {
+ input_is_tty = 1;
}
+ } else {
input = STDIN_FILENO;
output = STDERR_FILENO;
}
@@ -83,7 +91,7 @@ restart:
* If we are using a tty but are not the foreground pgrp this will
* generate SIGTTOU, so do it *before* installing the signal handlers.
*/
- if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
+ if (input_is_tty && tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON))
term.c_lflag &= ~(ECHO | ECHONL);
@@ -152,7 +160,7 @@ restart:
(void)__libc_sigaction(SIGTSTP, &savetstp, NULL);
(void)__libc_sigaction(SIGTTIN, &savettin, NULL);
(void)__libc_sigaction(SIGTTOU, &savettou, NULL);
- if (input != STDIN_FILENO)
+ if (input_is_tty)
(void)_close(input);
/*
diff --git a/lib/libc/mips/SYS.h b/lib/libc/mips/SYS.h
index 10205b8..ceb6812 100644
--- a/lib/libc/mips/SYS.h
+++ b/lib/libc/mips/SYS.h
@@ -100,13 +100,31 @@
* Do a syscall that cannot fail (sync, get{p,u,g,eu,eg)id)
*/
#define RSYSCALL_NOERROR(x) \
- PSEUDO_NOERROR(x)
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(x); \
+ _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ SYSTRAP(x); \
+ j ra; \
+END(__sys_ ## x)
/*
* Do a normal syscall.
*/
#define RSYSCALL(x) \
- PSEUDO(x)
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(x); \
+ _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ PIC_PROLOGUE(__sys_ ## x); \
+ SYSTRAP(x); \
+ bne a3,zero,err; \
+ PIC_RETURN(); \
+err: \
+ PIC_TAILCALL(__cerror); \
+END(__sys_ ## x)
/*
* Do a renamed or pseudo syscall (e.g., _exit()), where the entrypoint
@@ -114,18 +132,14 @@
*/
#define PSEUDO_NOERROR(x) \
LEAF(__sys_ ## x); \
- .weak _C_LABEL(x); \
- _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
.weak _C_LABEL(__CONCAT(_,x)); \
_C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
SYSTRAP(x); \
j ra; \
- END(__sys_ ## x)
+END(__sys_ ## x)
#define PSEUDO(x) \
LEAF(__sys_ ## x); \
- .weak _C_LABEL(x); \
- _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
.weak _C_LABEL(__CONCAT(_,x)); \
_C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
PIC_PROLOGUE(__sys_ ## x); \
diff --git a/lib/libdevctl/Makefile b/lib/libdevctl/Makefile
new file mode 100644
index 0000000..74687ec
--- /dev/null
+++ b/lib/libdevctl/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+LIB= devctl
+SRCS= devctl.c
+INCS= devctl.h
+MAN= devctl.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libdevctl/devctl.3 b/lib/libdevctl/devctl.3
new file mode 100644
index 0000000..b8a84d4
--- /dev/null
+++ b/lib/libdevctl/devctl.3
@@ -0,0 +1,254 @@
+.\"
+.\" Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" 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 AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 26, 2014
+.Dt DEVCTL 3
+.Os
+.Sh NAME
+.Nm devctl ,
+.Nm devctl_attach ,
+.Nm devctl_detach ,
+.Nm devctl_disable ,
+.Nm devctl_enable
+.Nd device control library
+.Sh LIBRARY
+.Lb libdevctl
+.Sh SYNOPSIS
+.In devctl.h
+.Ft int
+.Fn devctl_attach "const char *device"
+.Ft int
+.Fn devctl_detach "const char *device" "bool force"
+.Ft int
+.Fn devctl_disable "const char *device" "bool force_detach"
+.Ft int
+.Fn devctl_enable "const char *device"
+.Ft int
+.Fn devctl_set_driver "const char *device" "const char *driver" "bool force"
+.Sh DESCRIPTION
+The
+.Nm
+library adjusts the state of devices in the kernel's internal device
+hierarchy.
+Each control operation accepts a
+.Fa device
+argument that identifies the device to adjust.
+The
+.Fa device
+may be specified as either the name of an existing device or as a
+bus-specific address.
+The following bus-specific address formats are currently supported:
+.Bl -tag -offset indent
+.It Sy pci Ns Fa domain Ns : Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
+A PCI device with the specified
+.Fa domain ,
+.Fa bus ,
+.Fa slot ,
+and
+.Fa function .
+.It Sy pci Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
+A PCI device in domain zero with the specified
+.Fa bus ,
+.Fa slot ,
+and
+.Fa function .
+.It Fa handle
+A device with an ACPI handle of
+.Fa handle .
+The handle must be specified as an absolute path and must begin with a
+.Dq \e .
+.El
+.Pp
+The
+.Fn devctl_attach
+function probes a device and attaches a suitable device driver if one is
+found.
+.Pp
+The
+.Fn devctl_detach
+function detaches a device from its current device driver.
+The device is left detached until either a new driver for its parent
+bus is loaded or the device is explicitly probed via
+.Fn devctl_attach .
+If
+.Fa force
+is true,
+the current device driver will be detached even if the device is busy.
+.Pp
+The
+.Fn devctl_disable
+function disables a device.
+If the device is currently attached to a device driver,
+the device driver will be detached from the device,
+but the device will retain its current name.
+If
+.Fa force_detach
+is true,
+the current device driver will be detached even if the device is busy.
+The device will remain disabled and detached until it is explicitly enabled
+via
+.Fn devctl_enable .
+.Pp
+The
+.Fn devctl_enable
+function re-enables a disabled device.
+The device will probe and attach if a suitable device driver is found.
+.Pp
+The
+.Fn devctl_set_driver
+function attaches a device driver named
+.Fa driver
+to a device.
+If the device is already attached and
+.Fa force
+is false,
+the request will fail.
+If the device is already attached and
+.Fa force
+is true,
+the device will be detached from its current device driver before it is
+attached to the new device driver.
+.Sh RETURN VALUES
+.Rv -std devctl_attach devctl_detach devctl_disable devctl_enable \
+devctl_set_driver
+.Sh ERRORS
+In addition to specific errors noted below,
+all of the
+.Nm
+functions may fail for any of the errors described in
+.Xr open 2
+as well as:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The device name is too long.
+.It Bq Er ENOENT
+No existing device matches the specified name or location.
+.It Bq Er EPERM
+The current process is not permitted to adjust the state of
+.Fa device .
+.El
+.Pp
+The
+.Fn devctl_attach
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is already attached.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+The device is disabled.
+.It Bq Er ENXIO
+No suitable driver for the device could be found,
+or the driver failed to attach.
+.El
+.Pp
+The
+.Fn devctl_detach
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+Note that some drivers may return this even if
+.Fa force
+is true.
+.It Bq Er ENXIO
+The device is not attached to a driver.
+.It Bq Er ENXIO
+The current device driver for
+.Fa device
+does not support detaching.
+.El
+.Pp
+The
+.Fn devctl_enable
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is already enabled.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+No suitable driver for the device could be found,
+or the driver failed to attach.
+.El
+.Pp
+The
+.Fn devctl_disable
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+Note that some drivers may return this even if
+.Fa force_detach
+is true.
+.It Bq Er ENXIO
+The device is already disabled.
+.It Bq Er ENXIO
+The current device driver for
+.Fa device
+does not support detaching.
+.El
+.Pp
+The
+.Fn devctl_set_driver
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is currently attached to a device driver and
+.Fa force
+is false.
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+.It Bq Er EFAULT
+The
+.Fa driver
+argument points outside the process' allocated address space.
+.It Bq Er ENOENT
+No device driver with the requested name exists.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+The device is disabled.
+.It Bq Er ENXIO
+The new device driver failed to attach.
+.El
+.Sh SEE ALSO
+.Xr devinfo 3 ,
+.Xr devstat 3 ,
+.Xr devctl 8
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 11.0 .
diff --git a/lib/libdevctl/devctl.c b/lib/libdevctl/devctl.c
new file mode 100644
index 0000000..fa0e6a5
--- /dev/null
+++ b/lib/libdevctl/devctl.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "devctl.h"
+
+static int
+devctl_request(u_long cmd, struct devreq *req)
+{
+ static int devctl2_fd = -1;
+
+ if (devctl2_fd == -1) {
+ devctl2_fd = open("/dev/devctl2", O_RDONLY);
+ if (devctl2_fd == -1)
+ return (-1);
+ }
+ return (ioctl(devctl2_fd, cmd, req));
+}
+
+static int
+devctl_simple_request(u_long cmd, const char *name, int flags)
+{
+ struct devreq req;
+
+ memset(&req, 0, sizeof(req));
+ if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >=
+ sizeof(req.dr_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ req.dr_flags = flags;
+ return (devctl_request(cmd, &req));
+}
+
+int
+devctl_attach(const char *device)
+{
+
+ return (devctl_simple_request(DEV_ATTACH, device, 0));
+}
+
+int
+devctl_detach(const char *device, bool force)
+{
+
+ return (devctl_simple_request(DEV_DETACH, device, force ?
+ DEVF_FORCE_DETACH : 0));
+}
+
+int
+devctl_enable(const char *device)
+{
+
+ return (devctl_simple_request(DEV_ENABLE, device, 0));
+}
+
+int
+devctl_disable(const char *device, bool force_detach)
+{
+
+ return (devctl_simple_request(DEV_DISABLE, device, force_detach ?
+ DEVF_FORCE_DETACH : 0));
+}
+
+int
+devctl_set_driver(const char *device, const char *driver, bool force)
+{
+ struct devreq req;
+
+ memset(&req, 0, sizeof(req));
+ if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >=
+ sizeof(req.dr_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ req.dr_data = __DECONST(char *, driver);
+ if (force)
+ req.dr_flags |= DEVF_SET_DRIVER_DETACH;
+ return (devctl_request(DEV_SET_DRIVER, &req));
+}
diff --git a/lib/libdevctl/devctl.h b/lib/libdevctl/devctl.h
new file mode 100644
index 0000000..3426cce
--- /dev/null
+++ b/lib/libdevctl/devctl.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __DEVCTL_H__
+#define __DEVCTL_H__
+
+#include <stdbool.h>
+
+int devctl_attach(const char *device);
+int devctl_detach(const char *device, bool force);
+int devctl_enable(const char *device);
+int devctl_disable(const char *device, bool force_detach);
+int devctl_set_driver(const char *device, const char *driver, bool force);
+
+#endif /* !__DEVCTL_H__ */
diff --git a/lib/libdpv/dialog_util.c b/lib/libdpv/dialog_util.c
index d047a25..21baf98 100644
--- a/lib/libdpv/dialog_util.c
+++ b/lib/libdpv/dialog_util.c
@@ -261,6 +261,13 @@ dialog_spawn_gauge(char *init_prompt, pid_t *pid)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--title");
dargv[n++] = title;
+ } else {
+ if ((dargv[n] = malloc(8)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--title");
+ if ((dargv[n] = malloc(1)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ *dargv[n++] = '\0';
}
if (backtitle != NULL) {
if ((dargv[n] = malloc(12)) == NULL)
diff --git a/lib/libdpv/dialog_util.h b/lib/libdpv/dialog_util.h
index e279c3f..b0c73c5 100644
--- a/lib/libdpv/dialog_util.h
+++ b/lib/libdpv/dialog_util.h
@@ -55,7 +55,6 @@ extern int dheight, dwidth;
__BEGIN_DECLS
uint8_t dialog_prompt_nlstate(const char *_prompt);
-void dialog_gauge_free(void);
void dialog_maxsize_free(void);
char *dialog_prompt_lastline(char *_prompt, uint8_t _nlstate);
int dialog_maxcols(void);
diff --git a/lib/libdpv/dpv.3 b/lib/libdpv/dpv.3
index 4779540..97461eb 100644
--- a/lib/libdpv/dpv.3
+++ b/lib/libdpv/dpv.3
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2013-2015 Devin Teske
+.\" Copyright (c) 2013-2016 Devin Teske
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd Oct 22, 2015
+.Dd Jan 26, 2016
.Dt DPV 3
.Os
.Sh NAME
@@ -64,6 +64,7 @@ argument contains the following properties for configuring global display
features:
.Bd -literal -offset indent
struct dpv_config {
+ uint8_t keep_tite; /* Cleaner exit for scripts */
enum dpv_display display_type; /* Def. DPV_DISPLAY_LIBDIALOG */
enum dpv_output output_type; /* Default DPV_OUTPUT_NONE */
int debug; /* Enable debug on stderr */
diff --git a/lib/libdpv/dpv.c b/lib/libdpv/dpv.c
index d3506ca..8ac39b1 100644
--- a/lib/libdpv/dpv.c
+++ b/lib/libdpv/dpv.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,6 +69,7 @@ long long dpv_overall_read = 0;
static char pathbuf[PATH_MAX];
/* Extra display information */
+uint8_t keep_tite = FALSE; /* dpv_config.keep_tite */
uint8_t no_labels = FALSE; /* dpv_config.options & DPV_NO_LABELS */
uint8_t wide = FALSE; /* dpv_config.options & DPV_WIDE_MODE */
char *aprompt = NULL; /* dpv_config.aprompt */
@@ -150,6 +151,7 @@ dpv(struct dpv_config *config, struct dpv_file_node *file_list)
dialog_updates_per_second = DIALOG_UPDATES_PER_SEC;
display_limit = DISPLAY_LIMIT_DEFAULT;
display_type = DPV_DISPLAY_LIBDIALOG;
+ keep_tite = FALSE;
label_size = LABEL_SIZE_DEFAULT;
msg_done = NULL;
msg_fail = NULL;
@@ -193,6 +195,7 @@ dpv(struct dpv_config *config, struct dpv_file_node *file_list)
dialog_updates_per_second = config->dialog_updates_per_second;
display_limit = config->display_limit;
display_type = config->display_type;
+ keep_tite = config->keep_tite;
label_size = config->label_size;
msg_done = (char *)config->msg_done;
msg_fail = (char *)config->msg_fail;
@@ -695,7 +698,7 @@ dpv(struct dpv_config *config, struct dpv_file_node *file_list)
close(dialog_out);
waitpid(pid, (int *)NULL, 0);
}
- if (!dpv_interrupt)
+ if (!keep_tite && !dpv_interrupt)
printf("\n");
} else
warnx("%s: %lli overall read", __func__, dpv_overall_read);
diff --git a/lib/libdpv/dpv.h b/lib/libdpv/dpv.h
index 03768a7..a79962b 100644
--- a/lib/libdpv/dpv.h
+++ b/lib/libdpv/dpv.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,7 @@ struct dpv_file_node {
* Anatomy of config option to pass as dpv() config argument
*/
struct dpv_config {
+ uint8_t keep_tite; /* Prevent visually distracting exit */
enum dpv_display display_type; /* Display (default TYPE_LIBDIALOG) */
enum dpv_output output_type; /* Output (default TYPE_NONE) */
int debug; /* Enable debugging output on stderr */
diff --git a/lib/libdpv/dpv_private.h b/lib/libdpv/dpv_private.h
index 5164eb3..fd4734c 100644
--- a/lib/libdpv/dpv_private.h
+++ b/lib/libdpv/dpv_private.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@ extern uint8_t debug;
extern unsigned int dpv_nfiles;
/* Extra display information */
+extern uint8_t keep_tite;
extern uint8_t no_labels;
extern uint8_t wide;
extern char *msg_done, *msg_fail, *msg_pending;
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 1e6e627..fb8eb78 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -58,15 +58,23 @@ __FBSDID("$FreeBSD$");
#define MB (1024 * 1024UL)
#define GB (1024 * 1024 * 1024UL)
+/*
+ * Size of the guard region before and after the virtual address space
+ * mapping the guest physical memory. This must be a multiple of the
+ * superpage size for performance reasons.
+ */
+#define VM_MMAP_GUARD_SIZE (4 * MB)
+
+#define PROT_RW (PROT_READ | PROT_WRITE)
+#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
+
struct vmctx {
int fd;
uint32_t lowmem_limit;
- enum vm_mmap_style vms;
int memflags;
size_t lowmem;
- char *lowmem_addr;
size_t highmem;
- char *highmem_addr;
+ char *baseaddr;
char *name;
};
@@ -157,22 +165,6 @@ vm_parse_memsize(const char *optarg, size_t *ret_memsize)
return (error);
}
-int
-vm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa, size_t *ret_len,
- int *wired)
-{
- int error;
- struct vm_memory_segment seg;
-
- bzero(&seg, sizeof(seg));
- seg.gpa = gpa;
- error = ioctl(ctx->fd, VM_GET_MEMORY_SEG, &seg);
- *ret_len = seg.len;
- if (wired != NULL)
- *wired = seg.wired;
- return (error);
-}
-
uint32_t
vm_get_lowmem_limit(struct vmctx *ctx)
{
@@ -194,39 +186,184 @@ vm_set_memflags(struct vmctx *ctx, int flags)
ctx->memflags = flags;
}
+int
+vm_get_memflags(struct vmctx *ctx)
+{
+
+ return (ctx->memflags);
+}
+
+/*
+ * Map segment 'segid' starting at 'off' into guest address range [gpa,gpa+len).
+ */
+int
+vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid, vm_ooffset_t off,
+ size_t len, int prot)
+{
+ struct vm_memmap memmap;
+ int error, flags;
+
+ memmap.gpa = gpa;
+ memmap.segid = segid;
+ memmap.segoff = off;
+ memmap.len = len;
+ memmap.prot = prot;
+ memmap.flags = 0;
+
+ if (ctx->memflags & VM_MEM_F_WIRED)
+ memmap.flags |= VM_MEMMAP_F_WIRED;
+
+ /*
+ * If this mapping already exists then don't create it again. This
+ * is the common case for SYSMEM mappings created by bhyveload(8).
+ */
+ error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags);
+ if (error == 0 && gpa == memmap.gpa) {
+ if (segid != memmap.segid || off != memmap.segoff ||
+ prot != memmap.prot || flags != memmap.flags) {
+ errno = EEXIST;
+ return (-1);
+ } else {
+ return (0);
+ }
+ }
+
+ error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap);
+ return (error);
+}
+
+int
+vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid,
+ vm_ooffset_t *segoff, size_t *len, int *prot, int *flags)
+{
+ struct vm_memmap memmap;
+ int error;
+
+ bzero(&memmap, sizeof(struct vm_memmap));
+ memmap.gpa = *gpa;
+ error = ioctl(ctx->fd, VM_MMAP_GETNEXT, &memmap);
+ if (error == 0) {
+ *gpa = memmap.gpa;
+ *segid = memmap.segid;
+ *segoff = memmap.segoff;
+ *len = memmap.len;
+ *prot = memmap.prot;
+ *flags = memmap.flags;
+ }
+ return (error);
+}
+
+/*
+ * Return 0 if the segments are identical and non-zero otherwise.
+ *
+ * This is slightly complicated by the fact that only device memory segments
+ * are named.
+ */
+static int
+cmpseg(size_t len, const char *str, size_t len2, const char *str2)
+{
+
+ if (len == len2) {
+ if ((!str && !str2) || (str && str2 && !strcmp(str, str2)))
+ return (0);
+ }
+ return (-1);
+}
+
static int
-setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char **addr)
+vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name)
{
- int error, mmap_flags;
- struct vm_memory_segment seg;
+ struct vm_memseg memseg;
+ size_t n;
+ int error;
/*
- * Create and optionally map 'len' bytes of memory at guest
- * physical address 'gpa'
+ * If the memory segment has already been created then just return.
+ * This is the usual case for the SYSMEM segment created by userspace
+ * loaders like bhyveload(8).
*/
- bzero(&seg, sizeof(seg));
- seg.gpa = gpa;
- seg.len = len;
- error = ioctl(ctx->fd, VM_MAP_MEMORY, &seg);
- if (error == 0 && addr != NULL) {
- mmap_flags = MAP_SHARED;
- if ((ctx->memflags & VM_MEM_F_INCORE) == 0)
- mmap_flags |= MAP_NOCORE;
- *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, mmap_flags,
- ctx->fd, gpa);
+ error = vm_get_memseg(ctx, segid, &memseg.len, memseg.name,
+ sizeof(memseg.name));
+ if (error)
+ return (error);
+
+ if (memseg.len != 0) {
+ if (cmpseg(len, name, memseg.len, VM_MEMSEG_NAME(&memseg))) {
+ errno = EINVAL;
+ return (-1);
+ } else {
+ return (0);
+ }
+ }
+
+ bzero(&memseg, sizeof(struct vm_memseg));
+ memseg.segid = segid;
+ memseg.len = len;
+ if (name != NULL) {
+ n = strlcpy(memseg.name, name, sizeof(memseg.name));
+ if (n >= sizeof(memseg.name)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
}
+
+ error = ioctl(ctx->fd, VM_ALLOC_MEMSEG, &memseg);
return (error);
}
int
-vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
+vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf,
+ size_t bufsize)
{
- char **addr;
+ struct vm_memseg memseg;
+ size_t n;
int error;
- /* XXX VM_MMAP_SPARSE not implemented yet */
- assert(vms == VM_MMAP_NONE || vms == VM_MMAP_ALL);
- ctx->vms = vms;
+ memseg.segid = segid;
+ error = ioctl(ctx->fd, VM_GET_MEMSEG, &memseg);
+ if (error == 0) {
+ *lenp = memseg.len;
+ n = strlcpy(namebuf, memseg.name, bufsize);
+ if (n >= bufsize) {
+ errno = ENAMETOOLONG;
+ error = -1;
+ }
+ }
+ return (error);
+}
+
+static int
+setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base)
+{
+ char *ptr;
+ int error, flags;
+
+ /* Map 'len' bytes starting at 'gpa' in the guest address space */
+ error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL);
+ if (error)
+ return (error);
+
+ flags = MAP_SHARED | MAP_FIXED;
+ if ((ctx->memflags & VM_MEM_F_INCORE) == 0)
+ flags |= MAP_NOCORE;
+
+ /* mmap into the process address space on the host */
+ ptr = mmap(base + gpa, len, PROT_RW, flags, ctx->fd, gpa);
+ if (ptr == MAP_FAILED)
+ return (-1);
+
+ return (0);
+}
+
+int
+vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
+{
+ size_t objsize, len;
+ vm_paddr_t gpa;
+ char *baseaddr, *ptr;
+ int error, flags;
+
+ assert(vms == VM_MMAP_ALL);
/*
* If 'memsize' cannot fit entirely in the 'lowmem' segment then
@@ -234,43 +371,69 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
*/
if (memsize > ctx->lowmem_limit) {
ctx->lowmem = ctx->lowmem_limit;
- ctx->highmem = memsize - ctx->lowmem;
+ ctx->highmem = memsize - ctx->lowmem_limit;
+ objsize = 4*GB + ctx->highmem;
} else {
ctx->lowmem = memsize;
ctx->highmem = 0;
+ objsize = ctx->lowmem;
}
- if (ctx->lowmem > 0) {
- addr = (vms == VM_MMAP_ALL) ? &ctx->lowmem_addr : NULL;
- error = setup_memory_segment(ctx, 0, ctx->lowmem, addr);
+ error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL);
+ if (error)
+ return (error);
+
+ /*
+ * Stake out a contiguous region covering the guest physical memory
+ * and the adjoining guard regions.
+ */
+ len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE;
+ flags = MAP_PRIVATE | MAP_ANON | MAP_NOCORE | MAP_ALIGNED_SUPER;
+ ptr = mmap(NULL, len, PROT_NONE, flags, -1, 0);
+ if (ptr == MAP_FAILED)
+ return (-1);
+
+ baseaddr = ptr + VM_MMAP_GUARD_SIZE;
+ if (ctx->highmem > 0) {
+ gpa = 4*GB;
+ len = ctx->highmem;
+ error = setup_memory_segment(ctx, gpa, len, baseaddr);
if (error)
return (error);
}
- if (ctx->highmem > 0) {
- addr = (vms == VM_MMAP_ALL) ? &ctx->highmem_addr : NULL;
- error = setup_memory_segment(ctx, 4*GB, ctx->highmem, addr);
+ if (ctx->lowmem > 0) {
+ gpa = 0;
+ len = ctx->lowmem;
+ error = setup_memory_segment(ctx, gpa, len, baseaddr);
if (error)
return (error);
}
+ ctx->baseaddr = baseaddr;
+
return (0);
}
+/*
+ * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in
+ * the lowmem or highmem regions.
+ *
+ * In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region.
+ * The instruction emulation code depends on this behavior.
+ */
void *
vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len)
{
- /* XXX VM_MMAP_SPARSE not implemented yet */
- assert(ctx->vms == VM_MMAP_ALL);
-
- if (gaddr < ctx->lowmem && gaddr + len <= ctx->lowmem)
- return ((void *)(ctx->lowmem_addr + gaddr));
+ if (ctx->lowmem > 0) {
+ if (gaddr < ctx->lowmem && gaddr + len <= ctx->lowmem)
+ return (ctx->baseaddr + gaddr);
+ }
- if (gaddr >= 4*GB) {
- gaddr -= 4*GB;
- if (gaddr < ctx->highmem && gaddr + len <= ctx->highmem)
- return ((void *)(ctx->highmem_addr + gaddr));
+ if (ctx->highmem > 0) {
+ if (gaddr >= 4*GB && gaddr + len <= 4*GB + ctx->highmem)
+ return (ctx->baseaddr + gaddr);
}
return (NULL);
@@ -290,6 +453,56 @@ vm_get_highmem_size(struct vmctx *ctx)
return (ctx->highmem);
}
+void *
+vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len)
+{
+ char pathname[MAXPATHLEN];
+ size_t len2;
+ char *base, *ptr;
+ int fd, error, flags;
+
+ fd = -1;
+ ptr = MAP_FAILED;
+ if (name == NULL || strlen(name) == 0) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ error = vm_alloc_memseg(ctx, segid, len, name);
+ if (error)
+ goto done;
+
+ strlcpy(pathname, "/dev/vmm.io/", sizeof(pathname));
+ strlcat(pathname, ctx->name, sizeof(pathname));
+ strlcat(pathname, ".", sizeof(pathname));
+ strlcat(pathname, name, sizeof(pathname));
+
+ fd = open(pathname, O_RDWR);
+ if (fd < 0)
+ goto done;
+
+ /*
+ * Stake out a contiguous region covering the device memory and the
+ * adjoining guard regions.
+ */
+ len2 = VM_MMAP_GUARD_SIZE + len + VM_MMAP_GUARD_SIZE;
+ flags = MAP_PRIVATE | MAP_ANON | MAP_NOCORE | MAP_ALIGNED_SUPER;
+ base = mmap(NULL, len2, PROT_NONE, flags, -1, 0);
+ if (base == MAP_FAILED)
+ goto done;
+
+ flags = MAP_SHARED | MAP_FIXED;
+ if ((ctx->memflags & VM_MEM_F_INCORE) == 0)
+ flags |= MAP_NOCORE;
+
+ /* mmap the devmem region in the host address space */
+ ptr = mmap(base + VM_MMAP_GUARD_SIZE, len, PROT_RW, flags, fd, 0);
+done:
+ if (fd >= 0)
+ close(fd);
+ return (ptr);
+}
+
int
vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
uint64_t base, uint32_t limit, uint32_t access)
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index d3ecdc4..57f8c56 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -36,7 +36,7 @@
* API version for out-of-tree consumers like grub-bhyve for making compile
* time decisions.
*/
-#define VMMAPI_VERSION 0101 /* 2 digit major followed by 2 digit minor */
+#define VMMAPI_VERSION 0102 /* 2 digit major followed by 2 digit minor */
struct iovec;
struct vmctx;
@@ -52,14 +52,59 @@ enum vm_mmap_style {
VM_MMAP_SPARSE, /* mappings created on-demand */
};
+/*
+ * 'flags' value passed to 'vm_set_memflags()'.
+ */
#define VM_MEM_F_INCORE 0x01 /* include guest memory in core file */
+#define VM_MEM_F_WIRED 0x02 /* guest memory is wired */
+
+/*
+ * Identifiers for memory segments:
+ * - vm_setup_memory() uses VM_SYSMEM for the system memory segment.
+ * - the remaining identifiers can be used to create devmem segments.
+ */
+enum {
+ VM_SYSMEM,
+ VM_BOOTROM,
+ VM_FRAMEBUFFER,
+};
+
+/*
+ * Get the length and name of the memory segment identified by 'segid'.
+ * Note that system memory segments are identified with a nul name.
+ *
+ * Returns 0 on success and non-zero otherwise.
+ */
+int vm_get_memseg(struct vmctx *ctx, int ident, size_t *lenp, char *name,
+ size_t namesiz);
+
+/*
+ * Iterate over the guest address space. This function finds an address range
+ * that starts at an address >= *gpa.
+ *
+ * Returns 0 if the next address range was found and non-zero otherwise.
+ */
+int vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid,
+ vm_ooffset_t *segoff, size_t *len, int *prot, int *flags);
+/*
+ * Create a device memory segment identified by 'segid'.
+ *
+ * Returns a pointer to the memory segment on success and MAP_FAILED otherwise.
+ */
+void *vm_create_devmem(struct vmctx *ctx, int segid, const char *name,
+ size_t len);
+
+/*
+ * Map the memory segment identified by 'segid' into the guest address space
+ * at [gpa,gpa+len) with protection 'prot'.
+ */
+int vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid,
+ vm_ooffset_t segoff, size_t len, int prot);
int vm_create(const char *name);
struct vmctx *vm_open(const char *name);
void vm_destroy(struct vmctx *ctx);
int vm_parse_memsize(const char *optarg, size_t *memsize);
-int vm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa, size_t *ret_len,
- int *wired);
int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
void *vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len);
int vm_get_gpa_pmap(struct vmctx *, uint64_t gpa, uint64_t *pte, int *num);
@@ -68,6 +113,7 @@ int vm_gla2gpa(struct vmctx *, int vcpuid, struct vm_guest_paging *paging,
uint32_t vm_get_lowmem_limit(struct vmctx *ctx);
void vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit);
void vm_set_memflags(struct vmctx *ctx, int flags);
+int vm_get_memflags(struct vmctx *ctx);
size_t vm_get_lowmem_size(struct vmctx *ctx);
size_t vm_get_highmem_size(struct vmctx *ctx);
int vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
OpenPOWER on IntegriCloud