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