Statistics
| Branch: | Revision:

root / hw / display / xenfb.c @ 49ab747f

History | View | Annotate | Download (30.3 kB)

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 "hw/hw.h"
39
#include "ui/console.h"
40
#include "char/char.h"
41
#include "hw/xen/xen_backend.h"
42

    
43
#include <xen/event_channel.h>
44
#include <xen/io/fbif.h>
45
#include <xen/io/kbdif.h>
46
#include <xen/io/protocols.h>
47

    
48
#ifndef BTN_LEFT
49
#define BTN_LEFT 0x110 /* from <linux/input.h> */
50
#endif
51

    
52
/* -------------------------------------------------------------------- */
53

    
54
struct common {
55
    struct XenDevice  xendev;  /* must be first */
56
    void              *page;
57
    QemuConsole       *con;
58
};
59

    
60
struct XenInput {
61
    struct common c;
62
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
63
    int button_state;       /* Last seen pointer button state */
64
    int extended;
65
    QEMUPutMouseEntry *qmouse;
66
};
67

    
68
#define UP_QUEUE 8
69

    
70
struct XenFB {
71
    struct common     c;
72
    size_t            fb_len;
73
    int               row_stride;
74
    int               depth;
75
    int               width;
76
    int               height;
77
    int               offset;
78
    void              *pixels;
79
    int               fbpages;
80
    int               feature_update;
81
    int               refresh_period;
82
    int               bug_trigger;
83
    int               have_console;
84
    int               do_resize;
85

    
86
    struct {
87
        int x,y,w,h;
88
    } up_rects[UP_QUEUE];
89
    int               up_count;
90
    int               up_fullscreen;
91
};
92

    
93
/* -------------------------------------------------------------------- */
94

    
95
static int common_bind(struct common *c)
96
{
97
    int mfn;
98

    
99
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
100
        return -1;
101
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
102
        return -1;
103

    
104
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
105
                                   XC_PAGE_SIZE,
106
                                   PROT_READ | PROT_WRITE, mfn);
107
    if (c->page == NULL)
108
        return -1;
109

    
110
    xen_be_bind_evtchn(&c->xendev);
111
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
112
                  mfn, c->xendev.remote_port, c->xendev.local_port);
113

    
114
    return 0;
115
}
116

    
117
static void common_unbind(struct common *c)
118
{
119
    xen_be_unbind_evtchn(&c->xendev);
120
    if (c->page) {
121
        munmap(c->page, XC_PAGE_SIZE);
122
        c->page = NULL;
123
    }
124
}
125

    
126
/* -------------------------------------------------------------------- */
127

    
128
#if 0
129
/*
130
 * These two tables are not needed any more, but left in here
131
 * intentionally as documentation, to show how scancode2linux[]
132
 * was generated.
133
 *
134
 * Tables to map from scancode to Linux input layer keycode.
135
 * Scancodes are hardware-specific.  These maps assumes a
136
 * standard AT or PS/2 keyboard which is what QEMU feeds us.
137
 */
138
const unsigned char atkbd_set2_keycode[512] = {
139

140
     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
141
     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
142
     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
143
     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
144
     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
145
     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
146
     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
147
    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
148

149
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
150
    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
151
    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
152
    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
153
    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
154
    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
155
      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
156
    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
157

158
};
159

160
const unsigned char atkbd_unxlate_table[128] = {
161

162
      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
163
     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
164
     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
165
     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
166
     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
167
    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
168
     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
169
     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
170

171
};
172
#endif
173

    
174
/*
175
 * for (i = 0; i < 128; i++) {
176
 *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
177
 *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
178
 * }
179
 */
180
static const unsigned char scancode2linux[512] = {
181
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
182
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
183
     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
184
     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
185
     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
186
     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
187
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
188
     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
189

    
190
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
191
    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
192
    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
193
    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
194
      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
195
    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
196
      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
197
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
198
};
199

    
200
/* Send an event to the keyboard frontend driver */
201
static int xenfb_kbd_event(struct XenInput *xenfb,
202
                           union xenkbd_in_event *event)
203
{
204
    struct xenkbd_page *page = xenfb->c.page;
205
    uint32_t prod;
206

    
207
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
208
        return 0;
209
    if (!page)
210
        return 0;
211

    
212
    prod = page->in_prod;
213
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
214
        errno = EAGAIN;
215
        return -1;
216
    }
