Statistics
| Branch: | Revision:

root / hw / xenfb.c @ 57c83dac

History | View | Annotate | Download (30.5 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 <xs.h>
39
#include <xenctrl.h>
40
#include <xen/event_channel.h>
41
#include <xen/io/xenbus.h>
42
#include <xen/io/fbif.h>
43
#include <xen/io/kbdif.h>
44
#include <xen/io/protocols.h>
45

    
46
#include "hw.h"
47
#include "console.h"
48
#include "qemu-char.h"
49
#include "xen_backend.h"
50

    
51
#ifndef BTN_LEFT
52
#define BTN_LEFT 0x110 /* from <linux/input.h> */
53
#endif
54

    
55
/* -------------------------------------------------------------------- */
56

    
57
struct common {
58
    struct XenDevice  xendev;  /* must be first */
59
    void              *page;
60
    DisplayState      *ds;
61
};
62

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

    
71
#define UP_QUEUE 8
72

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

    
89
    struct {
90
        int x,y,w,h;
91
    } up_rects[UP_QUEUE];
92
    int               up_count;
93
    int               up_fullscreen;
94
};
95

    
96
/* -------------------------------------------------------------------- */
97

    
98
static int common_bind(struct common *c)
99
{
100
    int mfn;
101

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

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

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

    
117
    return 0;
118
}
119

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

    
129
/* -------------------------------------------------------------------- */
130

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

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

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

161
};
162

163
const unsigned char atkbd_unxlate_table[128] = {
164

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

174
};
175
#endif
176

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

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

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

    
210
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
211
        return 0;
212
    if (!page)
213
        return 0;
214

    
215
    prod = page->in_prod;
216
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
217
        errno = EAGAIN;
218
        return -1;
219
    }
220

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

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

    
233
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
234
    event.type = XENKBD_TYPE_KEY;
235
    event.key.pressed = down ? 1 : 0;
236
    event.key.keycode = keycode;
237

    
238
    return xenfb_kbd_event(xenfb, &event);
239
}
240

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

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

    
255
    return xenfb_kbd_event(xenfb, &event);
256
}
257

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

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

    
275
    return xenfb_kbd_event(xenfb, &event);
276
}
277

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

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

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

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

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

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

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

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

    
359
    if (!in->c.ds) {
360
        char *vfb = xenstore_read_str(NULL, "device/vfb");
361
        if (vfb == NULL) {
362
            /* there is no vfb, run vkbd on its own */
363
            in->c.ds = get_displaystate();
364
        } else {
365
            g_free(vfb);
366
            xen_be_printf(xendev, 1, "ds not set (yet)\n");
367
            return -1;
368
        }
369
    }
370

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

    
375
    qemu_add_kbd_event_handler(xenfb_key_event, in);
376
    return 0;
377
}
378

    
379
static void input_connected(struct XenDevice *xendev)
380
{
381
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
382

    
383
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
384
                             &in->abs_pointer_wanted) == -1) {
385
        in->abs_pointer_wanted = 0;
386
    }
387

    
388
    if (in->qmouse) {
389
        qemu_remove_mouse_event_handler(in->qmouse);
390
    }
391
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
392
                                              in->abs_pointer_wanted,
393
                                              "Xen PVFB Mouse");
394
}
395

    
396
static void input_disconnect(struct XenDevice *xendev)
397
{
398
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
399

    
400
    if (in->qmouse) {
401
        qemu_remove_mouse_event_handler(in->qmouse);
402
        in->qmouse = NULL;
403
    }
404
    qemu_add_kbd_event_handler(NULL, NULL);
405
    common_unbind(&in->c);
406
}
407

    
408
static void input_event(struct XenDevice *xendev)
409
{
410
    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
411
    struct xenkbd_page *page = xenfb->c.page;
412

    
413
    /* We don't understand any keyboard events, so just ignore them. */
414
    if (page->out_prod == page->out_cons)
415
        return;
416
    page->out_cons = page->out_prod;
417
    xen_be_send_notify(&xenfb->c.xendev);
418
}
419

    
420
/* -------------------------------------------------------------------- */
421

    
422
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
423
{
424
    uint32_t *src32 = src;
425
    uint64_t *src64 = src;
426
    int i;
427

    
428
    for (i = 0; i < count; i++)
429
        dst[i] = (mode == 32) ? src32[i] : src64[i];
430
}
431

    
432
static int xenfb_map_fb(struct XenFB *xenfb)
433
{
434
    struct xenfb_page *page = xenfb->c.page;
435
    char *protocol = xenfb->c.xendev.protocol;
436
    int n_fbdirs;
437
    unsigned long *pgmfns = NULL;
438
    unsigned long *fbmfns = NULL;
439
    void *map, *pd;
440
    int mode, ret = -1;
441

    
442
    /* default to native */
443
    pd = page->pd;
444
    mode = sizeof(unsigned long) * 8;
445

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

    
487
    if (xenfb->pixels) {
488
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
489
        xenfb->pixels = NULL;
490
    }
491

    
492
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
493
    n_fbdirs = xenfb->fbpages * mode / 8;
494
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
495

    
496
    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
497
    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
498

    
499
    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
500
    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
501
                               PROT_READ, pgmfns, n_fbdirs);
