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 return g_strdup(blk_name(ptr)); 130 } 131 132 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, 133 Error **errp) 134 { 135 get_pointer(obj, v, opaque, print_drive, name, errp); 136 } 137 138 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque, 139 Error **errp) 140 { 141 set_pointer(obj, v, opaque, parse_drive, name, errp); 142 } 143 144 PropertyInfo qdev_prop_drive = { 145 .name = "str", 146 .description = "Node name or ID of a block device to use as a backend", 147 .get = get_drive, 148 .set = set_drive, 149 .release = release_drive, 150 }; 151 152 /* --- character device --- */ 153 154 static void parse_chr(DeviceState *dev, const char *str, void **ptr, 155 const char *propname, Error **errp) 156 { 157 CharDriverState *chr = qemu_chr_find(str); 158 if (chr == NULL) { 159 error_setg(errp, "Property '%s.%s' can't find value '%s'", 160 object_get_typename(OBJECT(dev)), propname, str); 161 return; 162 } 163 if (qemu_chr_fe_claim(chr) != 0) { 164 error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use", 165 object_get_typename(OBJECT(dev)), propname, str); 166 return; 167 } 168 *ptr = chr; 169 } 170 171 static void release_chr(Object *obj, const char *name, void *opaque) 172 { 173 DeviceState *dev = DEVICE(obj); 174 Property *prop = opaque; 175 CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); 176 CharDriverState *chr = *ptr; 177 178 if (chr) { 179 qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL); 180 qemu_chr_fe_release(chr); 181 } 182 } 183 184 185 static char *print_chr(void *ptr) 186 { 187 CharDriverState *chr = ptr; 188 const char *val = chr->label ? chr->label : ""; 189 190 return g_strdup(val); 191 } 192 193 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque, 194 Error **errp) 195 { 196 get_pointer(obj, v, opaque, print_chr, name, errp); 197 } 198 199 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, 200 Error **errp) 201 { 202 set_pointer(obj, v, opaque, parse_chr, name, errp); 203 } 204 205 PropertyInfo qdev_prop_chr = { 206 .name = "str", 207 .description = "ID of a chardev to use as a backend", 208 .get = get_chr, 209 .set = set_chr, 210 .release = release_chr, 211 }; 212 213 /* --- netdev device --- */ 214 static void get_netdev(Object *obj, Visitor *v, const char *name, 215 void *opaque, Error **errp) 216 { 217 DeviceState *dev = DEVICE(obj); 218 Property *prop = opaque; 219 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); 220 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : ""); 221 222 visit_type_str(v, name, &p, errp); 223 g_free(p); 224 } 225 226 static void set_netdev(Object *obj, Visitor *v, const char *name, 227 void *opaque, Error **errp) 228 { 229 DeviceState *dev = DEVICE(obj); 230 Property *prop = opaque; 231 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); 232 NetClientState **ncs = peers_ptr->ncs; 233 NetClientState *peers[MAX_QUEUE_NUM]; 234 Error *local_err = NULL; 235 int queues, err = 0, i = 0; 236 char *str; 237 238 if (dev->realized) { 239 qdev_prop_set_after_realize(dev, name, errp); 240 return; 241 } 242 243 visit_type_str(v, name, &str, &local_err); 244 if (local_err) { 245 error_propagate(errp, local_err); 246 return; 247 } 248 249 queues = qemu_find_net_clients_except(str, peers, 250 NET_CLIENT_DRIVER_NIC, 251 MAX_QUEUE_NUM); 252 if (queues == 0) { 253 err = -ENOENT; 254 goto out; 255 } 256 257 if (queues > MAX_QUEUE_NUM) { 258 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)", 259 str, queues, MAX_QUEUE_NUM); 260 goto out; 261 } 262 263 for (i = 0; i < queues; i++) { 264 if (peers[i] == NULL) { 265 err = -ENOENT; 266 goto out; 267 } 268 269 if (peers[i]->peer) { 270 err = -EEXIST; 271 goto out; 272 } 273 274 if (ncs[i]) { 275 err = -EINVAL; 276 goto out; 277 } 278 279 ncs[i] = peers[i]; 280 ncs[i]->queue_index = i; 281 } 282 283 peers_ptr->queues = queues; 284 285 out: 286 error_set_from_qdev_prop_error(errp, err, dev, prop, str); 287 g_free(str); 288 } 289 290 PropertyInfo qdev_prop_netdev = { 291 .name = "str", 292 .description = "ID of a netdev to use as a backend", 293 .get = get_netdev, 294 .set = set_netdev, 295 }; 296 297 /* --- vlan --- */ 298 299 static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) 300 { 301 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 302 303 if (*ptr) { 304 int id; 305 if (!net_hub_id_for_client(*ptr, &id)) { 306 return snprintf(dest, len, "%d", id); 307 } 308 } 309 310 return snprintf(dest, len, "<null>"); 311 } 312 313 static void get_vlan(Object *obj, Visitor *v, const char *name, void *opaque, 314 Error **errp) 315 { 316 DeviceState *dev = DEVICE(obj); 317 Property *prop = opaque; 318 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 319 int32_t id = -1; 320 321 if (*ptr) { 322 int hub_id; 323 if (!net_hub_id_for_client(*ptr, &hub_id)) { 324 id = hub_id; 325 } 326 } 327 328 visit_type_int32(v, name, &id, errp); 329 } 330 331 static void set_vlan(Object *obj, Visitor *v, const char *name, void *opaque, 332 Error **errp) 333 { 334 DeviceState *dev = DEVICE(obj); 335 Property *prop = opaque; 336 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); 337 NetClientState **ptr = &peers_ptr->ncs[0]; 338 Error *local_err = NULL; 339 int32_t id; 340 NetClientState *hubport; 341 342 if (dev->realized) { 343 qdev_prop_set_after_realize(dev, name, errp); 344 return; 345 } 346 347 visit_type_int32(v, name, &id, &local_err); 348 if (local_err) { 349 error_propagate(errp, local_err); 350 return; 351 } 352 if (id == -1) { 353 *ptr = NULL; 354 return; 355 } 356 if (*ptr) { 357 error_set_from_qdev_prop_error(errp, -EINVAL, dev, prop, name); 358 return; 359 } 360 361 hubport = net_hub_port_find(id); 362 if (!hubport) { 363 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 364 name, prop->info->name); 365 return; 366 } 367 *ptr = hubport; 368 } 369 370 PropertyInfo qdev_prop_vlan = { 371 .name = "int32", 372 .description = "Integer VLAN id to connect to", 373 .print = print_vlan, 374 .get = get_vlan, 375 .set = set_vlan, 376 }; 377 378 void qdev_prop_set_drive(DeviceState *dev, const char *name, 379 BlockBackend *value, Error **errp) 380 { 381 const char *ref = ""; 382 383 if (value) { 384 ref = blk_name(value); 385 if (!*ref) { 386 BlockDriverState *bs = blk_bs(value); 387 if (bs) { 388 ref = bdrv_get_node_name(bs); 389 } 390 } 391 } 392 393 object_property_set_str(OBJECT(dev), ref, name, errp); 394 } 395 396 void qdev_prop_set_chr(DeviceState *dev, const char *name, 397 CharDriverState *value) 398 { 399 assert(!value || value->label); 400 object_property_set_str(OBJECT(dev), 401 value ? value->label : "", name, &error_abort); 402 } 403 404 void qdev_prop_set_netdev(DeviceState *dev, const char *name, 405 NetClientState *value) 406 { 407 assert(!value || value->name); 408 object_property_set_str(OBJECT(dev), 409 value ? value->name : "", name, &error_abort); 410 } 411 412 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) 413 { 414 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); 415 if (nd->netdev) { 416 qdev_prop_set_netdev(dev, "netdev", nd->netdev); 417 } 418 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && 419 object_property_find(OBJECT(dev), "vectors", NULL)) { 420 qdev_prop_set_uint32(dev, "vectors", nd->nvectors); 421 } 422 nd->instantiated = 1; 423 } 424