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