blob: 0a01ae30cc27a2c7bcfc0fa47751add78cf6d7e3 [file] [log] [blame]
aliguorie7151f82009-04-22 15:19:25 +00001/*
2 * xen paravirt framebuffer backend
3 *
4 * Copyright IBM, Corp. 2005-2006
5 * Copyright Red Hat, Inc. 2006-2008
6 *
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>,
9 * Markus Armbruster <armbru@redhat.com>,
10 * Daniel P. Berrange <berrange@redhat.com>,
11 * Pat Campbell <plc@novell.com>,
12 * Gerd Hoffmann <kraxel@redhat.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; under version 2 of the License.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
Blue Swirl8167ee82009-07-16 20:47:01 +000024 * with this program; if not, see <http://www.gnu.org/licenses/>.
aliguorie7151f82009-04-22 15:19:25 +000025 */
26
27#include <stdarg.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <fcntl.h>
31#include <unistd.h>
aliguorie7151f82009-04-22 15:19:25 +000032#include <sys/mman.h>
33#include <errno.h>
34#include <stdio.h>
35#include <string.h>
36#include <time.h>
37
38#include <xs.h>
39#include <xenctrl.h>
40#include <xen/event_channel.h>
41#include <xen/io/xenbus.h>
42#include <xen/io/fbif.h>
43#include <xen/io/kbdif.h>
44#include <xen/io/protocols.h>
45
46#include "hw.h"
aliguorie7151f82009-04-22 15:19:25 +000047#include "console.h"
48#include "qemu-char.h"
49#include "xen_backend.h"
50
51#ifndef BTN_LEFT
52#define BTN_LEFT 0x110 /* from <linux/input.h> */
53#endif
54
55/* -------------------------------------------------------------------- */
56
57struct common {
58 struct XenDevice xendev; /* must be first */
59 void *page;
60 DisplayState *ds;
61};
62
63struct XenInput {
64 struct common c;
65 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
66 int button_state; /* Last seen pointer button state */
67 int extended;
68 QEMUPutMouseEntry *qmouse;
69};
70
71#define UP_QUEUE 8
72
73struct XenFB {
74 struct common c;
75 size_t fb_len;
76 int row_stride;
77 int depth;
78 int width;
79 int height;
80 int offset;
81 void *pixels;
82 int fbpages;
83 int feature_update;
84 int refresh_period;
85 int bug_trigger;
86 int have_console;
87 int do_resize;
88
89 struct {
90 int x,y,w,h;
91 } up_rects[UP_QUEUE];
92 int up_count;
93 int up_fullscreen;
94};
95
96/* -------------------------------------------------------------------- */
97
98static int common_bind(struct common *c)
99{
100 int mfn;
101
102 if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
103 return -1;
104 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
105 return -1;
106
107 c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
108 XC_PAGE_SIZE,
109 PROT_READ | PROT_WRITE, mfn);
110 if (c->page == NULL)
111 return -1;
112
113 xen_be_bind_evtchn(&c->xendev);
114 xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
115 mfn, c->xendev.remote_port, c->xendev.local_port);
116
117 return 0;
118}
119
120static void common_unbind(struct common *c)
121{
122 xen_be_unbind_evtchn(&c->xendev);
123 if (c->page) {
124 munmap(c->page, XC_PAGE_SIZE);
125 c->page = NULL;
126 }
127}
128
129/* -------------------------------------------------------------------- */
130
131#if 0
132/*
133 * These two tables are not needed any more, but left in here
134 * intentionally as documentation, to show how scancode2linux[]
135 * was generated.
136 *
137 * Tables to map from scancode to Linux input layer keycode.
138 * Scancodes are hardware-specific. These maps assumes a
139 * standard AT or PS/2 keyboard which is what QEMU feeds us.
140 */
141const unsigned char atkbd_set2_keycode[512] = {
142
143 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
144 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
145 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
146 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
147 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
148 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
149 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
150 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
151
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
154 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
155 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
156 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
157 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
158 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
159 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
160
161};
162
163const unsigned char atkbd_unxlate_table[128] = {
164
165 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
166 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
167 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
168 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
169 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
170 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
171 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
172 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
173
174};
175#endif
176
177/*
178 * for (i = 0; i < 128; i++) {
179 * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
180 * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
181 * }
182 */
183static const unsigned char scancode2linux[512] = {
184 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
185 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
186 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
187 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
188 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
189 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
192
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
195 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
196 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
198 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
199 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201};
202
203/* Send an event to the keyboard frontend driver */
204static int xenfb_kbd_event(struct XenInput *xenfb,
205 union xenkbd_in_event *event)
206{
207 struct xenkbd_page *page = xenfb->c.page;
208 uint32_t prod;
209
210 if (xenfb->c.xendev.be_state != XenbusStateConnected)
211 return 0;
212 if (!page)
213 return 0;
214
215 prod = page->in_prod;
216 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
217 errno = EAGAIN;
218 return -1;
219 }
220
221 xen_mb(); /* ensure ring space available */
222 XENKBD_IN_RING_REF(page, prod) = *event;
223 xen_wmb(); /* ensure ring contents visible */
224 page->in_prod = prod + 1;
225 return xen_be_send_notify(&xenfb->c.xendev);
226}
227
228/* Send a keyboard (or mouse button) event */
229static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
230{
231 union xenkbd_in_event event;
232
233 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
234 event.type = XENKBD_TYPE_KEY;
235 event.key.pressed = down ? 1 : 0;
236 event.key.keycode = keycode;
237
238 return xenfb_kbd_event(xenfb, &event);
239}
240
241/* Send a relative mouse movement event */
242static int xenfb_send_motion(struct XenInput *xenfb,
243 int rel_x, int rel_y, int rel_z)
244{
245 union xenkbd_in_event event;
246
247 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
248 event.type = XENKBD_TYPE_MOTION;
249 event.motion.rel_x = rel_x;
250 event.motion.rel_y = rel_y;
251#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
252 event.motion.rel_z = rel_z;
253#endif
254
255 return xenfb_kbd_event(xenfb, &event);
256}
257
258/* Send an absolute mouse movement event */
259static int xenfb_send_position(struct XenInput *xenfb,
260 int abs_x, int abs_y, int z)
261{
262 union xenkbd_in_event event;
263
264 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
265 event.type = XENKBD_TYPE_POS;
266 event.pos.abs_x = abs_x;
267 event.pos.abs_y = abs_y;
268#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
269 event.pos.abs_z = z;
270#endif
271#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
272 event.pos.rel_z = z;
273#endif
274
275 return xenfb_kbd_event(xenfb, &event);
276}
277
278/*
279 * Send a key event from the client to the guest OS
280 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
281 * We have to turn this into a Linux Input layer keycode.
282 *
283 * Extra complexity from the fact that with extended scancodes
284 * (like those produced by arrow keys) this method gets called
285 * twice, but we only want to send a single event. So we have to
286 * track the '0xe0' scancode state & collapse the extended keys
287 * as needed.
288 *
289 * Wish we could just send scancodes straight to the guest which
290 * already has code for dealing with this...
291 */
292static void xenfb_key_event(void *opaque, int scancode)
293{
294 struct XenInput *xenfb = opaque;
295 int down = 1;
296
297 if (scancode == 0xe0) {
298 xenfb->extended = 1;
299 return;
300 } else if (scancode & 0x80) {
301 scancode &= 0x7f;
302 down = 0;
303 }
304 if (xenfb->extended) {
305 scancode |= 0x80;
306 xenfb->extended = 0;
307 }
308 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
309}
310
311/*
312 * Send a mouse event from the client to the guest OS
313 *
314 * The QEMU mouse can be in either relative, or absolute mode.
315 * Movement is sent separately from button state, which has to
316 * be encoded as virtual key events. We also don't actually get
317 * given any button up/down events, so have to track changes in
318 * the button state.
319 */
320static void xenfb_mouse_event(void *opaque,
321 int dx, int dy, int dz, int button_state)
322{
323 struct XenInput *xenfb = opaque;
324 int dw = ds_get_width(xenfb->c.ds);
325 int dh = ds_get_height(xenfb->c.ds);
326 int i;
327
328 if (xenfb->abs_pointer_wanted)
329 xenfb_send_position(xenfb,
330 dx * (dw - 1) / 0x7fff,
331 dy * (dh - 1) / 0x7fff,
332 dz);
333 else
334 xenfb_send_motion(xenfb, dx, dy, dz);
335
336 for (i = 0 ; i < 8 ; i++) {
337 int lastDown = xenfb->button_state & (1 << i);
338 int down = button_state & (1 << i);
339 if (down == lastDown)
340 continue;
341
342 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
343 return;
344 }
345 xenfb->button_state = button_state;
346}
347
348static int input_init(struct XenDevice *xendev)
349{
aliguorie7151f82009-04-22 15:19:25 +0000350 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
351 return 0;
352}
353
354static int input_connect(struct XenDevice *xendev)
355{
356 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
357 int rc;
358
359 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
360 &in->abs_pointer_wanted) == -1)
361 in->abs_pointer_wanted = 0;
362
Stefano Stabellini37cdfcf2011-06-24 17:36:11 +0100363 if (!in->c.ds) {
364 char *vfb = xenstore_read_str(NULL, "device/vfb");
365 if (vfb == NULL) {
366 /* there is no vfb, run vkbd on its own */
367 in->c.ds = get_displaystate();
368 } else {
369 qemu_free(vfb);
370 xen_be_printf(xendev, 1, "ds not set (yet)\n");
371 return -1;
372 }
373 }
374
aliguorie7151f82009-04-22 15:19:25 +0000375 rc = common_bind(&in->c);
376 if (rc != 0)
377 return rc;
378
379 qemu_add_kbd_event_handler(xenfb_key_event, in);
380 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
381 in->abs_pointer_wanted,
382 "Xen PVFB Mouse");
383 return 0;
384}
385
386static void input_disconnect(struct XenDevice *xendev)
387{
388 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
389
390 if (in->qmouse) {
391 qemu_remove_mouse_event_handler(in->qmouse);
392 in->qmouse = NULL;
393 }
394 qemu_add_kbd_event_handler(NULL, NULL);
395 common_unbind(&in->c);
396}
397
398static void input_event(struct XenDevice *xendev)
399{
400 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
401 struct xenkbd_page *page = xenfb->c.page;
402
403 /* We don't understand any keyboard events, so just ignore them. */
404 if (page->out_prod == page->out_cons)
405 return;
406 page->out_cons = page->out_prod;
407 xen_be_send_notify(&xenfb->c.xendev);
408}
409
410/* -------------------------------------------------------------------- */
411
412static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
413{
414 uint32_t *src32 = src;
415 uint64_t *src64 = src;
416 int i;
417
418 for (i = 0; i < count; i++)
419 dst[i] = (mode == 32) ? src32[i] : src64[i];
420}
421
422static int xenfb_map_fb(struct XenFB *xenfb)
423{
424 struct xenfb_page *page = xenfb->c.page;
425 char *protocol = xenfb->c.xendev.protocol;
426 int n_fbdirs;
427 unsigned long *pgmfns = NULL;
428 unsigned long *fbmfns = NULL;
429 void *map, *pd;
430 int mode, ret = -1;
431
432 /* default to native */
433 pd = page->pd;
434 mode = sizeof(unsigned long) * 8;
435
436 if (!protocol) {
437 /*
438 * Undefined protocol, some guesswork needed.
439 *
440 * Old frontends which don't set the protocol use
441 * one page directory only, thus pd[1] must be zero.
442 * pd[1] of the 32bit struct layout and the lower
443 * 32 bits of pd[0] of the 64bit struct layout have
444 * the same location, so we can check that ...
445 */
446 uint32_t *ptr32 = NULL;
447 uint32_t *ptr64 = NULL;
448#if defined(__i386__)
449 ptr32 = (void*)page->pd;
450 ptr64 = ((void*)page->pd) + 4;
451#elif defined(__x86_64__)
452 ptr32 = ((void*)page->pd) - 4;
453 ptr64 = (void*)page->pd;
454#endif
455 if (ptr32) {
456 if (ptr32[1] == 0) {
457 mode = 32;
458 pd = ptr32;
459 } else {
460 mode = 64;
461 pd = ptr64;
462 }
463 }
464#if defined(__x86_64__)
465 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
466 /* 64bit dom0, 32bit domU */
467 mode = 32;
468 pd = ((void*)page->pd) - 4;
469#elif defined(__i386__)
470 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
471 /* 32bit dom0, 64bit domU */
472 mode = 64;
473 pd = ((void*)page->pd) + 4;
474#endif
475 }
476
477 if (xenfb->pixels) {
478 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
479 xenfb->pixels = NULL;
480 }
481
482 xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
483 n_fbdirs = xenfb->fbpages * mode / 8;
484 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
485
486 pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
487 fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
488
489 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
490 map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
491 PROT_READ, pgmfns, n_fbdirs);
492 if (map == NULL)
493 goto out;
494 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
495 munmap(map, n_fbdirs * XC_PAGE_SIZE);
496
497 xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
498 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
499 if (xenfb->pixels == NULL)
500 goto out;
501
502 ret = 0; /* all is fine */
503
504out:
505 qemu_free(pgmfns);
506 qemu_free(fbmfns);
507 return ret;
508}
509
510static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
511 int width, int height, int depth,
512 size_t fb_len, int offset, int row_stride)
513{
514 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
515 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
516 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
517 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
518 int max_width, max_height;
519
520 if (fb_len_lim > fb_len_max) {
521 xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
522 fb_len_lim, fb_len_max);
523 fb_len_lim = fb_len_max;
524 }
525 if (fb_len_lim && fb_len > fb_len_lim) {
526 xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
527 fb_len, fb_len_lim);
528 fb_len = fb_len_lim;
529 }
530 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
531 xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
532 depth);
533 return -1;
534 }
535 if (row_stride <= 0 || row_stride > fb_len) {
536 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
537 return -1;
538 }
539 max_width = row_stride / (depth / 8);
540 if (width < 0 || width > max_width) {
541 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
542 width, max_width);
543 width = max_width;
544 }
545 if (offset < 0 || offset >= fb_len) {
546 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
547 offset, fb_len - 1);
548 return -1;
549 }
550 max_height = (fb_len - offset) / row_stride;
551 if (height < 0 || height > max_height) {
552 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
553 height, max_height);
554 height = max_height;
555 }
556 xenfb->fb_len = fb_len;
557 xenfb->row_stride = row_stride;
558 xenfb->depth = depth;
559 xenfb->width = width;
560 xenfb->height = height;
561 xenfb->offset = offset;
562 xenfb->up_fullscreen = 1;
563 xenfb->do_resize = 1;
564 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
565 width, height, depth, offset, row_stride);
566 return 0;
567}
568
569/* A convenient function for munging pixels between different depths */
570#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
571 for (line = y ; line < (y+h) ; line++) { \
572 SRC_T *src = (SRC_T *)(xenfb->pixels \
573 + xenfb->offset \
574 + (line * xenfb->row_stride) \
575 + (x * xenfb->depth / 8)); \
576 DST_T *dst = (DST_T *)(data \
577 + (line * linesize) \
578 + (x * bpp / 8)); \
579 int col; \
580 const int RSS = 32 - (RSB + GSB + BSB); \
581 const int GSS = 32 - (GSB + BSB); \
582 const int BSS = 32 - (BSB); \
583 const uint32_t RSM = (~0U) << (32 - RSB); \
584 const uint32_t GSM = (~0U) << (32 - GSB); \
585 const uint32_t BSM = (~0U) << (32 - BSB); \
586 const int RDS = 32 - (RDB + GDB + BDB); \
587 const int GDS = 32 - (GDB + BDB); \
588 const int BDS = 32 - (BDB); \
589 const uint32_t RDM = (~0U) << (32 - RDB); \
590 const uint32_t GDM = (~0U) << (32 - GDB); \
591 const uint32_t BDM = (~0U) << (32 - BDB); \
592 for (col = x ; col < (x+w) ; col++) { \
593 uint32_t spix = *src; \
594 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
595 (((spix << GSS) & GSM & GDM) >> GDS) | \
596 (((spix << BSS) & BSM & BDM) >> BDS); \
597 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
598 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
599 } \
600 }
601
602
603/*
604 * This copies data from the guest framebuffer region, into QEMU's
605 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
606 * uses something else we must convert and copy, otherwise we can
607 * supply the buffer directly and no thing here.
608 */
609static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
610{
611 int line, oops = 0;
612 int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
613 int linesize = ds_get_linesize(xenfb->c.ds);
614 uint8_t *data = ds_get_data(xenfb->c.ds);
615
616 if (!is_buffer_shared(xenfb->c.ds->surface)) {
617 switch (xenfb->depth) {
618 case 8:
619 if (bpp == 16) {
620 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
621 } else if (bpp == 32) {
622 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
623 } else {
624 oops = 1;
625 }
626 break;
627 case 24:
628 if (bpp == 16) {
629 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
630 } else if (bpp == 32) {
631 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
632 } else {
633 oops = 1;
634 }
635 break;
636 default:
637 oops = 1;
638 }
639 }
640 if (oops) /* should not happen */
641 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
642 __FUNCTION__, xenfb->depth, bpp);
643
644 dpy_update(xenfb->c.ds, x, y, w, h);
645}
646
647#ifdef XENFB_TYPE_REFRESH_PERIOD
648static int xenfb_queue_full(struct XenFB *xenfb)
649{
650 struct xenfb_page *page = xenfb->c.page;
651 uint32_t cons, prod;
652
653 if (!page)
654 return 1;
655
656 prod = page->in_prod;
657 cons = page->in_cons;
658 return prod - cons == XENFB_IN_RING_LEN;
659}
660
661static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
662{
663 uint32_t prod;
664 struct xenfb_page *page = xenfb->c.page;
665
666 prod = page->in_prod;
667 /* caller ensures !xenfb_queue_full() */
668 xen_mb(); /* ensure ring space available */
669 XENFB_IN_RING_REF(page, prod) = *event;
670 xen_wmb(); /* ensure ring contents visible */
671 page->in_prod = prod + 1;
672
673 xen_be_send_notify(&xenfb->c.xendev);
674}
675
676static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
677{
678 union xenfb_in_event event;
679
680 memset(&event, 0, sizeof(event));
681 event.type = XENFB_TYPE_REFRESH_PERIOD;
682 event.refresh_period.period = period;
683 xenfb_send_event(xenfb, &event);
684}
685#endif
686
687/*
688 * Periodic update of display.
689 * Also transmit the refresh interval to the frontend.
690 *
691 * Never ever do any qemu display operations
692 * (resize, screen update) outside this function.
693 * Our screen might be inactive. When asked for
694 * an update we know it is active.
695 */
696static void xenfb_update(void *opaque)
697{
698 struct XenFB *xenfb = opaque;
aliguorie7151f82009-04-22 15:19:25 +0000699 int i;
700
701 if (xenfb->c.xendev.be_state != XenbusStateConnected)
702 return;
703
704 if (xenfb->feature_update) {
705#ifdef XENFB_TYPE_REFRESH_PERIOD
Blue Swirlc433bed2009-04-25 07:31:43 +0000706 struct DisplayChangeListener *l;
aliguorie7151f82009-04-22 15:19:25 +0000707 int period = 99999999;
708 int idle = 1;
709
710 if (xenfb_queue_full(xenfb))
711 return;
712
713 for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
714 if (l->idle)
715 continue;
716 idle = 0;
717 if (!l->gui_timer_interval) {
718 if (period > GUI_REFRESH_INTERVAL)
719 period = GUI_REFRESH_INTERVAL;
720 } else {
721 if (period > l->gui_timer_interval)
722 period = l->gui_timer_interval;
723 }
724 }
725 if (idle)
726 period = XENFB_NO_REFRESH;
727
728 if (xenfb->refresh_period != period) {
729 xenfb_send_refresh_period(xenfb, period);
730 xenfb->refresh_period = period;
731 xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
732 }
733#else
734 ; /* nothing */
735#endif
736 } else {
737 /* we don't get update notifications, thus use the
738 * sledge hammer approach ... */
739 xenfb->up_fullscreen = 1;
740 }
741
742 /* resize if needed */
743 if (xenfb->do_resize) {
744 xenfb->do_resize = 0;
745 switch (xenfb->depth) {
746 case 16:
747 case 32:
748 /* console.c supported depth -> buffer can be used directly */
749 qemu_free_displaysurface(xenfb->c.ds);
750 xenfb->c.ds->surface = qemu_create_displaysurface_from
751 (xenfb->width, xenfb->height, xenfb->depth,
752 xenfb->row_stride, xenfb->pixels + xenfb->offset);
753 break;
754 default:
755 /* we must convert stuff */
756 qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
757 break;
758 }
759 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
760 xenfb->width, xenfb->height, xenfb->depth,
761 is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
762 dpy_resize(xenfb->c.ds);
763 xenfb->up_fullscreen = 1;
764 }
765
766 /* run queued updates */
767 if (xenfb->up_fullscreen) {
768 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
769 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
770 } else if (xenfb->up_count) {
771 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
772 for (i = 0; i < xenfb->up_count; i++)
773 xenfb_guest_copy(xenfb,
774 xenfb->up_rects[i].x,
775 xenfb->up_rects[i].y,
776 xenfb->up_rects[i].w,
777 xenfb->up_rects[i].h);
778 } else {
779 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
780 }
781 xenfb->up_count = 0;
782 xenfb->up_fullscreen = 0;
783}
784
785/* QEMU display state changed, so refresh the framebuffer copy */
786static void xenfb_invalidate(void *opaque)
787{
788 struct XenFB *xenfb = opaque;
789 xenfb->up_fullscreen = 1;
790}
791
792static void xenfb_handle_events(struct XenFB *xenfb)
793{
794 uint32_t prod, cons;
795 struct xenfb_page *page = xenfb->c.page;
796
797 prod = page->out_prod;
798 if (prod == page->out_cons)
799 return;
800 xen_rmb(); /* ensure we see ring contents up to prod */
801 for (cons = page->out_cons; cons != prod; cons++) {
802 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
803 int x, y, w, h;
804
805 switch (event->type) {
806 case XENFB_TYPE_UPDATE:
807 if (xenfb->up_count == UP_QUEUE)
808 xenfb->up_fullscreen = 1;
809 if (xenfb->up_fullscreen)
810 break;
811 x = MAX(event->update.x, 0);
812 y = MAX(event->update.y, 0);
813 w = MIN(event->update.width, xenfb->width - x);
814 h = MIN(event->update.height, xenfb->height - y);
815 if (w < 0 || h < 0) {
816 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
817 break;
818 }
819 if (x != event->update.x ||
820 y != event->update.y ||
821 w != event->update.width ||
822 h != event->update.height) {
823 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
824 }
825 if (w == xenfb->width && h > xenfb->height / 2) {
826 /* scroll detector: updated more than 50% of the lines,
827 * don't bother keeping track of the rectangles then */
828 xenfb->up_fullscreen = 1;
829 } else {
830 xenfb->up_rects[xenfb->up_count].x = x;
831 xenfb->up_rects[xenfb->up_count].y = y;
832 xenfb->up_rects[xenfb->up_count].w = w;
833 xenfb->up_rects[xenfb->up_count].h = h;
834 xenfb->up_count++;
835 }
836 break;
837#ifdef XENFB_TYPE_RESIZE
838 case XENFB_TYPE_RESIZE:
839 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
840 event->resize.width,
841 event->resize.height,
842 event->resize.depth,
843 xenfb->fb_len,
844 event->resize.offset,
845 event->resize.stride) < 0)
846 break;
847 xenfb_invalidate(xenfb);
848 break;
849#endif
850 }
851 }
852 xen_mb(); /* ensure we're done with ring contents */
853 page->out_cons = cons;
854}
855
856static int fb_init(struct XenDevice *xendev)
857{
858 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
859
860 fb->refresh_period = -1;
861
862#ifdef XENFB_TYPE_RESIZE
863 xenstore_write_be_int(xendev, "feature-resize", 1);
864#endif
865 return 0;
866}
867
868static int fb_connect(struct XenDevice *xendev)
869{
870 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
871 struct xenfb_page *fb_page;
872 int videoram;
873 int rc;
874
875 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
876 videoram = 0;
877
878 rc = common_bind(&fb->c);
879 if (rc != 0)
880 return rc;
881
882 fb_page = fb->c.page;
883 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
884 fb_page->width, fb_page->height, fb_page->depth,
885 fb_page->mem_length, 0, fb_page->line_length);
886 if (rc != 0)
887 return rc;
888
889 rc = xenfb_map_fb(fb);
890 if (rc != 0)
891 return rc;
892
893#if 0 /* handled in xen_init_display() for now */
894 if (!fb->have_console) {
895 fb->c.ds = graphic_console_init(xenfb_update,
896 xenfb_invalidate,
897 NULL,
898 NULL,
899 fb);
900 fb->have_console = 1;
901 }
902#endif
903
904 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
905 fb->feature_update = 0;
906 if (fb->feature_update)
907 xenstore_write_be_int(xendev, "request-update", 1);
908
909 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
910 fb->feature_update, videoram);
911 return 0;
912}
913
914static void fb_disconnect(struct XenDevice *xendev)
915{
916 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
917
918 /*
919 * FIXME: qemu can't un-init gfx display (yet?).
920 * Replacing the framebuffer with anonymous shared memory
921 * instead. This releases the guest pages and keeps qemu happy.
922 */
923 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
924 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
925 -1, 0);
926 common_unbind(&fb->c);
927 fb->feature_update = 0;
928 fb->bug_trigger = 0;
929}
930
931static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
932{
933 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
934
935 /*
936 * Set state to Connected *again* once the frontend switched
937 * to connected. We must trigger the watch a second time to
938 * workaround a frontend bug.
939 */
940 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
941 xendev->fe_state == XenbusStateConnected &&
942 xendev->be_state == XenbusStateConnected) {
943 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
944 xen_be_set_state(xendev, XenbusStateConnected);
945 fb->bug_trigger = 1; /* only once */
946 }
947}
948
949static void fb_event(struct XenDevice *xendev)
950{
951 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
952
953 xenfb_handle_events(xenfb);
954 xen_be_send_notify(&xenfb->c.xendev);
955}
956
957/* -------------------------------------------------------------------- */
958
959struct XenDevOps xen_kbdmouse_ops = {
960 .size = sizeof(struct XenInput),
961 .init = input_init,
962 .connect = input_connect,
963 .disconnect = input_disconnect,
964 .event = input_event,
965};
966
967struct XenDevOps xen_framebuffer_ops = {
968 .size = sizeof(struct XenFB),
969 .init = fb_init,
970 .connect = fb_connect,
971 .disconnect = fb_disconnect,
972 .event = fb_event,
973 .frontend_changed = fb_frontend_changed,
974};
975
976/*
977 * FIXME/TODO: Kill this.
978 * Temporary needed while DisplayState reorganization is in flight.
979 */
980void xen_init_display(int domid)
981{
982 struct XenDevice *xfb, *xin;
983 struct XenFB *fb;
984 struct XenInput *in;
985 int i = 0;
986
987wait_more:
988 i++;
Paolo Bonzinid6f4ade2010-03-10 11:38:54 +0100989 main_loop_wait(true);
aliguorie7151f82009-04-22 15:19:25 +0000990 xfb = xen_be_find_xendev("vfb", domid, 0);
991 xin = xen_be_find_xendev("vkbd", domid, 0);
992 if (!xfb || !xin) {
Paolo Bonzinid6f4ade2010-03-10 11:38:54 +0100993 if (i < 256) {
994 usleep(10000);
aliguorie7151f82009-04-22 15:19:25 +0000995 goto wait_more;
Paolo Bonzinid6f4ade2010-03-10 11:38:54 +0100996 }
aliguorie7151f82009-04-22 15:19:25 +0000997 xen_be_printf(NULL, 1, "displaystate setup failed\n");
998 return;
999 }
1000
1001 /* vfb */
1002 fb = container_of(xfb, struct XenFB, c.xendev);
1003 fb->c.ds = graphic_console_init(xenfb_update,
1004 xenfb_invalidate,
1005 NULL,
1006 NULL,
1007 fb);
1008 fb->have_console = 1;
1009
1010 /* vkbd */
1011 in = container_of(xin, struct XenInput, c.xendev);
1012 in->c.ds = fb->c.ds;
1013
1014 /* retry ->init() */
1015 xen_be_check_state(xin);
1016 xen_be_check_state(xfb);
1017}