1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28
29#include "hw/hw.h"
30#include "ui/console.h"
31#include "sysemu/char.h"
32#include "hw/xen/xen_backend.h"
33
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
39#include "trace.h"
40
41#ifndef BTN_LEFT
42#define BTN_LEFT 0x110
43#endif
44
45
46
47struct common {
48 struct XenDevice xendev;
49 void *page;
50 QemuConsole *con;
51};
52
53struct XenInput {
54 struct common c;
55 int abs_pointer_wanted;
56 int 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;
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{
89 uint64_t val;
90 xen_pfn_t mfn;
91
92 if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
93 return -1;
94 mfn = (xen_pfn_t)val;
95 assert(val == mfn);
96
97 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
98 return -1;
99
100 c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
101 PROT_READ | PROT_WRITE, 1, &mfn, NULL);
102 if (c->page == NULL)
103 return -1;
104
105 xen_be_bind_evtchn(&c->xendev);
106 xen_pv_printf(&c->xendev, 1,
107 "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n",
108 mfn, c->xendev.remote_port, c->xendev.local_port);
109
110 return 0;
111}
112
113static void common_unbind(struct common *c)
114{
115 xen_pv_unbind_evtchn(&c->xendev);
116 if (c->page) {
117 xenforeignmemory_unmap(xen_fmem, c->page, 1);
118 c->page = NULL;
119 }
120}
121
122
123
124#if 0
125
126
127
128
129
130
131
132
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
172
173
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
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();
215 XENKBD_IN_RING_REF(page, prod) = *event;
216 xen_wmb();
217 page->in_prod = prod + 1;
218 return xen_pv_send_notify(&xenfb->c.xendev);
219}
220
221
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
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;
244 event.motion.rel_z = rel_z;
245
246 return xenfb_kbd_event(xenfb, &event);
247}
248
249
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;
259 event.pos.rel_z = z;
260
261 return xenfb_kbd_event(xenfb, &event);
262}
263
264
265
266
267
268
269
270
271
272
273
274
275
276
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
299
300
301
302
303
304
305
306static void xenfb_mouse_event(void *opaque,
307 int dx, int dy, int dz, int button_state)
308{
309 struct XenInput *xenfb = opaque;
310 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
311 int dw = surface_width(surface);
312 int dh = surface_height(surface);
313 int i;
314
315 trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
316 xenfb->abs_pointer_wanted);
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{
339 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
340 return 0;
341}
342
343static int input_initialise(struct XenDevice *xendev)
344{
345 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
346 int rc;
347
348 if (!in->c.con) {
349 xen_pv_printf(xendev, 1, "ds not set (yet)\n");
350 return -1;
351 }
352
353 rc = common_bind(&in->c);
354 if (rc != 0)
355 return rc;
356
357 qemu_add_kbd_event_handler(xenfb_key_event, in);
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 }
373 trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
374 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
375 in->abs_pointer_wanted,
376 "Xen PVFB Mouse");
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
397 if (page->out_prod == page->out_cons)
398 return;
399 page->out_cons = page->out_prod;
400 xen_pv_send_notify(&xenfb->c.xendev);
401}
402
403
404
405static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
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;
420 xen_pfn_t *pgmfns = NULL;
421 xen_pfn_t *fbmfns = NULL;
422 void *map, *pd;
423 int mode, ret = -1;
424
425
426 pd = page->pd;
427 mode = sizeof(unsigned long) * 8;
428
429 if (!protocol) {
430
431
432
433
434
435
436
437
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
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
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
475 xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
476 n_fbdirs = xenfb->fbpages * mode / 8;
477 n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
478
479 pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
480 fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
481
482 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
483 map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
484 PROT_READ, n_fbdirs, pgmfns, NULL);
485 if (map == NULL)
486 goto out;
487 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
488 xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
489
490 xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
491 PROT_READ, xenfb->fbpages, fbmfns, NULL);
492 if (xenfb->pixels == NULL)
493 goto out;
494
495 ret = 0;
496
497out:
498 g_free(pgmfns);
499 g_free(fbmfns);
500 return ret;
501}
502
503static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
504 int width, int height, int depth,
505 size_t fb_len, int offset, int row_stride)
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) {
514 xen_pv_printf(&xenfb->c.xendev, 0,
515 "fb size limit %zu exceeds %zu, corrected\n",
516 fb_len_lim, fb_len_max);
517 fb_len_lim = fb_len_max;
518 }
519 if (fb_len_lim && fb_len > fb_len_lim) {
520 xen_pv_printf(&xenfb->c.xendev, 0,
521 "frontend fb size %zu limited to %zu\n",
522 fb_len, fb_len_lim);
523 fb_len = fb_len_lim;
524 }
525 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
526 xen_pv_printf(&xenfb->c.xendev, 0,
527 "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_pv_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n",
533 row_stride);
534 return -1;
535 }
536 max_width = row_stride / (depth / 8);
537 if (width < 0 || width > max_width) {
538 xen_pv_printf(&xenfb->c.xendev, 0,
539 "invalid frontend width %d limited to %d\n",
540 width, max_width);
541 width = max_width;
542 }
543 if (offset < 0 || offset >= fb_len) {
544 xen_pv_printf(&xenfb->c.xendev, 0,
545 "invalid frontend offset %d (max %zu)\n",
546 offset, fb_len - 1);
547 return -1;
548 }
549 max_height = (fb_len - offset) / row_stride;
550 if (height < 0 || height > max_height) {
551 xen_pv_printf(&xenfb->c.xendev, 0,
552 "invalid frontend height %d limited to %d\n",
553 height, max_height);
554 height = max_height;
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;
564 xen_pv_printf(&xenfb->c.xendev, 1,
565 "framebuffer %dx%dx%d offset %d stride %d\n",
566 width, height, depth, offset, row_stride);
567 return 0;
568}
569
570
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
606
607
608
609
610static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
611{
612 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
613 int line, oops = 0;
614 int bpp = surface_bits_per_pixel(surface);
615 int linesize = surface_stride(surface);
616 uint8_t *data = surface_data(surface);
617
618 if (!is_buffer_shared(surface)) {
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)
643 xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
644 __FUNCTION__, xenfb->depth, bpp);
645
646 dpy_gfx_update(xenfb->c.con, x, y, w, h);
647}
648
649#ifdef XENFB_TYPE_REFRESH_PERIOD
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
670 xen_mb();
671 XENFB_IN_RING_REF(page, prod) = *event;
672 xen_wmb();
673 page->in_prod = prod + 1;
674
675 xen_pv_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
691
692
693
694
695
696
697
698static void xenfb_update(void *opaque)
699{
700 struct XenFB *xenfb = opaque;
701 DisplaySurface *surface;
702 int i;
703
704 if (xenfb->c.xendev.be_state != XenbusStateConnected)
705 return;
706
707 if (!xenfb->feature_update) {
708
709
710 xenfb->up_fullscreen = 1;
711 }
712
713
714 if (xenfb->do_resize) {
715 pixman_format_code_t format;
716
717 xenfb->do_resize = 0;
718 switch (xenfb->depth) {
719 case 16:
720 case 32:
721
722 format = qemu_default_pixman_format(xenfb->depth, true);
723 surface = qemu_create_displaysurface_from
724 (xenfb->width, xenfb->height, format,
725 xenfb->row_stride, xenfb->pixels + xenfb->offset);
726 break;
727 default:
728
729 surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
730 break;
731 }
732 dpy_gfx_replace_surface(xenfb->c.con, surface);
733 xen_pv_printf(&xenfb->c.xendev, 1,
734 "update: resizing: %dx%d @ %d bpp%s\n",
735 xenfb->width, xenfb->height, xenfb->depth,
736 is_buffer_shared(surface) ? " (shared)" : "");
737 xenfb->up_fullscreen = 1;
738 }
739
740
741 if (xenfb->up_fullscreen) {
742 xen_pv_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
743 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
744 } else if (xenfb->up_count) {
745 xen_pv_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
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);
753 } else {
754 xen_pv_printf(&xenfb->c.xendev, 3, "update: nothing\n");
755 }
756 xenfb->up_count = 0;
757 xenfb->up_fullscreen = 0;
758}
759
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
774
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{
783 uint32_t prod, cons, out_cons;
784 struct xenfb_page *page = xenfb->c.page;
785
786 prod = page->out_prod;
787 out_cons = page->out_cons;
788 if (prod - out_cons > XENFB_OUT_RING_LEN) {
789 return;
790 }
791 xen_rmb();
792 for (cons = out_cons; cons != prod; cons++) {
793 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
794 uint8_t type = event->type;
795 int x, y, w, h;
796
797 switch (type) {
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) {
808 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
809 break;
810 }
811 if (x != event->update.x ||
812 y != event->update.y ||
813 w != event->update.width ||
814 h != event->update.height) {
815 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
816 }
817 if (w == xenfb->width && h > xenfb->height / 2) {
818
819
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();
845 page->out_cons = cons;
846}
847
848static int fb_init(struct XenDevice *xendev)
849{
850#ifdef XENFB_TYPE_RESIZE
851 xenstore_write_be_int(xendev, "feature-resize", 1);
852#endif
853 return 0;
854}
855
856static int fb_initialise(struct XenDevice *xendev)
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
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
897 xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
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
908
909
910
911 xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
912 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
913 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
914 -1, 0);
915 if (fb->pixels == MAP_FAILED) {
916 xen_pv_printf(xendev, 0,
917 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
918 errno);
919 }
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
931
932
933
934 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
935 xendev->fe_state == XenbusStateConnected &&
936 xendev->be_state == XenbusStateConnected) {
937 xen_pv_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
938 xen_be_set_state(xendev, XenbusStateConnected);
939 fb->bug_trigger = 1;
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_pv_send_notify(&xenfb->c.xendev);
949}
950
951
952
953struct XenDevOps xen_kbdmouse_ops = {
954 .size = sizeof(struct XenInput),
955 .init = input_init,
956 .initialise = input_initialise,
957 .connected = input_connected,
958 .disconnect = input_disconnect,
959 .event = input_event,
960};
961
962struct XenDevOps xen_framebuffer_ops = {
963 .size = sizeof(struct XenFB),
964 .init = fb_init,
965 .initialise = fb_initialise,
966 .disconnect = fb_disconnect,
967 .event = fb_event,
968 .frontend_changed = fb_frontend_changed,
969};
970
971static const GraphicHwOps xenfb_ops = {
972 .invalidate = xenfb_invalidate,
973 .gfx_update = xenfb_update,
974 .update_interval = xenfb_update_interval,
975};
976
977
978
979
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++;
990 main_loop_wait(true);
991 xfb = xen_pv_find_xendev("vfb", domid, 0);
992 xin = xen_pv_find_xendev("vkbd", domid, 0);
993 if (!xfb || !xin) {
994 if (i < 256) {
995 usleep(10000);
996 goto wait_more;
997 }
998 xen_pv_printf(NULL, 1, "displaystate setup failed\n");
999 return;
1000 }
1001
1002
1003 fb = container_of(xfb, struct XenFB, c.xendev);
1004 fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
1005 fb->have_console = 1;
1006
1007
1008 in = container_of(xin, struct XenInput, c.xendev);
1009 in->c.con = fb->c.con;
1010
1011
1012 xen_be_check_state(xin);
1013 xen_be_check_state(xfb);
1014}
1015