Statistics
| Branch: | Revision:

root / hw / xenfb.c @ 6693665a

History | View | Annotate | Download (30.1 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, write to the Free Software Foundation, Inc.,
25
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26
 */
27

    
28
#include <stdarg.h>
29
#include <stdlib.h>
30
#include <sys/types.h>
31
#include <fcntl.h>
32
#include <unistd.h>
33
#include <stdbool.h>
34
#include <sys/mman.h>
35
#include <errno.h>
36
#include <stdio.h>
37
#include <string.h>
38
#include <time.h>
39

    
40
#include <xs.h>
41
#include <xenctrl.h>
42
#include <xen/event_channel.h>
43
#include <xen/io/xenbus.h>
44
#include <xen/io/fbif.h>
45
#include <xen/io/kbdif.h>
46
#include <xen/io/protocols.h>
47

    
48
#include "hw.h"
49
#include "sysemu.h"
50
#include "console.h"
51
#include "qemu-char.h"
52
#include "xen_backend.h"
53

    
54
#ifndef BTN_LEFT
55
#define BTN_LEFT 0x110 /* from <linux/input.h> */
56
#endif
57

    
58
/* -------------------------------------------------------------------- */
59

    
60
struct common {
61
    struct XenDevice  xendev;  /* must be first */
62
    void              *page;
63
    DisplayState      *ds;
64
};
65

    
66
struct XenInput {
67
    struct common c;
68
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
69
    int button_state;       /* Last seen pointer button state */
70
    int extended;
71
    QEMUPutMouseEntry *qmouse;
72
};
73

    
74
#define UP_QUEUE 8
75

    
76
struct XenFB {
77
    struct common     c;
78
    size_t            fb_len;
79
    int               row_stride;
80
    int               depth;
81
    int               width;
82
    int               height;
83
    int               offset;
84
    void              *pixels;
85
    int               fbpages;
86
    int               feature_update;
87
    int               refresh_period;
88
    int               bug_trigger;
89
    int               have_console;
90
    int               do_resize;
91

    
92
    struct {
93
        int x,y,w,h;
94
    } up_rects[UP_QUEUE];
95
    int               up_count;
96
    int               up_fullscreen;
97
};
98

    
99
/* -------------------------------------------------------------------- */
100

    
101
static int common_bind(struct common *c)
102
{
103
    int mfn;
104

    
105
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
106
        return -1;
107
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
108
        return -1;
109

    
110
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
111
                                   XC_PAGE_SIZE,
112
                                   PROT_READ | PROT_WRITE, mfn);
113
    if (c->page == NULL)
114
        return -1;
115

    
116
    xen_be_bind_evtchn(&c->xendev);
117
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
118
                  mfn, c->xendev.remote_port, c->xendev.local_port);
119

    
120
    return 0;
121
}
122

    
123
static void common_unbind(struct common *c)
124
{
125
    xen_be_unbind_evtchn(&c->xendev);
126
    if (c->page) {
127
        munmap(c->page, XC_PAGE_SIZE);
128
        c->page = NULL;
129
    }
130
}
131

    
132
/* -------------------------------------------------------------------- */
133

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

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

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

164
};
165

166
const unsigned char atkbd_unxlate_table[128] = {
167

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

177
};
178
#endif
179

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

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

    
206
/* Send an event to the keyboard frontend driver */
207
static int xenfb_kbd_event(struct XenInput *xenfb,
208
                           union xenkbd_in_event *event)
209
{
210
    struct xenkbd_page *page = xenfb->c.page;
211
    uint32_t prod;
212

    
213
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
214
        return 0;
215
    if (!page)
216
        return 0;
217

    
218
    prod = page->in_prod;
219
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
220
        errno = EAGAIN;
221
        return -1;
222
    }
223

    
224
    xen_mb();                /* ensure ring space available */
225
    XENKBD_IN_RING_REF(page, prod) = *event;
