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