qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 541 lines 15 kB view raw
1/* 2 * This work is licensed under the terms of the GNU GPL, version 2 or 3 * (at your option) any later version. See the COPYING file in the 4 * top-level directory. 5 */ 6 7#include "qemu/osdep.h" 8#include "qapi/error.h" 9#include "qemu/config-file.h" 10#include "qemu/main-loop.h" 11#include "qemu/module.h" 12#include "qemu/sockets.h" 13#include "ui/input.h" 14#include "qom/object_interfaces.h" 15#include "sysemu/iothread.h" 16#include "block/aio.h" 17 18#include <sys/ioctl.h> 19#include "standard-headers/linux/input.h" 20 21static bool linux_is_button(unsigned int lnx) 22{ 23 if (lnx < 0x100) { 24 return false; 25 } 26 if (lnx >= 0x160 && lnx < 0x2c0) { 27 return false; 28 } 29 return true; 30} 31 32#define TYPE_INPUT_LINUX "input-linux" 33#define INPUT_LINUX(obj) \ 34 OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX) 35#define INPUT_LINUX_GET_CLASS(obj) \ 36 OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX) 37#define INPUT_LINUX_CLASS(klass) \ 38 OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX) 39 40typedef struct InputLinux InputLinux; 41typedef struct InputLinuxClass InputLinuxClass; 42 43struct InputLinux { 44 Object parent; 45 46 char *evdev; 47 int fd; 48 bool repeat; 49 bool grab_request; 50 bool grab_active; 51 bool grab_all; 52 bool keydown[KEY_CNT]; 53 int keycount; 54 int wheel; 55 bool initialized; 56 57 bool has_rel_x; 58 bool has_abs_x; 59 int num_keys; 60 int num_btns; 61 int abs_x_min; 62 int abs_x_max; 63 int abs_y_min; 64 int abs_y_max; 65 struct input_event event; 66 int read_offset; 67 68 enum GrabToggleKeys grab_toggle; 69 70 QTAILQ_ENTRY(InputLinux) next; 71}; 72 73struct InputLinuxClass { 74 ObjectClass parent_class; 75}; 76 77static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs); 78 79static void input_linux_toggle_grab(InputLinux *il) 80{ 81 intptr_t request = !il->grab_active; 82 InputLinux *item; 83 int rc; 84 85 rc = ioctl(il->fd, EVIOCGRAB, request); 86 if (rc < 0) { 87 return; 88 } 89 il->grab_active = !il->grab_active; 90 91 if (!il->grab_all) { 92 return; 93 } 94 QTAILQ_FOREACH(item, &inputs, next) { 95 if (item == il || item->grab_all) { 96 /* avoid endless loops */ 97 continue; 98 } 99 if (item->grab_active != il->grab_active) { 100 input_linux_toggle_grab(item); 101 } 102 } 103} 104 105static bool input_linux_check_toggle(InputLinux *il) 106{ 107 switch (il->grab_toggle) { 108 case GRAB_TOGGLE_KEYS_CTRL_CTRL: 109 return il->keydown[KEY_LEFTCTRL] && 110 il->keydown[KEY_RIGHTCTRL]; 111 112 case GRAB_TOGGLE_KEYS_ALT_ALT: 113 return il->keydown[KEY_LEFTALT] && 114 il->keydown[KEY_RIGHTALT]; 115 116 case GRAB_TOGGLE_KEYS_SHIFT_SHIFT: 117 return il->keydown[KEY_LEFTSHIFT] && 118 il->keydown[KEY_RIGHTSHIFT]; 119 120 case GRAB_TOGGLE_KEYS_META_META: 121 return il->keydown[KEY_LEFTMETA] && 122 il->keydown[KEY_RIGHTMETA]; 123 124 case GRAB_TOGGLE_KEYS_SCROLLLOCK: 125 return il->keydown[KEY_SCROLLLOCK]; 126 127 case GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK: 128 return (il->keydown[KEY_LEFTCTRL] || 129 il->keydown[KEY_RIGHTCTRL]) && 130 il->keydown[KEY_SCROLLLOCK]; 131 132 case GRAB_TOGGLE_KEYS__MAX: 133 /* avoid gcc error */ 134 break; 135 } 136 return false; 137} 138 139static bool input_linux_should_skip(InputLinux *il, 140 struct input_event *event) 141{ 142 return (il->grab_toggle == GRAB_TOGGLE_KEYS_SCROLLLOCK || 143 il->grab_toggle == GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK) && 144 event->code == KEY_SCROLLLOCK; 145} 146 147static void input_linux_handle_keyboard(InputLinux *il, 148 struct input_event *event) 149{ 150 if (event->type == EV_KEY) { 151 if (event->value > 2 || (event->value > 1 && !il->repeat)) { 152 /* 153 * ignore autorepeat + unknown key events 154 * 0 == up, 1 == down, 2 == autorepeat, other == undefined 155 */ 156 return; 157 } 158 if (event->code >= KEY_CNT) { 159 /* 160 * Should not happen. But better safe than sorry, 161 * and we make Coverity happy too. 162 */ 163 return; 164 } 165 166 /* keep track of key state */ 167 if (!il->keydown[event->code] && event->value) { 168 il->keydown[event->code] = true; 169 il->keycount++; 170 } 171 if (il->keydown[event->code] && !event->value) { 172 il->keydown[event->code] = false; 173 il->keycount--; 174 } 175 176 /* send event to guest when grab is active */ 177 if (il->grab_active && !input_linux_should_skip(il, event)) { 178 int qcode = qemu_input_linux_to_qcode(event->code); 179 qemu_input_event_send_key_qcode(NULL, qcode, event->value); 180 } 181 182 /* hotkey -> record switch request ... */ 183 if (input_linux_check_toggle(il)) { 184 il->grab_request = true; 185 } 186 187 /* 188 * ... and do the switch when all keys are lifted, so we 189 * confuse neither guest nor host with keys which seem to 190 * be stuck due to missing key-up events. 191 */ 192 if (il->grab_request && !il->keycount) { 193 il->grab_request = false; 194 input_linux_toggle_grab(il); 195 } 196 } 197} 198 199static void input_linux_event_mouse_button(int button) 200{ 201 qemu_input_queue_btn(NULL, button, true); 202 qemu_input_event_sync(); 203 qemu_input_queue_btn(NULL, button, false); 204 qemu_input_event_sync(); 205} 206 207static void input_linux_handle_mouse(InputLinux *il, struct input_event *event) 208{ 209 if (!il->grab_active) { 210 return; 211 } 212 213 switch (event->type) { 214 case EV_KEY: 215 switch (event->code) { 216 case BTN_LEFT: 217 qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event->value); 218 break; 219 case BTN_RIGHT: 220 qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event->value); 221 break; 222 case BTN_MIDDLE: 223 qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event->value); 224 break; 225 case BTN_GEAR_UP: 226 qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event->value); 227 break; 228 case BTN_GEAR_DOWN: 229 qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN, 230 event->value); 231 break; 232 case BTN_SIDE: 233 qemu_input_queue_btn(NULL, INPUT_BUTTON_SIDE, event->value); 234 break; 235 case BTN_EXTRA: 236 qemu_input_queue_btn(NULL, INPUT_BUTTON_EXTRA, event->value); 237 break; 238 }; 239 break; 240 case EV_REL: 241 switch (event->code) { 242 case REL_X: 243 qemu_input_queue_rel(NULL, INPUT_AXIS_X, event->value); 244 break; 245 case REL_Y: 246 qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event->value); 247 break; 248 case REL_WHEEL: 249 il->wheel = event->value; 250 break; 251 } 252 break; 253 case EV_ABS: 254 switch (event->code) { 255 case ABS_X: 256 qemu_input_queue_abs(NULL, INPUT_AXIS_X, event->value, 257 il->abs_x_min, il->abs_x_max); 258 break; 259 case ABS_Y: 260 qemu_input_queue_abs(NULL, INPUT_AXIS_Y, event->value, 261 il->abs_y_min, il->abs_y_max); 262 break; 263 } 264 break; 265 case EV_SYN: 266 qemu_input_event_sync(); 267 if (il->wheel != 0) { 268 input_linux_event_mouse_button((il->wheel > 0) 269 ? INPUT_BUTTON_WHEEL_UP 270 : INPUT_BUTTON_WHEEL_DOWN); 271 il->wheel = 0; 272 } 273 break; 274 } 275} 276 277static void input_linux_event(void *opaque) 278{ 279 InputLinux *il = opaque; 280 int rc; 281 int read_size; 282 uint8_t *p = (uint8_t *)&il->event; 283 284 for (;;) { 285 read_size = sizeof(il->event) - il->read_offset; 286 rc = read(il->fd, &p[il->read_offset], read_size); 287 if (rc != read_size) { 288 if (rc < 0 && errno != EAGAIN) { 289 fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); 290 qemu_set_fd_handler(il->fd, NULL, NULL, NULL); 291 close(il->fd); 292 } else if (rc > 0) { 293 il->read_offset += rc; 294 } 295 break; 296 } 297 il->read_offset = 0; 298 299 if (il->num_keys) { 300 input_linux_handle_keyboard(il, &il->event); 301 } 302 if ((il->has_rel_x || il->has_abs_x) && il->num_btns) { 303 input_linux_handle_mouse(il, &il->event); 304 } 305 } 306} 307 308static void input_linux_complete(UserCreatable *uc, Error **errp) 309{ 310 InputLinux *il = INPUT_LINUX(uc); 311 uint8_t evtmap, relmap, absmap; 312 uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8]; 313 unsigned int i; 314 int rc, ver; 315 struct input_absinfo absinfo; 316 317 if (!il->evdev) { 318 error_setg(errp, "no input device specified"); 319 return; 320 } 321 322 il->fd = open(il->evdev, O_RDWR); 323 if (il->fd < 0) { 324 error_setg_file_open(errp, errno, il->evdev); 325 return; 326 } 327 qemu_set_nonblock(il->fd); 328 329 rc = ioctl(il->fd, EVIOCGVERSION, &ver); 330 if (rc < 0) { 331 error_setg(errp, "%s: is not an evdev device", il->evdev); 332 goto err_close; 333 } 334 335 rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); 336 if (rc < 0) { 337 goto err_read_event_bits; 338 } 339 340 if (evtmap & (1 << EV_REL)) { 341 relmap = 0; 342 rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); 343 if (rc < 0) { 344 goto err_read_event_bits; 345 } 346 if (relmap & (1 << REL_X)) { 347 il->has_rel_x = true; 348 } 349 } 350 351 if (evtmap & (1 << EV_ABS)) { 352 absmap = 0; 353 rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); 354 if (rc < 0) { 355 goto err_read_event_bits; 356 } 357 if (absmap & (1 << ABS_X)) { 358 il->has_abs_x = true; 359 rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo); 360 if (rc < 0) { 361 error_setg(errp, "%s: failed to get get absolute X value", 362 il->evdev); 363 goto err_close; 364 } 365 il->abs_x_min = absinfo.minimum; 366 il->abs_x_max = absinfo.maximum; 367 rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo); 368 if (rc < 0) { 369 error_setg(errp, "%s: failed to get get absolute Y value", 370 il->evdev); 371 goto err_close; 372 } 373 il->abs_y_min = absinfo.minimum; 374 il->abs_y_max = absinfo.maximum; 375 } 376 } 377 378 if (evtmap & (1 << EV_KEY)) { 379 memset(keymap, 0, sizeof(keymap)); 380 rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap); 381 if (rc < 0) { 382 goto err_read_event_bits; 383 } 384 rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate); 385 if (rc < 0) { 386 error_setg(errp, "%s: failed to get global key state", il->evdev); 387 goto err_close; 388 } 389 for (i = 0; i < KEY_CNT; i++) { 390 if (keymap[i / 8] & (1 << (i % 8))) { 391 if (linux_is_button(i)) { 392 il->num_btns++; 393 } else { 394 il->num_keys++; 395 } 396 if (keystate[i / 8] & (1 << (i % 8))) { 397 il->keydown[i] = true; 398 il->keycount++; 399 } 400 } 401 } 402 } 403 404 qemu_set_fd_handler(il->fd, input_linux_event, NULL, il); 405 if (il->keycount) { 406 /* delay grab until all keys are released */ 407 il->grab_request = true; 408 } else { 409 input_linux_toggle_grab(il); 410 } 411 QTAILQ_INSERT_TAIL(&inputs, il, next); 412 il->initialized = true; 413 return; 414 415err_read_event_bits: 416 error_setg(errp, "%s: failed to read event bits", il->evdev); 417 418err_close: 419 close(il->fd); 420 return; 421} 422 423static void input_linux_instance_finalize(Object *obj) 424{ 425 InputLinux *il = INPUT_LINUX(obj); 426 427 if (il->initialized) { 428 QTAILQ_REMOVE(&inputs, il, next); 429 close(il->fd); 430 } 431 g_free(il->evdev); 432} 433 434static char *input_linux_get_evdev(Object *obj, Error **errp) 435{ 436 InputLinux *il = INPUT_LINUX(obj); 437 438 return g_strdup(il->evdev); 439} 440 441static void input_linux_set_evdev(Object *obj, const char *value, 442 Error **errp) 443{ 444 InputLinux *il = INPUT_LINUX(obj); 445 446 if (il->evdev) { 447 error_setg(errp, "evdev property already set"); 448 return; 449 } 450 il->evdev = g_strdup(value); 451} 452 453static bool input_linux_get_grab_all(Object *obj, Error **errp) 454{ 455 InputLinux *il = INPUT_LINUX(obj); 456 457 return il->grab_all; 458} 459 460static void input_linux_set_grab_all(Object *obj, bool value, 461 Error **errp) 462{ 463 InputLinux *il = INPUT_LINUX(obj); 464 465 il->grab_all = value; 466} 467 468static bool input_linux_get_repeat(Object *obj, Error **errp) 469{ 470 InputLinux *il = INPUT_LINUX(obj); 471 472 return il->repeat; 473} 474 475static void input_linux_set_repeat(Object *obj, bool value, 476 Error **errp) 477{ 478 InputLinux *il = INPUT_LINUX(obj); 479 480 il->repeat = value; 481} 482 483static int input_linux_get_grab_toggle(Object *obj, Error **errp) 484{ 485 InputLinux *il = INPUT_LINUX(obj); 486 487 return il->grab_toggle; 488} 489 490static void input_linux_set_grab_toggle(Object *obj, int value, 491 Error **errp) 492{ 493 InputLinux *il = INPUT_LINUX(obj); 494 495 il->grab_toggle = value; 496} 497 498static void input_linux_instance_init(Object *obj) 499{ 500 object_property_add_str(obj, "evdev", 501 input_linux_get_evdev, 502 input_linux_set_evdev); 503 object_property_add_bool(obj, "grab_all", 504 input_linux_get_grab_all, 505 input_linux_set_grab_all); 506 object_property_add_bool(obj, "repeat", 507 input_linux_get_repeat, 508 input_linux_set_repeat); 509 object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys", 510 &GrabToggleKeys_lookup, 511 input_linux_get_grab_toggle, 512 input_linux_set_grab_toggle); 513} 514 515static void input_linux_class_init(ObjectClass *oc, void *data) 516{ 517 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 518 519 ucc->complete = input_linux_complete; 520} 521 522static const TypeInfo input_linux_info = { 523 .name = TYPE_INPUT_LINUX, 524 .parent = TYPE_OBJECT, 525 .class_size = sizeof(InputLinuxClass), 526 .class_init = input_linux_class_init, 527 .instance_size = sizeof(InputLinux), 528 .instance_init = input_linux_instance_init, 529 .instance_finalize = input_linux_instance_finalize, 530 .interfaces = (InterfaceInfo[]) { 531 { TYPE_USER_CREATABLE }, 532 { } 533 } 534}; 535 536static void register_types(void) 537{ 538 type_register_static(&input_linux_info); 539} 540 541type_init(register_types);