217

    
218
    xen_mb();                /* ensure ring space available */
219
    XENKBD_IN_RING_REF(page, prod) = *event;
220
    xen_wmb();                /* ensure ring contents visible */
221
    page->in_prod = prod + 1;
222
    return xen_be_send_notify(&xenfb->c.xendev);
223
}
224

    
225
/* Send a keyboard (or mouse button) event */
226
static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
227
{
228
    union xenkbd_in_event event;
229

    
230
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
231
    event.type = XENKBD_TYPE_KEY;
232
    event.key.pressed = down ? 1 : 0;
233
    event.key.keycode = keycode;
234

    
235
    return xenfb_kbd_event(xenfb, &event);
236
}
237

    
238
/* Send a relative mouse movement event */
239
static int xenfb_send_motion(struct XenInput *xenfb,
240
                             int rel_x, int rel_y, int rel_z)
241
{
242
    union xenkbd_in_event event;
243

    
244
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
245
    event.type = XENKBD_TYPE_MOTION;
246
    event.motion.rel_x = rel_x;
247
    event.motion.rel_y = rel_y;
248
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
249
    event.motion.rel_z = rel_z;
250
#endif
251

    
252
    return xenfb_kbd_event(xenfb, &event);
253
}
254

    
255
/* Send an absolute mouse movement event */
256
static int xenfb_send_position(struct XenInput *xenfb,
257
                               int abs_x, int abs_y, int z)
258
{
259
    union xenkbd_in_event event;
260

    
261
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
262
    event.type = XENKBD_TYPE_POS;
263
    event.pos.abs_x = abs_x;
264
    event.pos.abs_y = abs_y;
265
#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
266
    event.pos.abs_z = z;
267
#endif
268
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
269
    event.pos.rel_z = z;
270
#endif
271

    
272
    return xenfb_kbd_event(xenfb, &event);
273
}
274

    
275
/*
276
 * Send a key event from the client to the guest OS
277
 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
278
 * We have to turn this into a Linux Input layer keycode.
279
 *
280
 * Extra complexity from the fact that with extended scancodes
281
 * (like those produced by arrow keys) this method gets called
282
 * twice, but we only want to send a single event. So we have to
283
 * track the '0xe0' scancode state & collapse the extended keys
284
 * as needed.
285
 *
286
 * Wish we could just send scancodes straight to the guest which
287
 * already has code for dealing with this...
288
 */
289
static void xenfb_key_event(void *opaque, int scancode)
290
{
291
    struct XenInput *xenfb = opaque;
292
    int down = 1;
293

    
294
    if (scancode == 0xe0) {
295
        xenfb->extended = 1;
296
        return;
297
    } else if (scancode & 0x80) {
298
        scancode &= 0x7f;
299
        down = 0;
300
    }
301
    if (xenfb->extended) {
302
        scancode |= 0x80;
303
        xenfb->extended = 0;
304
    }
305
    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
306
}
307

    
308
/*
309
 * Send a mouse event from the client to the guest OS
310
 *
311
 * The QEMU mouse can be in either relative, or absolute mode.
312
 * Movement is sent separately from button state, which has to
313
 * be encoded as virtual key events. We also don't actually get
314
 * given any button up/down events, so have to track changes in
315
 * the button state.
316
 */
317
static void xenfb_mouse_event(void *opaque,
318
                              int dx, int dy, int dz, int button_state)
