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