502
    if (map == NULL)
503
        goto out;
504
    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
505
    munmap(map, n_fbdirs * XC_PAGE_SIZE);
506

    
507
    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
508
                                         PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
509
    if (xenfb->pixels == NULL)
510
        goto out;
511

    
512
    ret = 0; /* all is fine */
513

    
514
out:
515
    g_free(pgmfns);
516
    g_free(fbmfns);
517
    return ret;
518
}
519

    
520
static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
521
                              int width, int height, int depth,
522
                              size_t fb_len, int offset, int row_stride)
523
{
524
    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
525
    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
526
    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
527
    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
528
    int max_width, max_height;
529

    
530
    if (fb_len_lim > fb_len_max) {
531
        xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
532
                      fb_len_lim, fb_len_max);
533
        fb_len_lim = fb_len_max;
534
    }
535
    if (fb_len_lim && fb_len > fb_len_lim) {
536
        xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
537
                      fb_len, fb_len_lim);
538
        fb_len = fb_len_lim;
539
    }
540
    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
541
        xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
542
                      depth);
543
        return -1;
544
    }
545
    if (row_stride <= 0 || row_stride > fb_len) {
546
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
547
        return -1;
548
    }
549
    max_width = row_stride / (depth / 8);
550
    if (width < 0 || width > max_width) {
551
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
552
                      width, max_width);
553
        width = max_width;
554
    }
555
    if (offset < 0 || offset >= fb_len) {
556
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
557
                      offset, fb_len - 1);
558
        return -1;
559
    }
560
    max_height = (fb_len - offset) / row_stride;
561
    if (height < 0 || height > max_height) {
562
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
563
                      height, max_height);
564
        height = max_height;
565
    }
566
    xenfb->fb_len = fb_len;
567
    xenfb->row_stride = row_stride;
568
    xenfb->depth = depth;
569
    xenfb->width = width;
570
    xenfb->height = height;
571
    xenfb->offset = offset;
572
    xenfb->up_fullscreen = 1;
573
    xenfb->do_resize = 1;
574
    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
575
                  width, height, depth, offset, row_stride);
576
    return 0;
577
}
578

    
579
/* A convenient function for munging pixels between different depths */
580
#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
581
    for (line = y ; line < (y+h) ; line++) {                                \
582
        SRC_T *src = (SRC_T *)(xenfb->pixels                                \
583
                               + xenfb->offset                                \
584
                               + (line * xenfb->row_stride)                \
585
                               + (x * xenfb->depth / 8));                \
586
        DST_T *dst = (DST_T *)(data                                        \
587
                               + (line * linesize)                        \
588
                               + (x * bpp / 8));                        \
589
        int col;                                                        \
590
        const int RSS = 32 - (RSB + GSB + BSB);                                \
591
        const int GSS = 32 - (GSB + BSB);                                \
592
        const int BSS = 32 - (BSB);                                        \
593
        const uint32_t RSM = (~0U) << (32 - RSB);                        \
594
        const uint32_t GSM = (~0U) << (32 - GSB);                        \
595
        const uint32_t BSM = (~0U) << (32 - BSB);                        \
596
        const int RDS = 32 - (RDB + GDB + BDB);                                \
597
        const int GDS = 32 - (GDB + BDB);                                \
598
        const int BDS = 32 - (BDB);                                        \
599
        const uint32_t RDM = (~0U) << (32 - RDB);                        \
600
        const uint32_t GDM = (~0U) << (32 - GDB);                        \
601
        const uint32_t BDM = (~0U) << (32 - BDB);                        \
602
        for (col = x ; col < (x+w) ; col++) {                                \
603
            uint32_t spix = *src;                                        \
604
            *dst = (((spix << RSS) & RSM & RDM) >> RDS) |                \
605
                (((spix << GSS) & GSM & GDM) >> GDS) |                        \
606
                (((spix << BSS) & BSM & BDM) >> BDS);                        \
607
            src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);        \
608
            dst = (DST_T *) ((unsigned long) dst + bpp / 8);                \
609
        }                                                                \
610
    }
611

    
612

    
613
/*
614
 * This copies data from the guest framebuffer region, into QEMU's
615
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
616
 * uses something else we must convert and copy, otherwise we can
617
 * supply the buffer directly and no thing here.
618
 */
