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