aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extras/mini-os/fbfront.c76
-rw-r--r--extras/mini-os/include/fbfront.h3
-rw-r--r--extras/mini-os/kernel.c13
-rw-r--r--tools/ioemu/hw/cirrus_vga.c4
-rw-r--r--tools/ioemu/hw/vga.c6
-rw-r--r--tools/ioemu/hw/xenfb.c145
-rw-r--r--tools/ioemu/vl.h1
7 files changed, 170 insertions, 78 deletions
diff --git a/extras/mini-os/fbfront.c b/extras/mini-os/fbfront.c
index d16576f728..8586d03865 100644
--- a/extras/mini-os/fbfront.c
+++ b/extras/mini-os/fbfront.c
@@ -243,12 +243,12 @@ struct fbfront_dev {
char *backend;
int request_update;
- char *data;
int width;
int height;
int depth;
- int line_length;
+ int stride;
int mem_length;
+ int offset;
};
void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
@@ -256,7 +256,7 @@ void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
wake_up(&fbfront_queue);
}
-struct fbfront_dev *init_fbfront(char *nodename, void *data, int width, int height, int depth, int line_length, int mem_length)
+struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
{
xenbus_transaction_t xbt;
char* err;
@@ -289,24 +289,17 @@ struct fbfront_dev *init_fbfront(char *nodename, void *data, int width, int heig
dev->width = s->width = width;
dev->height = s->height = height;
dev->depth = s->depth = depth;
- dev->line_length = s->line_length = line_length;
- dev->mem_length = s->mem_length = mem_length;
-
- ASSERT(!((unsigned long)data & ~PAGE_MASK));
- dev->data = data;
+ dev->stride = s->line_length = stride;
+ dev->mem_length = s->mem_length = n * PAGE_SIZE;
+ dev->offset = 0;
const int max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
unsigned long mapped = 0;
- for (i = 0; mapped < mem_length && i < max_pd; i++) {
+ for (i = 0; mapped < n && i < max_pd; i++) {
unsigned long *pd = (unsigned long *) alloc_page();
- for (j = 0; mapped < mem_length && j < PAGE_SIZE / sizeof(unsigned long); j++) {
- /* Trigger CoW */
- * ((char *)data + mapped) = 0;
- barrier();
- pd[j] = virtual_to_mfn((unsigned long) data + mapped);
- mapped += PAGE_SIZE;
- }
+ for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
+ pd[j] = mfns[mapped++];
for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
pd[j] = 0;
s->pd[i] = virt_to_mfn(pd);
@@ -395,12 +388,29 @@ done:
return dev;
}
-void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
+static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
{
struct xenfb_page *page = dev->page;
uint32_t prod;
DEFINE_WAIT(w);
+ add_waiter(w, fbfront_queue);
+ while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
+ schedule();
+ remove_waiter(w);
+
+ prod = page->out_prod;
+ mb(); /* ensure ring space available */
+ XENFB_OUT_RING_REF(page, prod) = *event;
+ wmb(); /* ensure ring contents visible */
+ page->out_prod = prod + 1;
+ notify_remote_via_evtchn(dev->evtchn);
+}
+
+void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
+{
+ struct xenfb_update update;
+
if (dev->request_update <= 0)
return;
@@ -421,21 +431,25 @@ void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height
if (width <= 0 || height <= 0)
return;
- add_waiter(w, fbfront_queue);
- while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
- schedule();
- remove_waiter(w);
+ update.type = XENFB_TYPE_UPDATE;
+ update.x = x;
+ update.y = y;
+ update.width = width;
+ update.height = height;
+ fbfront_out_event(dev, (union xenfb_out_event *) &update);
+}
- prod = page->out_prod;
- mb(); /* ensure ring space available */
- XENFB_OUT_RING_REF(page, prod).type = XENFB_TYPE_UPDATE;
- XENFB_OUT_RING_REF(page, prod).update.x = x;
- XENFB_OUT_RING_REF(page, prod).update.y = y;
- XENFB_OUT_RING_REF(page, prod).update.width = width;
- XENFB_OUT_RING_REF(page, prod).update.height = height;
- wmb(); /* ensure ring contents visible */
- page->out_prod = prod + 1;
- notify_remote_via_evtchn(dev->evtchn);
+void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
+{
+ struct xenfb_resize resize;
+
+ resize.type = XENFB_TYPE_RESIZE;
+ dev->width = resize.width = width;
+ dev->height = resize.height = height;
+ dev->stride = resize.stride = stride;
+ dev->depth = resize.depth = depth;
+ dev->offset = resize.offset = offset;
+ fbfront_out_event(dev, (union xenfb_out_event *) &resize);
}
void shutdown_fbfront(struct fbfront_dev *dev)
diff --git a/extras/mini-os/include/fbfront.h b/extras/mini-os/include/fbfront.h
index fa98942e76..70b2f2a681 100644
--- a/extras/mini-os/include/fbfront.h
+++ b/extras/mini-os/include/fbfront.h
@@ -31,11 +31,12 @@ extern struct wait_queue_head kbdfront_queue;
void shutdown_kbdfront(struct kbdfront_dev *dev);
-struct fbfront_dev *init_fbfront(char *nodename, void *data, int width, int height, int depth, int line_length, int mem_length);
+struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n);
#ifdef HAVE_LIBC
int fbfront_open(struct fbfront_dev *dev);
#endif
void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height);
+void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset);
void shutdown_fbfront(struct fbfront_dev *dev);
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index 6888eee508..c37644bf4f 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -297,9 +297,20 @@ static void fbfront_thread(void *p)
{
size_t line_length = WIDTH * (DEPTH / 8);
size_t memsize = HEIGHT * line_length;
+ unsigned long *mfns;
+ int i, n = (memsize + PAGE_SIZE-1) / PAGE_SIZE;
+ memsize = n * PAGE_SIZE;
fb = _xmalloc(memsize, PAGE_SIZE);
- fb_dev = init_fbfront(NULL, fb, WIDTH, HEIGHT, DEPTH, line_length, memsize);
+ mfns = xmalloc_array(unsigned long, n);
+ for (i = 0; i < n; i++) {
+ /* trigger CoW */
+ ((char *) fb) [i * PAGE_SIZE] = 0;
+ barrier();
+ mfns[i] = virtual_to_mfn((char *) fb + i * PAGE_SIZE);
+ }
+ fb_dev = init_fbfront(NULL, mfns, WIDTH, HEIGHT, DEPTH, line_length, n);
+ xfree(mfns);
if (!fb_dev) {
xfree(fb);
return;
diff --git a/tools/ioemu/hw/cirrus_vga.c b/tools/ioemu/hw/cirrus_vga.c
index 8a637c57fd..8572cf85b7 100644
--- a/tools/ioemu/hw/cirrus_vga.c
+++ b/tools/ioemu/hw/cirrus_vga.c
@@ -2595,6 +2595,10 @@ static void *set_vram_mapping(unsigned long begin, unsigned long end)
memset(vram_pointer, 0, nr_extents * TARGET_PAGE_SIZE);
+#ifdef CONFIG_STUBDOM
+ xenfb_pv_display_start(vram_pointer);
+#endif
+
free(extent_start);
return vram_pointer;
diff --git a/tools/ioemu/hw/vga.c b/tools/ioemu/hw/vga.c
index 9aba2222f8..fb64036468 100644
--- a/tools/ioemu/hw/vga.c
+++ b/tools/ioemu/hw/vga.c
@@ -2067,8 +2067,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
& ~(TARGET_PAGE_SIZE - 1));
/* Video RAM must be 128-bit aligned for SSE optimizations later */
- s->vram_alloc = qemu_malloc(vga_ram_size + 15);
- s->vram_ptr = (uint8_t *)((long)(s->vram_alloc + 15) & ~15L);
+ /* and page-aligned for PVFB memory sharing */
+ s->vram_ptr = s->vram_alloc = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size);
s->vram_offset = vga_ram_offset;
s->vram_size = vga_ram_size;
@@ -2210,7 +2210,7 @@ void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
}
if (!vga_ram_base) {
- vga_ram_base = qemu_malloc(vga_ram_size + TARGET_PAGE_SIZE + 1);
+ vga_ram_base = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size + TARGET_PAGE_SIZE + 1);
if (!vga_ram_base) {
fprintf(stderr, "reallocate error\n");
return NULL;
diff --git a/tools/ioemu/hw/xenfb.c b/tools/ioemu/hw/xenfb.c
index b699552361..ee75795a29 100644
--- a/tools/ioemu/hw/xenfb.c
+++ b/tools/ioemu/hw/xenfb.c
@@ -1235,15 +1235,11 @@ static int xenfb_register_console(struct xenfb *xenfb) {
static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
static struct kbdfront_dev *kbd_dev;
static char *kbd_path, *fb_path;
+static void *vga_vram, *nonshared_vram;
+static DisplayState *xenfb_ds;
static unsigned char linux2scancode[KEY_MAX + 1];
-#define WIDTH 1024
-#define HEIGHT 768
-#define DEPTH 32
-#define LINESIZE (1280 * (DEPTH / 8))
-#define MEMSIZE (LINESIZE * HEIGHT)
-
int xenfb_connect_vkbd(const char *path)
{
kbd_path = strdup(path);
@@ -1256,33 +1252,73 @@ int xenfb_connect_vfb(const char *path)
return 0;
}
-static void xenfb_pv_update(DisplayState *s, int x, int y, int w, int h)
+static void xenfb_pv_update(DisplayState *ds, int x, int y, int w, int h)
{
- struct fbfront_dev *fb_dev = s->opaque;
+ struct fbfront_dev *fb_dev = ds->opaque;
+ if (!fb_dev)
+ return;
fbfront_update(fb_dev, x, y, w, h);
}
-static void xenfb_pv_resize(DisplayState *s, int w, int h, int linesize)
+static void xenfb_pv_resize(DisplayState *ds, int w, int h, int linesize)
{
- struct fbfront_dev *fb_dev = s->opaque;
- fprintf(stderr,"resize to %dx%d required\n", w, h);
- s->width = w;
- s->height = h;
- /* TODO: send resize event if supported */
- memset(s->data, 0, MEMSIZE);
- fbfront_update(fb_dev, 0, 0, WIDTH, HEIGHT);
+ struct fbfront_dev *fb_dev = ds->opaque;
+ fprintf(stderr,"resize to %dx%d, %d required\n", w, h, linesize);
+ ds->width = w;
+ ds->height = h;
+ if (!linesize)
+ ds->shared_buf = 0;
+ if (!ds->shared_buf)
+ linesize = w * 4;
+ ds->linesize = linesize;
+ if (!fb_dev)
+ return;
+ if (ds->shared_buf) {
+ ds->data = NULL;
+ } else {
+ ds->data = nonshared_vram;
+ fbfront_resize(fb_dev, w, h, linesize, ds->depth, VGA_RAM_SIZE);
+ }
}
static void xenfb_pv_colourdepth(DisplayState *ds, int depth)
{
- /* TODO: send redepth event if supported */
+ struct fbfront_dev *fb_dev = ds->opaque;
static int lastdepth = -1;
+ if (!depth) {
+ ds->shared_buf = 0;
+ ds->depth = 32;
+ } else {
+ ds->shared_buf = 1;
+ ds->depth = depth;
+ }
if (depth != lastdepth) {
fprintf(stderr,"redepth to %d required\n", depth);
lastdepth = depth;
+ } else return;
+ if (!fb_dev)
+ return;
+ if (ds->shared_buf) {
+ ds->data = NULL;
+ } else {
+ ds->data = nonshared_vram;
+ fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, VGA_RAM_SIZE);
}
- /* We can't redepth for now */
- ds->depth = DEPTH;
+}
+
+static void xenfb_pv_setdata(DisplayState *ds, void *pixels)
+{
+ struct fbfront_dev *fb_dev = ds->opaque;
+ int offset = pixels - vga_vram;
+ ds->data = pixels;
+ if (!fb_dev)
+ return;
+ fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, offset);
+}
+
+static void xenfb_pv_refresh(DisplayState *ds)
+{
+ vga_hw_update();
}
static void xenfb_kbd_handler(void *opaque)
@@ -1373,13 +1409,6 @@ static void xenfb_kbd_handler(void *opaque)
}
}
-static void xenfb_pv_refresh(DisplayState *ds)
-{
- /* always request negociation */
- ds->depth = -1;
- vga_hw_update();
-}
-
static void kbdfront_thread(void *p)
{
int scancode, keycode;
@@ -1399,40 +1428,72 @@ static void kbdfront_thread(void *p)
int xenfb_pv_display_init(DisplayState *ds)
{
- void *data;
+ if (!fb_path || !kbd_path)
+ return -1;
+
+ create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
+
+ xenfb_ds = ds;
+
+ ds->data = nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
+ memset(ds->data, 0, VGA_RAM_SIZE);
+ ds->depth = 32;
+ ds->bgr = 0;
+ ds->width = 640;
+ ds->height = 400;
+ ds->linesize = 640 * 4;
+ ds->dpy_update = xenfb_pv_update;
+ ds->dpy_resize = xenfb_pv_resize;
+ ds->dpy_colourdepth = xenfb_pv_colourdepth;
+ ds->dpy_setdata = xenfb_pv_setdata;
+ ds->dpy_refresh = xenfb_pv_refresh;
+ return 0;
+}
+
+int xenfb_pv_display_start(void *data)
+{
+ DisplayState *ds = xenfb_ds;
struct fbfront_dev *fb_dev;
int kbd_fd;
+ int offset = 0;
+ unsigned long *mfns;
+ int n = VGA_RAM_SIZE / PAGE_SIZE;
+ int i;
if (!fb_path || !kbd_path)
- return -1;
+ return 0;
- create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
+ vga_vram = data;
+ mfns = malloc(2 * n * sizeof(*mfns));
+ for (i = 0; i < n; i++)
+ mfns[i] = virtual_to_mfn(vga_vram + i * PAGE_SIZE);
+ for (i = 0; i < n; i++)
+ mfns[n + i] = virtual_to_mfn(nonshared_vram + i * PAGE_SIZE);
- data = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
- fb_dev = init_fbfront(fb_path, data, WIDTH, HEIGHT, DEPTH, LINESIZE, MEMSIZE);
+ fb_dev = init_fbfront(fb_path, mfns, ds->width, ds->height, ds->depth, ds->linesize, 2 * n);
+ free(mfns);
if (!fb_dev) {
fprintf(stderr,"can't open frame buffer\n");
exit(1);
}
free(fb_path);
+ if (ds->shared_buf) {
+ offset = (void*) ds->data - vga_vram;
+ } else {
+ offset = VGA_RAM_SIZE;
+ ds->data = nonshared_vram;
+ }
+ if (offset)
+ fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, offset);
+
down(&kbd_sem);
free(kbd_path);
kbd_fd = kbdfront_open(kbd_dev);
qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds);
- ds->data = data;
- ds->linesize = LINESIZE;
- ds->depth = DEPTH;
- ds->bgr = 0;
- ds->width = WIDTH;
- ds->height = HEIGHT;
- ds->dpy_update = xenfb_pv_update;
- ds->dpy_resize = xenfb_pv_resize;
- ds->dpy_colourdepth = xenfb_pv_colourdepth;
- ds->dpy_refresh = xenfb_pv_refresh;
- ds->opaque = fb_dev;
+ xenfb_ds->opaque = fb_dev;
return 0;
}
#endif
diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h
index 7ccd256a31..babe8d4d27 100644
--- a/tools/ioemu/vl.h
+++ b/tools/ioemu/vl.h
@@ -1545,6 +1545,7 @@ char *xenstore_vm_read(int domid, char *key, unsigned int *len);
/* xenfb.c */
int xenfb_pv_display_init(DisplayState *ds);
+int xenfb_pv_display_start(void *vram_start);
int xenfb_connect_vkbd(const char *path);
int xenfb_connect_vfb(const char *path);