]> Git Repo - qemu.git/blame - hw/display/xenfb.c
xen: Rename xen_be_unbind_evtchn
[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
21cbfe5f 27#include "qemu/osdep.h"
e7151f83 28
83c9f4ca 29#include "hw/hw.h"
28ecbaee 30#include "ui/console.h"
dccfcd0e 31#include "sysemu/char.h"
0d09e41a 32#include "hw/xen/xen_backend.h"
e7151f83 33
b41f6719
AP
34#include <xen/event_channel.h>
35#include <xen/io/fbif.h>
36#include <xen/io/kbdif.h>
37#include <xen/io/protocols.h>
38
91043dad
DK
39#include "trace.h"
40
e7151f83
AL
41#ifndef BTN_LEFT
42#define BTN_LEFT 0x110 /* from <linux/input.h> */
43#endif
44
45/* -------------------------------------------------------------------- */
46
47struct common {
48 struct XenDevice xendev; /* must be first */
49 void *page;
c78f7137 50 QemuConsole *con;
e7151f83
AL
51};
52
53struct XenInput {
54 struct common c;
55 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
56 int button_state; /* Last seen pointer button state */
57 int extended;
58 QEMUPutMouseEntry *qmouse;
59};
60
61#define UP_QUEUE 8
62
63struct XenFB {
64 struct common c;
65 size_t fb_len;
66 int row_stride;
67 int depth;
68 int width;
69 int height;
70 int offset;
71 void *pixels;
72 int fbpages;
73 int feature_update;
e7151f83
AL
74 int bug_trigger;
75 int have_console;
76 int do_resize;
77
78 struct {
79 int x,y,w,h;
80 } up_rects[UP_QUEUE];
81 int up_count;
82 int up_fullscreen;
83};
84
85/* -------------------------------------------------------------------- */
86
87static int common_bind(struct common *c)
88{
9ed257d1
IC
89 uint64_t val;
90 xen_pfn_t mfn;
e7151f83 91
9ed257d1 92 if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
c22e91b1 93 return -1;
9ed257d1
IC
94 mfn = (xen_pfn_t)val;
95 assert(val == mfn);
643f5932 96
e7151f83 97 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
c22e91b1 98 return -1;
e7151f83 99
e0cb42ae
IC
100 c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
101 PROT_READ | PROT_WRITE, 1, &mfn, NULL);
e7151f83 102 if (c->page == NULL)
c22e91b1 103 return -1;
e7151f83
AL
104
105 xen_be_bind_evtchn(&c->xendev);
96c77dba 106 xen_pv_printf(&c->xendev, 1,
c22e91b1
EC
107 "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n",
108 mfn, c->xendev.remote_port, c->xendev.local_port);
e7151f83
AL
109
110 return 0;
111}
112
113static void common_unbind(struct common *c)
114{
65807f4b 115 xen_pv_unbind_evtchn(&c->xendev);
e7151f83 116 if (c->page) {
e0cb42ae 117 xenforeignmemory_unmap(xen_fmem, c->page, 1);
e7151f83
AL
118 c->page = NULL;
119 }
120}
121
122/* -------------------------------------------------------------------- */
123
124#if 0
125/*
126 * These two tables are not needed any more, but left in here
127 * intentionally as documentation, to show how scancode2linux[]
128 * was generated.
129 *
130 * Tables to map from scancode to Linux input layer keycode.
131 * Scancodes are hardware-specific. These maps assumes a
132 * standard AT or PS/2 keyboard which is what QEMU feeds us.
133 */
134const unsigned char atkbd_set2_keycode[512] = {
135
136 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
137 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
138 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
139 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
140 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
141 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
142 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
143 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
144
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
147 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
148 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
149 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
150 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
151 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
152 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
153
154};
155
156const unsigned char atkbd_unxlate_table[128] = {
157
158 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
159 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
160 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
161 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
162 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
163 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
164 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
165 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
166
167};
168#endif
169
170/*
171 * for (i = 0; i < 128; i++) {
172 * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
173 * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
174 * }
175 */
176static const unsigned char scancode2linux[512] = {
177 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
178 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
179 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
180 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
181 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
182 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
185
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
188 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
189 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
190 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
191 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
192 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194};
195
196/* Send an event to the keyboard frontend driver */
197static int xenfb_kbd_event(struct XenInput *xenfb,
198 union xenkbd_in_event *event)
199{
200 struct xenkbd_page *page = xenfb->c.page;
201 uint32_t prod;
202
203 if (xenfb->c.xendev.be_state != XenbusStateConnected)
204 return 0;
205 if (!page)
206 return 0;
207
208 prod = page->in_prod;
209 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
210 errno = EAGAIN;
211 return -1;
212 }
213
214 xen_mb(); /* ensure ring space available */
215 XENKBD_IN_RING_REF(page, prod) = *event;
216 xen_wmb(); /* ensure ring contents visible */
217 page->in_prod = prod + 1;
218 return xen_be_send_notify(&xenfb->c.xendev);
219}
220
221/* Send a keyboard (or mouse button) event */
222static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
223{
224 union xenkbd_in_event event;
225
226 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
227 event.type = XENKBD_TYPE_KEY;
228 event.key.pressed = down ? 1 : 0;
229 event.key.keycode = keycode;
230
231 return xenfb_kbd_event(xenfb, &event);
232}
233
234/* Send a relative mouse movement event */
235static int xenfb_send_motion(struct XenInput *xenfb,
236 int rel_x, int rel_y, int rel_z)
237{
238 union xenkbd_in_event event;
239
240 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
241 event.type = XENKBD_TYPE_MOTION;
242 event.motion.rel_x = rel_x;
243 event.motion.rel_y = rel_y;
e7151f83 244 event.motion.rel_z = rel_z;
e7151f83
AL
245
246 return xenfb_kbd_event(xenfb, &event);
247}
248
249/* Send an absolute mouse movement event */
250static int xenfb_send_position(struct XenInput *xenfb,
251 int abs_x, int abs_y, int z)
252{
253 union xenkbd_in_event event;
254
255 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
256 event.type = XENKBD_TYPE_POS;
257 event.pos.abs_x = abs_x;
258 event.pos.abs_y = abs_y;
e7151f83 259 event.pos.rel_z = z;
e7151f83
AL
260
261 return xenfb_kbd_event(xenfb, &event);
262}
263
264/*
265 * Send a key event from the client to the guest OS
266 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
267 * We have to turn this into a Linux Input layer keycode.
268 *
269 * Extra complexity from the fact that with extended scancodes
270 * (like those produced by arrow keys) this method gets called
271 * twice, but we only want to send a single event. So we have to
272 * track the '0xe0' scancode state & collapse the extended keys
273 * as needed.
274 *
275 * Wish we could just send scancodes straight to the guest which
276 * already has code for dealing with this...
277 */
278static void xenfb_key_event(void *opaque, int scancode)
279{
280 struct XenInput *xenfb = opaque;
281 int down = 1;
282
283 if (scancode == 0xe0) {
284 xenfb->extended = 1;
285 return;
286 } else if (scancode & 0x80) {
287 scancode &= 0x7f;
288 down = 0;
289 }
290 if (xenfb->extended) {
291 scancode |= 0x80;
292 xenfb->extended = 0;
293 }
294 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
295}
296
297/*
298 * Send a mouse event from the client to the guest OS
299 *
300 * The QEMU mouse can be in either relative, or absolute mode.
301 * Movement is sent separately from button state, which has to
302 * be encoded as virtual key events. We also don't actually get
303 * given any button up/down events, so have to track changes in
304 * the button state.
305 */
306static void xenfb_mouse_event(void *opaque,
307 int dx, int dy, int dz, int button_state)
308{
309 struct XenInput *xenfb = opaque;
c78f7137
GH
310 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
311 int dw = surface_width(surface);
312 int dh = surface_height(surface);
e7151f83
AL
313 int i;
314
91043dad
DK
315 trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
316 xenfb->abs_pointer_wanted);
e7151f83
AL
317 if (xenfb->abs_pointer_wanted)
318 xenfb_send_position(xenfb,
319 dx * (dw - 1) / 0x7fff,
320 dy * (dh - 1) / 0x7fff,
321 dz);
322 else
323 xenfb_send_motion(xenfb, dx, dy, dz);
324
325 for (i = 0 ; i < 8 ; i++) {
326 int lastDown = xenfb->button_state & (1 << i);
327 int down = button_state & (1 << i);
328 if (down == lastDown)
329 continue;
330
331 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
332 return;
333 }
334 xenfb->button_state = button_state;
335}
336
337static int input_init(struct XenDevice *xendev)
338{
e7151f83
AL
339 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
340 return 0;
341}
342
384087b2 343static int input_initialise(struct XenDevice *xendev)
e7151f83
AL
344{
345 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
346 int rc;
347
c78f7137 348 if (!in->c.con) {
96c77dba 349 xen_pv_printf(xendev, 1, "ds not set (yet)\n");
c78f7137 350 return -1;
37cdfcf1
SS
351 }
352
e7151f83
AL
353 rc = common_bind(&in->c);
354 if (rc != 0)
355 return rc;
356
357 qemu_add_kbd_event_handler(xenfb_key_event, in);
6d646730
JH
358 return 0;
359}
360
361static void input_connected(struct XenDevice *xendev)
362{
363 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
364
365 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
366 &in->abs_pointer_wanted) == -1) {
367 in->abs_pointer_wanted = 0;
368 }
369
370 if (in->qmouse) {
371 qemu_remove_mouse_event_handler(in->qmouse);
372 }
91043dad 373 trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
e7151f83
AL
374 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
375 in->abs_pointer_wanted,
376 "Xen PVFB Mouse");
e7151f83
AL
377}
378
379static void input_disconnect(struct XenDevice *xendev)
380{
381 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
382
383 if (in->qmouse) {
384 qemu_remove_mouse_event_handler(in->qmouse);
385 in->qmouse = NULL;
386 }
387 qemu_add_kbd_event_handler(NULL, NULL);
388 common_unbind(&in->c);
389}
390
391static void input_event(struct XenDevice *xendev)
392{
393 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
394 struct xenkbd_page *page = xenfb->c.page;
395
396 /* We don't understand any keyboard events, so just ignore them. */
397 if (page->out_prod == page->out_cons)
398 return;
399 page->out_cons = page->out_prod;
400 xen_be_send_notify(&xenfb->c.xendev);
401}
402
403/* -------------------------------------------------------------------- */
404
643f5932 405static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
e7151f83
AL
406{
407 uint32_t *src32 = src;
408 uint64_t *src64 = src;
409 int i;
410
411 for (i = 0; i < count; i++)
412 dst[i] = (mode == 32) ? src32[i] : src64[i];
413}
414
415static int xenfb_map_fb(struct XenFB *xenfb)
416{
417 struct xenfb_page *page = xenfb->c.page;
418 char *protocol = xenfb->c.xendev.protocol;
419 int n_fbdirs;
643f5932
SS
420 xen_pfn_t *pgmfns = NULL;
421 xen_pfn_t *fbmfns = NULL;
e7151f83
AL
422 void *map, *pd;
423 int mode, ret = -1;
424
425 /* default to native */
426 pd = page->pd;
427 mode = sizeof(unsigned long) * 8;
428
429 if (!protocol) {
430 /*
431 * Undefined protocol, some guesswork needed.
432 *
433 * Old frontends which don't set the protocol use
434 * one page directory only, thus pd[1] must be zero.
435 * pd[1] of the 32bit struct layout and the lower
436 * 32 bits of pd[0] of the 64bit struct layout have
437 * the same location, so we can check that ...
438 */
439 uint32_t *ptr32 = NULL;
440 uint32_t *ptr64 = NULL;
441#if defined(__i386__)
442 ptr32 = (void*)page->pd;
443 ptr64 = ((void*)page->pd) + 4;
444#elif defined(__x86_64__)
445 ptr32 = ((void*)page->pd) - 4;
446 ptr64 = (void*)page->pd;
447#endif
448 if (ptr32) {
449 if (ptr32[1] == 0) {
450 mode = 32;
451 pd = ptr32;
452 } else {
453 mode = 64;
454 pd = ptr64;
455 }
456 }
457#if defined(__x86_64__)
458 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
459 /* 64bit dom0, 32bit domU */
460 mode = 32;
461 pd = ((void*)page->pd) - 4;
462#elif defined(__i386__)
463 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
464 /* 32bit dom0, 64bit domU */
465 mode = 64;
466 pd = ((void*)page->pd) + 4;
467#endif
468 }
469
470 if (xenfb->pixels) {
471 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
472 xenfb->pixels = NULL;
473 }
474
d0448de7 475 xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
e7151f83 476 n_fbdirs = xenfb->fbpages * mode / 8;
d0448de7 477 n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
e7151f83 478
643f5932
SS
479 pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
480 fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
e7151f83
AL
481
482 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
e0cb42ae
IC
483 map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
484 PROT_READ, n_fbdirs, pgmfns, NULL);
e7151f83
AL
485 if (map == NULL)
486 goto out;
487 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
e0cb42ae 488 xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
e7151f83 489
e0cb42ae
IC
490 xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
491 PROT_READ, xenfb->fbpages, fbmfns, NULL);
e7151f83
AL
492 if (xenfb->pixels == NULL)
493 goto out;
494
495 ret = 0; /* all is fine */
496
497out:
7267c094
AL
498 g_free(pgmfns);
499 g_free(fbmfns);
e7151f83
AL
500 return ret;
501}
502
503static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
c22e91b1
EC
504 int width, int height, int depth,
505 size_t fb_len, int offset, int row_stride)
e7151f83
AL
506{
507 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
508 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
509 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
510 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
511 int max_width, max_height;
512
513 if (fb_len_lim > fb_len_max) {
96c77dba 514 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
515 "fb size limit %zu exceeds %zu, corrected\n",
516 fb_len_lim, fb_len_max);
517 fb_len_lim = fb_len_max;
e7151f83
AL
518 }
519 if (fb_len_lim && fb_len > fb_len_lim) {
96c77dba 520 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
521 "frontend fb size %zu limited to %zu\n",
522 fb_len, fb_len_lim);
523 fb_len = fb_len_lim;
e7151f83
AL
524 }
525 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
96c77dba 526 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
527 "can't handle frontend fb depth %d\n",
528 depth);
529 return -1;
e7151f83
AL
530 }
531 if (row_stride <= 0 || row_stride > fb_len) {
96c77dba 532 xen_pv_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n",
c22e91b1
EC
533 row_stride);
534 return -1;
e7151f83
AL
535 }
536 max_width = row_stride / (depth / 8);
537 if (width < 0 || width > max_width) {
96c77dba 538 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
539 "invalid frontend width %d limited to %d\n",
540 width, max_width);
541 width = max_width;
e7151f83
AL
542 }
543 if (offset < 0 || offset >= fb_len) {
96c77dba 544 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
545 "invalid frontend offset %d (max %zu)\n",
546 offset, fb_len - 1);
547 return -1;
e7151f83
AL
548 }
549 max_height = (fb_len - offset) / row_stride;
550 if (height < 0 || height > max_height) {
96c77dba 551 xen_pv_printf(&xenfb->c.xendev, 0,
c22e91b1
EC
552 "invalid frontend height %d limited to %d\n",
553 height, max_height);
554 height = max_height;
e7151f83
AL
555 }
556 xenfb->fb_len = fb_len;
557 xenfb->row_stride = row_stride;
558 xenfb->depth = depth;
559 xenfb->width = width;
560 xenfb->height = height;
561 xenfb->offset = offset;
562 xenfb->up_fullscreen = 1;
563 xenfb->do_resize = 1;
96c77dba 564 xen_pv_printf(&xenfb->c.xendev, 1,
b9730c5b 565 "framebuffer %dx%dx%d offset %d stride %d\n",
c22e91b1 566 width, height, depth, offset, row_stride);
e7151f83
AL
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 */
96c77dba 643 xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
e7151f83
AL
644 __FUNCTION__, xenfb->depth, bpp);
645
c78f7137 646 dpy_gfx_update(xenfb->c.con, x, y, w, h);
e7151f83
AL
647}
648
dea1b0bd 649#ifdef 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
dea1b0bd 707 if (!xenfb->feature_update) {
c22e91b1
EC
708 /* we don't get update notifications, thus use the
709 * sledge hammer approach ... */
710 xenfb->up_fullscreen = 1;
e7151f83
AL
711 }
712
713 /* resize if needed */
714 if (xenfb->do_resize) {
30f1e661
GH
715 pixman_format_code_t format;
716
e7151f83
AL
717 xenfb->do_resize = 0;
718 switch (xenfb->depth) {
719 case 16:
720 case 32:
721 /* console.c supported depth -> buffer can be used directly */
30f1e661 722 format = qemu_default_pixman_format(xenfb->depth, true);
da229ef3 723 surface = qemu_create_displaysurface_from
30f1e661
GH
724 (xenfb->width, xenfb->height, format,
725 xenfb->row_stride, xenfb->pixels + xenfb->offset);
e7151f83
AL
726 break;
727 default:
728 /* we must convert stuff */
da229ef3 729 surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
e7151f83
AL
730 break;
731 }
c78f7137 732 dpy_gfx_replace_surface(xenfb->c.con, surface);
96c77dba 733 xen_pv_printf(&xenfb->c.xendev, 1,
b9730c5b 734 "update: resizing: %dx%d @ %d bpp%s\n",
e7151f83 735 xenfb->width, xenfb->height, xenfb->depth,
c78f7137 736 is_buffer_shared(surface) ? " (shared)" : "");
e7151f83
AL
737 xenfb->up_fullscreen = 1;
738 }
739
740 /* run queued updates */
741 if (xenfb->up_fullscreen) {
96c77dba 742 xen_pv_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
c22e91b1 743 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
e7151f83 744 } else if (xenfb->up_count) {
96c77dba 745 xen_pv_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
c22e91b1
EC
746 xenfb->up_count);
747 for (i = 0; i < xenfb->up_count; i++)
748 xenfb_guest_copy(xenfb,
749 xenfb->up_rects[i].x,
750 xenfb->up_rects[i].y,
751 xenfb->up_rects[i].w,
752 xenfb->up_rects[i].h);
e7151f83 753 } else {
96c77dba 754 xen_pv_printf(&xenfb->c.xendev, 3, "update: nothing\n");
e7151f83
AL
755 }
756 xenfb->up_count = 0;
757 xenfb->up_fullscreen = 0;
758}
759
dea1b0bd
GH
760static void xenfb_update_interval(void *opaque, uint64_t interval)
761{
762 struct XenFB *xenfb = opaque;
763
764 if (xenfb->feature_update) {
765#ifdef XENFB_TYPE_REFRESH_PERIOD
766 if (xenfb_queue_full(xenfb)) {
767 return;
768 }
769 xenfb_send_refresh_period(xenfb, interval);
770#endif
771 }
772}
773
e7151f83
AL
774/* QEMU display state changed, so refresh the framebuffer copy */
775static void xenfb_invalidate(void *opaque)
776{
777 struct XenFB *xenfb = opaque;
778 xenfb->up_fullscreen = 1;
779}
780
781static void xenfb_handle_events(struct XenFB *xenfb)
782{
7ea11bf3 783 uint32_t prod, cons, out_cons;
e7151f83
AL
784 struct xenfb_page *page = xenfb->c.page;
785
786 prod = page->out_prod;
7ea11bf3 787 out_cons = page->out_cons;
4df26e88 788 if (prod - out_cons > XENFB_OUT_RING_LEN) {
ac0487e1
SS
789 return;
790 }
e7151f83 791 xen_rmb(); /* ensure we see ring contents up to prod */
7ea11bf3 792 for (cons = out_cons; cons != prod; cons++) {
e7151f83 793 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
7ea11bf3 794 uint8_t type = event->type;
e7151f83
AL
795 int x, y, w, h;
796
7ea11bf3 797 switch (type) {
e7151f83
AL
798 case XENFB_TYPE_UPDATE:
799 if (xenfb->up_count == UP_QUEUE)
800 xenfb->up_fullscreen = 1;
801 if (xenfb->up_fullscreen)
802 break;
803 x = MAX(event->update.x, 0);
804 y = MAX(event->update.y, 0);
805 w = MIN(event->update.width, xenfb->width - x);
806 h = MIN(event->update.height, xenfb->height - y);
807 if (w < 0 || h < 0) {
96c77dba 808 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
e7151f83
AL
809 break;
810 }
811 if (x != event->update.x ||
812 y != event->update.y ||
813 w != event->update.width ||
814 h != event->update.height) {
96c77dba 815 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
e7151f83
AL
816 }
817 if (w == xenfb->width && h > xenfb->height / 2) {
818 /* scroll detector: updated more than 50% of the lines,
819 * don't bother keeping track of the rectangles then */
820 xenfb->up_fullscreen = 1;
821 } else {
822 xenfb->up_rects[xenfb->up_count].x = x;
823 xenfb->up_rects[xenfb->up_count].y = y;
824 xenfb->up_rects[xenfb->up_count].w = w;
825 xenfb->up_rects[xenfb->up_count].h = h;
826 xenfb->up_count++;
827 }
828 break;
829#ifdef XENFB_TYPE_RESIZE
830 case XENFB_TYPE_RESIZE:
831 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
832 event->resize.width,
833 event->resize.height,
834 event->resize.depth,
835 xenfb->fb_len,
836 event->resize.offset,
837 event->resize.stride) < 0)
838 break;
839 xenfb_invalidate(xenfb);
840 break;
841#endif
842 }
843 }
844 xen_mb(); /* ensure we're done with ring contents */
845 page->out_cons = cons;
846}
847
848static int fb_init(struct XenDevice *xendev)
849{
e7151f83
AL
850#ifdef XENFB_TYPE_RESIZE
851 xenstore_write_be_int(xendev, "feature-resize", 1);
852#endif
853 return 0;
854}
855
384087b2 856static int fb_initialise(struct XenDevice *xendev)
e7151f83
AL
857{
858 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
859 struct xenfb_page *fb_page;
860 int videoram;
861 int rc;
862
863 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
864 videoram = 0;
865
866 rc = common_bind(&fb->c);
867 if (rc != 0)
868 return rc;
869
870 fb_page = fb->c.page;
871 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
872 fb_page->width, fb_page->height, fb_page->depth,
873 fb_page->mem_length, 0, fb_page->line_length);
874 if (rc != 0)
875 return rc;
876
877 rc = xenfb_map_fb(fb);
878 if (rc != 0)
879 return rc;
880
881#if 0 /* handled in xen_init_display() for now */
882 if (!fb->have_console) {
883 fb->c.ds = graphic_console_init(xenfb_update,
884 xenfb_invalidate,
885 NULL,
886 NULL,
887 fb);
888 fb->have_console = 1;
889 }
890#endif
891
892 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
893 fb->feature_update = 0;
894 if (fb->feature_update)
895 xenstore_write_be_int(xendev, "request-update", 1);
896
96c77dba 897 xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
e7151f83
AL
898 fb->feature_update, videoram);
899 return 0;
900}
901
902static void fb_disconnect(struct XenDevice *xendev)
903{
904 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
905
906 /*
907 * FIXME: qemu can't un-init gfx display (yet?).
908 * Replacing the framebuffer with anonymous shared memory
909 * instead. This releases the guest pages and keeps qemu happy.
910 */
e0cb42ae 911 xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
e7151f83
AL
912 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
913 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
914 -1, 0);
0193c62c 915 if (fb->pixels == MAP_FAILED) {
96c77dba 916 xen_pv_printf(xendev, 0,
0193c62c
SS
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) {
96c77dba 937 xen_pv_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
e7151f83
AL
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 }
96c77dba 998 xen_pv_printf(NULL, 1, "displaystate setup failed\n");
e7151f83
AL
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.907202 seconds and 4 git commands to generate.