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