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