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