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 = "drive", 113 .get = get_drive, 114 .set = set_drive, 115 .release = release_drive, 116 }; 117 118 /* --- character device --- */ 119 120 static int parse_chr(DeviceState *dev, const char *str, void **ptr) 121 { 122 CharDriverState *chr = qemu_chr_find(str); 123 if (chr == NULL) { 124 return -ENOENT; 125 } 126 if (qemu_chr_fe_claim(chr) != 0) { 127 return -EEXIST; 128 } 129 *ptr = chr; 130 return 0; 131 } 132 133 static void release_chr(Object *obj, const char *name, void *opaque) 134 { 135 DeviceState *dev = DEVICE(obj); 136 Property *prop = opaque; 137 CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); 138 CharDriverState *chr = *ptr; 139 140 if (chr) { 141 qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL); 142 qemu_chr_fe_release(chr); 143 } 144 } 145 146 147 static const char *print_chr(void *ptr) 148 { 149 CharDriverState *chr = ptr; 150 151 return chr->label ? chr->label : ""; 152 } 153 154 static void get_chr(Object *obj, Visitor *v, void *opaque, 155 const char *name, Error **errp) 156 { 157 get_pointer(obj, v, opaque, print_chr, name, errp); 158 } 159 160 static void set_chr(Object *obj, Visitor *v, void *opaque, 161 const char *name, Error **errp) 162 { 163 set_pointer(obj, v, opaque, parse_chr, name, errp); 164 } 165 166 PropertyInfo qdev_prop_chr = { 167 .name = "chr", 168 .get = get_chr, 169 .set = set_chr, 170 .release = release_chr, 171 }; 172 173 /* --- netdev device --- */ 174 175 static int parse_netdev(DeviceState *dev, const char *str, void **ptr) 176 { 177 NICPeers *peers_ptr = (NICPeers *)ptr; 178 NICConf *conf = container_of(peers_ptr, NICConf, peers); 179 NetClientState **ncs = peers_ptr->ncs; 180 NetClientState *peers[MAX_QUEUE_NUM]; 181 int queues, i = 0; 182 int ret; 183 184 queues = qemu_find_net_clients_except(str, peers, 185 NET_CLIENT_OPTIONS_KIND_NIC, 186 MAX_QUEUE_NUM); 187 if (queues == 0) { 188 ret = -ENOENT; 189 goto err; 190 } 191 192 if (queues > MAX_QUEUE_NUM) { 193 ret = -E2BIG; 194 goto err; 195 } 196 197 for (i = 0; i < queues; i++) { 198 if (peers[i] == NULL) { 199 ret = -ENOENT; 200 goto err; 201 } 202 203 if (peers[i]->peer) { 204 ret = -EEXIST; 205 goto err; 206 } 207 208 if (ncs[i]) { 209 ret = -EINVAL; 210 goto err; 211 } 212 213 ncs[i] = peers[i]; 214 ncs[i]->queue_index = i; 215 } 216 217 conf->queues = queues; 218 219 return 0; 220 221 err: 222 return ret; 223 } 224 225 static const char *print_netdev(void *ptr) 226 { 227 NetClientState *netdev = ptr; 228 229 return netdev->name ? netdev->name : ""; 230 } 231 232 static void get_netdev(Object *obj, Visitor *v, void *opaque, 233 const char *name, Error **errp) 234 { 235 get_pointer(obj, v, opaque, print_netdev, name, errp); 236 } 237 238 static void set_netdev(Object *obj, Visitor *v, void *opaque, 239 const char *name, Error **errp) 240 { 241 set_pointer(obj, v, opaque, parse_netdev, name, errp); 242 } 243 244 PropertyInfo qdev_prop_netdev = { 245 .name = "netdev", 246 .get = get_netdev, 247 .set = set_netdev, 248 }; 249 250 /* --- vlan --- */ 251 252 static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) 253 { 254 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 255 256 if (*ptr) { 257 int id; 258 if (!net_hub_id_for_client(*ptr, &id)) { 259 return snprintf(dest, len, "%d", id); 260 } 261 } 262 263 return snprintf(dest, len, "<null>"); 264 } 265 266 static void get_vlan(Object *obj, Visitor *v, void *opaque, 267 const char *name, Error **errp) 268 { 269 DeviceState *dev = DEVICE(obj); 270 Property *prop = opaque; 271 NetClientState **ptr = qdev_get_prop_ptr(dev, prop); 272 int32_t id = -1; 273 274 if (*ptr) { 275 int hub_id; 276 if (!net_hub_id_for_client(*ptr, &hub_id)) { 277 id = hub_id; 278 } 279 } 280 281 visit_type_int32(v, &id, name, errp); 282 } 283 284 static void set_vlan(Object *obj, Visitor *v, void *opaque, 285 const char *name, Error **errp) 286 { 287 DeviceState *dev = DEVICE(obj); 288 Property *prop = opaque; 289 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); 290 NetClientState **ptr = &peers_ptr->ncs[0]; 291 Error *local_err = NULL; 292 int32_t id; 293 NetClientState *hubport; 294 295 if (dev->realized) { 296 qdev_prop_set_after_realize(dev, name, errp); 297 return; 298 } 299 300 visit_type_int32(v, &id, name, &local_err); 301 if (local_err) { 302 error_propagate(errp, local_err); 303 return; 304 } 305 if (id == -1) { 306 *ptr = NULL; 307 return; 308 } 309 if (*ptr) { 310 error_set_from_qdev_prop_error(errp, -EINVAL, dev, prop, name); 311 return; 312 } 313 314 hubport = net_hub_port_find(id); 315 if (!hubport) { 316 error_set(errp, QERR_INVALID_PARAMETER_VALUE, 317 name, prop->info->name); 318 return; 319 } 320 *ptr = hubport; 321 } 322 323 PropertyInfo qdev_prop_vlan = { 324 .name = "vlan", 325 .print = print_vlan, 326 .get = get_vlan, 327 .set = set_vlan, 328 }; 329 330 int qdev_prop_set_drive(DeviceState *dev, const char *name, 331 BlockDriverState *value) 332 { 333 Error *errp = NULL; 334 const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; 335 object_property_set_str(OBJECT(dev), bdrv_name, 336 name, &errp); 337 if (errp) { 338 qerror_report_err(errp); 339 error_free(errp); 340 return -1; 341 } 342 return 0; 343 } 344 345 void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, 346 BlockDriverState *value) 347 { 348 if (qdev_prop_set_drive(dev, name, value) < 0) { 349 exit(1); 350 } 351 } 352 void qdev_prop_set_chr(DeviceState *dev, const char *name, 353 CharDriverState *value) 354 { 355 Error *errp = NULL; 356 assert(!value || value->label); 357 object_property_set_str(OBJECT(dev), 358 value ? value->label : "", name, &errp); 359 assert_no_error(errp); 360 } 361 362 void qdev_prop_set_netdev(DeviceState *dev, const char *name, 363 NetClientState *value) 364 { 365 Error *errp = NULL; 366 assert(!value || value->name); 367 object_property_set_str(OBJECT(dev), 368 value ? value->name : "", name, &errp); 369 assert_no_error(errp); 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