226
    xen_wmb();                /* ensure ring contents visible */
227
    page->in_prod = prod + 1;
228
    return xen_be_send_notify(&xenfb->c.xendev);
229
}
230

    
231
/* Send a keyboard (or mouse button) event */
232
static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
233
{
234
    union xenkbd_in_event event;
235

    
236
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
237
    event.type = XENKBD_TYPE_KEY;
238
    event.key.pressed = down ? 1 : 0;
239
    event.key.keycode = keycode;
240

    
241
    return xenfb_kbd_event(xenfb, &event);
242
}
243

    
244
/* Send a relative mouse movement event */
245
static int xenfb_send_motion(struct XenInput *xenfb,
246
                             int rel_x, int rel_y, int rel_z)
247
{
248
    union xenkbd_in_event event;
249

    
250
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
251
    event.type = XENKBD_TYPE_MOTION;
252
    event.motion.rel_x = rel_x;
253
    event.motion.rel_y = rel_y;
254
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
255
    event.motion.rel_z = rel_z;
256
#endif
257

    
258
    return xenfb_kbd_event(xenfb, &event);
259
}
260

    
261
/* Send an absolute mouse movement event */
262
static int xenfb_send_position(struct XenInput *xenfb,
263
                               int abs_x, int abs_y, int z)
264
{
265
    union xenkbd_in_event event;
266

    
267
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
268
    event.type = XENKBD_TYPE_POS;
269
    event.pos.abs_x = abs_x;
270
    event.pos.abs_y = abs_y;
271
#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
272
    event.pos.abs_z = z;
273
#endif
274
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
275
    event.pos.rel_z = z;
276
#endif
277

    
278
    return xenfb_kbd_event(xenfb, &event);
279
}
280

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

    
300
    if (scancode == 0xe0) {
301
        xenfb->extended = 1;
302
        return;
303
    } else if (scancode & 0x80) {
304
        scancode &= 0x7f;
305
        down = 0;
306
    }
307
    if (xenfb->extended) {
308
        scancode |= 0x80;
309
        xenfb->extended = 0;
310
    }
311
    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
312
}
313

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

    
331
    if (xenfb->abs_pointer_wanted)
332
        xenfb_send_position(xenfb,
333
                            dx * (dw - 1) / 0x7fff,
334
                            dy * (dh - 1) / 0x7fff,
335
                            dz);
336
    else
337
        xenfb_send_motion(xenfb, dx, dy, dz);
338

    
339
    for (i = 0 ; i < 8 ; i++) {
340
        int lastDown = xenfb->button_state & (1 << i);
341
        int down = button_state & (1 << i);
342
        if (down == lastDown)
343
            continue;
344

    
345
        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
346
            return;
347
    }
348
    xenfb->button_state = button_state;
349
}
350

    
351
static int input_init(struct XenDevice *xendev)
352
{
353
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354

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

    
360
    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
361
    return 0;
362
}
363

    
364
static int input_connect(struct XenDevice *xendev)
365
{
366
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
367
    int rc;
368

    
369
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
370
                             &in->abs_pointer_wanted) == -1)
371
        in->abs_pointer_wanted = 0;
372

    
373
    rc = common_bind(&in->c);
374
    if (rc != 0)
375
        return rc;
376

    
377
    qemu_add_kbd_event_handler(xenfb_key_event, in);
378
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
379
                                              in->abs_pointer_wanted,
380
                                              "Xen PVFB Mouse");
381
    return 0;
382
}
383

    
384
static void input_disconnect(struct XenDevice *xendev)
385
{
386
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
387

    
388
    if (in->qmouse) {
389
        qemu_remove_mouse_event_handler(in->qmouse);
390
        in->qmouse = NULL;
391
    }
392
    qemu_add_kbd_event_handler(NULL, NULL);
393
    common_unbind(&in->c);
394
}
395

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

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

    
408
/* -------------------------------------------------------------------- */
409

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

    
416
    for (i = 0; i < count; i++)
