mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
bimodal pvfb backend: Deal with both 32 and 64 bit frontends.
Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
This commit is contained in:
1 parent
7606be28a6
commit
7bd46b4635
1 file changed
+87
-11
+87
-11
@@ -7,6 +7,7 @@
|
||||
#include <xen/io/xenbus.h>
|
||||
#include <xen/io/fbif.h>
|
||||
#include <xen/io/kbdif.h>
|
||||
#include <xen/io/protocols.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdbool.h>
|
||||
#include <xen/linux/evtchn.h>
|
||||
@@ -40,6 +41,7 @@ struct xenfb_private {
|
||||
struct xs_handle *xsh; /* xs daemon handle */
|
||||
struct xenfb_device fb, kbd;
|
||||
size_t fb_len; /* size of framebuffer */
|
||||
char protocol[64]; /* frontend protocol */
|
||||
};
|
||||
|
||||
static void xenfb_detach_dom(struct xenfb_private *);
|
||||
@@ -324,36 +326,107 @@ static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
|
||||
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_private *xenfb, int domid)
|
||||
{
|
||||
struct xenfb_page *page = xenfb->fb.page;
|
||||
int n_fbmfns;
|
||||
int n_fbdirs;
|
||||
unsigned long *fbmfns;
|
||||
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 = page->pd;
|
||||
ptr64 = ((void*)page->pd) + 4;
|
||||
#elif defined(__x86_64__)
|
||||
ptr32 = ((void*)page->pd) - 4;
|
||||
ptr64 = 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 * sizeof(unsigned long);
|
||||
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;
|
||||
|
||||
/*
|
||||
* Bug alert: xc_map_foreign_batch() can fail partly and
|
||||
* return a non-null value. This is a design flaw. When it
|
||||
* happens, we happily continue here, and later crash on
|
||||
* access.
|
||||
*/
|
||||
fbmfns = xc_map_foreign_batch(xenfb->xc, domid,
|
||||
PROT_READ, page->pd, n_fbdirs);
|
||||
if (fbmfns == NULL)
|
||||
return -1;
|
||||
xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
|
||||
map = xc_map_foreign_batch(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->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
|
||||
PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
|
||||
if (xenfb->pub.pixels == NULL) {
|
||||
munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
|
||||
return -1;
|
||||
}
|
||||
if (xenfb->pub.pixels == NULL)
|
||||
goto out;
|
||||
|
||||
return munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
|
||||
ret = 0; /* all is fine */
|
||||
|
||||
out:
|
||||
if (pgmfns)
|
||||
free(pgmfns);
|
||||
if (fbmfns)
|
||||
free(fbmfns);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xenfb_bind(struct xenfb_device *dev)
|
||||
@@ -368,6 +441,9 @@ static int xenfb_bind(struct xenfb_device *dev)
|
||||
if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
|
||||
&evtchn) < 0)
|
||||
return -1;
|
||||
if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "protocol", "%63s",
|
||||
xenfb->protocol) < 0)
|
||||
xenfb->protocol[0] = '\0';
|
||||
|
||||
dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
|
||||
dev->otherend_id, evtchn);
|
||||
|
||||