619
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
620
{
621
    int line, oops = 0;
622
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
623
    int linesize = ds_get_linesize(xenfb->c.ds);
624
    uint8_t *data = ds_get_data(xenfb->c.ds);
625

    
626
    if (!is_buffer_shared(xenfb->c.ds->surface)) {
627
        switch (xenfb->depth) {
628
        case 8:
629
            if (bpp == 16) {
630
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
631
            } else if (bpp == 32) {
632
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
633
            } else {
634
                oops = 1;
635
            }
636
            break;
637
        case 24:
638
            if (bpp == 16) {
639
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
640
            } else if (bpp == 32) {
641
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
642
            } else {
643
                oops = 1;
644
            }
645
            break;
646
        default:
647
            oops = 1;
648
        }
649
    }
650
    if (oops) /* should not happen */
651
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
652
                      __FUNCTION__, xenfb->depth, bpp);
653

    
654
    dpy_update(xenfb->c.ds, x, y, w, h);
655
}
656

    
657
#ifdef XENFB_TYPE_REFRESH_PERIOD
658
static int xenfb_queue_full(struct XenFB *xenfb)
659
{
660
    struct xenfb_page *page = xenfb->c.page;
661
    uint32_t cons, prod;
662

    
663
    if (!page)
664
        return 1;
665

    
666
    prod = page->in_prod;
667
    cons = page->in_cons;
668
    return prod - cons == XENFB_IN_RING_LEN;
669
}
670

    
671
static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
672
{
673
    uint32_t prod;
674
    struct xenfb_page *page = xenfb->c.page;
675

    
676
    prod = page->in_prod;
677
    /* caller ensures !xenfb_queue_full() */
678
    xen_mb();                   /* ensure ring space available */
679
    XENFB_IN_RING_REF(page, prod) = *event;
680
    xen_wmb();                  /* ensure ring contents visible */
681
    page->in_prod = prod + 1;
682

    
683
    xen_be_send_notify(&xenfb->c.xendev);
684
}
685

    
686
static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
687
{
688
    union xenfb_in_event event;
689

    
690
    memset(&event, 0, sizeof(event));
691
    event.type = XENFB_TYPE_REFRESH_PERIOD;
692
    event.refresh_period.period = period;
693
    xenfb_send_event(xenfb, &event);
694
}
695
#endif
696

    
697
/*
698
 * Periodic update of display.
699
 * Also transmit the refresh interval to the frontend.
700
 *
701
 * Never ever do any qemu display operations
702
 * (resize, screen update) outside this function.
703
 * Our screen might be inactive.  When asked for
704
 * an update we know it is active.
705
 */
706
static void xenfb_update(void *opaque)
707
{
708
    struct XenFB *xenfb = opaque;
709
    int i;
710

    
711
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
712
        return;
713

    
714
    if (xenfb->feature_update) {
715
#ifdef XENFB_TYPE_REFRESH_PERIOD
716
        struct DisplayChangeListener *l;
717
        int period = 99999999;
718
        int idle = 1;
719

    
720
        if (xenfb_queue_full(xenfb))
721
            return;
722

    
723
        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
724
            if (l->idle)
725
                continue;
726
            idle = 0;
727
            if (!l->gui_timer_interval) {
728
                if (period > GUI_REFRESH_INTERVAL)
729
                    period = GUI_REFRESH_INTERVAL;
730
            } else {
731
                if (period > l->gui_timer_interval)
732
                    period = l->gui_timer_interval;
733
            }
734
        }
735
        if (idle)
736
            period = XENFB_NO_REFRESH;
737

    
738
        if (xenfb->refresh_period != period) {
739
            xenfb_send_refresh_period(xenfb, period);
740
            xenfb->refresh_period = period;
741
            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
742
        }
743
#else
744
        ; /* nothing */
745
#endif
746
    } else {
747
        /* we don't get update notifications, thus use the
748
         * sledge hammer approach ... */
749
        xenfb->up_fullscreen = 1;
750
    }
751

    
752
    /* resize if needed */
