2
0

qmp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * QEMU Management Protocol
  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. #include "qemu/osdep.h"
  16. #include "qemu-version.h"
  17. #include "qemu/cutils.h"
  18. #include "monitor/monitor.h"
  19. #include "sysemu/sysemu.h"
  20. #include "qemu/config-file.h"
  21. #include "qemu/uuid.h"
  22. #include "qmp-commands.h"
  23. #include "chardev/char.h"
  24. #include "ui/qemu-spice.h"
  25. #include "ui/vnc.h"
  26. #include "sysemu/kvm.h"
  27. #include "sysemu/arch_init.h"
  28. #include "hw/qdev.h"
  29. #include "sysemu/blockdev.h"
  30. #include "sysemu/block-backend.h"
  31. #include "qom/qom-qobject.h"
  32. #include "qapi/qmp/qerror.h"
  33. #include "qapi/qmp/qobject.h"
  34. #include "qapi/qobject-input-visitor.h"
  35. #include "hw/boards.h"
  36. #include "qom/object_interfaces.h"
  37. #include "hw/mem/pc-dimm.h"
  38. #include "hw/acpi/acpi_dev_interface.h"
  39. NameInfo *qmp_query_name(Error **errp)
  40. {
  41. NameInfo *info = g_malloc0(sizeof(*info));
  42. if (qemu_name) {
  43. info->has_name = true;
  44. info->name = g_strdup(qemu_name);
  45. }
  46. return info;
  47. }
  48. VersionInfo *qmp_query_version(Error **errp)
  49. {
  50. VersionInfo *info = g_new0(VersionInfo, 1);
  51. info->qemu = g_new0(VersionTriple, 1);
  52. info->qemu->major = QEMU_VERSION_MAJOR;
  53. info->qemu->minor = QEMU_VERSION_MINOR;
  54. info->qemu->micro = QEMU_VERSION_MICRO;
  55. info->package = g_strdup(QEMU_PKGVERSION);
  56. return info;
  57. }
  58. KvmInfo *qmp_query_kvm(Error **errp)
  59. {
  60. KvmInfo *info = g_malloc0(sizeof(*info));
  61. info->enabled = kvm_enabled();
  62. info->present = kvm_available();
  63. return info;
  64. }
  65. UuidInfo *qmp_query_uuid(Error **errp)
  66. {
  67. UuidInfo *info = g_malloc0(sizeof(*info));
  68. info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid);
  69. return info;
  70. }
  71. void qmp_quit(Error **errp)
  72. {
  73. no_shutdown = 0;
  74. qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP);
  75. }
  76. void qmp_stop(Error **errp)
  77. {
  78. /* if there is a dump in background, we should wait until the dump
  79. * finished */
  80. if (dump_in_progress()) {
  81. error_setg(errp, "There is a dump in process, please wait.");
  82. return;
  83. }
  84. if (runstate_check(RUN_STATE_INMIGRATE)) {
  85. autostart = 0;
  86. } else {
  87. vm_stop(RUN_STATE_PAUSED);
  88. }
  89. }
  90. void qmp_system_reset(Error **errp)
  91. {
  92. qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP);
  93. }
  94. void qmp_system_powerdown(Error **erp)
  95. {
  96. qemu_system_powerdown_request();
  97. }
  98. void qmp_cpu(int64_t index, Error **errp)
  99. {
  100. /* Just do nothing */
  101. }
  102. void qmp_cpu_add(int64_t id, Error **errp)
  103. {
  104. MachineClass *mc;
  105. mc = MACHINE_GET_CLASS(current_machine);
  106. if (mc->hot_add_cpu) {
  107. mc->hot_add_cpu(id, errp);
  108. } else {
  109. error_setg(errp, "Not supported");
  110. }
  111. }
  112. #ifndef CONFIG_VNC
  113. /* If VNC support is enabled, the "true" query-vnc command is
  114. defined in the VNC subsystem */
  115. VncInfo *qmp_query_vnc(Error **errp)
  116. {
  117. error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
  118. return NULL;
  119. };
  120. VncInfo2List *qmp_query_vnc_servers(Error **errp)
  121. {
  122. error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
  123. return NULL;
  124. };
  125. #endif
  126. #ifndef CONFIG_SPICE
  127. /*
  128. * qmp-commands.hx ensures that QMP command query-spice exists only
  129. * #ifdef CONFIG_SPICE. Necessary for an accurate query-commands
  130. * result. However, the QAPI schema is blissfully unaware of that,
  131. * and the QAPI code generator happily generates a dead
  132. * qmp_marshal_query_spice() that calls qmp_query_spice(). Provide it
  133. * one, or else linking fails. FIXME Educate the QAPI schema on
  134. * CONFIG_SPICE.
  135. */
  136. SpiceInfo *qmp_query_spice(Error **errp)
  137. {
  138. abort();
  139. };
  140. #endif
  141. void qmp_cont(Error **errp)
  142. {
  143. BlockBackend *blk;
  144. Error *local_err = NULL;
  145. /* if there is a dump in background, we should wait until the dump
  146. * finished */
  147. if (dump_in_progress()) {
  148. error_setg(errp, "There is a dump in process, please wait.");
  149. return;
  150. }
  151. if (runstate_needs_reset()) {
  152. error_setg(errp, "Resetting the Virtual Machine is required");
  153. return;
  154. } else if (runstate_check(RUN_STATE_SUSPENDED)) {
  155. return;
  156. }
  157. for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
  158. blk_iostatus_reset(blk);
  159. }
  160. /* Continuing after completed migration. Images have been inactivated to
  161. * allow the destination to take control. Need to get control back now.
  162. *
  163. * If there are no inactive block nodes (e.g. because the VM was just
  164. * paused rather than completing a migration), bdrv_inactivate_all() simply
  165. * doesn't do anything. */
  166. bdrv_invalidate_cache_all(&local_err);
  167. if (local_err) {
  168. error_propagate(errp, local_err);
  169. return;
  170. }
  171. if (runstate_check(RUN_STATE_INMIGRATE)) {
  172. autostart = 1;
  173. } else {
  174. vm_start();
  175. }
  176. }
  177. void qmp_system_wakeup(Error **errp)
  178. {
  179. qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
  180. }
  181. ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
  182. {
  183. Object *obj;
  184. bool ambiguous = false;
  185. ObjectPropertyInfoList *props = NULL;
  186. ObjectProperty *prop;
  187. ObjectPropertyIterator iter;
  188. obj = object_resolve_path(path, &ambiguous);
  189. if (obj == NULL) {
  190. if (ambiguous) {
  191. error_setg(errp, "Path '%s' is ambiguous", path);
  192. } else {
  193. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  194. "Device '%s' not found", path);
  195. }
  196. return NULL;
  197. }
  198. object_property_iter_init(&iter, obj);
  199. while ((prop = object_property_iter_next(&iter))) {
  200. ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
  201. entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
  202. entry->next = props;
  203. props = entry;
  204. entry->value->name = g_strdup(prop->name);
  205. entry->value->type = g_strdup(prop->type);
  206. }
  207. return props;
  208. }
  209. void qmp_qom_set(const char *path, const char *property, QObject *value,
  210. Error **errp)
  211. {
  212. Object *obj;
  213. obj = object_resolve_path(path, NULL);
  214. if (!obj) {
  215. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  216. "Device '%s' not found", path);
  217. return;
  218. }
  219. object_property_set_qobject(obj, value, property, errp);
  220. }
  221. QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
  222. {
  223. Object *obj;
  224. obj = object_resolve_path(path, NULL);
  225. if (!obj) {
  226. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  227. "Device '%s' not found", path);
  228. return NULL;
  229. }
  230. return object_property_get_qobject(obj, property, errp);
  231. }
  232. void qmp_set_password(const char *protocol, const char *password,
  233. bool has_connected, const char *connected, Error **errp)
  234. {
  235. int disconnect_if_connected = 0;
  236. int fail_if_connected = 0;
  237. int rc;
  238. if (has_connected) {
  239. if (strcmp(connected, "fail") == 0) {
  240. fail_if_connected = 1;
  241. } else if (strcmp(connected, "disconnect") == 0) {
  242. disconnect_if_connected = 1;
  243. } else if (strcmp(connected, "keep") == 0) {
  244. /* nothing */
  245. } else {
  246. error_setg(errp, QERR_INVALID_PARAMETER, "connected");
  247. return;
  248. }
  249. }
  250. if (strcmp(protocol, "spice") == 0) {
  251. if (!qemu_using_spice(errp)) {
  252. return;
  253. }
  254. rc = qemu_spice_set_passwd(password, fail_if_connected,
  255. disconnect_if_connected);
  256. if (rc != 0) {
  257. error_setg(errp, QERR_SET_PASSWD_FAILED);
  258. }
  259. return;
  260. }
  261. if (strcmp(protocol, "vnc") == 0) {
  262. if (fail_if_connected || disconnect_if_connected) {
  263. /* vnc supports "connected=keep" only */
  264. error_setg(errp, QERR_INVALID_PARAMETER, "connected");
  265. return;
  266. }
  267. /* Note that setting an empty password will not disable login through
  268. * this interface. */
  269. rc = vnc_display_password(NULL, password);
  270. if (rc < 0) {
  271. error_setg(errp, QERR_SET_PASSWD_FAILED);
  272. }
  273. return;
  274. }
  275. error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
  276. }
  277. void qmp_expire_password(const char *protocol, const char *whenstr,
  278. Error **errp)
  279. {
  280. time_t when;
  281. int rc;
  282. if (strcmp(whenstr, "now") == 0) {
  283. when = 0;
  284. } else if (strcmp(whenstr, "never") == 0) {
  285. when = TIME_MAX;
  286. } else if (whenstr[0] == '+') {
  287. when = time(NULL) + strtoull(whenstr+1, NULL, 10);
  288. } else {
  289. when = strtoull(whenstr, NULL, 10);
  290. }
  291. if (strcmp(protocol, "spice") == 0) {
  292. if (!qemu_using_spice(errp)) {
  293. return;
  294. }
  295. rc = qemu_spice_set_pw_expire(when);
  296. if (rc != 0) {
  297. error_setg(errp, QERR_SET_PASSWD_FAILED);
  298. }
  299. return;
  300. }
  301. if (strcmp(protocol, "vnc") == 0) {
  302. rc = vnc_display_pw_expire(NULL, when);
  303. if (rc != 0) {
  304. error_setg(errp, QERR_SET_PASSWD_FAILED);
  305. }
  306. return;
  307. }
  308. error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
  309. }
  310. #ifdef CONFIG_VNC
  311. void qmp_change_vnc_password(const char *password, Error **errp)
  312. {
  313. if (vnc_display_password(NULL, password) < 0) {
  314. error_setg(errp, QERR_SET_PASSWD_FAILED);
  315. }
  316. }
  317. static void qmp_change_vnc_listen(const char *target, Error **errp)
  318. {
  319. QemuOptsList *olist = qemu_find_opts("vnc");
  320. QemuOpts *opts;
  321. if (strstr(target, "id=")) {
  322. error_setg(errp, "id not supported");
  323. return;
  324. }
  325. opts = qemu_opts_find(olist, "default");
  326. if (opts) {
  327. qemu_opts_del(opts);
  328. }
  329. opts = vnc_parse(target, errp);
  330. if (!opts) {
  331. return;
  332. }
  333. vnc_display_open("default", errp);
  334. }
  335. static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
  336. Error **errp)
  337. {
  338. if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
  339. if (!has_arg) {
  340. error_setg(errp, QERR_MISSING_PARAMETER, "password");
  341. } else {
  342. qmp_change_vnc_password(arg, errp);
  343. }
  344. } else {
  345. qmp_change_vnc_listen(target, errp);
  346. }
  347. }
  348. #else
  349. void qmp_change_vnc_password(const char *password, Error **errp)
  350. {
  351. error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
  352. }
  353. static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
  354. Error **errp)
  355. {
  356. error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
  357. }
  358. #endif /* !CONFIG_VNC */
  359. void qmp_change(const char *device, const char *target,
  360. bool has_arg, const char *arg, Error **errp)
  361. {
  362. if (strcmp(device, "vnc") == 0) {
  363. qmp_change_vnc(target, has_arg, arg, errp);
  364. } else {
  365. qmp_blockdev_change_medium(true, device, false, NULL, target,
  366. has_arg, arg, false, 0, errp);
  367. }
  368. }
  369. static void qom_list_types_tramp(ObjectClass *klass, void *data)
  370. {
  371. ObjectTypeInfoList *e, **pret = data;
  372. ObjectTypeInfo *info;
  373. ObjectClass *parent = object_class_get_parent(klass);
  374. info = g_malloc0(sizeof(*info));
  375. info->name = g_strdup(object_class_get_name(klass));
  376. info->has_abstract = info->abstract = object_class_is_abstract(klass);
  377. if (parent) {
  378. info->has_parent = true;
  379. info->parent = g_strdup(object_class_get_name(parent));
  380. }
  381. e = g_malloc0(sizeof(*e));
  382. e->value = info;
  383. e->next = *pret;
  384. *pret = e;
  385. }
  386. ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
  387. const char *implements,
  388. bool has_abstract,
  389. bool abstract,
  390. Error **errp)
  391. {
  392. ObjectTypeInfoList *ret = NULL;
  393. object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
  394. return ret;
  395. }
  396. /* Return a DevicePropertyInfo for a qdev property.
  397. *
  398. * If a qdev property with the given name does not exist, use the given default
  399. * type. If the qdev property info should not be shown, return NULL.
  400. *
  401. * The caller must free the return value.
  402. */
  403. static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
  404. const char *name,
  405. const char *default_type,
  406. const char *description)
  407. {
  408. DevicePropertyInfo *info;
  409. Property *prop;
  410. do {
  411. for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
  412. if (strcmp(name, prop->name) != 0) {
  413. continue;
  414. }
  415. /*
  416. * TODO Properties without a parser are just for dirty hacks.
  417. * qdev_prop_ptr is the only such PropertyInfo. It's marked
  418. * for removal. This conditional should be removed along with
  419. * it.
  420. */
  421. if (!prop->info->set && !prop->info->create) {
  422. return NULL; /* no way to set it, don't show */
  423. }
  424. info = g_malloc0(sizeof(*info));
  425. info->name = g_strdup(prop->name);
  426. info->type = default_type ? g_strdup(default_type)
  427. : g_strdup(prop->info->name);
  428. info->has_description = !!prop->info->description;
  429. info->description = g_strdup(prop->info->description);
  430. return info;
  431. }
  432. klass = object_class_get_parent(klass);
  433. } while (klass != object_class_by_name(TYPE_DEVICE));
  434. /* Not a qdev property, use the default type */
  435. info = g_malloc0(sizeof(*info));
  436. info->name = g_strdup(name);
  437. info->type = g_strdup(default_type);
  438. info->has_description = !!description;
  439. info->description = g_strdup(description);
  440. return info;
  441. }
  442. DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
  443. Error **errp)
  444. {
  445. ObjectClass *klass;
  446. Object *obj;
  447. ObjectProperty *prop;
  448. ObjectPropertyIterator iter;
  449. DevicePropertyInfoList *prop_list = NULL;
  450. klass = object_class_by_name(typename);
  451. if (klass == NULL) {
  452. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  453. "Device '%s' not found", typename);
  454. return NULL;
  455. }
  456. klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
  457. if (klass == NULL) {
  458. error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_DEVICE);
  459. return NULL;
  460. }
  461. if (object_class_is_abstract(klass)) {
  462. error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename",
  463. "non-abstract device type");
  464. return NULL;
  465. }
  466. obj = object_new(typename);
  467. object_property_iter_init(&iter, obj);
  468. while ((prop = object_property_iter_next(&iter))) {
  469. DevicePropertyInfo *info;
  470. DevicePropertyInfoList *entry;
  471. /* Skip Object and DeviceState properties */
  472. if (strcmp(prop->name, "type") == 0 ||
  473. strcmp(prop->name, "realized") == 0 ||
  474. strcmp(prop->name, "hotpluggable") == 0 ||
  475. strcmp(prop->name, "hotplugged") == 0 ||
  476. strcmp(prop->name, "parent_bus") == 0) {
  477. continue;
  478. }
  479. /* Skip legacy properties since they are just string versions of
  480. * properties that we already list.
  481. */
  482. if (strstart(prop->name, "legacy-", NULL)) {
  483. continue;
  484. }
  485. info = make_device_property_info(klass, prop->name, prop->type,
  486. prop->description);
  487. if (!info) {
  488. continue;
  489. }
  490. entry = g_malloc0(sizeof(*entry));
  491. entry->value = info;
  492. entry->next = prop_list;
  493. prop_list = entry;
  494. }
  495. object_unref(obj);
  496. return prop_list;
  497. }
  498. CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
  499. {
  500. return arch_query_cpu_definitions(errp);
  501. }
  502. CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
  503. CpuModelInfo *model,
  504. Error **errp)
  505. {
  506. return arch_query_cpu_model_expansion(type, model, errp);
  507. }
  508. CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *modela,
  509. CpuModelInfo *modelb,
  510. Error **errp)
  511. {
  512. return arch_query_cpu_model_comparison(modela, modelb, errp);
  513. }
  514. CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *modela,
  515. CpuModelInfo *modelb,
  516. Error **errp)
  517. {
  518. return arch_query_cpu_model_baseline(modela, modelb, errp);
  519. }
  520. void qmp_add_client(const char *protocol, const char *fdname,
  521. bool has_skipauth, bool skipauth, bool has_tls, bool tls,
  522. Error **errp)
  523. {
  524. Chardev *s;
  525. int fd;
  526. fd = monitor_get_fd(cur_mon, fdname, errp);
  527. if (fd < 0) {
  528. return;
  529. }
  530. if (strcmp(protocol, "spice") == 0) {
  531. if (!qemu_using_spice(errp)) {
  532. close(fd);
  533. return;
  534. }
  535. skipauth = has_skipauth ? skipauth : false;
  536. tls = has_tls ? tls : false;
  537. if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) {
  538. error_setg(errp, "spice failed to add client");
  539. close(fd);
  540. }
  541. return;
  542. #ifdef CONFIG_VNC
  543. } else if (strcmp(protocol, "vnc") == 0) {
  544. skipauth = has_skipauth ? skipauth : false;
  545. vnc_display_add_client(NULL, fd, skipauth);
  546. return;
  547. #endif
  548. } else if ((s = qemu_chr_find(protocol)) != NULL) {
  549. if (qemu_chr_add_client(s, fd) < 0) {
  550. error_setg(errp, "failed to add client");
  551. close(fd);
  552. return;
  553. }
  554. return;
  555. }
  556. error_setg(errp, "protocol '%s' is invalid", protocol);
  557. close(fd);
  558. }
  559. void qmp_object_add(const char *type, const char *id,
  560. bool has_props, QObject *props, Error **errp)
  561. {
  562. QDict *pdict;
  563. Visitor *v;
  564. Object *obj;
  565. if (props) {
  566. pdict = qobject_to_qdict(props);
  567. if (!pdict) {
  568. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
  569. return;
  570. }
  571. QINCREF(pdict);
  572. } else {
  573. pdict = qdict_new();
  574. }
  575. v = qobject_input_visitor_new(QOBJECT(pdict));
  576. obj = user_creatable_add_type(type, id, pdict, v, errp);
  577. visit_free(v);
  578. if (obj) {
  579. object_unref(obj);
  580. }
  581. QDECREF(pdict);
  582. }
  583. void qmp_object_del(const char *id, Error **errp)
  584. {
  585. user_creatable_del(id, errp);
  586. }
  587. MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
  588. {
  589. MemoryDeviceInfoList *head = NULL;
  590. MemoryDeviceInfoList **prev = &head;
  591. qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
  592. return head;
  593. }
  594. ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
  595. {
  596. bool ambig;
  597. ACPIOSTInfoList *head = NULL;
  598. ACPIOSTInfoList **prev = &head;
  599. Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);
  600. if (obj) {
  601. AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
  602. AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
  603. adevc->ospm_status(adev, &prev);
  604. } else {
  605. error_setg(errp, "command is not supported, missing ACPI device");
  606. }
  607. return head;
  608. }
  609. MemoryInfo *qmp_query_memory_size_summary(Error **errp)
  610. {
  611. MemoryInfo *mem_info = g_malloc0(sizeof(MemoryInfo));
  612. mem_info->base_memory = ram_size;
  613. mem_info->plugged_memory = get_plugged_memory_size();
  614. mem_info->has_plugged_memory =
  615. mem_info->plugged_memory != (uint64_t)-1;
  616. return mem_info;
  617. }