cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

spice-input.c (7805B)


      1/*
      2 * Copyright (C) 2010 Red Hat, Inc.
      3 *
      4 * This program is free software; you can redistribute it and/or
      5 * modify it under the terms of the GNU General Public License as
      6 * published by the Free Software Foundation; either version 2 or
      7 * (at your option) version 3 of the License.
      8 *
      9 * This program is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "qemu/osdep.h"
     19
     20#include <spice.h>
     21#include <spice/enums.h>
     22
     23#include "ui/qemu-spice.h"
     24#include "ui/console.h"
     25#include "keymaps.h"
     26#include "ui/input.h"
     27
     28/* keyboard bits */
     29
     30typedef struct QemuSpiceKbd {
     31    SpiceKbdInstance sin;
     32    int ledstate;
     33    bool emul0;
     34    size_t pauseseq;
     35} QemuSpiceKbd;
     36
     37static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
     38static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
     39
     40static const SpiceKbdInterface kbd_interface = {
     41    .base.type          = SPICE_INTERFACE_KEYBOARD,
     42    .base.description   = "qemu keyboard",
     43    .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
     44    .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
     45    .push_scan_freg     = kbd_push_key,
     46    .get_leds           = kbd_get_leds,
     47};
     48
     49static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
     50{
     51    static const uint8_t pauseseq[] = { 0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5 };
     52    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
     53    int keycode;
     54    bool up;
     55
     56    if (scancode == SCANCODE_EMUL0) {
     57        kbd->emul0 = true;
     58        return;
     59    }
     60
     61    if (scancode == pauseseq[kbd->pauseseq]) {
     62        kbd->pauseseq++;
     63        if (kbd->pauseseq == G_N_ELEMENTS(pauseseq)) {
     64            qemu_input_event_send_key_qcode(NULL, Q_KEY_CODE_PAUSE, true);
     65            kbd->pauseseq = 0;
     66        }
     67        return;
     68    } else {
     69        kbd->pauseseq = 0;
     70    }
     71
     72    keycode = scancode & ~SCANCODE_UP;
     73    up = scancode & SCANCODE_UP;
     74    if (kbd->emul0) {
     75        kbd->emul0 = false;
     76        keycode |= SCANCODE_GREY;
     77    }
     78
     79    qemu_input_event_send_key_number(NULL, keycode, !up);
     80}
     81
     82static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
     83{
     84    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
     85    return kbd->ledstate;
     86}
     87
     88static void kbd_leds(void *opaque, int ledstate)
     89{
     90    QemuSpiceKbd *kbd = opaque;
     91
     92    kbd->ledstate = 0;
     93    if (ledstate & QEMU_SCROLL_LOCK_LED) {
     94        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
     95    }
     96    if (ledstate & QEMU_NUM_LOCK_LED) {
     97        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
     98    }
     99    if (ledstate & QEMU_CAPS_LOCK_LED) {
    100        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
    101    }
    102    spice_server_kbd_leds(&kbd->sin, kbd->ledstate);
    103}
    104
    105/* mouse bits */
    106
    107typedef struct QemuSpicePointer {
    108    SpiceMouseInstance  mouse;
    109    SpiceTabletInstance tablet;
    110    int width, height;
    111    uint32_t last_bmask;
    112    Notifier mouse_mode;
    113    bool absolute;
    114} QemuSpicePointer;
    115
    116static void spice_update_buttons(QemuSpicePointer *pointer,
    117                                 int wheel, uint32_t button_mask)
    118{
    119    static uint32_t bmap[INPUT_BUTTON__MAX] = {
    120        [INPUT_BUTTON_LEFT]        = 0x01,
    121        [INPUT_BUTTON_MIDDLE]      = 0x04,
    122        [INPUT_BUTTON_RIGHT]       = 0x02,
    123        [INPUT_BUTTON_WHEEL_UP]    = 0x10,
    124        [INPUT_BUTTON_WHEEL_DOWN]  = 0x20,
    125        [INPUT_BUTTON_SIDE]        = 0x40,
    126        [INPUT_BUTTON_EXTRA]       = 0x80,
    127    };
    128
    129    if (wheel < 0) {
    130        button_mask |= 0x10;
    131    }
    132    if (wheel > 0) {
    133        button_mask |= 0x20;
    134    }
    135
    136    if (pointer->last_bmask == button_mask) {
    137        return;
    138    }
    139    qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask);
    140    pointer->last_bmask = button_mask;
    141}
    142
    143static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
    144                         uint32_t buttons_state)
    145{
    146    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
    147    spice_update_buttons(pointer, dz, buttons_state);
    148    qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
    149    qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
    150    qemu_input_event_sync();
    151}
    152
    153static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
    154{
    155    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
    156    spice_update_buttons(pointer, 0, buttons_state);
    157    qemu_input_event_sync();
    158}
    159
    160static const SpiceMouseInterface mouse_interface = {
    161    .base.type          = SPICE_INTERFACE_MOUSE,
    162    .base.description   = "mouse",
    163    .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
    164    .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
    165    .motion             = mouse_motion,
    166    .buttons            = mouse_buttons,
    167};
    168
    169static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
    170{
    171    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
    172
    173    if (height < 16) {
    174        height = 16;
    175    }
    176    if (width < 16) {
    177        width = 16;
    178    }
    179    pointer->width  = width;
    180    pointer->height = height;
    181}
    182
    183static void tablet_position(SpiceTabletInstance* sin, int x, int y,
    184                            uint32_t buttons_state)
    185{
    186    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
    187
    188    spice_update_buttons(pointer, 0, buttons_state);
    189    qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, 0, pointer->width);
    190    qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, 0, pointer->height);
    191    qemu_input_event_sync();
    192}
    193
    194
    195static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
    196                         uint32_t buttons_state)
    197{
    198    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
    199
    200    spice_update_buttons(pointer, wheel, buttons_state);
    201    qemu_input_event_sync();
    202}
    203
    204static void tablet_buttons(SpiceTabletInstance *sin,
    205                           uint32_t buttons_state)
    206{
    207    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
    208
    209    spice_update_buttons(pointer, 0, buttons_state);
    210    qemu_input_event_sync();
    211}
    212
    213static const SpiceTabletInterface tablet_interface = {
    214    .base.type          = SPICE_INTERFACE_TABLET,
    215    .base.description   = "tablet",
    216    .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
    217    .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
    218    .set_logical_size   = tablet_set_logical_size,
    219    .position           = tablet_position,
    220    .wheel              = tablet_wheel,
    221    .buttons            = tablet_buttons,
    222};
    223
    224static void mouse_mode_notifier(Notifier *notifier, void *data)
    225{
    226    QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
    227    bool is_absolute  = qemu_input_is_absolute();
    228
    229    if (pointer->absolute == is_absolute) {
    230        return;
    231    }
    232
    233    if (is_absolute) {
    234        qemu_spice.add_interface(&pointer->tablet.base);
    235    } else {
    236        spice_server_remove_interface(&pointer->tablet.base);
    237    }
    238    pointer->absolute = is_absolute;
    239}
    240
    241void qemu_spice_input_init(void)
    242{
    243    QemuSpiceKbd *kbd;
    244    QemuSpicePointer *pointer;
    245
    246    kbd = g_malloc0(sizeof(*kbd));
    247    kbd->sin.base.sif = &kbd_interface.base;
    248    qemu_spice.add_interface(&kbd->sin.base);
    249    qemu_add_led_event_handler(kbd_leds, kbd);
    250
    251    pointer = g_malloc0(sizeof(*pointer));
    252    pointer->mouse.base.sif  = &mouse_interface.base;
    253    pointer->tablet.base.sif = &tablet_interface.base;
    254    qemu_spice.add_interface(&pointer->mouse.base);
    255
    256    pointer->absolute = false;
    257    pointer->mouse_mode.notify = mouse_mode_notifier;
    258    qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
    259    mouse_mode_notifier(&pointer->mouse_mode, NULL);
    260}