diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/libc/gen/readpassphrase.c | 24 | ||||
-rw-r--r-- | lib/libc/mips/SYS.h | 28 | ||||
-rw-r--r-- | lib/libdevctl/Makefile | 8 | ||||
-rw-r--r-- | lib/libdevctl/devctl.3 | 254 | ||||
-rw-r--r-- | lib/libdevctl/devctl.c | 110 | ||||
-rw-r--r-- | lib/libdevctl/devctl.h | 40 | ||||
-rw-r--r-- | lib/libdpv/dialog_util.c | 7 | ||||
-rw-r--r-- | lib/libdpv/dialog_util.h | 1 | ||||
-rw-r--r-- | lib/libdpv/dpv.3 | 5 | ||||
-rw-r--r-- | lib/libdpv/dpv.c | 7 | ||||
-rw-r--r-- | lib/libdpv/dpv.h | 3 | ||||
-rw-r--r-- | lib/libdpv/dpv_private.h | 3 | ||||
-rw-r--r-- | lib/libvmmapi/vmmapi.c | 323 | ||||
-rw-r--r-- | lib/libvmmapi/vmmapi.h | 52 |
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, |