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-properties.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 "chardev/char-fe.h"
24 #include "sysemu/iothread.h"
25 #include "sysemu/tpm_backend.h"
26 
27 static void get_pointer(Object *obj, Visitor *v, Property *prop,
28                         char *(*print)(void *ptr),
29                         const char *name, Error **errp)
30 {
31     DeviceState *dev = DEVICE(obj);
32     void **ptr = qdev_get_prop_ptr(dev, prop);
33     char *p;
34 
35     p = *ptr ? print(*ptr) : g_strdup("");
36     visit_type_str(v, name, &p, errp);
37     g_free(p);
38 }
39 
40 static void set_pointer(Object *obj, Visitor *v, Property *prop,
41                         void (*parse)(DeviceState *dev, const char *str,
42                                       void **ptr, const char *propname,
43                                       Error **errp),
44                         const char *name, Error **errp)
45 {
46     DeviceState *dev = DEVICE(obj);
47     Error *local_err = NULL;
48     void **ptr = qdev_get_prop_ptr(dev, prop);
49     char *str;
50 
51     if (dev->realized) {
52         qdev_prop_set_after_realize(dev, name, errp);
53         return;
54     }
55 
56     visit_type_str(v, name, &str, &local_err);
57     if (local_err) {
58         error_propagate(errp, local_err);
59         return;
60     }
61     if (!*str) {
62         g_free(str);
63         *ptr = NULL;
64         return;
65     }
66     parse(dev, str, ptr, prop->name, errp);
67     g_free(str);
68 }
69 
70 /* --- drive --- */
71 
72 static void do_parse_drive(DeviceState *dev, const char *str, void **ptr,
73                            const char *propname, bool iothread, Error **errp)
74 {
75     BlockBackend *blk;
76     bool blk_created = false;
77     int ret;
78 
79     blk = blk_by_name(str);
80     if (!blk) {
81         BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
82         if (bs) {
83             /*
84              * If the device supports iothreads, it will make sure to move the
85              * block node to the right AioContext if necessary (or fail if this
86              * isn't possible because of other users). Devices that are not
87              * aware of iothreads require their BlockBackends to be in the main
88              * AioContext.
89              */
90             AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
91                                          qemu_get_aio_context();
92             blk = blk_new(ctx, 0, BLK_PERM_ALL);
93             blk_created = true;
94 
95             ret = blk_insert_bs(blk, bs, errp);
96             if (ret < 0) {
97                 goto fail;
98             }
99         }
100     }
101     if (!blk) {
102         error_setg(errp, "Property '%s.%s' can't find value '%s'",
103                    object_get_typename(OBJECT(dev)), propname, str);
104         goto fail;
105     }
106     if (blk_attach_dev(blk, dev) < 0) {
107         DriveInfo *dinfo = blk_legacy_dinfo(blk);
108 
109         if (dinfo && dinfo->type != IF_NONE) {
110             error_setg(errp, "Drive '%s' is already in use because "
111                        "it has been automatically connected to another "
112                        "device (did you need 'if=none' in the drive options?)",
113                        str);
114         } else {
115             error_setg(errp, "Drive '%s' is already in use by another device",
116                        str);
117         }
118         goto fail;
119     }
120 
121     *ptr = blk;
122 
123 fail:
124     if (blk_created) {
125         /* If we need to keep a reference, blk_attach_dev() took it */
126         blk_unref(blk);
127     }
128 }
129 
130 static void parse_drive(DeviceState *dev, const char *str, void **ptr,
131                         const char *propname, Error **errp)
132 {
133     do_parse_drive(dev, str, ptr, propname, false, errp);
134 }
135 
136 static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr,
137                                  const char *propname, Error **errp)
138 {
139     do_parse_drive(dev, str, ptr, propname, true, errp);
140 }
141 
142 static void release_drive(Object *obj, const char *name, void *opaque)
143 {
144     DeviceState *dev = DEVICE(obj);
145     Property *prop = opaque;
146     BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
147 
148     if (*ptr) {
149         AioContext *ctx = blk_get_aio_context(*ptr);
150 
151         aio_context_acquire(ctx);
152         blockdev_auto_del(*ptr);
153         blk_detach_dev(*ptr, dev);
154         aio_context_release(ctx);
155     }
156 }
157 
158 static char *print_drive(void *ptr)
159 {
160     const char *name;
161 
162     name = blk_name(ptr);
163     if (!*name) {
164         BlockDriverState *bs = blk_bs(ptr);
165         if (bs) {
166             name = bdrv_get_node_name(bs);
167         }
168     }
169     return g_strdup(name);
170 }
171 
172 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
173                       Error **errp)
174 {
175     get_pointer(obj, v, opaque, print_drive, name, errp);
176 }
177 
178 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
179                       Error **errp)
180 {
181     set_pointer(obj, v, opaque, parse_drive, name, errp);
182 }
183 
184 static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
185                                void *opaque, Error **errp)
186 {
187     set_pointer(obj, v, opaque, parse_drive_iothread, name, errp);
188 }
189 
190 const PropertyInfo qdev_prop_drive = {
191     .name  = "str",
192     .description = "Node name or ID of a block device to use as a backend",
193     .get   = get_drive,
194     .set   = set_drive,
195     .release = release_drive,
196 };
197 
198 const PropertyInfo qdev_prop_drive_iothread = {
199     .name  = "str",
200     .description = "Node name or ID of a block device to use as a backend",
201     .get   = get_drive,
202     .set   = set_drive_iothread,
203     .release = release_drive,
204 };
205 
206 /* --- character device --- */
207 
208 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
209                     Error **errp)
210 {
211     DeviceState *dev = DEVICE(obj);
212     CharBackend *be = qdev_get_prop_ptr(dev, opaque);
213     char *p;
214 
215     p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
216     visit_type_str(v, name, &p, errp);
217     g_free(p);
218 }
219 
220 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
221                     Error **errp)
222 {
223     DeviceState *dev = DEVICE(obj);
224     Error *local_err = NULL;
225     Property *prop = opaque;
226     CharBackend *be = qdev_get_prop_ptr(dev, prop);
227     Chardev *s;
228     char *str;
229 
230     if (dev->realized) {
231         qdev_prop_set_after_realize(dev, name, errp);
232         return;
233     }
234 
235     visit_type_str(v, name, &str, &local_err);
236     if (local_err) {
237         error_propagate(errp, local_err);
238         return;
239     }
240 
241     if (!*str) {
242         g_free(str);
243         be->chr = NULL;
244         return;
245     }
246 
247     s = qemu_chr_find(str);
248     if (s == NULL) {
249         error_setg(errp, "Property '%s.%s' can't find value '%s'",
250                    object_get_typename(obj), prop->name, str);
251     } else if (!qemu_chr_fe_init(be, s, errp)) {
252         error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
253                       object_get_typename(obj), prop->name, str);
254     }
255     g_free(str);
256 }
257 
258 static void release_chr(Object *obj, const char *name, void *opaque)
259 {
260     DeviceState *dev = DEVICE(obj);
261     Property *prop = opaque;
262     CharBackend *be = qdev_get_prop_ptr(dev, prop);
263 
264     qemu_chr_fe_deinit(be, false);
265 }
266 
267 const PropertyInfo qdev_prop_chr = {
268     .name  = "str",
269     .description = "ID of a chardev to use as a backend",
270     .get   = get_chr,
271     .set   = set_chr,
272     .release = release_chr,
273 };
274 
275 /* --- netdev device --- */
276 static void get_netdev(Object *obj, Visitor *v, const char *name,
277                        void *opaque, Error **errp)
278 {
279     DeviceState *dev = DEVICE(obj);
280     Property *prop = opaque;
281     NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
282     char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
283 
284     visit_type_str(v, name, &p, errp);
285     g_free(p);
286 }
287 
288 static void set_netdev(Object *obj, Visitor *v, const char *name,
289                        void *opaque, Error **errp)
290 {
291     DeviceState *dev = DEVICE(obj);
292     Property *prop = opaque;
293     NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
294     NetClientState **ncs = peers_ptr->ncs;
295     NetClientState *peers[MAX_QUEUE_NUM];
296     Error *local_err = NULL;
297     int queues, err = 0, i = 0;
298     char *str;
299 
300     if (dev->realized) {
301         qdev_prop_set_after_realize(dev, name, errp);
302         return;
303     }
304 
305     visit_type_str(v, name, &str, &local_err);
306     if (local_err) {
307         error_propagate(errp, local_err);
308         return;
309     }
310 
311     queues = qemu_find_net_clients_except(str, peers,
312                                           NET_CLIENT_DRIVER_NIC,
313                                           MAX_QUEUE_NUM);
314     if (queues == 0) {
315         err = -ENOENT;
316         goto out;
317     }
318 
319     if (queues > MAX_QUEUE_NUM) {
320         error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
321                    str, queues, MAX_QUEUE_NUM);
322         goto out;
323     }
324 
325     for (i = 0; i < queues; i++) {
326 
327         if (peers[i]->peer) {
328             err = -EEXIST;
329             goto out;
330         }
331 
332         if (ncs[i]) {
333             err = -EINVAL;
334             goto out;
335         }
336 
337         ncs[i] = peers[i];
338         ncs[i]->queue_index = i;
339     }
340 
341     peers_ptr->queues = queues;
342 
343 out:
344     error_set_from_qdev_prop_error(errp, err, dev, prop, str);
345     g_free(str);
346 }
347 
348 const PropertyInfo qdev_prop_netdev = {
349     .name  = "str",
350     .description = "ID of a netdev to use as a backend",
351     .get   = get_netdev,
352     .set   = set_netdev,
353 };
354 
355 
356 void qdev_prop_set_drive(DeviceState *dev, const char *name,
357                          BlockBackend *value, Error **errp)
358 {
359     const char *ref = "";
360 
361     if (value) {
362         ref = blk_name(value);
363         if (!*ref) {
364             const BlockDriverState *bs = blk_bs(value);
365             if (bs) {
366                 ref = bdrv_get_node_name(bs);
367             }
368         }
369     }
370 
371     object_property_set_str(OBJECT(dev), ref, name, errp);
372 }
373 
374 void qdev_prop_set_chr(DeviceState *dev, const char *name,
375                        Chardev *value)
376 {
377     assert(!value || value->label);
378     object_property_set_str(OBJECT(dev),
379                             value ? value->label : "", name, &error_abort);
380 }
381 
382 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
383                           NetClientState *value)
384 {
385     assert(!value || value->name);
386     object_property_set_str(OBJECT(dev),
387                             value ? value->name : "", name, &error_abort);
388 }
389 
390 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
391 {
392     qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
393     if (nd->netdev) {
394         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
395     }
396     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
397         object_property_find(OBJECT(dev), "vectors", NULL)) {
398         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
399     }
400     nd->instantiated = 1;
401 }
402