319
{
320
    struct XenInput *xenfb = opaque;
321
    DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
322
    int dw = surface_width(surface);
323
    int dh = surface_height(surface);
324
    int i;
325

    
326
    if (xenfb->abs_pointer_wanted)
327
        xenfb_send_position(xenfb,
328
                            dx * (dw - 1) / 0x7fff,
329
                            dy * (dh - 1) / 0x7fff,
330
                            dz);
331
    else
332
        xenfb_send_motion(xenfb, dx, dy, dz);
333

    
334
    for (i = 0 ; i < 8 ; i++) {
335
        int lastDown = xenfb->button_state & (1 << i);
336
        int down = button_state & (1 << i);
337
        if (down == lastDown)
338
            continue;
339

    
340
        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
341
            return;
342
    }
343
    xenfb->button_state = button_state;
344
}
345

    
346
static int input_init(struct XenDevice *xendev)
347
{
348
    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
349
    return 0;
350
}
351

    
352
static int input_initialise(struct XenDevice *xendev)
353
{
354
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
355
    int rc;
356

    
357
    if (!in->c.con) {
358
        xen_be_printf(xendev, 1, "ds not set (yet)\n");
359
        return -1;
360
    }
361

    
362
    rc = common_bind(&in->c);
363
    if (rc != 0)
364
        return rc;
365

    
366
    qemu_add_kbd_event_handler(xenfb_key_event, in);
367
    return 0;
368
}
369

    
370
static void input_connected(struct XenDevice *xendev)
371
{
372
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
373

    
374
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
375
                             &in->abs_pointer_wanted) == -1) {
376
        in->abs_pointer_wanted = 0;
377
    }
378

    
379
    if (in->qmouse) {
380
        qemu_remove_mouse_event_handler(in->qmouse);
381
    }
382
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
383
                                              in->abs_pointer_wanted,
384
                                              "Xen PVFB Mouse");
385
}
386

    
387
static void input_disconnect(struct XenDevice *xendev)
388
{
389
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
390

    
391
    if (in->qmouse) {
392
        qemu_remove_mouse_event_handler(in->qmouse);
393
        in->qmouse = NULL;
394
    }
395
    qemu_add_kbd_event_handler(NULL, NULL);
396
    common_unbind(&in->c);
397
}
398

    
399
static void input_event(struct XenDevice *xendev)
400
{
401
    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
402
    struct xenkbd_page *page = xenfb->c.page;
403

    
404
    /* We don't understand any keyboard events, so just ignore them. */
405
    if (page->out_prod == page->out_cons)
406
        return;
407
    page->out_cons = page->out_prod;
408
    xen_be_send_notify(&xenfb->c.xendev);
409
}
410

    
411
/* -------------------------------------------------------------------- */
412

    
413
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
414
{
415
    uint32_t *src32 = src;
416
    uint64_t *src64 = src;
417
    int i;
418

    
419
    for (i = 0; i < count; i++)
420
        dst[i] = (mode == 32) ? src32[i] : src64[i];
421
}
422

    
423
static int xenfb_map_fb(struct XenFB *xenfb)
424
{
425
    struct xenfb_page *page = xenfb->c.page;
426
    char *protocol = xenfb->c.xendev.protocol;
427
    int n_fbdirs;
428
    unsigned long *pgmfns = NULL;
429
    unsigned long *fbmfns = NULL;
430
    void *map, *pd;
431
    int mode, ret = -1;
432

    
433
    /* default to native */
434
    pd = page->pd;
435
    mode = sizeof(unsigned long) * 8;
436

    
437
    if (!protocol) {
438
        /*
439
         * Undefined protocol, some guesswork needed.
440
         *
441
         * Old frontends which don't set the protocol use
442
         * one page directory only, thus pd[1] must be zero.
443
         * pd[1] of the 32bit struct layout and the lower
444
         * 32 bits of pd[0] of the 64bit struct layout have
445
         * the same location, so we can check that ...
446
         */
447
        uint32_t *ptr32 = NULL;
448
        uint32_t *ptr64 = NULL;
449
#if defined(__i386__)
450
        ptr32 = (void*)page->pd;
451
        ptr64 = ((void*)page->pd) + 4;
452
#elif defined(__x86_64__)
453
        ptr32 = ((void*)page->pd) - 4;
454
        ptr64 = (void*)page->pd;
455
#endif
456
        if (ptr32) {
457
            if (ptr32[1] == 0) {
458
                mode = 32;
459
                pd   = ptr32;
460
            } else {
461
                mode = 64;
462
                pd   = ptr64;
463
            }
464
        }
465
#if defined(__x86_64__)
466
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
467
        /* 64bit dom0, 32bit domU */
468
        mode = 32;
469
        pd   = ((void*)page->pd) - 4;
470
#elif defined(__i386__)
471
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
472
        /* 32bit dom0, 64bit domU */
473
        mode = 64;
474
        pd   = ((void*)page->pd) + 4;
475
#endif
476
    }
477

    
478
    if (xenfb->pixels) {
479
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
480
        xenfb->pixels = NULL;
481
    }
482

    
483
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
484
    n_fbdirs = xenfb->fbpages * mode / 8;
485
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
486

    
487
    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
488
    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
489

    
490
    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
491
    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
492
                               PROT_READ, pgmfns, n_fbdirs);
