qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xenfb.c (31929B)


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