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