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