493
    if (map == NULL)
494
        goto out;
495
    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
496
    munmap(map, n_fbdirs * XC_PAGE_SIZE);
497

    
498
    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
499
                                         PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
500
    if (xenfb->pixels == NULL)
501
        goto out;
502

    
503
    ret = 0; /* all is fine */
504

    
505
out:
506
    g_free(pgmfns);
507
    g_free(fbmfns);
508
    return ret;
509
}
510

    
511
static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
512
                              int width, int height, int depth,
513
                              size_t fb_len, int offset, int row_stride)
514
{
515
    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
516
    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
517
    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
518
    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
519
    int max_width, max_height;
520

    
521
    if (fb_len_lim > fb_len_max) {
522
        xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
523
                      fb_len_lim, fb_len_max);
524
        fb_len_lim = fb_len_max;
525
    }
526
    if (fb_len_lim && fb_len > fb_len_lim) {
527
        xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
528
                      fb_len, fb_len_lim);
529
        fb_len = fb_len_lim;
530
    }
531
    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
532
        xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
533
                      depth);
534
        return -1;
535
    }
536
    if (row_stride <= 0 || row_stride > fb_len) {
537
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
538
        return -1;
539
    }
540
    max_width = row_stride / (depth / 8);
541
    if (width < 0 || width > max_width) {
542
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
543
                      width, max_width);
544
        width = max_width;
545
    }
546
    if (offset < 0 || offset >= fb_len) {
547
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
548
                      offset, fb_len - 1);
549
        return -1;
550
    }
551
    max_height = (fb_len - offset) / row_stride;
552
    if (height < 0 || height > max_height) {
553
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
554
                      height, max_height);
555
        height = max_height;
556
    }
557
    xenfb->fb_len = fb_len;
558
    xenfb->row_stride = row_stride;
559
    xenfb->depth = depth;
560
    xenfb->width = width;
561
    xenfb->height = height;
562
    xenfb->offset = offset;
563
    xenfb->up_fullscreen = 1;
564
    xenfb->do_resize = 1;
565
    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
566
                  width, height, depth, offset, row_stride);
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
 */
610
static 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) /* should not happen */
643
        xen_be_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
#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */
650
static 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

663
static 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

678
static 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
 */
698
static 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
#if 0 /* XENFB_TYPE_REFRESH_PERIOD */
709
        struct DisplayChangeListener *l;
710
        int period = 99999999;
711
        int idle = 1;
712

713
        if (xenfb_queue_full(xenfb))
714
            return;
715

716
        QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) {
717
            if (l->idle)
718
                continue;
719
            idle = 0;
720
            if (!l->gui_timer_interval) {
721
                if (period > GUI_REFRESH_INTERVAL)
722
                    period = GUI_REFRESH_INTERVAL;
723
            } else {
724
                if (period > l->gui_timer_interval)
725
                    period = l->gui_timer_interval;
726
            }
727
        }
728
        if (idle)
729
            period = XENFB_NO_REFRESH;
730

731
        if (xenfb->refresh_period != period) {
732
            xenfb_send_refresh_period(xenfb, period);
733
            xenfb->refresh_period = period;
734
            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
735
        }
736
#else
737
        ; /* nothing */
738
#endif
739
    } else {
740
        /* we don't get update notifications, thus use the
741
         * sledge hammer approach ... */
742
        xenfb->up_fullscreen = 1;
743
    }
744

    
745
    /* resize if needed */
746
    if (xenfb->do_resize) {
747
        xenfb->do_resize = 0;
748
        switch (xenfb->depth) {
749
        case 16:
750
        case 32:
751
            /* console.c supported depth -> buffer can be used directly */
752
            surface = qemu_create_displaysurface_from
753
                (xenfb->width, xenfb->height, xenfb->depth,
754
                 xenfb->row_stride, xenfb->pixels + xenfb->offset,
755
                 false);
756
            break;
757
        default:
758
            /* we must convert stuff */
759
            surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
760
            break;
761
        }
762
        dpy_gfx_replace_surface(xenfb->c.con, surface);
763
        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
764
                      xenfb->width, xenfb->height, xenfb->depth,
765
                      is_buffer_shared(surface) ? " (shared)" : "");
