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