qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 402 lines 11 kB view raw
1/* 2 * QEMU Management Protocol commands 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16#include "qemu/osdep.h" 17#include "qemu-common.h" 18#include "qemu/cutils.h" 19#include "qemu/option.h" 20#include "monitor/monitor.h" 21#include "sysemu/sysemu.h" 22#include "qemu/config-file.h" 23#include "qemu/uuid.h" 24#include "chardev/char.h" 25#include "ui/qemu-spice.h" 26#include "ui/vnc.h" 27#include "sysemu/kvm.h" 28#include "sysemu/runstate.h" 29#include "sysemu/arch_init.h" 30#include "sysemu/blockdev.h" 31#include "sysemu/block-backend.h" 32#include "qapi/error.h" 33#include "qapi/qapi-commands-block.h" 34#include "qapi/qapi-commands-control.h" 35#include "qapi/qapi-commands-machine.h" 36#include "qapi/qapi-commands-misc.h" 37#include "qapi/qapi-commands-ui.h" 38#include "qapi/qmp/qerror.h" 39#include "hw/mem/memory-device.h" 40#include "hw/acpi/acpi_dev_interface.h" 41 42NameInfo *qmp_query_name(Error **errp) 43{ 44 NameInfo *info = g_malloc0(sizeof(*info)); 45 46 if (qemu_name) { 47 info->has_name = true; 48 info->name = g_strdup(qemu_name); 49 } 50 51 return info; 52} 53 54KvmInfo *qmp_query_kvm(Error **errp) 55{ 56 KvmInfo *info = g_malloc0(sizeof(*info)); 57 58 info->enabled = kvm_enabled(); 59 info->present = kvm_available(); 60 61 return info; 62} 63 64UuidInfo *qmp_query_uuid(Error **errp) 65{ 66 UuidInfo *info = g_malloc0(sizeof(*info)); 67 68 info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); 69 return info; 70} 71 72void qmp_quit(Error **errp) 73{ 74 no_shutdown = 0; 75 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT); 76} 77 78void qmp_stop(Error **errp) 79{ 80 /* if there is a dump in background, we should wait until the dump 81 * finished */ 82 if (dump_in_progress()) { 83 error_setg(errp, "There is a dump in process, please wait."); 84 return; 85 } 86 87 if (runstate_check(RUN_STATE_INMIGRATE)) { 88 autostart = 0; 89 } else { 90 vm_stop(RUN_STATE_PAUSED); 91 } 92} 93 94void qmp_system_reset(Error **errp) 95{ 96 qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); 97} 98 99void qmp_system_powerdown(Error **errp) 100{ 101 qemu_system_powerdown_request(); 102} 103 104void qmp_x_exit_preconfig(Error **errp) 105{ 106 if (!runstate_check(RUN_STATE_PRECONFIG)) { 107 error_setg(errp, "The command is permitted only in '%s' state", 108 RunState_str(RUN_STATE_PRECONFIG)); 109 return; 110 } 111 qemu_exit_preconfig_request(); 112} 113 114void qmp_cont(Error **errp) 115{ 116 BlockBackend *blk; 117 BlockJob *job; 118 Error *local_err = NULL; 119 120 /* if there is a dump in background, we should wait until the dump 121 * finished */ 122 if (dump_in_progress()) { 123 error_setg(errp, "There is a dump in process, please wait."); 124 return; 125 } 126 127 if (runstate_needs_reset()) { 128 error_setg(errp, "Resetting the Virtual Machine is required"); 129 return; 130 } else if (runstate_check(RUN_STATE_SUSPENDED)) { 131 return; 132 } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { 133 error_setg(errp, "Migration is not finalized yet"); 134 return; 135 } 136 137 for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { 138 blk_iostatus_reset(blk); 139 } 140 141 for (job = block_job_next(NULL); job; job = block_job_next(job)) { 142 block_job_iostatus_reset(job); 143 } 144 145 /* Continuing after completed migration. Images have been inactivated to 146 * allow the destination to take control. Need to get control back now. 147 * 148 * If there are no inactive block nodes (e.g. because the VM was just 149 * paused rather than completing a migration), bdrv_inactivate_all() simply 150 * doesn't do anything. */ 151 bdrv_invalidate_cache_all(&local_err); 152 if (local_err) { 153 error_propagate(errp, local_err); 154 return; 155 } 156 157 if (runstate_check(RUN_STATE_INMIGRATE)) { 158 autostart = 1; 159 } else { 160 vm_start(); 161 } 162} 163 164void qmp_system_wakeup(Error **errp) 165{ 166 if (!qemu_wakeup_suspend_enabled()) { 167 error_setg(errp, 168 "wake-up from suspend is not supported by this guest"); 169 return; 170 } 171 172 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); 173} 174 175void qmp_set_password(const char *protocol, const char *password, 176 bool has_connected, const char *connected, Error **errp) 177{ 178 int disconnect_if_connected = 0; 179 int fail_if_connected = 0; 180 int rc; 181 182 if (has_connected) { 183 if (strcmp(connected, "fail") == 0) { 184 fail_if_connected = 1; 185 } else if (strcmp(connected, "disconnect") == 0) { 186 disconnect_if_connected = 1; 187 } else if (strcmp(connected, "keep") == 0) { 188 /* nothing */ 189 } else { 190 error_setg(errp, QERR_INVALID_PARAMETER, "connected"); 191 return; 192 } 193 } 194 195 if (strcmp(protocol, "spice") == 0) { 196 if (!qemu_using_spice(errp)) { 197 return; 198 } 199 rc = qemu_spice_set_passwd(password, fail_if_connected, 200 disconnect_if_connected); 201 if (rc != 0) { 202 error_setg(errp, QERR_SET_PASSWD_FAILED); 203 } 204 return; 205 } 206 207 if (strcmp(protocol, "vnc") == 0) { 208 if (fail_if_connected || disconnect_if_connected) { 209 /* vnc supports "connected=keep" only */ 210 error_setg(errp, QERR_INVALID_PARAMETER, "connected"); 211 return; 212 } 213 /* Note that setting an empty password will not disable login through 214 * this interface. */ 215 rc = vnc_display_password(NULL, password); 216 if (rc < 0) { 217 error_setg(errp, QERR_SET_PASSWD_FAILED); 218 } 219 return; 220 } 221 222 error_setg(errp, QERR_INVALID_PARAMETER, "protocol"); 223} 224 225void qmp_expire_password(const char *protocol, const char *whenstr, 226 Error **errp) 227{ 228 time_t when; 229 int rc; 230 231 if (strcmp(whenstr, "now") == 0) { 232 when = 0; 233 } else if (strcmp(whenstr, "never") == 0) { 234 when = TIME_MAX; 235 } else if (whenstr[0] == '+') { 236 when = time(NULL) + strtoull(whenstr+1, NULL, 10); 237 } else { 238 when = strtoull(whenstr, NULL, 10); 239 } 240 241 if (strcmp(protocol, "spice") == 0) { 242 if (!qemu_using_spice(errp)) { 243 return; 244 } 245 rc = qemu_spice_set_pw_expire(when); 246 if (rc != 0) { 247 error_setg(errp, QERR_SET_PASSWD_FAILED); 248 } 249 return; 250 } 251 252 if (strcmp(protocol, "vnc") == 0) { 253 rc = vnc_display_pw_expire(NULL, when); 254 if (rc != 0) { 255 error_setg(errp, QERR_SET_PASSWD_FAILED); 256 } 257 return; 258 } 259 260 error_setg(errp, QERR_INVALID_PARAMETER, "protocol"); 261} 262 263#ifdef CONFIG_VNC 264void qmp_change_vnc_password(const char *password, Error **errp) 265{ 266 if (vnc_display_password(NULL, password) < 0) { 267 error_setg(errp, QERR_SET_PASSWD_FAILED); 268 } 269} 270 271static void qmp_change_vnc_listen(const char *target, Error **errp) 272{ 273 QemuOptsList *olist = qemu_find_opts("vnc"); 274 QemuOpts *opts; 275 276 if (strstr(target, "id=")) { 277 error_setg(errp, "id not supported"); 278 return; 279 } 280 281 opts = qemu_opts_find(olist, "default"); 282 if (opts) { 283 qemu_opts_del(opts); 284 } 285 opts = vnc_parse(target, errp); 286 if (!opts) { 287 return; 288 } 289 290 vnc_display_open("default", errp); 291} 292 293static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, 294 Error **errp) 295{ 296 if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) { 297 if (!has_arg) { 298 error_setg(errp, QERR_MISSING_PARAMETER, "password"); 299 } else { 300 qmp_change_vnc_password(arg, errp); 301 } 302 } else { 303 qmp_change_vnc_listen(target, errp); 304 } 305} 306#endif /* !CONFIG_VNC */ 307 308void qmp_change(const char *device, const char *target, 309 bool has_arg, const char *arg, Error **errp) 310{ 311 if (strcmp(device, "vnc") == 0) { 312#ifdef CONFIG_VNC 313 qmp_change_vnc(target, has_arg, arg, errp); 314#else 315 error_setg(errp, QERR_FEATURE_DISABLED, "vnc"); 316#endif 317 } else { 318 qmp_blockdev_change_medium(true, device, false, NULL, target, 319 has_arg, arg, false, 0, errp); 320 } 321} 322 323void qmp_add_client(const char *protocol, const char *fdname, 324 bool has_skipauth, bool skipauth, bool has_tls, bool tls, 325 Error **errp) 326{ 327 Chardev *s; 328 int fd; 329 330 fd = monitor_get_fd(cur_mon, fdname, errp); 331 if (fd < 0) { 332 return; 333 } 334 335 if (strcmp(protocol, "spice") == 0) { 336 if (!qemu_using_spice(errp)) { 337 close(fd); 338 return; 339 } 340 skipauth = has_skipauth ? skipauth : false; 341 tls = has_tls ? tls : false; 342 if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { 343 error_setg(errp, "spice failed to add client"); 344 close(fd); 345 } 346 return; 347#ifdef CONFIG_VNC 348 } else if (strcmp(protocol, "vnc") == 0) { 349 skipauth = has_skipauth ? skipauth : false; 350 vnc_display_add_client(NULL, fd, skipauth); 351 return; 352#endif 353 } else if ((s = qemu_chr_find(protocol)) != NULL) { 354 if (qemu_chr_add_client(s, fd) < 0) { 355 error_setg(errp, "failed to add client"); 356 close(fd); 357 return; 358 } 359 return; 360 } 361 362 error_setg(errp, "protocol '%s' is invalid", protocol); 363 close(fd); 364} 365 366 367MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) 368{ 369 return qmp_memory_device_list(); 370} 371 372ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) 373{ 374 bool ambig; 375 ACPIOSTInfoList *head = NULL; 376 ACPIOSTInfoList **prev = &head; 377 Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig); 378 379 if (obj) { 380 AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); 381 AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); 382 383 adevc->ospm_status(adev, &prev); 384 } else { 385 error_setg(errp, "command is not supported, missing ACPI device"); 386 } 387 388 return head; 389} 390 391MemoryInfo *qmp_query_memory_size_summary(Error **errp) 392{ 393 MemoryInfo *mem_info = g_malloc0(sizeof(MemoryInfo)); 394 395 mem_info->base_memory = ram_size; 396 397 mem_info->plugged_memory = get_plugged_memory_size(); 398 mem_info->has_plugged_memory = 399 mem_info->plugged_memory != (uint64_t)-1; 400 401 return mem_info; 402}