766
        xenfb->up_fullscreen = 1;
767
    }
768

    
769
    /* run queued updates */
770
    if (xenfb->up_fullscreen) {
771
        xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
772
        xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
773
    } else if (xenfb->up_count) {
774
        xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
775
        for (i = 0; i < xenfb->up_count; i++)
776
            xenfb_guest_copy(xenfb,
777
                             xenfb->up_rects[i].x,
778
                             xenfb->up_rects[i].y,
779
                             xenfb->up_rects[i].w,
780
                             xenfb->up_rects[i].h);
781
    } else {
782
        xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
783
    }
784
    xenfb->up_count = 0;
785
    xenfb->up_fullscreen = 0;
786
}
787

    
788
/* QEMU display state changed, so refresh the framebuffer copy */
789
static void xenfb_invalidate(void *opaque)
790
{
791
    struct XenFB *xenfb = opaque;
792
    xenfb->up_fullscreen = 1;
793
}
794

    
795
static void xenfb_handle_events(struct XenFB *xenfb)
796
{
797
    uint32_t prod, cons;
798
    struct xenfb_page *page = xenfb->c.page;
799

    
800
    prod = page->out_prod;
801
    if (prod == page->out_cons)
802
        return;
803
    xen_rmb();                /* ensure we see ring contents up to prod */
804
    for (cons = page->out_cons; cons != prod; cons++) {
805
        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
806
        int x, y, w, h;
807

    
808
        switch (event->type) {
809
        case XENFB_TYPE_UPDATE:
810
            if (xenfb->up_count == UP_QUEUE)
811
                xenfb->up_fullscreen = 1;
812
            if (xenfb->up_fullscreen)
813
                break;
814
            x = MAX(event->update.x, 0);
815
            y = MAX(event->update.y, 0);
816
            w = MIN(event->update.width, xenfb->width - x);
817
            h = MIN(event->update.height, xenfb->height - y);
818
            if (w < 0 || h < 0) {
819
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
820
                break;
821
            }
822
            if (x != event->update.x ||
823
                y != event->update.y ||
824
                w != event->update.width ||
825
                h != event->update.height) {
826
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
827
            }
828
            if (w == xenfb->width && h > xenfb->height / 2) {
829
                /* scroll detector: updated more than 50% of the lines,
830
                 * don't bother keeping track of the rectangles then */
831
                xenfb->up_fullscreen = 1;
832
            } else {
833
                xenfb->up_rects[xenfb->up_count].x = x;
834
                xenfb->up_rects[xenfb->up_count].y = y;
835
                xenfb->up_rects[xenfb->up_count].w = w;
836
                xenfb->up_rects[xenfb->up_count].h = h;
837
                xenfb->up_count++;
838
            }
839
            break;
840
#ifdef XENFB_TYPE_RESIZE
841
        case XENFB_TYPE_RESIZE:
842
            if (xenfb_configure_fb(xenfb, xenfb->fb_len,
843
                                   event->resize.width,
844
                                   event->resize.height,
845
                                   event->resize.depth,
846
                                   xenfb->fb_len,
847
                                   event->resize.offset,
848
                                   event->resize.stride) < 0)
849
                break;
850
            xenfb_invalidate(xenfb);
851
            break;
852
#endif
853
        }
854
    }
855
    xen_mb();                /* ensure we're done with ring contents */
856
    page->out_cons = cons;
857
}
858

    
859
static int fb_init(struct XenDevice *xendev)
860
{
861
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
862

    
863
    fb->refresh_period = -1;
864

    
865
#ifdef XENFB_TYPE_RESIZE
866
    xenstore_write_be_int(xendev, "feature-resize", 1);
867
#endif
868
    return 0;
869
}
870

    
871
static int fb_initialise(struct XenDevice *xendev)
872
{
873
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
874
    struct xenfb_page *fb_page;
875
    int videoram;
876
    int rc;
877

    
878
    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
879
        videoram = 0;
880

    
881
    rc = common_bind(&fb->c);
882
    if (rc != 0)
883
        return rc;
884

    
885
    fb_page = fb->c.page;
886
    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
887
                            fb_page->width, fb_page->height, fb_page->depth,
888
                            fb_page->mem_length, 0, fb_page->line_length);
