1 /* 2 * qdev property parsing and global properties 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 "net/net.h" 14 #include "hw/qdev.h" 15 #include "qapi/qmp/qerror.h" 16 #include "sysemu/blockdev.h" 17 #include "hw/block/block.h" 18 #include "net/hub.h" 19 #include "qapi/visitor.h" 20 #include "sysemu/char.h" 21 #include "sysemu/iothread.h" 22 23 static void get_pointer(Object *obj, Visitor *v, Property *prop, 24 char *(*print)(void *ptr), 25 const char *name, Error **errp) 26 { 27 DeviceState *dev = DEVICE(obj); 28 void **ptr = qdev_get_prop_ptr(dev, prop); 29 char *p; 30 31 p = *ptr ? print(*ptr) : g_strdup(""); 32 visit_type_str(v, &p, name, errp); 33 g_free(p); 34 } 35 36 static void set_pointer(Object *obj, Visitor *v, Property *prop, 37 int (*parse)(DeviceState *dev, const char *str, 38 void **ptr), 39 const char *name, Error **errp) 40 { 41 DeviceState *dev = DEVICE(obj); 42 Error *local_err = NULL; 43 void **ptr = qdev_get_prop_ptr(dev, prop); 44 char *str; 45 int ret; 46 47 if (dev->realized) { 48 qdev_prop_set_after_realize(dev, name, errp); 49 return; 50 } 51 52 visit_type_str(v, &str, name, &local_err); 53 if (local_err) { 54 error_propagate(errp, local_err); 55 return; 56 } 57 if (!*str) { 58 g_free(str); 59 *ptr = NULL; 60 return; 61 } 62 ret = parse(dev, str, ptr); 63 error_set_from_qdev_prop_error(errp, ret, dev, prop, str); 64 g_free(str); 65 } 66 67 /* --- drive --- */ 68 69 static int parse_drive(DeviceState *dev, const char *str, void **ptr) 70 { 71 BlockDriverState *bs; 72 73 bs = bdrv_find(str); 74 if (bs == NULL) { 75 return -ENOENT; 76 } 77 if (bdrv_attach_dev(bs, dev) < 0) { 78 return -EEXIST; 79 } 80 *ptr = bs; 81 return 0; 82 } 83 84 static void release_drive(Object *obj, const char *name, void *opaque) 85 { 86 DeviceState *dev = DEVICE(obj); 87 Property *prop = opaque; 88 BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); 89 90 if (*ptr) { 91 bdrv_detach_dev(*ptr, dev); 92 blockdev_auto_del(*ptr); 93 } 94 } 95 96 static char *print_drive(void *ptr) 97 { 98 return g_strdup(bdrv_get_device_name(ptr)); 99 } 100 101 static void get_drive(Object *obj, Visitor *v, void *opaque, 102 const char *name, Error **errp) 103 { 104 get_pointer(obj, v, opaque, print_drive, name, errp); 105 } 106 107 static void set_drive(Object *obj, Visitor *v, void *opaque, 108 const char *name, Error **errp) 109 { 110 set_pointer(obj, v, opaque, parse_drive, name, errp); 111 } 112 113 PropertyInfo qdev_prop_drive = { 114 .name = "str", 115 .legacy_name = "drive", 116 .get = get_drive, 117 .set = set_drive, 118 .release = release_drive, 119 }; 120 121 /* --- character device --- */ 122 123 static int parse_chr(DeviceState *dev, const char *str, void **ptr) 124 { 125 CharDriverState *chr = qemu_chr_find(str); 126 if (chr == NULL) { 127 return -ENOENT; 128 } 129 if (qemu_chr_fe_claim(chr) != 0) { 130 return -EEXIST; 131 } 132 *ptr = chr; 133 return 0; 134 } 135 136 static void release_chr(Object *obj, const char *name, void *opaque) 137 { 138 DeviceState *dev = DEVICE(obj); 139 Property *prop = opaque; 140 CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); 141 CharDriverState *chr = *ptr; 142 143 if (chr) { 144 qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL); 145 qemu_chr_fe_release(chr); 146 } 147 } 148 149 150 static char *print_chr(void *ptr) 151 { 152 CharDriverState *chr = ptr; 153 const char *val = chr->label ? chr->label : ""; 154 155 return g_strdup(val); 156 } 157 158 static void get_chr(Object *obj, Visitor *v, void *opaque, 159 const char *name, Error **errp) 160 { 161 get_pointer(obj, v, opaque, print_chr, name, errp); 162 } 163 164 static void set_chr(Object *obj, Visitor *v, void *opaque, 165 const char *name, Error **errp) 166 { 167 set_pointer(obj, v, opaque, parse_chr, name, errp); 168 } 169 170 PropertyInfo qdev_prop_chr = { 171 .name = "str", 172 .legacy_name = "chr", 173 .get = get_chr, 174 .set = set_chr, 175 .release = release_chr, 176 }; 177 178 /* --- netdev device --- */ 179 180 static int parse_netdev(DeviceState *dev, const char *str, void **ptr) 181 { 182 NICPeers *peers_ptr = (NICPeers *)ptr; 183 NICConf *conf = container_of(peers_ptr, NICConf, peers); 184 NetClientState **ncs = peers_ptr->ncs; 185 NetClientState *peers[MAX_QUEUE_NUM]; 186 int queues, i = 0; 187 int ret; 188 189 queues = qemu_find_net_clients_except(str, peers, 190 NET_CLIENT_OPTIONS_KIND_NIC, 191 MAX_QUEUE_NUM); 192 if (queues == 0) { 193 ret = -ENOENT; 194 goto err; 195 } 196 197 if (queues > MAX_QUEUE_NUM) { 198 ret = -E2BIG; 199 goto err; 200 } 201 202 for (i = 0; i < queues; i++) { 203 if (peers[i] == NULL) { 204 ret = -ENOENT; 205 goto err; 206 } 207 208 if (peers[i]->peer) { 209 ret = -EEXIST; 210 goto err; 211 } 212 213 if (ncs[i]) { 214 ret = -EINVAL; 215 goto err; 216 } 217 218 ncs[i] = peers[i]; 219 ncs[i]->queue_index = i; 220 } 221 222 conf->queues = queues; 223 224 return 0; 225 226 err: 227 return ret; 228 } 229 230 static char *print_netdev(void *ptr) 231 { 232 NetClientState *netdev = ptr; 233 const char *val = netdev->name ? netdev->name : ""; 234 235 return g_strdup(val); 236 } 237 238 static void get_netdev(Object *obj, Visitor *v, void *opaque, 239 const char *name, Error **errp) 240 { 241 get_pointer(obj, v, opaque, print_netdev, name, errp); 242 } 243 244 static void set_netdev(Object *obj, Visitor *v, void *opaque, 245 const char *name, Error **errp) 246 { 247 set_pointer(obj, v, opaque, parse_netdev, name, errp); 248 } 249 250 PropertyInfo qdev_prop_netdev = { 251 .name = "str", 252 .legacy_name = "netdev", 253 .get = get_netdev, 254 .set = set_netdev, 255 }; 256 257 /* --- vlan --- */ 258 259 static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) 260 { 261 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 262 263 if (*ptr) { 264 int id; 265 if (!net_hub_id_for_client(*ptr, &id)) { 266 return snprintf(dest, len, "%d", id); 267 } 268 } 269 270 return snprintf(dest, len, "<null>"); 271 } 272 273 static void get_vlan(Object *obj, Visitor *v, void *opaque, 274 const char *name, Error **errp) 275 { 276 DeviceState *dev = DEVICE(obj); 277 Property *prop = opaque; 278 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 279 int32_t id = -1; 280 281 if (*ptr) { 282 int hub_id; 283 if (!net_hub_id_for_client(*ptr, &hub_id)) { 284 id = hub_id; 285 } 286 } 287 288 visit_type_int32(v, &id, name, errp); 289 } 290 291 static void set_vlan(Object *obj, Visitor *v, void *opaque, 292 const char *name, Error **errp) 293 { 294 DeviceState *dev = DEVICE(obj); 295 Property *prop = opaque; 296 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); 297 NetClientState **ptr = &peers_ptr->ncs[0]; 298 Error *local_err = NULL; 299 int32_t id; 300 NetClientState *hubport; 301 302 if (dev->realized) { 303 qdev_prop_set_after_realize(dev, name, errp); 304 return; 305 } 306 307 visit_type_int32(v, &id, name, &local_err); 308 if (local_err) { 309 error_propagate(errp, local_err); 310 return; 311 } 312 if (id == -1) { 313 *ptr = NULL; 314 return; 315 } 316 if (*ptr) { 317 error_set_from_qdev_prop_error(errp, -EINVAL, dev, prop, name); 318 return; 319 } 320 321 hubport = net_hub_port_find(id); 322 if (!hubport) { 323 error_set(errp, QERR_INVALID_PARAMETER_VALUE, 324 name, prop->info->name); 325 return; 326 } 327 *ptr = hubport; 328 } 329 330 PropertyInfo qdev_prop_vlan = { 331 .name = "int32", 332 .legacy_name = "vlan", 333 .print = print_vlan, 334 .get = get_vlan, 335 .set = set_vlan, 336 }; 337 338 int qdev_prop_set_drive(DeviceState *dev, const char *name, 339 BlockDriverState *value) 340 { 341 Error *err = NULL; 342 const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; 343 object_property_set_str(OBJECT(dev), bdrv_name, 344 name, &err); 345 if (err) { 346 qerror_report_err(err); 347 error_free(err); 348 return -1; 349 } 350 return 0; 351 } 352 353 void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, 354 BlockDriverState *value) 355 { 356 if (qdev_prop_set_drive(dev, name, value) < 0) { 357 exit(1); 358 } 359 } 360 void qdev_prop_set_chr(DeviceState *dev, const char *name, 361 CharDriverState *value) 362 { 363 assert(!value || value->label); 364 object_property_set_str(OBJECT(dev), 365 value ? value->label : "", name, &error_abort); 366 } 367 368 void qdev_prop_set_netdev(DeviceState *dev, const char *name, 369 NetClientState *value) 370 { 371 assert(!value || value->name); 372 object_property_set_str(OBJECT(dev), 373 value ? value->name : "", name, &error_abort); 374 } 375 376 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) 377 { 378 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); 379 if (nd->netdev) { 380 qdev_prop_set_netdev(dev, "netdev", nd->netdev); 381 } 382 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && 383 object_property_find(OBJECT(dev), "vectors", NULL)) { 384 qdev_prop_set_uint32(dev, "vectors", nd->nvectors); 385 } 386 nd->instantiated = 1; 387 } 388 389 /* --- iothread --- */ 390 391 static char *print_iothread(void *ptr) 392 { 393 return iothread_get_id(ptr); 394 } 395 396 static int parse_iothread(DeviceState *dev, const char *str, void **ptr) 397 { 398 IOThread *iothread; 399 400 iothread = iothread_find(str); 401 if (!iothread) { 402 return -ENOENT; 403 } 404 object_ref(OBJECT(iothread)); 405 *ptr = iothread; 406 return 0; 407 } 408 409 static void get_iothread(Object *obj, struct Visitor *v, void *opaque, 410 const char *name, Error **errp) 411 { 412 get_pointer(obj, v, opaque, print_iothread, name, errp); 413 } 414 415 static void set_iothread(Object *obj, struct Visitor *v, void *opaque, 416 const char *name, Error **errp) 417 { 418 set_pointer(obj, v, opaque, parse_iothread, name, errp); 419 } 420 421 static void release_iothread(Object *obj, const char *name, void *opaque) 422 { 423 DeviceState *dev = DEVICE(obj); 424 Property *prop = opaque; 425 IOThread **ptr = qdev_get_prop_ptr(dev, prop); 426 427 if (*ptr) { 428 object_unref(OBJECT(*ptr)); 429 } 430 } 431 432 PropertyInfo qdev_prop_iothread = { 433 .name = "iothread", 434 .get = get_iothread, 435 .set = set_iothread, 436 .release = release_iothread, 437 }; 438 439 static int qdev_add_one_global(QemuOpts *opts, void *opaque) 440 { 441 GlobalProperty *g; 442 443 g = g_malloc0(sizeof(*g)); 444 g->driver = qemu_opt_get(opts, "driver"); 445 g->property = qemu_opt_get(opts, "property"); 446 g->value = qemu_opt_get(opts, "value"); 447 qdev_prop_register_global(g); 448 return 0; 449 } 450 451 void qemu_add_globals(void) 452 { 453 qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); 454 } 455