Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107648667
D11768.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D11768.diff
View Options
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -57,6 +57,7 @@
usb_mouse.c \
virtio.c \
vga.c \
+ vncserver.c \
xmsr.c \
spinup_ap.c
Index: usr.sbin/bhyve/bhyve.8
===================================================================
--- usr.sbin/bhyve/bhyve.8
+++ usr.sbin/bhyve/bhyve.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 2, 2017
+.Dd July 28, 2017
.Dt BHYVE 8
.Os
.Sh NAME
@@ -193,6 +193,9 @@
The LPC bridge emulation can only be configured on bus 0.
.It Li fbuf
Raw framebuffer device attached to VNC server.
+.It Li vncserver
+Raw framebuffer device attached to a third party library that provides
+the VNC server.
.It Li xhci
eXtensible Host Controller Interface (xHCI) USB controller.
.El
@@ -482,7 +485,7 @@
-s 3,ahci-cd,/path/to/uefi-OS-install.iso \\
-s 4,ahci-hd,disk.img \\
-s 5,virtio-net,tap0 \\
- -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \\
+ -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait,vncserver \\
-s 30,xhci,tablet \\
-s 31,lpc -l com1,stdio \\
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
Index: usr.sbin/bhyve/pci_fbuf.c
===================================================================
--- usr.sbin/bhyve/pci_fbuf.c
+++ usr.sbin/bhyve/pci_fbuf.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2017 Marcelo Araujo <araujo@FreeBSD.org>.
* Copyright (c) 2015 Nahanni Systems, Inc.
* All rights reserved.
*
@@ -38,8 +39,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
+#include <dlfcn.h>
#include <errno.h>
+#include <err.h>
#include <unistd.h>
#include "bhyvegc.h"
@@ -61,7 +65,7 @@
static int fbuf_debug = 1;
#define DEBUG_INFO 1
#define DEBUG_VERBOSE 4
-#define DPRINTF(level, params) if (level <= fbuf_debug) printf params
+#define DPRINTF(level, params) if (level <= fbuf_debug) printf params
#define KB (1024UL)
@@ -92,18 +96,19 @@
} __packed memregs;
/* rfb server */
- char *rfb_host;
- char *rfb_password;
- int rfb_port;
- int rfb_wait;
- int vga_enabled;
- int vga_full;
+ char *rfb_host;
+ char *rfb_password;
+ int rfb_port;
+ int rfb_wait;
+ int vga_enabled;
+ int vga_full;
+ int vncserver_enabled;
- uint32_t fbaddr;
- char *fb_base;
- uint16_t gc_width;
- uint16_t gc_height;
- void *vgasc;
+ uint32_t fbaddr;
+ char *fb_base;
+ uint16_t gc_width;
+ uint16_t gc_height;
+ void *vgasc;
struct bhyvegc_image *gc_image;
};
@@ -222,10 +227,13 @@
static int
pci_fbuf_parse_opts(struct pci_fbuf_softc *sc, char *opts)
{
- char *uopts, *xopts, *config;
- char *tmpstr;
- int ret;
+ char *uopts, *xopts, *config;
+ char *tmpstr;
+ char *loader;
+ int ret;
+ void *shlib;
+ loader = NULL;
ret = 0;
uopts = strdup(opts);
for (xopts = strtok(uopts, ",");
@@ -236,6 +244,23 @@
continue;
}
+ if (strcmp(xopts, "vncserver") == 0) {
+ if (loader == NULL) {
+ loader = strdup("/usr/local/lib/libhyverem.so");
+ if (loader == NULL)
+ err(EX_OSERR, "malloc");
+ }
+ shlib = dlopen(loader, RTLD_LAZY);
+ if (!shlib) {
+ sc->vncserver_enabled = 0;
+ fprintf(stderr, "Using RFB bhyve implementation.\n");
+ } else
+ sc->vncserver_enabled = 1;
+ dlclose(shlib);
+ free(loader);
+ continue;
+ }
+
if ((config = strchr(xopts, '=')) == NULL) {
pci_fbuf_usage(xopts);
ret = -1;
@@ -247,16 +272,17 @@
DPRINTF(DEBUG_VERBOSE, ("pci_fbuf option %s = %s\r\n",
xopts, config));
- if (!strcmp(xopts, "tcp") || !strcmp(xopts, "rfb")) {
+ if (!strcmp(xopts, "tcp") || !strcmp(xopts, "rfb") ||
+ !strcmp(xopts, "vncserver")) {
/* parse host-ip:port */
- tmpstr = strsep(&config, ":");
+ tmpstr = strsep(&config, ":");
if (!config)
sc->rfb_port = atoi(tmpstr);
else {
sc->rfb_port = atoi(config);
sc->rfb_host = tmpstr;
}
- } else if (!strcmp(xopts, "vga")) {
+ } else if (!strcmp(xopts, "vga")) {
if (!strcmp(config, "off")) {
sc->vga_enabled = 0;
} else if (!strcmp(config, "io")) {
@@ -270,8 +296,8 @@
ret = -1;
goto done;
}
- } else if (!strcmp(xopts, "w")) {
- sc->memregs.width = atoi(config);
+ } else if (!strcmp(xopts, "w")) {
+ sc->memregs.width = atoi(config);
if (sc->memregs.width > COLS_MAX) {
pci_fbuf_usage(xopts);
ret = -1;
@@ -383,7 +409,7 @@
goto done;
}
DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]\r\n",
- sc->fb_base, FB_SIZE));
+ sc->fb_base, FB_SIZE));
/*
* Map the framebuffer into the guest address space.
@@ -409,7 +435,10 @@
memset((void *)sc->fb_base, 0, FB_SIZE);
- error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
+ if (sc->vncserver_enabled)
+ error = vncserver_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
+ else
+ error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
done:
if (error)
free(sc);
Index: usr.sbin/bhyve/rfb.h
===================================================================
--- usr.sbin/bhyve/rfb.h
+++ usr.sbin/bhyve/rfb.h
@@ -32,5 +32,6 @@
#define RFB_PORT 5900
int rfb_init(char *hostname, int port, int wait, char *password);
+int vncserver_init(char *hostname, int port, int wait, char *password);
#endif /* _RFB_H_ */
Index: usr.sbin/bhyve/vncserver.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/vncserver.c
@@ -0,0 +1,442 @@
+/*-
+ * Copyright (c) 2017 Marcelo Araujo <araujo@FreeBSD.org>
+ * Copyright (c) 2016 Jakub Klama <jakub@ixsystems.com>
+ * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
+ * Copyright (c) 2015 Leon Dang
+ * 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 ``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/socket.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <sys/param.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <cpuid.h>
+#include <zlib.h>
+
+#include "bhyvegc.h"
+#include "console.h"
+
+static int vncserver_debug = 1;
+#define DPRINTF(params) if (vncserver_debug) printf params
+#define WPRINTF(params) printf params
+
+struct vncserver_softc {
+ struct bhyvegc_image *vs_gc;
+ pthread_t vs_tid;
+ int vs_width;
+ int vs_height;
+ int vs_conn_wait;
+ int vs_sending;
+ pthread_mutex_t vs_mtx;
+ pthread_cond_t vs_cond;
+
+ int vs_hw_crc;
+ uint32_t * vs_crc; /* WxH crc cells */
+ uint32_t * vs_crc_tmp; /* buffer to store single crc row */
+ int vs_crc_width;
+ int vs_crc_height;
+
+ char *desktopName;
+ bool alwaysShared;
+ int redShift;
+ int greenShift;
+ int blueShift;
+ char *frameBuffer;
+ int bitsPerSample;
+ int samplesPerPixel;
+ int bytesPerPixel;
+ int bind_port;
+ void (*kdb_handler)(int down, uint32_t keysym);
+ void (*ptr_handler)(uint8_t button, int x, int y);
+};
+
+#define RFB_MAX_WIDTH 2000
+#define RFB_MAX_HEIGHT 1200
+#define RFB_ZLIB_BUFSZ RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4
+
+#define PIX_PER_CELL 32
+#define PIXCELL_SHIFT 5
+#define PIXCELL_MASK 0x1F
+
+/* percentage changes to screen before sending the entire screen */
+#define RFB_SEND_ALL_THRESH 25
+
+/* path of libhyve-remote */
+#define LIB_HYVE_REMOTE "/usr/local/lib/libhyverem.so"
+
+/* prototype functions from shared library libhyve-remote */
+int (*vnc_init_server)(struct vncserver_softc *sc);
+int (*vnc_event_loop)(int time, bool b);
+int (*vnc_enable_http)(char *webdir, bool enable);
+int (*vnc_enable_password)(char *vnc_password);
+void (*vnc_mark_rect_modified)(struct vncserver_softc *sc, int x1, int y1,
+ int x2, int y2);
+
+/* Try to load libhyve-remote */
+static int
+load_shared_lib(void)
+{
+ char *loader = NULL;
+ void *shlib;
+
+ if (loader == NULL) {
+ loader = strdup(LIB_HYVE_REMOTE);
+ if (loader == NULL)
+ err(ENOMEM, "malloc error");
+ }
+
+ shlib = dlopen(loader, RTLD_GLOBAL);
+ if (!shlib) {
+ dlclose(shlib);
+ free(loader);
+ return (1);
+ } else {
+ vnc_init_server = dlsym(shlib, "vnc_init_server");
+ vnc_event_loop = dlsym(shlib, "vnc_event_loop");
+ vnc_enable_http = dlsym(shlib, "vnc_enable_http");
+ vnc_mark_rect_modified = dlsym(shlib, "vnc_mark_rect_modified");
+ vnc_enable_password = dlsym(shlib, "vnc_enable_password");
+ }
+ return (0);
+}
+
+/*
+ * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only
+ */
+static __inline uint32_t
+fast_crc32(void *buf, int len, uint32_t crcval)
+{
+ uint32_t q = len / sizeof(uint32_t);
+ uint32_t *p = (uint32_t *)buf;
+
+ while (q--) {
+ asm volatile (
+ ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
+ :"=S" (crcval)
+ :"0" (crcval), "c" (*p)
+ );
+ p++;
+ }
+
+ return (crcval);
+}
+
+static int
+vncserver_send_screen(struct vncserver_softc *sc, int all)
+{
+ struct bhyvegc_image *gc_image;
+ int x, y;
+ int celly, cellwidth;
+ int xcells, ycells;
+ int w, h;
+ uint32_t *p;
+ int rem_x, rem_y; /* remainder for resolutions not x32 pixels ratio */
+ int retval;
+ uint32_t *crc_p, *orig_crc;
+ int changes;
+
+ console_refresh();
+
+ pthread_mutex_lock(&sc->vs_mtx);
+ if (sc->vs_sending) {
+ pthread_mutex_unlock(&sc->vs_mtx);
+ return (1);
+ }
+ sc->vs_sending = 1;
+ pthread_mutex_unlock(&sc->vs_mtx);
+
+ retval = 0;
+
+ if (all) {
+ vnc_mark_rect_modified(sc, 0, 0, sc->vs_width, sc->vs_height);
+ goto done;
+ }
+
+ /*
+ * Calculate the checksum for each 32x32 cell. Send each that
+ * has changed since the last scan.
+ */
+
+ /* Resolution changed */
+
+ gc_image = sc->vs_gc;
+ sc->vs_crc_width = gc_image->width;
+ sc->vs_crc_height = gc_image->height;
+
+ w = sc->vs_crc_width;
+ h = sc->vs_crc_height;
+ xcells = howmany(sc->vs_crc_width, PIX_PER_CELL);
+ ycells = howmany(sc->vs_crc_height, PIX_PER_CELL);
+
+ rem_x = w & PIXCELL_MASK;
+
+ rem_y = h & PIXCELL_MASK;
+ if (!rem_y)
+ rem_y = PIX_PER_CELL;
+
+ p = gc_image->data;
+
+ /*
+ * Go through all cells and calculate crc. If significant number
+ * of changes, then send entire screen.
+ * crc_tmp is dual purpose: to store the new crc and to flag as
+ * a cell that has changed.
+ */
+ crc_p = sc->vs_crc_tmp - xcells;
+ orig_crc = sc->vs_crc - xcells;
+ changes = 0;
+ memset(sc->vs_crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);
+ for (y = 0; y < h; y++) {
+ if ((y & PIXCELL_MASK) == 0) {
+ crc_p += xcells;
+ orig_crc += xcells;
+ }
+
+ for (x = 0; x < xcells; x++) {
+ if (sc->vs_hw_crc)
+ crc_p[x] = fast_crc32(p,
+ PIX_PER_CELL * sizeof(uint32_t),
+ crc_p[x]);
+ else
+ crc_p[x] = (uint32_t)crc32(crc_p[x],
+ (Bytef *)p,
+ PIX_PER_CELL * sizeof(uint32_t));
+
+ p += PIX_PER_CELL;
+
+ /* check for crc delta if last row in cell */
+ if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
+ if (orig_crc[x] != crc_p[x]) {
+ orig_crc[x] = crc_p[x];
+ crc_p[x] = 1;
+ changes++;
+ } else {
+ crc_p[x] = 0;
+ }
+ }
+ }
+
+ if (rem_x) {
+ if (sc->vs_hw_crc)
+ crc_p[x] = fast_crc32(p,
+ rem_x * sizeof(uint32_t),
+ crc_p[x]);
+ else
+ crc_p[x] = (uint32_t)crc32(crc_p[x],
+ (Bytef *)p,
+ rem_x * sizeof(uint32_t));
+ p += rem_x;
+
+ if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
+ if (orig_crc[x] != crc_p[x]) {
+ orig_crc[x] = crc_p[x];
+ crc_p[x] = 1;
+ changes++;
+ } else {
+ crc_p[x] = 0;
+ }
+ }
+ }
+ }
+
+ /* If number of changes is > THRESH percent, send the whole screen */
+ if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {
+ vnc_mark_rect_modified(sc, 0, 0, sc->vs_width, sc->vs_height);
+ goto done;
+ }
+
+ /* Go through all cells, and send only changed ones */
+ crc_p = sc->vs_crc_tmp;
+ for (y = 0; y < h; y += PIX_PER_CELL) {
+ /* previous cell's row */
+ celly = (y >> PIXCELL_SHIFT);
+
+ /* Delta check crc to previous set */
+ for (x = 0; x < xcells; x++) {
+ if (*crc_p++ == 0)
+ continue;
+
+ if (x == (xcells - 1) && rem_x > 0)
+ cellwidth = rem_x;
+ else
+ cellwidth = PIX_PER_CELL;
+
+ vnc_mark_rect_modified(sc, x * PIX_PER_CELL,
+ celly * PIX_PER_CELL,
+ x * PIX_PER_CELL + cellwidth,
+ (celly * PIX_PER_CELL) + (y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL));
+ }
+ }
+
+ retval = 1;
+
+done:
+ pthread_mutex_lock(&sc->vs_mtx);
+ sc->vs_sending = 0;
+ pthread_mutex_unlock(&sc->vs_mtx);
+
+ return (retval);
+}
+
+static void
+handle_keyboard(int down, uint32_t keysym) {
+ console_key_event(down, keysym);
+}
+
+static void
+handle_ptr(uint8_t button, int x, int y) {
+ console_ptr_event(button, x, y);
+}
+
+static int64_t
+timeval_delta(struct timeval *prev, struct timeval *now)
+{
+ int64_t n1, n2;
+ n1 = now->tv_sec * 1000000 + now->tv_usec;
+ n2 = prev->tv_sec * 1000000 + prev->tv_usec;
+ return (n1 - n2);
+}
+
+static void *
+vncserver_thr(void *arg)
+{
+ struct vncserver_softc *sc;
+ struct kevent kev, ret;
+ int kq, err;
+
+ sc = arg;
+ kq = kqueue();
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 40, NULL);
+
+ err = kevent(kq, &kev, 1, NULL, 0, NULL);
+ if (err < 0)
+ goto out;
+
+ for (;;) {
+ err = kevent(kq, NULL, 0, &ret, 1, NULL);
+ if (err < 0)
+ goto out;
+
+ if (ret.filter == EVFILT_TIMER) {
+ if (vncserver_send_screen(sc, 0) < 0)
+ goto out;
+ }
+ }
+
+out:
+ close(kq);
+ return (NULL);
+}
+
+static int
+sse42_supported()
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __get_cpuid(1, &eax, &ebx, &ecx, &edx);
+
+ return ((ecx & bit_SSE42) != 0);
+}
+
+int
+vncserver_init(char *hostname, int port, int wait, char *password)
+{
+ struct vncserver_softc *sc;
+
+ if(load_shared_lib() == 1)
+ errx(EX_SOFTWARE, "cannot load shared library libhyve-remote");
+
+ sc = calloc(1, sizeof(struct vncserver_softc));
+
+ sc->vs_crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
+ sizeof(uint32_t));
+ sc->vs_crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
+ sizeof(uint32_t));
+ sc->vs_crc_width = RFB_MAX_WIDTH;
+ sc->vs_crc_height = RFB_MAX_HEIGHT;
+
+ sc->vs_hw_crc = sse42_supported();
+
+ sc->vs_conn_wait = wait;
+
+ if (wait) {
+ pthread_mutex_init(&sc->vs_mtx, NULL);
+ pthread_cond_init(&sc->vs_cond, NULL);
+ }
+
+ sc->vs_gc = console_get_image();
+ sc->vs_height = sc->vs_gc->height;
+ sc->vs_width = sc->vs_gc->width;
+
+ sc->desktopName = "bhyve";
+ if (password) {
+ vnc_enable_password(password);
+ }
+ sc->alwaysShared = true;
+ sc->redShift = 16;
+ sc->greenShift = 8;
+ sc->blueShift = 0;
+ sc->bind_port = port ? port : 5900;
+ sc->frameBuffer = (char *)sc->vs_gc->data;
+
+ sc->kdb_handler = handle_keyboard;
+ sc->ptr_handler = handle_ptr;
+
+ vnc_init_server(sc);
+ vnc_event_loop(4000, true);
+
+ pthread_create(&sc->vs_tid, NULL, vncserver_thr, sc);
+ pthread_set_name_np(sc->vs_tid, "vncserver");
+
+ if (wait) {
+ DPRINTF(("Waiting for vnc client...\n"));
+ pthread_mutex_lock(&sc->vs_mtx);
+ pthread_cond_wait(&sc->vs_cond, &sc->vs_mtx);
+ pthread_mutex_unlock(&sc->vs_mtx);
+ }
+
+ return (0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 18, 3:31 AM (18 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15849720
Default Alt Text
D11768.diff (16 KB)
Attached To
Mode
D11768: Add support to devel/libhyve-remote. (VNC Server)
Attached
Detach File
Event Timeline
Log In to Comment