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