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