417
        dst[i] = (mode == 32) ? src32[i] : src64[i];
418
}
419

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

    
430
    /* default to native */
431
    pd = page->pd;
432
    mode = sizeof(unsigned long) * 8;
433

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

    
475
    if (xenfb->pixels) {
476
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
477
        xenfb->pixels = NULL;
478
    }
479

    
480
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
481
    n_fbdirs = xenfb->fbpages * mode / 8;
482
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
483

    
484
    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
485
    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
486

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

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

    
500
    ret = 0; /* all is fine */
501

    
502
out:
503
    qemu_free(pgmfns);
504
    qemu_free(fbmfns);
505
    return ret;
506
}
507

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

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

    
567
/* A convenient function for munging pixels between different depths */
568
#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
569
    for (line = y ; line < (y+h) ; line++) {                                \
570
        SRC_T *src = (SRC_T *)(xenfb->pixels                                \
571
                               + xenfb->offset                                \
572
                               + (line * xenfb->row_stride)                \
573
                               + (x * xenfb->depth / 8));                \
574
        DST_T *dst = (DST_T *)(data                                        \
575
                               + (line * linesize)                        \
576
                               + (x * bpp / 8));                        \
577
        int col;                                                        \
578
        const int RSS = 32 - (RSB + GSB + BSB);                                \
579
        const int GSS = 32 - (GSB + BSB);                                \
580
        const int BSS = 32 - (BSB);                                        \
581
        const uint32_t RSM = (~0U) << (32 - RSB);                        \
582
        const uint32_t GSM = (~0U) << (32 - GSB);                        \
583
        const uint32_t BSM = (~0U) << (32 - BSB);                        \
584
        const int RDS = 32 - (RDB + GDB + BDB);                                \
585
        const int GDS = 32 - (GDB + BDB);                                \
586
        const int BDS = 32 - (BDB);                                        \
587
        const uint32_t RDM = (~0U) << (32 - RDB);                        \
588
        const uint32_t GDM = (~0U) << (32 - GDB);                        \
589
        const uint32_t BDM = (~0U) << (32 - BDB);                        \
590
        for (col = x ; col < (x+w) ; col++) {                                \
591
            uint32_t spix = *src;                                        \
592
            *dst = (((spix << RSS) & RSM & RDM) >> RDS) |                \
593
                (((spix << GSS) & GSM & GDM) >> GDS) |                        \
594
                (((spix << BSS) & BSM & BDM) >> BDS);                        \
595
            src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);        \
596
            dst = (DST_T *) ((unsigned long) dst + bpp / 8);                \
597
        }                                                                \
598
    }
599

    
600

    
601
/*
602
 * This copies data from the guest framebuffer region, into QEMU's
603
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
604
 * uses something else we must convert and copy, otherwise we can
605
 * supply the buffer directly and no thing here.
606
 */
607
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
608
{
609
    int line, oops = 0;
610
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
611
    int linesize = ds_get_linesize(xenfb->c.ds);
612
    uint8_t *data = ds_get_data(xenfb->c.ds);
613

    
614
    if (!is_buffer_shared(xenfb->c.ds->surface)) {
615
        switch (xenfb->depth) {
616
        case 8:
617
            if (bpp == 16) {
618
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
619
            } else if (bpp == 32) {
620
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
621
            } else {
622
                oops = 1;
623
            }
624
            break;
625
        case 24:
626
            if (bpp == 16) {
627
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
628
            } else if (bpp == 32) {
629
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
630
            } else {
631
                oops = 1;
632
            }
633
            break;
634
        default:
635
            oops = 1;
636
        }
637
    }
638
    if (oops) /* should not happen */
639
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
640
                      __FUNCTION__, xenfb->depth, bpp);
641

    
642
    dpy_update(xenfb->c.ds, x, y, w, h);
