]> Git Repo - qemu.git/blob - hw/xenfb.c
Makefile.hw: allow hw/ files to include glib headers
[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 <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"
47 #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
57 struct common {
58     struct XenDevice  xendev;  /* must be first */
59     void              *page;
60     DisplayState      *ds;
61 };
62
63 struct 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
73 struct 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
98 static 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
120 static 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  */
141 const 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
163 const 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  */
183 static 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 */
204 static 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 */
229 static 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 */
242 static 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 */
259 static 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  */
292 static 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  */
320 static 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
348 static int input_init(struct XenDevice *xendev)
349 {
350     xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
351     return 0;
352 }
353
354 static 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
363     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             g_free(vfb);
370             xen_be_printf(xendev, 1, "ds not set (yet)\n");
371             return -1;
372         }
373     }
374
375     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
386 static 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
398 static 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
412 static 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
422 static 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 = g_malloc0(sizeof(unsigned long) * n_fbdirs);
487     fbmfns = g_malloc0(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
504 out:
505     g_free(pgmfns);
506     g_free(fbmfns);
507     return ret;
508 }
509
510 static 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  */
609 static 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
648 static 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
661 static 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
676 static 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  */
696 static void xenfb_update(void *opaque)
697 {
698     struct XenFB *xenfb = opaque;
699     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
706         struct DisplayChangeListener *l;
707         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 */
786 static void xenfb_invalidate(void *opaque)
787 {
788     struct XenFB *xenfb = opaque;
789     xenfb->up_fullscreen = 1;
790 }
791
792 static 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
856 static 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
868 static 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
914 static 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
931 static 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
949 static 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
959 struct 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
967 struct 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  */
980 void xen_init_display(int domid)
981 {
982     struct XenDevice *xfb, *xin;
983     struct XenFB *fb;
984     struct XenInput *in;
985     int i = 0;
986
987 wait_more:
988     i++;
989     main_loop_wait(true);
990     xfb = xen_be_find_xendev("vfb", domid, 0);
991     xin = xen_be_find_xendev("vkbd", domid, 0);
992     if (!xfb || !xin) {
993         if (i < 256) {
994             usleep(10000);
995             goto wait_more;
996         }
997         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 }
This page took 0.085737 seconds and 4 git commands to generate.