⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xenfb.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <stdarg.h>#include <stdlib.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <xenctrl.h>#include <xen/io/xenbus.h>#include <xen/io/fbif.h>#include <xen/io/kbdif.h>#include <xen/io/protocols.h>#include <stdbool.h>#include <xen/event_channel.h>#include <sys/mman.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <time.h>#include <xs.h>#include "xenfb.h"#ifndef BTN_LEFT#define BTN_LEFT 0x110 /* from <linux/input.h> */#endifstruct xenfb;struct xenfb_device {	const char *devicetype;	char nodename[64];	/* backend xenstore dir */	char otherend[64];	/* frontend xenstore dir */	int otherend_id;	/* frontend domid */	enum xenbus_state state; /* backend state */	void *page;		/* shared page */	evtchn_port_t port;	struct xenfb *xenfb;};struct xenfb {	DisplayState *ds;       /* QEMU graphical console state */	int evt_xch;		/* event channel driver handle */	int xc;			/* hypervisor interface handle */	struct xs_handle *xsh;	/* xs daemon handle */	struct xenfb_device fb, kbd;	void *pixels;           /* guest framebuffer data */	size_t fb_len;		/* size of framebuffer */	int row_stride;         /* width of one row in framebuffer */	int depth;              /* colour depth of guest framebuffer */	int width;              /* pixel width of guest framebuffer */	int height;             /* pixel height of guest framebuffer */	int offset;             /* offset of the framebuffer */	int abs_pointer_wanted; /* Whether guest supports absolute pointer */	int button_state;       /* Last seen pointer button state */	int refresh_period;     /* The refresh period we have advised */	char protocol[64];	/* frontend protocol */};/* Functions for frontend/backend state machine*/static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler);static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler);static void xenfb_backend_created_kbd(void *opaque);static void xenfb_backend_created_fb(void *opaque);static void xenfb_frontend_initialized_kbd(void *opaque);static void xenfb_frontend_initialized_fb(void *opaque);static void xenfb_frontend_connected_kbd(void *opaque);/* Helper functions for checking state of frontend/backend devices */static int xenfb_frontend_connected(struct xenfb_device *dev);static int xenfb_frontend_initialized(struct xenfb_device *dev);static int xenfb_backend_created(struct xenfb_device *dev);/* Functions which tie the PVFB into the QEMU device model */static void xenfb_key_event(void *opaque, int keycode);static void xenfb_mouse_event(void *opaque,			      int dx, int dy, int dz, int button_state);static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h);static void xenfb_update(void *opaque);static void xenfb_invalidate(void *opaque);static void xenfb_screen_dump(void *opaque, const char *name);static int xenfb_register_console(struct xenfb *xenfb);/* * Tables to map from scancode to Linux input layer keycode. * Scancodes are hardware-specific.  These maps assumes a  * standard AT or PS/2 keyboard which is what QEMU feeds us. */const unsigned char atkbd_set2_keycode[512] = {	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,	  0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,	  0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,	  0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,};const unsigned char atkbd_unxlate_table[128] = {	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,	 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,	 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,	 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,	 11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,	114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,	 71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,	 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110};static unsigned char scancode2linux[512];static int xenfb_xs_scanf1(struct xs_handle *xsh,			   const char *dir, const char *node,			   const char *fmt, void *dest){	char buf[1024];	char *p;	int ret;	if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {		errno = ENOENT;		return -1;        }	p = xs_read(xsh, XBT_NULL, buf, NULL);	if (!p) {		errno = ENOENT;		return -1;        }	ret = sscanf(p, fmt, dest);	free(p);	if (ret != 1) {		errno = EDOM;		return -1;        }	return ret;}static int xenfb_xs_printf(struct xs_handle *xsh,			   const char *dir, const char *node, char *fmt, ...){	va_list ap;	char key[1024];	char val[1024];	int n;	if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {		errno = ENOENT;		return -1;        }	va_start(ap, fmt);	n = vsnprintf(val, sizeof(val), fmt, ap);	va_end(ap);	if (n >= sizeof(val)) {		errno = ENOSPC; /* close enough */		return -1;	}	if (!xs_write(xsh, XBT_NULL, key, val, n))		return -1;	return 0;}static void xenfb_device_init(struct xenfb_device *dev,			      const char *type,			      struct xenfb *xenfb){	dev->devicetype = type;	dev->otherend_id = -1;	dev->port = -1;	dev->xenfb = xenfb;}static char *xenfb_path_in_dom(struct xs_handle *xsh,                               char *buf, size_t size,                               unsigned domid, const char *fmt, ...){        va_list ap;        char *domp = xs_get_domain_path(xsh, domid);        int n;        if (domp == NULL)                return NULL;        n = snprintf(buf, size, "%s/", domp);        free(domp);        if (n >= size)                return NULL;        va_start(ap, fmt);        n += vsnprintf(buf + n, size - n, fmt, ap);        va_end(ap);        if (n >= size)                return NULL;        return buf;}static int xenfb_device_set_domain(struct xenfb_device *dev, int domid){        dev->otherend_id = domid;        if (!xenfb_path_in_dom(dev->xenfb->xsh,                               dev->otherend, sizeof(dev->otherend),                               domid, "device/%s/0", dev->devicetype)) {                errno = ENOENT;                return -1;        }        if (!xenfb_path_in_dom(dev->xenfb->xsh,                               dev->nodename, sizeof(dev->nodename),                               0, "backend/%s/%d/0", dev->devicetype, domid)) {                errno = ENOENT;                return -1;        }        return 0;}struct xenfb *xenfb_new(int domid, DisplayState *ds){	struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb));	int serrno;	int i;	if (xenfb == NULL)		return NULL;	/* Prepare scancode mapping table */	for (i = 0; i < 128; i++) {		scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];		scancode2linux[i | 0x80] = 			atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];	}	memset(xenfb, 0, sizeof(*xenfb));	xenfb->evt_xch = xenfb->xc = -1;	xenfb_device_init(&xenfb->fb, "vfb", xenfb);	xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);	xenfb->evt_xch = xc_evtchn_open();	if (xenfb->evt_xch == -1)		goto fail;	xenfb->xc = xc_interface_open();	if (xenfb->xc == -1)		goto fail;	xenfb->xsh = xs_daemon_open();	if (!xenfb->xsh)		goto fail;	xenfb->ds = ds;	xenfb_device_set_domain(&xenfb->fb, domid);	xenfb_device_set_domain(&xenfb->kbd, domid);	fprintf(stderr, "FB: Waiting for KBD backend creation\n");	xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);	return xenfb; fail:	serrno = errno;	xenfb_shutdown(xenfb);	errno = serrno;	return NULL;}static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,					  const char *dir){	int ret, state;	ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);	if (ret < 0)		return XenbusStateUnknown;	if ((unsigned)state > XenbusStateClosed)		state = XenbusStateUnknown;	return state;}static int xenfb_switch_state(struct xenfb_device *dev,			      enum xenbus_state state){	struct xs_handle *xsh = dev->xenfb->xsh;	if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)		return -1;	dev->state = state;	return 0;}static int xenfb_hotplug(struct xenfb_device *dev){	if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,			    "hotplug-status", "connected"))		return -1;	return 0;}static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src){	uint32_t *src32 = src;	uint64_t *src64 = src;	int i;	for (i = 0; i < count; i++)		dst[i] = (mode == 32) ? src32[i] : src64[i];}static int xenfb_map_fb(struct xenfb *xenfb, int domid){	struct xenfb_page *page = xenfb->fb.page;	int n_fbmfns;	int n_fbdirs;	unsigned long *pgmfns = NULL;	unsigned long *fbmfns = NULL;	void *map, *pd;	int mode, ret = -1;	/* default to native */	pd = page->pd;	mode = sizeof(unsigned long) * 8;	if (0 == strlen(xenfb->protocol)) {		/*		 * Undefined protocol, some guesswork needed.		 *		 * Old frontends which don't set the protocol use		 * one page directory only, thus pd[1] must be zero.		 * pd[1] of the 32bit struct layout and the lower		 * 32 bits of pd[0] of the 64bit struct layout have		 * the same location, so we can check that ...		 */		uint32_t *ptr32 = NULL;		uint32_t *ptr64 = NULL;#if defined(__i386__)		ptr32 = (void*)page->pd;		ptr64 = ((void*)page->pd) + 4;#elif defined(__x86_64__)		ptr32 = ((void*)page->pd) - 4;		ptr64 = (void*)page->pd;#endif		if (ptr32) {			if (0 == ptr32[1]) {				mode = 32;				pd   = ptr32;			} else {				mode = 64;				pd   = ptr64;			}		}#if defined(__x86_64__)	} else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {		/* 64bit dom0, 32bit domU */		mode = 32;		pd   = ((void*)page->pd) - 4;#elif defined(__i386__)	} else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {		/* 32bit dom0, 64bit domU */		mode = 64;		pd   = ((void*)page->pd) + 4;#endif	}	n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;	n_fbdirs = n_fbmfns * mode / 8;	n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;	pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);	fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);	if (!pgmfns || !fbmfns)		goto out;	xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);	map = xc_map_foreign_pages(xenfb->xc, domid,				   PROT_READ, pgmfns, n_fbdirs);	if (map == NULL)		goto out;	xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);	munmap(map, n_fbdirs * XC_PAGE_SIZE);	xenfb->pixels = xc_map_foreign_pages(xenfb->xc, domid,				PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);	if (xenfb->pixels == NULL)		goto out;	ret = 0; /* all is fine */ out:	if (pgmfns)		free(pgmfns);	if (fbmfns)		free(fbmfns);	return ret;}static int xenfb_bind(struct xenfb_device *dev){	struct xenfb *xenfb = dev->xenfb;	unsigned long mfn;	evtchn_port_t evtchn;	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",			    &mfn) < 0)		return -1;	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",			    &evtchn) < 0)		return -1;	dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,					       dev->otherend_id, evtchn);	if (dev->port == -1)		return -1;	dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,			XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);	if (dev->page == NULL)		return -1;	return 0;}static void xenfb_unbind(struct xenfb_device *dev){	if (dev->page) {		munmap(dev->page, XC_PAGE_SIZE);		dev->page = NULL;	}        if (dev->port >= 0) {		xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);		dev->port = -1;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -