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