889
    if (rc != 0)
890
        return rc;
891

    
892
    rc = xenfb_map_fb(fb);
893
    if (rc != 0)
894
        return rc;
895

    
896
#if 0  /* handled in xen_init_display() for now */
897
    if (!fb->have_console) {
898
        fb->c.ds = graphic_console_init(xenfb_update,
899
                                        xenfb_invalidate,
900
                                        NULL,
901
                                        NULL,
902
                                        fb);
903
        fb->have_console = 1;
904
    }
905
#endif
906

    
907
    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
908
        fb->feature_update = 0;
909
    if (fb->feature_update)
910
        xenstore_write_be_int(xendev, "request-update", 1);
911

    
912
    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
913
                  fb->feature_update, videoram);
914
    return 0;
915
}
916

    
917
static void fb_disconnect(struct XenDevice *xendev)
918
{
919
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
920

    
921
    /*
922
     * FIXME: qemu can't un-init gfx display (yet?).
923
     *   Replacing the framebuffer with anonymous shared memory
924
     *   instead.  This releases the guest pages and keeps qemu happy.
925
     */
926
    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
927
                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
928
                      -1, 0);
929
    common_unbind(&fb->c);
930
    fb->feature_update = 0;
931
    fb->bug_trigger    = 0;
932
}
933

    
934
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
935
{
936
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
937

    
938
    /*
939
     * Set state to Connected *again* once the frontend switched
940
     * to connected.  We must trigger the watch a second time to
941
     * workaround a frontend bug.
942
     */
943
    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
944
        xendev->fe_state == XenbusStateConnected &&
945
        xendev->be_state == XenbusStateConnected) {
946
        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
947
        xen_be_set_state(xendev, XenbusStateConnected);
948
        fb->bug_trigger = 1; /* only once */
949
    }
950
}
951

    
952
static void fb_event(struct XenDevice *xendev)
953
{
954
    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
955

    
956
    xenfb_handle_events(xenfb);
957
    xen_be_send_notify(&xenfb->c.xendev);
958
}
959

    
960
/* -------------------------------------------------------------------- */
961

    
962
struct XenDevOps xen_kbdmouse_ops = {
963
    .size       = sizeof(struct XenInput),
964
    .init       = input_init,
965
    .initialise = input_initialise,
966
    .connected  = input_connected,
967
    .disconnect = input_disconnect,
968
    .event      = input_event,
969
};
970

    
971
struct XenDevOps xen_framebuffer_ops = {
972
    .size       = sizeof(struct XenFB),
973
    .init       = fb_init,
974
    .initialise = fb_initialise,
975
    .disconnect = fb_disconnect,
976
    .event      = fb_event,
977
    .frontend_changed = fb_frontend_changed,
978
};
979

    
980
/*
981
 * FIXME/TODO: Kill this.
982
 * Temporary needed while DisplayState reorganization is in flight.
983
 */
984
void xen_init_display(int domid)
985
{
986
    struct XenDevice *xfb, *xin;
987
    struct XenFB *fb;
988
    struct XenInput *in;
989
    int i = 0;
990

    
991
wait_more:
992
    i++;
993
    main_loop_wait(true);
994
    xfb = xen_be_find_xendev("vfb", domid, 0);
995
    xin = xen_be_find_xendev("vkbd", domid, 0);
996
    if (!xfb || !xin) {
997
        if (i < 256) {
998
            usleep(10000);
999
            goto wait_more;
1000
        }
1001
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
1002
        return;
1003
    }
1004

    
1005
    /* vfb */
1006
    fb = container_of(xfb, struct XenFB, c.xendev);
1007
    fb->c.con = graphic_console_init(xenfb_update,
1008
                                     xenfb_invalidate,
1009
                                     NULL,
1010
                                     NULL,
1011
                                     fb);
1012
    fb->have_console = 1;
1013

    
1014
    /* vkbd */
1015
    in = container_of(xin, struct XenInput, c.xendev);
1016
    in->c.con = fb->c.con;
1017

    
1018
    /* retry ->init() */
1019
    xen_be_check_state(xin);
1020
    xen_be_check_state(xfb);
1021
}