2
0

qdev-properties-system.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. * qdev property parsing
  3. * (parts specific for qemu-system-*)
  4. *
  5. * This file is based on code from hw/qdev-properties.c from
  6. * commit 074a86fccd185616469dfcdc0e157f438aebba18,
  7. * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. #include "qemu/osdep.h"
  13. #include "audio/audio.h"
  14. #include "net/net.h"
  15. #include "hw/qdev-properties.h"
  16. #include "qapi/error.h"
  17. #include "qapi/qmp/qerror.h"
  18. #include "sysemu/block-backend.h"
  19. #include "sysemu/blockdev.h"
  20. #include "hw/block/block.h"
  21. #include "net/hub.h"
  22. #include "qapi/visitor.h"
  23. #include "chardev/char-fe.h"
  24. #include "sysemu/iothread.h"
  25. #include "sysemu/tpm_backend.h"
  26. static void get_pointer(Object *obj, Visitor *v, Property *prop,
  27. char *(*print)(void *ptr),
  28. const char *name, Error **errp)
  29. {
  30. DeviceState *dev = DEVICE(obj);
  31. void **ptr = qdev_get_prop_ptr(dev, prop);
  32. char *p;
  33. p = *ptr ? print(*ptr) : g_strdup("");
  34. visit_type_str(v, name, &p, errp);
  35. g_free(p);
  36. }
  37. static void set_pointer(Object *obj, Visitor *v, Property *prop,
  38. void (*parse)(DeviceState *dev, const char *str,
  39. void **ptr, const char *propname,
  40. Error **errp),
  41. const char *name, Error **errp)
  42. {
  43. DeviceState *dev = DEVICE(obj);
  44. Error *local_err = NULL;
  45. void **ptr = qdev_get_prop_ptr(dev, prop);
  46. char *str;
  47. if (dev->realized) {
  48. qdev_prop_set_after_realize(dev, name, errp);
  49. return;
  50. }
  51. visit_type_str(v, name, &str, &local_err);
  52. if (local_err) {
  53. error_propagate(errp, local_err);
  54. return;
  55. }
  56. if (!*str) {
  57. g_free(str);
  58. *ptr = NULL;
  59. return;
  60. }
  61. parse(dev, str, ptr, prop->name, errp);
  62. g_free(str);
  63. }
  64. /* --- drive --- */
  65. static void do_parse_drive(DeviceState *dev, const char *str, void **ptr,
  66. const char *propname, bool iothread, Error **errp)
  67. {
  68. BlockBackend *blk;
  69. bool blk_created = false;
  70. int ret;
  71. blk = blk_by_name(str);
  72. if (!blk) {
  73. BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
  74. if (bs) {
  75. /*
  76. * If the device supports iothreads, it will make sure to move the
  77. * block node to the right AioContext if necessary (or fail if this
  78. * isn't possible because of other users). Devices that are not
  79. * aware of iothreads require their BlockBackends to be in the main
  80. * AioContext.
  81. */
  82. AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
  83. qemu_get_aio_context();
  84. blk = blk_new(ctx, 0, BLK_PERM_ALL);
  85. blk_created = true;
  86. ret = blk_insert_bs(blk, bs, errp);
  87. if (ret < 0) {
  88. goto fail;
  89. }
  90. }
  91. }
  92. if (!blk) {
  93. error_setg(errp, "Property '%s.%s' can't find value '%s'",
  94. object_get_typename(OBJECT(dev)), propname, str);
  95. goto fail;
  96. }
  97. if (blk_attach_dev(blk, dev) < 0) {
  98. DriveInfo *dinfo = blk_legacy_dinfo(blk);
  99. if (dinfo && dinfo->type != IF_NONE) {
  100. error_setg(errp, "Drive '%s' is already in use because "
  101. "it has been automatically connected to another "
  102. "device (did you need 'if=none' in the drive options?)",
  103. str);
  104. } else {
  105. error_setg(errp, "Drive '%s' is already in use by another device",
  106. str);
  107. }
  108. goto fail;
  109. }
  110. *ptr = blk;
  111. fail:
  112. if (blk_created) {
  113. /* If we need to keep a reference, blk_attach_dev() took it */
  114. blk_unref(blk);
  115. }
  116. }
  117. static void parse_drive(DeviceState *dev, const char *str, void **ptr,
  118. const char *propname, Error **errp)
  119. {
  120. do_parse_drive(dev, str, ptr, propname, false, errp);
  121. }
  122. static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr,
  123. const char *propname, Error **errp)
  124. {
  125. do_parse_drive(dev, str, ptr, propname, true, errp);
  126. }
  127. static void release_drive(Object *obj, const char *name, void *opaque)
  128. {
  129. DeviceState *dev = DEVICE(obj);
  130. Property *prop = opaque;
  131. BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
  132. if (*ptr) {
  133. AioContext *ctx = blk_get_aio_context(*ptr);
  134. aio_context_acquire(ctx);
  135. blockdev_auto_del(*ptr);
  136. blk_detach_dev(*ptr, dev);
  137. aio_context_release(ctx);
  138. }
  139. }
  140. static char *print_drive(void *ptr)
  141. {
  142. const char *name;
  143. name = blk_name(ptr);
  144. if (!*name) {
  145. BlockDriverState *bs = blk_bs(ptr);
  146. if (bs) {
  147. name = bdrv_get_node_name(bs);
  148. }
  149. }
  150. return g_strdup(name);
  151. }
  152. static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
  153. Error **errp)
  154. {
  155. get_pointer(obj, v, opaque, print_drive, name, errp);
  156. }
  157. static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
  158. Error **errp)
  159. {
  160. set_pointer(obj, v, opaque, parse_drive, name, errp);
  161. }
  162. static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
  163. void *opaque, Error **errp)
  164. {
  165. set_pointer(obj, v, opaque, parse_drive_iothread, name, errp);
  166. }
  167. const PropertyInfo qdev_prop_drive = {
  168. .name = "str",
  169. .description = "Node name or ID of a block device to use as a backend",
  170. .get = get_drive,
  171. .set = set_drive,
  172. .release = release_drive,
  173. };
  174. const PropertyInfo qdev_prop_drive_iothread = {
  175. .name = "str",
  176. .description = "Node name or ID of a block device to use as a backend",
  177. .get = get_drive,
  178. .set = set_drive_iothread,
  179. .release = release_drive,
  180. };
  181. /* --- character device --- */
  182. static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
  183. Error **errp)
  184. {
  185. DeviceState *dev = DEVICE(obj);
  186. CharBackend *be = qdev_get_prop_ptr(dev, opaque);
  187. char *p;
  188. p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
  189. visit_type_str(v, name, &p, errp);
  190. g_free(p);
  191. }
  192. static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
  193. Error **errp)
  194. {
  195. DeviceState *dev = DEVICE(obj);
  196. Error *local_err = NULL;
  197. Property *prop = opaque;
  198. CharBackend *be = qdev_get_prop_ptr(dev, prop);
  199. Chardev *s;
  200. char *str;
  201. if (dev->realized) {
  202. qdev_prop_set_after_realize(dev, name, errp);
  203. return;
  204. }
  205. visit_type_str(v, name, &str, &local_err);
  206. if (local_err) {
  207. error_propagate(errp, local_err);
  208. return;
  209. }
  210. if (!*str) {
  211. g_free(str);
  212. be->chr = NULL;
  213. return;
  214. }
  215. s = qemu_chr_find(str);
  216. if (s == NULL) {
  217. error_setg(errp, "Property '%s.%s' can't find value '%s'",
  218. object_get_typename(obj), prop->name, str);
  219. } else if (!qemu_chr_fe_init(be, s, errp)) {
  220. error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
  221. object_get_typename(obj), prop->name, str);
  222. }
  223. g_free(str);
  224. }
  225. static void release_chr(Object *obj, const char *name, void *opaque)
  226. {
  227. DeviceState *dev = DEVICE(obj);
  228. Property *prop = opaque;
  229. CharBackend *be = qdev_get_prop_ptr(dev, prop);
  230. qemu_chr_fe_deinit(be, false);
  231. }
  232. const PropertyInfo qdev_prop_chr = {
  233. .name = "str",
  234. .description = "ID of a chardev to use as a backend",
  235. .get = get_chr,
  236. .set = set_chr,
  237. .release = release_chr,
  238. };
  239. /* --- netdev device --- */
  240. static void get_netdev(Object *obj, Visitor *v, const char *name,
  241. void *opaque, Error **errp)
  242. {
  243. DeviceState *dev = DEVICE(obj);
  244. Property *prop = opaque;
  245. NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
  246. char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
  247. visit_type_str(v, name, &p, errp);
  248. g_free(p);
  249. }
  250. static void set_netdev(Object *obj, Visitor *v, const char *name,
  251. void *opaque, Error **errp)
  252. {
  253. DeviceState *dev = DEVICE(obj);
  254. Property *prop = opaque;
  255. NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
  256. NetClientState **ncs = peers_ptr->ncs;
  257. NetClientState *peers[MAX_QUEUE_NUM];
  258. Error *local_err = NULL;
  259. int queues, err = 0, i = 0;
  260. char *str;
  261. if (dev->realized) {
  262. qdev_prop_set_after_realize(dev, name, errp);
  263. return;
  264. }
  265. visit_type_str(v, name, &str, &local_err);
  266. if (local_err) {
  267. error_propagate(errp, local_err);
  268. return;
  269. }
  270. queues = qemu_find_net_clients_except(str, peers,
  271. NET_CLIENT_DRIVER_NIC,
  272. MAX_QUEUE_NUM);
  273. if (queues == 0) {
  274. err = -ENOENT;
  275. goto out;
  276. }
  277. if (queues > MAX_QUEUE_NUM) {
  278. error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
  279. str, queues, MAX_QUEUE_NUM);
  280. goto out;
  281. }
  282. for (i = 0; i < queues; i++) {
  283. if (peers[i]->peer) {
  284. err = -EEXIST;
  285. goto out;
  286. }
  287. if (ncs[i]) {
  288. err = -EINVAL;
  289. goto out;
  290. }
  291. ncs[i] = peers[i];
  292. ncs[i]->queue_index = i;
  293. }
  294. peers_ptr->queues = queues;
  295. out:
  296. error_set_from_qdev_prop_error(errp, err, dev, prop, str);
  297. g_free(str);
  298. }
  299. const PropertyInfo qdev_prop_netdev = {
  300. .name = "str",
  301. .description = "ID of a netdev to use as a backend",
  302. .get = get_netdev,
  303. .set = set_netdev,
  304. };
  305. /* --- audiodev --- */
  306. static void get_audiodev(Object *obj, Visitor *v, const char* name,
  307. void *opaque, Error **errp)
  308. {
  309. DeviceState *dev = DEVICE(obj);
  310. Property *prop = opaque;
  311. QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
  312. char *p = g_strdup(audio_get_id(card));
  313. visit_type_str(v, name, &p, errp);
  314. g_free(p);
  315. }
  316. static void set_audiodev(Object *obj, Visitor *v, const char* name,
  317. void *opaque, Error **errp)
  318. {
  319. DeviceState *dev = DEVICE(obj);
  320. Property *prop = opaque;
  321. QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
  322. AudioState *state;
  323. Error *local_err = NULL;
  324. int err = 0;
  325. char *str;
  326. if (dev->realized) {
  327. qdev_prop_set_after_realize(dev, name, errp);
  328. return;
  329. }
  330. visit_type_str(v, name, &str, &local_err);
  331. if (local_err) {
  332. error_propagate(errp, local_err);
  333. return;
  334. }
  335. state = audio_state_by_name(str);
  336. if (!state) {
  337. err = -ENOENT;
  338. goto out;
  339. }
  340. card->state = state;
  341. out:
  342. error_set_from_qdev_prop_error(errp, err, dev, prop, str);
  343. g_free(str);
  344. }
  345. const PropertyInfo qdev_prop_audiodev = {
  346. .name = "str",
  347. .description = "ID of an audiodev to use as a backend",
  348. /* release done on shutdown */
  349. .get = get_audiodev,
  350. .set = set_audiodev,
  351. };
  352. void qdev_prop_set_drive(DeviceState *dev, const char *name,
  353. BlockBackend *value, Error **errp)
  354. {
  355. const char *ref = "";
  356. if (value) {
  357. ref = blk_name(value);
  358. if (!*ref) {
  359. const BlockDriverState *bs = blk_bs(value);
  360. if (bs) {
  361. ref = bdrv_get_node_name(bs);
  362. }
  363. }
  364. }
  365. object_property_set_str(OBJECT(dev), ref, name, errp);
  366. }
  367. void qdev_prop_set_chr(DeviceState *dev, const char *name,
  368. Chardev *value)
  369. {
  370. assert(!value || value->label);
  371. object_property_set_str(OBJECT(dev),
  372. value ? value->label : "", name, &error_abort);
  373. }
  374. void qdev_prop_set_netdev(DeviceState *dev, const char *name,
  375. NetClientState *value)
  376. {
  377. assert(!value || value->name);
  378. object_property_set_str(OBJECT(dev),
  379. value ? value->name : "", name, &error_abort);
  380. }
  381. void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
  382. {
  383. qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
  384. if (nd->netdev) {
  385. qdev_prop_set_netdev(dev, "netdev", nd->netdev);
  386. }
  387. if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
  388. object_property_find(OBJECT(dev), "vectors", NULL)) {
  389. qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
  390. }
  391. nd->instantiated = 1;
  392. }