753
    if (xenfb->do_resize) {
754
        xenfb->do_resize = 0;
755
        switch (xenfb->depth) {
756
        case 16:
757
        case 32:
758
            /* console.c supported depth -> buffer can be used directly */
759
            qemu_free_displaysurface(xenfb->c.ds);
760
            xenfb->c.ds->surface = qemu_create_displaysurface_from
761
                (xenfb->width, xenfb->height, xenfb->depth,
762
                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
763
            break;
764
        default:
765
            /* we must convert stuff */
766
            qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
767
            break;
768
        }
769
        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
770
                      xenfb->width, xenfb->height, xenfb->depth,
771
                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
772
        dpy_resize(xenfb->c.ds);
773
        xenfb->up_fullscreen = 1;
774
    }
775

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

    
795
/* QEMU display state changed, so refresh the framebuffer copy */
796
static void xenfb_invalidate(void *opaque)
797
{
798
    struct XenFB *xenfb = opaque;
799
    xenfb->up_fullscreen = 1;
800
}
801

    
802
static void xenfb_handle_events(struct XenFB *xenfb)
803
{
804
    uint32_t prod, cons;
805
    struct xenfb_page *page = xenfb->c.page;
806

    
807
    prod = page->out_prod;
808
    if (prod == page->out_cons)
809
        return;
810
    xen_rmb();                /* ensure we see ring contents up to prod */
811
    for (cons = page->out_cons; cons != prod; cons++) {
812
        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
813
        int x, y, w, h;
814

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

    
866
static int fb_init(struct XenDevice *xendev)
867
{
868
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
869

    
870
    fb->refresh_period = -1;
871

    
872
#ifdef XENFB_TYPE_RESIZE
873
    xenstore_write_be_int(xendev, "feature-resize", 1);
874
#endif
875
    return 0;
876
}
877

    
878
static int fb_initialise(struct XenDevice *xendev)
879
{
880
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
881
    struct xenfb_page *fb_page;
882
    int videoram;
883
    int rc;
884

    
885
    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
886
        videoram = 0;
887

    
888
    rc = common_bind(&fb->c);
889
    if (rc != 0)
890
        return rc;
891

    
892
    fb_page = fb->c.page;
893
    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
894
                            fb_page->width, fb_page->height, fb_page->depth,
895
                            fb_page->mem_length, 0, fb_page->line_length);
896
    if (rc != 0)
897
        return rc;
898

    
899
    rc = xenfb_map_fb(fb);
900
    if (rc != 0)
901
        return rc;
902

    
903
#if 0  /* handled in xen_init_display() for now */
904
    if (!fb->have_console) {
905
        fb->c.ds = graphic_console_init(xenfb_update,
906
                                        xenfb_invalidate,
907
                                        NULL,
908
                                        NULL,
909
                                        fb);
910
        fb->have_console = 1;
911
    }
912
#endif
913

    
914
    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
915
        fb->feature_update = 0;
916
    if (fb->feature_update)
917
        xenstore_write_be_int(xendev, "request-update", 1);
918

    
919
    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
920
                  fb->feature_update, videoram);
921
    return 0;
922
}
923

    
924
static void fb_disconnect(struct XenDevice *xendev)
925
{
926
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
927

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

    
941
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
942
{
943
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
944

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

    
959
static void fb_event(struct XenDevice *xendev)
960
{
961
    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
962

    
963
    xenfb_handle_events(xenfb);
964
    xen_be_send_notify(&xenfb->c.xendev);
965
}
966

    
967
/* -------------------------------------------------------------------- */
968

    
969
struct XenDevOps xen_kbdmouse_ops = {
970
    .size       = sizeof(struct XenInput),
971
    .init       = input_init,
972
    .initialise = input_initialise,
973
    .connected  = input_connected,
974
    .disconnect = input_disconnect,
975
    .event      = input_event,
976
};
977

    
978
struct XenDevOps xen_framebuffer_ops = {
979
    .size       = sizeof(struct XenFB),
980
    .init       = fb_init,
981
    .initialise = fb_initialise,
982
    .disconnect = fb_disconnect,
983
    .event      = fb_event,
984
    .frontend_changed = fb_frontend_changed,
985
};
986

    
987
/*
988
 * FIXME/TODO: Kill this.
989
 * Temporary needed while DisplayState reorganization is in flight.
990
 */
991
void xen_init_display(int domid)
992
{
993
    struct XenDevice *xfb, *xin;
994
    struct XenFB *fb;
995
    struct XenInput *in;
996
    int i = 0;
997

    
998
wait_more:
999
    i++;
1000
    main_loop_wait(true);
1001
    xfb = xen_be_find_xendev("vfb", domid, 0);
1002
    xin = xen_be_find_xendev("vkbd", domid, 0);
1003
    if (!xfb || !xin) {
1004
        if (i < 256) {
1005
            usleep(10000);
1006
            goto wait_more;
1007
        }
1008
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
1009
        return;
1010
    }
1011

    
1012
    /* vfb */
1013
    fb = container_of(xfb, struct XenFB, c.xendev);
1014
    fb->c.ds = graphic_console_init(xenfb_update,
1015
                                    xenfb_invalidate,
1016
                                    NULL,
1017
                                    NULL,
1018
                                    fb);
1019
    fb->have_console = 1;
1020

    
1021
    /* vkbd */
1022
    in = container_of(xin, struct XenInput, c.xendev);
1023
    in->c.ds = fb->c.ds;
1024

    
1025
    /* retry ->init() */
1026
    xen_be_check_state(xin);
1027
    xen_be_check_state(xfb);
1028
}