]> Git Repo - qemu.git/blob - hw/xenfb.c
scsi-disk: support DVD profile in GET CONFIGURATION
[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_initialise(struct XenDevice *xendev)
355 {
356     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
357     int rc;
358
359     if (!in->c.ds) {
360         char *vfb = xenstore_read_str(NULL, "device/vfb");
361         if (vfb == NULL) {
362             /* there is no vfb, run vkbd on its own */
363             in->c.ds = get_displaystate();
364         } else {
365             g_free(vfb);
366             xen_be_printf(xendev, 1, "ds not set (yet)\n");
367             return -1;
368         }
369     }
370
371     rc = common_bind(&in->c);
372     if (rc != 0)
373         return rc;
374
375     qemu_add_kbd_event_handler(xenfb_key_event, in);
376     return 0;
377 }
378
379 static void input_connected(struct XenDevice *xendev)
380 {
381     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
382
383     if (xenstore_read_fe_int(xendev, "request-abs-pointer",
384                              &in->abs_pointer_wanted) == -1) {
385         in->abs_pointer_wanted = 0;
386     }
387
388     if (in->qmouse) {
389         qemu_remove_mouse_event_handler(in->qmouse);
390     }
391     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
392                                               in->abs_pointer_wanted,
393                                               "Xen PVFB Mouse");
394 }
395
396 static void input_disconnect(struct XenDevice *xendev)
397 {
398     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
399
400     if (in->qmouse) {
401         qemu_remove_mouse_event_handler(in->qmouse);
402         in->qmouse = NULL;
403     }
404     qemu_add_kbd_event_handler(NULL, NULL);
405     common_unbind(&in->c);
406 }
407
408 static void input_event(struct XenDevice *xendev)
409 {
410     struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
411     struct xenkbd_page *page = xenfb->c.page;
412
413     /* We don't understand any keyboard events, so just ignore them. */
414     if (page->out_prod == page->out_cons)
415         return;
416     page->out_cons = page->out_prod;
417     xen_be_send_notify(&xenfb->c.xendev);
418 }
419
420 /* -------------------------------------------------------------------- */
421
422 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
423 {
424     uint32_t *src32 = src;
425     uint64_t *src64 = src;
426     int i;
427
428     for (i = 0; i < count; i++)
429         dst[i] = (mode == 32) ? src32[i] : src64[i];
430 }
431
432 static int xenfb_map_fb(struct XenFB *xenfb)
433 {
434     struct xenfb_page *page = xenfb->c.page;
435     char *protocol = xenfb->c.xendev.protocol;
436     int n_fbdirs;
437     unsigned long *pgmfns = NULL;
438     unsigned long *fbmfns = NULL;
439     void *map, *pd;
440     int mode, ret = -1;
441
442     /* default to native */
443     pd = page->pd;
444     mode = sizeof(unsigned long) * 8;
445
446     if (!protocol) {
447         /*
448          * Undefined protocol, some guesswork needed.
449          *
450          * Old frontends which don't set the protocol use
451          * one page directory only, thus pd[1] must be zero.
452          * pd[1] of the 32bit struct layout and the lower
453          * 32 bits of pd[0] of the 64bit struct layout have
454          * the same location, so we can check that ...
455          */
456         uint32_t *ptr32 = NULL;
457         uint32_t *ptr64 = NULL;
458 #if defined(__i386__)
459         ptr32 = (void*)page->pd;
460         ptr64 = ((void*)page->pd) + 4;
461 #elif defined(__x86_64__)
462         ptr32 = ((void*)page->pd) - 4;
463         ptr64 = (void*)page->pd;
464 #endif
465         if (ptr32) {
466             if (ptr32[1] == 0) {
467                 mode = 32;
468                 pd   = ptr32;
469             } else {
470                 mode = 64;
471                 pd   = ptr64;
472             }
473         }
474 #if defined(__x86_64__)
475     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
476         /* 64bit dom0, 32bit domU */
477         mode = 32;
478         pd   = ((void*)page->pd) - 4;
479 #elif defined(__i386__)
480     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
481         /* 32bit dom0, 64bit domU */
482         mode = 64;
483         pd   = ((void*)page->pd) + 4;
484 #endif
485     }
486
487     if (xenfb->pixels) {
488         munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
489         xenfb->pixels = NULL;
490     }
491
492     xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
493     n_fbdirs = xenfb->fbpages * mode / 8;
494     n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
495
496     pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
497     fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
498
499     xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
500     map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
501                                PROT_READ, pgmfns, n_fbdirs);
502     if (map == NULL)
503         goto out;
504     xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
505     munmap(map, n_fbdirs * XC_PAGE_SIZE);
506
507     xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
508                                          PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
509     if (xenfb->pixels == NULL)
510         goto out;
511
512     ret = 0; /* all is fine */
513
514 out:
515     g_free(pgmfns);
516     g_free(fbmfns);
517     return ret;
518 }
519
520 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
521                               int width, int height, int depth,
522                               size_t fb_len, int offset, int row_stride)
523 {
524     size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
525     size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
526     size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
527     size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
528     int max_width, max_height;
529
530     if (fb_len_lim > fb_len_max) {
531         xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
532                       fb_len_lim, fb_len_max);
533         fb_len_lim = fb_len_max;
534     }
535     if (fb_len_lim && fb_len > fb_len_lim) {
536         xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
537                       fb_len, fb_len_lim);
538         fb_len = fb_len_lim;
539     }
540     if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
541         xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
542                       depth);
543         return -1;
544     }
545     if (row_stride <= 0 || row_stride > fb_len) {
546         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
547         return -1;
548     }
549     max_width = row_stride / (depth / 8);
550     if (width < 0 || width > max_width) {
551         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
552                       width, max_width);
553         width = max_width;
554     }
555     if (offset < 0 || offset >= fb_len) {
556         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
557                       offset, fb_len - 1);
558         return -1;
559     }
560     max_height = (fb_len - offset) / row_stride;
561     if (height < 0 || height > max_height) {
562         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
563                       height, max_height);
564         height = max_height;
565     }
566     xenfb->fb_len = fb_len;
567     xenfb->row_stride = row_stride;
568     xenfb->depth = depth;
569     xenfb->width = width;
570     xenfb->height = height;
571     xenfb->offset = offset;
572     xenfb->up_fullscreen = 1;
573     xenfb->do_resize = 1;
574     xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
575                   width, height, depth, offset, row_stride);
576     return 0;
577 }
578
579 /* A convenient function for munging pixels between different depths */
580 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
581     for (line = y ; line < (y+h) ; line++) {                            \
582         SRC_T *src = (SRC_T *)(xenfb->pixels                            \
583                                + xenfb->offset                          \
584                                + (line * xenfb->row_stride)             \
585                                + (x * xenfb->depth / 8));               \
586         DST_T *dst = (DST_T *)(data                                     \
587                                + (line * linesize)                      \
588                                + (x * bpp / 8));                        \
589         int col;                                                        \
590         const int RSS = 32 - (RSB + GSB + BSB);                         \
591         const int GSS = 32 - (GSB + BSB);                               \
592         const int BSS = 32 - (BSB);                                     \
593         const uint32_t RSM = (~0U) << (32 - RSB);                       \
594         const uint32_t GSM = (~0U) << (32 - GSB);                       \
595         const uint32_t BSM = (~0U) << (32 - BSB);                       \
596         const int RDS = 32 - (RDB + GDB + BDB);                         \
597         const int GDS = 32 - (GDB + BDB);                               \
598         const int BDS = 32 - (BDB);                                     \
599         const uint32_t RDM = (~0U) << (32 - RDB);                       \
600         const uint32_t GDM = (~0U) << (32 - GDB);                       \
601         const uint32_t BDM = (~0U) << (32 - BDB);                       \
602         for (col = x ; col < (x+w) ; col++) {                           \
603             uint32_t spix = *src;                                       \
604             *dst = (((spix << RSS) & RSM & RDM) >> RDS) |               \
605                 (((spix << GSS) & GSM & GDM) >> GDS) |                  \
606                 (((spix << BSS) & BSM & BDM) >> BDS);                   \
607             src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);   \
608             dst = (DST_T *) ((unsigned long) dst + bpp / 8);            \
609         }                                                               \
610     }
611
612
613 /*
614  * This copies data from the guest framebuffer region, into QEMU's
615  * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
616  * uses something else we must convert and copy, otherwise we can
617  * supply the buffer directly and no thing here.
618  */
619 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
620 {
621     int line, oops = 0;
622     int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
623     int linesize = ds_get_linesize(xenfb->c.ds);
624     uint8_t *data = ds_get_data(xenfb->c.ds);
625
626     if (!is_buffer_shared(xenfb->c.ds->surface)) {
627         switch (xenfb->depth) {
628         case 8:
629             if (bpp == 16) {
630                 BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
631             } else if (bpp == 32) {
632                 BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
633             } else {
634                 oops = 1;
635             }
636             break;
637         case 24:
638             if (bpp == 16) {
639                 BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
640             } else if (bpp == 32) {
641                 BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
642             } else {
643                 oops = 1;
644             }
645             break;
646         default:
647             oops = 1;
648         }
649     }
650     if (oops) /* should not happen */
651         xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
652                       __FUNCTION__, xenfb->depth, bpp);
653
654     dpy_update(xenfb->c.ds, x, y, w, h);
655 }
656
657 #ifdef XENFB_TYPE_REFRESH_PERIOD
658 static int xenfb_queue_full(struct XenFB *xenfb)
659 {
660     struct xenfb_page *page = xenfb->c.page;
661     uint32_t cons, prod;
662
663     if (!page)
664         return 1;
665
666     prod = page->in_prod;
667     cons = page->in_cons;
668     return prod - cons == XENFB_IN_RING_LEN;
669 }
670
671 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
672 {
673     uint32_t prod;
674     struct xenfb_page *page = xenfb->c.page;
675
676     prod = page->in_prod;
677     /* caller ensures !xenfb_queue_full() */
678     xen_mb();                   /* ensure ring space available */
679     XENFB_IN_RING_REF(page, prod) = *event;
680     xen_wmb();                  /* ensure ring contents visible */
681     page->in_prod = prod + 1;
682
683     xen_be_send_notify(&xenfb->c.xendev);
684 }
685
686 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
687 {
688     union xenfb_in_event event;
689
690     memset(&event, 0, sizeof(event));
691     event.type = XENFB_TYPE_REFRESH_PERIOD;
692     event.refresh_period.period = period;
693     xenfb_send_event(xenfb, &event);
694 }
695 #endif
696
697 /*
698  * Periodic update of display.
699  * Also transmit the refresh interval to the frontend.
700  *
701  * Never ever do any qemu display operations
702  * (resize, screen update) outside this function.
703  * Our screen might be inactive.  When asked for
704  * an update we know it is active.
705  */
706 static void xenfb_update(void *opaque)
707 {
708     struct XenFB *xenfb = opaque;
709     int i;
710
711     if (xenfb->c.xendev.be_state != XenbusStateConnected)
712         return;
713
714     if (xenfb->feature_update) {
715 #ifdef XENFB_TYPE_REFRESH_PERIOD
716         struct DisplayChangeListener *l;
717         int period = 99999999;
718         int idle = 1;
719
720         if (xenfb_queue_full(xenfb))
721             return;
722
723         for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
724             if (l->idle)
725                 continue;
726             idle = 0;
727             if (!l->gui_timer_interval) {
728                 if (period > GUI_REFRESH_INTERVAL)
729                     period = GUI_REFRESH_INTERVAL;
730             } else {
731                 if (period > l->gui_timer_interval)
732                     period = l->gui_timer_interval;
733             }
734         }
735         if (idle)
736             period = XENFB_NO_REFRESH;
737
738         if (xenfb->refresh_period != period) {
739             xenfb_send_refresh_period(xenfb, period);
740             xenfb->refresh_period = period;
741             xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
742         }
743 #else
744         ; /* nothing */
745 #endif
746     } else {
747         /* we don't get update notifications, thus use the
748          * sledge hammer approach ... */
749         xenfb->up_fullscreen = 1;
750     }
751
752     /* resize if needed */
753     if (xenfb->do_resize) {
754         xenfb->do_resize = 0;
755         switch (xenfb->depth) {
756         case 16:
757         case 32:
758             /* console.c supported depth -> buffer can be used directly */
759             qemu_free_displaysurface(xenfb->c.ds);
760             xenfb->c.ds->surface = qemu_create_displaysurface_from
761                 (xenfb->width, xenfb->height, xenfb->depth,
762                  xenfb->row_stride, xenfb->pixels + xenfb->offset);
763             break;
764         default:
765             /* we must convert stuff */
766             qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
767             break;
768         }
769         xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
770                       xenfb->width, xenfb->height, xenfb->depth,
771                       is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
772         dpy_resize(xenfb->c.ds);
773         xenfb->up_fullscreen = 1;
774     }
775
776     /* run queued updates */
777     if (xenfb->up_fullscreen) {
778         xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
779         xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
780     } else if (xenfb->up_count) {
781         xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
782         for (i = 0; i < xenfb->up_count; i++)
783             xenfb_guest_copy(xenfb,
784                              xenfb->up_rects[i].x,
785                              xenfb->up_rects[i].y,
786                              xenfb->up_rects[i].w,
787                              xenfb->up_rects[i].h);
788     } else {
789         xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
790     }
791     xenfb->up_count = 0;
792     xenfb->up_fullscreen = 0;
793 }
794
795 /* QEMU display state changed, so refresh the framebuffer copy */
796 static void xenfb_invalidate(void *opaque)
797 {
798     struct XenFB *xenfb = opaque;
799     xenfb->up_fullscreen = 1;
800 }
801
802 static void xenfb_handle_events(struct XenFB *xenfb)
803 {
804     uint32_t prod, cons;
805     struct xenfb_page *page = xenfb->c.page;
806
807     prod = page->out_prod;
808     if (prod == page->out_cons)
809         return;
810     xen_rmb();          /* ensure we see ring contents up to prod */
811     for (cons = page->out_cons; cons != prod; cons++) {
812         union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
813         int x, y, w, h;
814
815         switch (event->type) {
816         case XENFB_TYPE_UPDATE:
817             if (xenfb->up_count == UP_QUEUE)
818                 xenfb->up_fullscreen = 1;
819             if (xenfb->up_fullscreen)
820                 break;
821             x = MAX(event->update.x, 0);
822             y = MAX(event->update.y, 0);
823             w = MIN(event->update.width, xenfb->width - x);
824             h = MIN(event->update.height, xenfb->height - y);
825             if (w < 0 || h < 0) {
826                 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
827                 break;
828             }
829             if (x != event->update.x ||
830                 y != event->update.y ||
831                 w != event->update.width ||
832                 h != event->update.height) {
833                 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
834             }
835             if (w == xenfb->width && h > xenfb->height / 2) {
836                 /* scroll detector: updated more than 50% of the lines,
837                  * don't bother keeping track of the rectangles then */
838                 xenfb->up_fullscreen = 1;
839             } else {
840                 xenfb->up_rects[xenfb->up_count].x = x;
841                 xenfb->up_rects[xenfb->up_count].y = y;
842                 xenfb->up_rects[xenfb->up_count].w = w;
843                 xenfb->up_rects[xenfb->up_count].h = h;
844                 xenfb->up_count++;
845             }
846             break;
847 #ifdef XENFB_TYPE_RESIZE
848         case XENFB_TYPE_RESIZE:
849             if (xenfb_configure_fb(xenfb, xenfb->fb_len,
850                                    event->resize.width,
851                                    event->resize.height,
852                                    event->resize.depth,
853                                    xenfb->fb_len,
854                                    event->resize.offset,
855                                    event->resize.stride) < 0)
856                 break;
857             xenfb_invalidate(xenfb);
858             break;
859 #endif
860         }
861     }
862     xen_mb();           /* ensure we're done with ring contents */
863     page->out_cons = cons;
864 }
865
866 static int fb_init(struct XenDevice *xendev)
867 {
868     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
869
870     fb->refresh_period = -1;
871
872 #ifdef XENFB_TYPE_RESIZE
873     xenstore_write_be_int(xendev, "feature-resize", 1);
874 #endif
875     return 0;
876 }
877
878 static int fb_initialise(struct XenDevice *xendev)
879 {
880     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
881     struct xenfb_page *fb_page;
882     int videoram;
883     int rc;
884
885     if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
886         videoram = 0;
887
888     rc = common_bind(&fb->c);
889     if (rc != 0)
890         return rc;
891
892     fb_page = fb->c.page;
893     rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
894                             fb_page->width, fb_page->height, fb_page->depth,
895                             fb_page->mem_length, 0, fb_page->line_length);
896     if (rc != 0)
897         return rc;
898
899     rc = xenfb_map_fb(fb);
900     if (rc != 0)
901         return rc;
902
903 #if 0  /* handled in xen_init_display() for now */
904     if (!fb->have_console) {
905         fb->c.ds = graphic_console_init(xenfb_update,
906                                         xenfb_invalidate,
907                                         NULL,
908                                         NULL,
909                                         fb);
910         fb->have_console = 1;
911     }
912 #endif
913
914     if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
915         fb->feature_update = 0;
916     if (fb->feature_update)
917         xenstore_write_be_int(xendev, "request-update", 1);
918
919     xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
920                   fb->feature_update, videoram);
921     return 0;
922 }
923
924 static void fb_disconnect(struct XenDevice *xendev)
925 {
926     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
927
928     /*
929      * FIXME: qemu can't un-init gfx display (yet?).
930      *   Replacing the framebuffer with anonymous shared memory
931      *   instead.  This releases the guest pages and keeps qemu happy.
932      */
933     fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
934                       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
935                       -1, 0);
936     common_unbind(&fb->c);
937     fb->feature_update = 0;
938     fb->bug_trigger    = 0;
939 }
940
941 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
942 {
943     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
944
945     /*
946      * Set state to Connected *again* once the frontend switched
947      * to connected.  We must trigger the watch a second time to
948      * workaround a frontend bug.
949      */
950     if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
951         xendev->fe_state == XenbusStateConnected &&
952         xendev->be_state == XenbusStateConnected) {
953         xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
954         xen_be_set_state(xendev, XenbusStateConnected);
955         fb->bug_trigger = 1; /* only once */
956     }
957 }
958
959 static void fb_event(struct XenDevice *xendev)
960 {
961     struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
962
963     xenfb_handle_events(xenfb);
964     xen_be_send_notify(&xenfb->c.xendev);
965 }
966
967 /* -------------------------------------------------------------------- */
968
969 struct XenDevOps xen_kbdmouse_ops = {
970     .size       = sizeof(struct XenInput),
971     .init       = input_init,
972     .initialise = input_initialise,
973     .connected  = input_connected,
974     .disconnect = input_disconnect,
975     .event      = input_event,
976 };
977
978 struct XenDevOps xen_framebuffer_ops = {
979     .size       = sizeof(struct XenFB),
980     .init       = fb_init,
981     .initialise = fb_initialise,
982     .disconnect = fb_disconnect,
983     .event      = fb_event,
984     .frontend_changed = fb_frontend_changed,
985 };
986
987 /*
988  * FIXME/TODO: Kill this.
989  * Temporary needed while DisplayState reorganization is in flight.
990  */
991 void xen_init_display(int domid)
992 {
993     struct XenDevice *xfb, *xin;
994     struct XenFB *fb;
995     struct XenInput *in;
996     int i = 0;
997
998 wait_more:
999     i++;
1000     main_loop_wait(true);
1001     xfb = xen_be_find_xendev("vfb", domid, 0);
1002     xin = xen_be_find_xendev("vkbd", domid, 0);
1003     if (!xfb || !xin) {
1004         if (i < 256) {
1005             usleep(10000);
1006             goto wait_more;
1007         }
1008         xen_be_printf(NULL, 1, "displaystate setup failed\n");
1009         return;
1010     }
1011
1012     /* vfb */
1013     fb = container_of(xfb, struct XenFB, c.xendev);
1014     fb->c.ds = graphic_console_init(xenfb_update,
1015                                     xenfb_invalidate,
1016                                     NULL,
1017                                     NULL,
1018                                     fb);
1019     fb->have_console = 1;
1020
1021     /* vkbd */
1022     in = container_of(xin, struct XenInput, c.xendev);
1023     in->c.ds = fb->c.ds;
1024
1025     /* retry ->init() */
1026     xen_be_check_state(xin);
1027     xen_be_check_state(xfb);
1028 }
This page took 0.082526 seconds and 4 git commands to generate.