643
}
644

    
645
#ifdef XENFB_TYPE_REFRESH_PERIOD
646
static int xenfb_queue_full(struct XenFB *xenfb)
647
{
648
    struct xenfb_page *page = xenfb->c.page;
649
    uint32_t cons, prod;
650

    
651
    if (!page)
652
        return 1;
653

    
654
    prod = page->in_prod;
655
    cons = page->in_cons;
656
    return prod - cons == XENFB_IN_RING_LEN;
657
}
658

    
659
static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
660
{
661
    uint32_t prod;
662
    struct xenfb_page *page = xenfb->c.page;
663

    
664
    prod = page->in_prod;
665
    /* caller ensures !xenfb_queue_full() */
666
    xen_mb();                   /* ensure ring space available */
667
    XENFB_IN_RING_REF(page, prod) = *event;
668
    xen_wmb();                  /* ensure ring contents visible */
669
    page->in_prod = prod + 1;
670

    
671
    xen_be_send_notify(&xenfb->c.xendev);
672
}
673

    
674
static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
675
{
676
    union xenfb_in_event event;
677

    
678
    memset(&event, 0, sizeof(event));
679
    event.type = XENFB_TYPE_REFRESH_PERIOD;
680
    event.refresh_period.period = period;
681
    xenfb_send_event(xenfb, &event);
682
}
683
#endif
684

    
685
/*
686
 * Periodic update of display.
687
 * Also transmit the refresh interval to the frontend.
688
 *
689
 * Never ever do any qemu display operations
690
 * (resize, screen update) outside this function.
691
 * Our screen might be inactive.  When asked for
692
 * an update we know it is active.
693
 */
694
static void xenfb_update(void *opaque)
695
{
696
    struct XenFB *xenfb = opaque;
697
    int i;
698

    
699
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
700
        return;
701

    
702
    if (xenfb->feature_update) {
703
#ifdef XENFB_TYPE_REFRESH_PERIOD
704
        struct DisplayChangeListener *l;
705
        int period = 99999999;
706
        int idle = 1;
707

    
708
        if (xenfb_queue_full(xenfb))
709
            return;
710

    
711
        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
712
            if (l->idle)
713
                continue;
714
            idle = 0;
715
            if (!l->gui_timer_interval) {
716
                if (period > GUI_REFRESH_INTERVAL)
717
                    period = GUI_REFRESH_INTERVAL;
718
            } else {
719
                if (period > l->gui_timer_interval)
720
                    period = l->gui_timer_interval;
721
            }
722
        }
723
        if (idle)
724
            period = XENFB_NO_REFRESH;
725

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

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

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

    
783
/* QEMU display state changed, so refresh the framebuffer copy */
784
static void xenfb_invalidate(void *opaque)
785
{
786
    struct XenFB *xenfb = opaque;
787
    xenfb->up_fullscreen = 1;
788
}
789

    
790
static void xenfb_handle_events(struct XenFB *xenfb)
791
{
792
    uint32_t prod, cons;
793
    struct xenfb_page *page = xenfb->c.page;
794

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

    
803
        switch (event->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

    
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

    
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

    
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

    
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

    
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
 */
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(10); /* miliseconds */
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
            goto wait_more;
993
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
994
        return;
995
    }
996

    
997
    /* vfb */
998
    fb = container_of(xfb, struct XenFB, c.xendev);
999
    fb->c.ds = graphic_console_init(xenfb_update,
1000
                                    xenfb_invalidate,
1001
                                    NULL,
1002
                                    NULL,
1003
                                    fb);
1004
    fb->have_console = 1;
1005

    
1006
    /* vkbd */
1007
    in = container_of(xin, struct XenInput, c.xendev);
1008
    in->c.ds = fb->c.ds;
1009

    
1010
    /* retry ->init() */
1011
    xen_be_check_state(xin);
1012
    xen_be_check_state(xfb);
1013
}