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