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