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    trace_xenfb_key_event(opaque, scancode2linux[scancode], down);
 294    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
 295}
 296
 297/*
 298 * Send a mouse event from the client to the guest OS
 299 *
 300 * The QEMU mouse can be in either relative, or absolute mode.
 301 * Movement is sent separately from button state, which has to
 302 * be encoded as virtual key events. We also don't actually get
 303 * given any button up/down events, so have to track changes in
 304 * the button state.
 305 */
 306static void xenfb_mouse_event(void *opaque,
 307                              int dx, int dy, int dz, int button_state)
 308{
 309    struct XenInput *xenfb = opaque;
 310    QemuConsole *con = qemu_console_lookup_by_index(0);
 311    DisplaySurface *surface;
 312    int dw, dh, i;
 313
 314    if (!con) {
 315        xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available");
 316        return;
 317    }
 318
 319    surface = qemu_console_surface(con);
 320    dw = surface_width(surface);
 321    dh = surface_height(surface);
 322
 323    trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
 324                            xenfb->abs_pointer_wanted);
 325    if (xenfb->abs_pointer_wanted)
 326        xenfb_send_position(xenfb,
 327                            dx * (dw - 1) / 0x7fff,
 328                            dy * (dh - 1) / 0x7fff,
 329                            dz);
 330    else
 331        xenfb_send_motion(xenfb, dx, dy, dz);
 332
 333    for (i = 0 ; i < 8 ; i++) {
 334        int lastDown = xenfb->button_state & (1 << i);
 335        int down = button_state & (1 << i);
 336        if (down == lastDown)
 337            continue;
 338
 339        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
 340            return;
 341    }
 342    xenfb->button_state = button_state;
 343}
 344
 345static int input_init(struct XenDevice *xendev)
 346{
 347    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
 348    return 0;
 349}
 350
 351static int input_initialise(struct XenDevice *xendev)
 352{
 353    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
 354    int rc;
 355
 356    rc = common_bind(&in->c);
 357    if (rc != 0)
 358        return rc;
 359
 360    qemu_add_kbd_event_handler(xenfb_key_event, in);
 361    return 0;
 362}
 363
 364static void input_connected(struct XenDevice *xendev)
 365{
 366    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
 367
 368    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
 369                             &in->abs_pointer_wanted) == -1) {
 370        in->abs_pointer_wanted = 0;
 371    }
 372
 373    if (in->qmouse) {
 374        qemu_remove_mouse_event_handler(in->qmouse);
 375    }
 376    trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
 377    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
 378                                              in->abs_pointer_wanted,
 379                                              "Xen PVFB Mouse");
 380}
 381
 382static void input_disconnect(struct XenDevice *xendev)
 383{
 384    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
 385
 386    if (in->qmouse) {
 387        qemu_remove_mouse_event_handler(in->qmouse);
 388        in->qmouse = NULL;
 389    }
 390    qemu_add_kbd_event_handler(NULL, NULL);
 391    common_unbind(&in->c);
 392}
 393
 394static void input_event(struct XenDevice *xendev)
 395{
 396    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
 397    struct xenkbd_page *page = xenfb->c.page;
 398
 399    /* We don't understand any keyboard events, so just ignore them. */
 400    if (page->out_prod == page->out_cons)
 401        return;
 402    page->out_cons = page->out_prod;
 403    xen_pv_send_notify(&xenfb->c.xendev);
 404}
 405
 406/* -------------------------------------------------------------------- */
 407
 408static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
 409{
 410    uint32_t *src32 = src;
 411    uint64_t *src64 = src;
 412    int i;
 413
 414    for (i = 0; i < count; i++)
 415        dst[i] = (mode == 32) ? src32[i] : src64[i];
 416}
 417
 418static int xenfb_map_fb(struct XenFB *xenfb)
 419{
 420    struct xenfb_page *page = xenfb->c.page;
 421    char *protocol = xenfb->c.xendev.protocol;
 422    int n_fbdirs;
 423    xen_pfn_t *pgmfns = NULL;
 424    xen_pfn_t *fbmfns = NULL;
 425    void *map, *pd;
 426    int mode, ret = -1;
 427
 428    /* default to native */
 429    pd = page->pd;
 430    mode = sizeof(unsigned long) * 8;
 431
 432    if (!protocol) {
 433        /*
 434         * Undefined protocol, some guesswork needed.
 435         *
 436         * Old frontends which don't set the protocol use
 437         * one page directory only, thus pd[1] must be zero.
 438         * pd[1] of the 32bit struct layout and the lower
 439         * 32 bits of pd[0] of the 64bit struct layout have
 440         * the same location, so we can check that ...
 441         */
 442        uint32_t *ptr32 = NULL;
 443        uint32_t *ptr64 = NULL;
 444#if defined(__i386__)
 445        ptr32 = (void*)page->pd;
 446        ptr64 = ((void*)page->pd) + 4;
 447#elif defined(__x86_64__)
 448        ptr32 = ((void*)page->pd) - 4;
 449        ptr64 = (void*)page->pd;
 450#endif
 451        if (ptr32) {
 452            if (ptr32[1] == 0) {
 453                mode = 32;
 454                pd   = ptr32;
 455            } else {
 456                mode = 64;
 457                pd   = ptr64;
 458            }
 459        }
 460#if defined(__x86_64__)
 461    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
 462        /* 64bit dom0, 32bit domU */
 463        mode = 32;
 464        pd   = ((void*)page->pd) - 4;
 465#elif defined(__i386__)
 466    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
 467        /* 32bit dom0, 64bit domU */
 468        mode = 64;
 469        pd   = ((void*)page->pd) + 4;
 470#endif
 471    }
 472
 473    if (xenfb->pixels) {
 474        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
 475        xenfb->pixels = NULL;
 476    }
 477
 478    xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
 479    n_fbdirs = xenfb->fbpages * mode / 8;
 480    n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
 481
 482    pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
 483    fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
 484
 485    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
 486    map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
 487                               PROT_READ, n_fbdirs, pgmfns, NULL);
 488    if (map == NULL)
 489        goto out;
 490    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
 491    xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
 492
 493    xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
 494            PROT_READ, xenfb->fbpages, fbmfns, NULL);
 495    if (xenfb->pixels == NULL)
 496        goto out;
 497
 498    ret = 0; /* all is fine */
 499
 500out:
 501    g_free(pgmfns);
 502    g_free(fbmfns);
 503    return ret;
 504}
 505
 506static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
 507                              int width, int height, int depth,
 508                              size_t fb_len, int offset, int row_stride)
 509{
 510    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
 511    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
 512    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
 513    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
 514    int max_width, max_height;
 515
 516    if (fb_len_lim > fb_len_max) {
 517        xen_pv_printf(&xenfb->c.xendev, 0,
 518                      "fb size limit %zu exceeds %zu, corrected\n",
 519                      fb_len_lim, fb_len_max);
 520        fb_len_lim = fb_len_max;
 521    }
 522    if (fb_len_lim && fb_len > fb_len_lim) {
 523        xen_pv_printf(&xenfb->c.xendev, 0,
 524                      "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_pv_printf(&xenfb->c.xendev, 0,
 530                      "can't handle frontend fb depth %d\n",
 531                      depth);
 532        return -1;
 533    }
 534    if (row_stride <= 0 || row_stride > fb_len) {
 535        xen_pv_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n",
 536                      row_stride);
 537        return -1;
 538    }
 539    max_width = row_stride / (depth / 8);
 540    if (width < 0 || width > max_width) {
 541        xen_pv_printf(&xenfb->c.xendev, 0,
 542                      "invalid frontend width %d limited to %d\n",
 543                      width, max_width);
 544        width = max_width;
 545    }
 546    if (offset < 0 || offset >= fb_len) {
 547        xen_pv_printf(&xenfb->c.xendev, 0,
 548                      "invalid frontend offset %d (max %zu)\n",
 549                      offset, fb_len - 1);
 550        return -1;
 551    }
 552    max_height = (fb_len - offset) / row_stride;
 553    if (height < 0 || height > max_height) {
 554        xen_pv_printf(&xenfb->c.xendev, 0,
 555                      "invalid frontend height %d limited to %d\n",
 556                      height, max_height);
 557        height = max_height;
 558    }
 559    xenfb->fb_len = fb_len;
 560    xenfb->row_stride = row_stride;
 561    xenfb->depth = depth;
 562    xenfb->width = width;
 563    xenfb->height = height;
 564    xenfb->offset = offset;
 565    xenfb->up_fullscreen = 1;
 566    xenfb->do_resize = 1;
 567    xen_pv_printf(&xenfb->c.xendev, 1,
 568                  "framebuffer %dx%dx%d offset %d stride %d\n",
 569                  width, height, depth, offset, row_stride);
 570    return 0;
 571}
 572
 573/* A convenient function for munging pixels between different depths */
 574#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
 575    for (line = y ; line < (y+h) ; line++) {                            \
 576        SRC_T *src = (SRC_T *)(xenfb->pixels                            \
 577                               + xenfb->offset                          \
 578                               + (line * xenfb->row_stride)             \
 579                               + (x * xenfb->depth / 8));               \
 580        DST_T *dst = (DST_T *)(data                                     \
 581                               + (line * linesize)                      \
 582                               + (x * bpp / 8));                        \
 583        int col;                                                        \
 584        const int RSS = 32 - (RSB + GSB + BSB);                         \
 585        const int GSS = 32 - (GSB + BSB);                               \
 586        const int BSS = 32 - (BSB);                                     \
 587        const uint32_t RSM = (~0U) << (32 - RSB);                       \
 588        const uint32_t GSM = (~0U) << (32 - GSB);                       \
 589        const uint32_t BSM = (~0U) << (32 - BSB);                       \
 590        const int RDS = 32 - (RDB + GDB + BDB);                         \
 591        const int GDS = 32 - (GDB + BDB);                               \
 592        const int BDS = 32 - (BDB);                                     \
 593        const uint32_t RDM = (~0U) << (32 - RDB);                       \
 594        const uint32_t GDM = (~0U) << (32 - GDB);                       \
 595        const uint32_t BDM = (~0U) << (32 - BDB);                       \
 596        for (col = x ; col < (x+w) ; col++) {                           \
 597            uint32_t spix = *src;                                       \
 598            *dst = (((spix << RSS) & RSM & RDM) >> RDS) |               \
 599                (((spix << GSS) & GSM & GDM) >> GDS) |                  \
 600                (((spix << BSS) & BSM & BDM) >> BDS);                   \
 601            src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);   \
 602            dst = (DST_T *) ((unsigned long) dst + bpp / 8);            \
 603        }                                                               \
 604    }
 605
 606
 607/*
 608 * This copies data from the guest framebuffer region, into QEMU's
 609 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
 610 * uses something else we must convert and copy, otherwise we can
 611 * supply the buffer directly and no thing here.
 612 */
 613static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
 614{
 615    DisplaySurface *surface = qemu_console_surface(xenfb->con);
 616    int line, oops = 0;
 617    int bpp = surface_bits_per_pixel(surface);
 618    int linesize = surface_stride(surface);
 619    uint8_t *data = surface_data(surface);
 620
 621    if (!is_buffer_shared(surface)) {
 622        switch (xenfb->depth) {
 623        case 8:
 624            if (bpp == 16) {
 625                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
 626            } else if (bpp == 32) {
 627                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
 628            } else {
 629                oops = 1;
 630            }
 631            break;
 632        case 24:
 633            if (bpp == 16) {
 634                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
 635            } else if (bpp == 32) {
 636                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
 637            } else {
 638                oops = 1;
 639            }
 640            break;
 641        default:
 642            oops = 1;
 643        }
 644    }
 645    if (oops) /* should not happen */
 646        xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
 647                      __FUNCTION__, xenfb->depth, bpp);
 648
 649    dpy_gfx_update(xenfb->con, x, y, w, h);
 650}
 651
 652#ifdef XENFB_TYPE_REFRESH_PERIOD
 653static int xenfb_queue_full(struct XenFB *xenfb)
 654{
 655    struct xenfb_page *page = xenfb->c.page;
 656    uint32_t cons, prod;
 657
 658    if (!page)
 659        return 1;
 660
 661    prod = page->in_prod;
 662    cons = page->in_cons;
 663    return prod - cons == XENFB_IN_RING_LEN;
 664}
 665
 666static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
 667{
 668    uint32_t prod;
 669    struct xenfb_page *page = xenfb->c.page;
 670
 671    prod = page->in_prod;
 672    /* caller ensures !xenfb_queue_full() */
 673    xen_mb();                   /* ensure ring space available */
 674    XENFB_IN_RING_REF(page, prod) = *event;
 675    xen_wmb();                  /* ensure ring contents visible */
 676    page->in_prod = prod + 1;
 677
 678    xen_pv_send_notify(&xenfb->c.xendev);
 679}
 680
 681static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
 682{
 683    union xenfb_in_event event;
 684
 685    memset(&event, 0, sizeof(event));
 686    event.type = XENFB_TYPE_REFRESH_PERIOD;
 687    event.refresh_period.period = period;
 688    xenfb_send_event(xenfb, &event);
 689}
 690#endif
 691
 692/*
 693 * Periodic update of display.
 694 * Also transmit the refresh interval to the frontend.
 695 *
 696 * Never ever do any qemu display operations
 697 * (resize, screen update) outside this function.
 698 * Our screen might be inactive.  When asked for
 699 * an update we know it is active.
 700 */
 701static void xenfb_update(void *opaque)
 702{
 703    struct XenFB *xenfb = opaque;
 704    DisplaySurface *surface;
 705    int i;
 706
 707    if (xenfb->c.xendev.be_state != XenbusStateConnected)
 708        return;
 709
 710    if (!xenfb->feature_update) {
 711        /* we don't get update notifications, thus use the
 712         * sledge hammer approach ... */
 713        xenfb->up_fullscreen = 1;
 714    }
 715
 716    /* resize if needed */
 717    if (xenfb->do_resize) {
 718        pixman_format_code_t format;
 719
 720        xenfb->do_resize = 0;
 721        switch (xenfb->depth) {
 722        case 16:
 723        case 32:
 724            /* console.c supported depth -> buffer can be used directly */
 725            format = qemu_default_pixman_format(xenfb->depth, true);
 726            surface = qemu_create_displaysurface_from
 727                (xenfb->width, xenfb->height, format,
 728                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
 729            break;
 730        default:
 731            /* we must convert stuff */
 732            surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
 733            break;
 734        }
 735        dpy_gfx_replace_surface(xenfb->con, surface);
 736        xen_pv_printf(&xenfb->c.xendev, 1,
 737                      "update: resizing: %dx%d @ %d bpp%s\n",
 738                      xenfb->width, xenfb->height, xenfb->depth,
 739                      is_buffer_shared(surface) ? " (shared)" : "");
 740        xenfb->up_fullscreen = 1;
 741    }
 742
 743    /* run queued updates */
 744    if (xenfb->up_fullscreen) {
 745        xen_pv_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
 746        xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
 747    } else if (xenfb->up_count) {
 748        xen_pv_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
 749                      xenfb->up_count);
 750        for (i = 0; i < xenfb->up_count; i++)
 751            xenfb_guest_copy(xenfb,
 752                             xenfb->up_rects[i].x,
 753                             xenfb->up_rects[i].y,
 754                             xenfb->up_rects[i].w,
 755                             xenfb->up_rects[i].h);
 756    } else {
 757        xen_pv_printf(&xenfb->c.xendev, 3, "update: nothing\n");
 758    }
 759    xenfb->up_count = 0;
 760    xenfb->up_fullscreen = 0;
 761}
 762
 763static void xenfb_update_interval(void *opaque, uint64_t interval)
 764{
 765    struct XenFB *xenfb = opaque;
 766
 767    if (xenfb->feature_update) {
 768#ifdef XENFB_TYPE_REFRESH_PERIOD
 769        if (xenfb_queue_full(xenfb)) {
 770            return;
 771        }
 772        xenfb_send_refresh_period(xenfb, interval);
 773#endif
 774    }
 775}
 776
 777/* QEMU display state changed, so refresh the framebuffer copy */
 778static void xenfb_invalidate(void *opaque)
 779{
 780    struct XenFB *xenfb = opaque;
 781    xenfb->up_fullscreen = 1;
 782}
 783
 784static void xenfb_handle_events(struct XenFB *xenfb)
 785{
 786    uint32_t prod, cons, out_cons;
 787    struct xenfb_page *page = xenfb->c.page;
 788
 789    prod = page->out_prod;
 790    out_cons = page->out_cons;
 791    if (prod - out_cons > XENFB_OUT_RING_LEN) {
 792        return;
 793    }
 794    xen_rmb();          /* ensure we see ring contents up to prod */
 795    for (cons = out_cons; cons != prod; cons++) {
 796        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
 797        uint8_t type = event->type;
 798        int x, y, w, h;
 799
 800        switch (type) {
 801        case XENFB_TYPE_UPDATE:
 802            if (xenfb->up_count == UP_QUEUE)
 803                xenfb->up_fullscreen = 1;
 804            if (xenfb->up_fullscreen)
 805                break;
 806            x = MAX(event->update.x, 0);
 807            y = MAX(event->update.y, 0);
 808            w = MIN(event->update.width, xenfb->width - x);
 809            h = MIN(event->update.height, xenfb->height - y);
 810            if (w < 0 || h < 0) {
 811                xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
 812                break;
 813            }
 814            if (x != event->update.x ||
 815                y != event->update.y ||
 816                w != event->update.width ||
 817                h != event->update.height) {
 818                xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
 819            }
 820            if (w == xenfb->width && h > xenfb->height / 2) {
 821                /* scroll detector: updated more than 50% of the lines,
 822                 * don't bother keeping track of the rectangles then */
 823                xenfb->up_fullscreen = 1;
 824            } else {
 825                xenfb->up_rects[xenfb->up_count].x = x;
 826                xenfb->up_rects[xenfb->up_count].y = y;
 827                xenfb->up_rects[xenfb->up_count].w = w;
 828                xenfb->up_rects[xenfb->up_count].h = h;
 829                xenfb->up_count++;
 830            }
 831            break;
 832#ifdef XENFB_TYPE_RESIZE
 833        case XENFB_TYPE_RESIZE:
 834            if (xenfb_configure_fb(xenfb, xenfb->fb_len,
 835                                   event->resize.width,
 836                                   event->resize.height,
 837                                   event->resize.depth,
 838                                   xenfb->fb_len,
 839                                   event->resize.offset,
 840                                   event->resize.stride) < 0)
 841                break;
 842            xenfb_invalidate(xenfb);
 843            break;
 844#endif
 845        }
 846    }
 847    xen_mb();           /* ensure we're done with ring contents */
 848    page->out_cons = cons;
 849}
 850
 851static int fb_init(struct XenDevice *xendev)
 852{
 853#ifdef XENFB_TYPE_RESIZE
 854    xenstore_write_be_int(xendev, "feature-resize", 1);
 855#endif
 856    return 0;
 857}
 858
 859static int fb_initialise(struct XenDevice *xendev)
 860{
 861    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
 862    struct xenfb_page *fb_page;
 863    int videoram;
 864    int rc;
 865
 866    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
 867        videoram = 0;
 868
 869    rc = common_bind(&fb->c);
 870    if (rc != 0)
 871        return rc;
 872
 873    fb_page = fb->c.page;
 874    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
 875                            fb_page->width, fb_page->height, fb_page->depth,
 876                            fb_page->mem_length, 0, fb_page->line_length);
 877    if (rc != 0)
 878        return rc;
 879
 880    rc = xenfb_map_fb(fb);
 881    if (rc != 0)
 882        return rc;
 883
 884    fb->con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
 885
 886    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
 887        fb->feature_update = 0;
 888    if (fb->feature_update)
 889        xenstore_write_be_int(xendev, "request-update", 1);
 890
 891    xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
 892                  fb->feature_update, videoram);
 893    return 0;
 894}
 895
 896static void fb_disconnect(struct XenDevice *xendev)
 897{
 898    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
 899
 900    /*
 901     * FIXME: qemu can't un-init gfx display (yet?).
 902     *   Replacing the framebuffer with anonymous shared memory
 903     *   instead.  This releases the guest pages and keeps qemu happy.
 904     */
 905    xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
 906    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
 907                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
 908                      -1, 0);
 909    if (fb->pixels == MAP_FAILED) {
 910        xen_pv_printf(xendev, 0,
 911                "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
 912                errno);
 913    }
 914    common_unbind(&fb->c);
 915    fb->feature_update = 0;
 916    fb->bug_trigger    = 0;
 917}
 918
 919static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
 920{
 921    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
 922
 923    /*
 924     * Set state to Connected *again* once the frontend switched
 925     * to connected.  We must trigger the watch a second time to
 926     * workaround a frontend bug.
 927     */
 928    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
 929        xendev->fe_state == XenbusStateConnected &&
 930        xendev->be_state == XenbusStateConnected) {
 931        xen_pv_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
 932        xen_be_set_state(xendev, XenbusStateConnected);
 933        fb->bug_trigger = 1; /* only once */
 934    }
 935}
 936
 937static void fb_event(struct XenDevice *xendev)
 938{
 939    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
 940
 941    xenfb_handle_events(xenfb);
 942    xen_pv_send_notify(&xenfb->c.xendev);
 943}
 944
 945/* -------------------------------------------------------------------- */
 946
 947struct XenDevOps xen_kbdmouse_ops = {
 948    .size       = sizeof(struct XenInput),
 949    .init       = input_init,
 950    .initialise = input_initialise,
 951    .connected  = input_connected,
 952    .disconnect = input_disconnect,
 953    .event      = input_event,
 954};
 955
 956struct XenDevOps xen_framebuffer_ops = {
 957    .size       = sizeof(struct XenFB),
 958    .init       = fb_init,
 959    .initialise = fb_initialise,
 960    .disconnect = fb_disconnect,
 961    .event      = fb_event,
 962    .frontend_changed = fb_frontend_changed,
 963};
 964
 965static const GraphicHwOps xenfb_ops = {
 966    .invalidate  = xenfb_invalidate,
 967    .gfx_update  = xenfb_update,
 968    .update_interval = xenfb_update_interval,
 969};
 970