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.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 parse_drive(DeviceState *dev, const char *str, void **ptr,
73                         const char *propname, 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             blk = blk_new(0, BLK_PERM_ALL);
84             blk_created = true;
85 
86             ret = blk_insert_bs(blk, bs, errp);
87             if (ret < 0) {
88                 goto fail;
89             }
90         }
91     }
92     if (!blk) {
93         error_setg(errp, "Property '%s.%s' can't find value '%s'",
94                    object_get_typename(OBJECT(dev)), propname, str);
95         goto fail;
96     }
97     if (blk_attach_dev(blk, dev) < 0) {
98         DriveInfo *dinfo = blk_legacy_dinfo(blk);
99 
100         if (dinfo && dinfo->type != IF_NONE) {
101             error_setg(errp, "Drive '%s' is already in use because "
102                        "it has been automatically connected to another "
103                        "device (did you need 'if=none' in the drive options?)",
104                        str);
105         } else {
106             error_setg(errp, "Drive '%s' is already in use by another device",
107                        str);
108         }
109         goto fail;
110     }
111 
112     *ptr = blk;
113 
114 fail:
115     if (blk_created) {
116         /* If we need to keep a reference, blk_attach_dev() took it */
117         blk_unref(blk);
118     }
119 }
120 
121 static void release_drive(Object *obj, const char *name, void *opaque)
122 {
123     DeviceState *dev = DEVICE(obj);
124     Property *prop = opaque;
125     BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
126 
127     if (*ptr) {
128         AioContext *ctx = blk_get_aio_context(*ptr);
129 
130         aio_context_acquire(ctx);
131         blockdev_auto_del(*ptr);
132         blk_detach_dev(*ptr, dev);
133         aio_context_release(ctx);
134     }
135 }
136 
137 static char *print_drive(void *ptr)
138 {
139     const char *name;
140 
141     name = blk_name(ptr);
142     if (!*name) {
143         BlockDriverState *bs = blk_bs(ptr);
144         if (bs) {
145             name = bdrv_get_node_name(bs);
146         }
147     }
148     return g_strdup(name);
149 }
150 
151 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
152                       Error **errp)
153 {
154     get_pointer(obj, v, opaque, print_drive, name, errp);
155 }
156 
157 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
158                       Error **errp)
159 {
160     set_pointer(obj, v, opaque, parse_drive, name, errp);
161 }
162 
163 const PropertyInfo qdev_prop_drive = {
164     .name  = "str",
165     .description = "Node name or ID of a block device to use as a backend",
166     .get   = get_drive,
167     .set   = set_drive,
168     .release = release_drive,
169 };
170 
171 /* --- character device --- */
172 
173 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
174                     Error **errp)
175 {
176     DeviceState *dev = DEVICE(obj);
177     CharBackend *be = qdev_get_prop_ptr(dev, opaque);
178     char *p;
179 
180     p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
181     visit_type_str(v, name, &p, errp);
182     g_free(p);
183 }
184 
185 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
186                     Error **errp)
187 {
188     DeviceState *dev = DEVICE(obj);
189     Error *local_err = NULL;
190     Property *prop = opaque;
191     CharBackend *be = qdev_get_prop_ptr(dev, prop);
192     Chardev *s;
193     char *str;
194 
195     if (dev->realized) {
196         qdev_prop_set_after_realize(dev, name, errp);
197         return;
198     }
199 
200     visit_type_str(v, name, &str, &local_err);
201     if (local_err) {
202         error_propagate(errp, local_err);
203         return;
204     }
205 
206     if (!*str) {
207         g_free(str);
208         be->chr = NULL;
209         return;
210     }
211 
212     s = qemu_chr_find(str);
213     if (s == NULL) {
214         error_setg(errp, "Property '%s.%s' can't find value '%s'",
215                    object_get_typename(obj), prop->name, str);
216     } else if (!qemu_chr_fe_init(be, s, errp)) {
217         error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
218                       object_get_typename(obj), prop->name, str);
219     }
220     g_free(str);
221 }
222 
223 static void release_chr(Object *obj, const char *name, void *opaque)
224 {
225     DeviceState *dev = DEVICE(obj);
226     Property *prop = opaque;
227     CharBackend *be = qdev_get_prop_ptr(dev, prop);
228 
229     qemu_chr_fe_deinit(be, false);
230 }
231 
232 const PropertyInfo qdev_prop_chr = {
233     .name  = "str",
234     .description = "ID of a chardev to use as a backend",
235     .get   = get_chr,
236     .set   = set_chr,
237     .release = release_chr,
238 };
239 
240 /* --- netdev device --- */
241 static void get_netdev(Object *obj, Visitor *v, const char *name,
242                        void *opaque, Error **errp)
243 {
244     DeviceState *dev = DEVICE(obj);
245     Property *prop = opaque;
246     NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
247     char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
248 
249     visit_type_str(v, name, &p, errp);
250     g_free(p);
251 }
252 
253 static void set_netdev(Object *obj, Visitor *v, const char *name,
254                        void *opaque, Error **errp)
255 {
256     DeviceState *dev = DEVICE(obj);
257     Property *prop = opaque;
258     NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
259     NetClientState **ncs = peers_ptr->ncs;
260     NetClientState *peers[MAX_QUEUE_NUM];
261     Error *local_err = NULL;
262     int queues, err = 0, i = 0;
263     char *str;
264 
265     if (dev->realized) {
266         qdev_prop_set_after_realize(dev, name, errp);
267         return;
268     }
269 
270     visit_type_str(v, name, &str, &local_err);
271     if (local_err) {
272         error_propagate(errp, local_err);
273         return;
274     }
275 
276     queues = qemu_find_net_clients_except(str, peers,
277                                           NET_CLIENT_DRIVER_NIC,
278                                           MAX_QUEUE_NUM);
279     if (queues == 0) {
280         err = -ENOENT;
281         goto out;
282     }
283 
284     if (queues > MAX_QUEUE_NUM) {
285         error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
286                    str, queues, MAX_QUEUE_NUM);
287         goto out;
288     }
289 
290     for (i = 0; i < queues; i++) {
291         if (peers[i] == NULL) {
292             err = -ENOENT;
293             goto out;
294         }
295 
296         if (peers[i]->peer) {
297             err = -EEXIST;
298             goto out;
299         }
300 
301         if (ncs[i]) {
302             err = -EINVAL;
303             goto out;
304         }
305 
306         ncs[i] = peers[i];
307         ncs[i]->queue_index = i;
308     }
309 
310     peers_ptr->queues = queues;
311 
312 out:
313     error_set_from_qdev_prop_error(errp, err, dev, prop, str);
314     g_free(str);
315 }
316 
317 const PropertyInfo qdev_prop_netdev = {
318     .name  = "str",
319     .description = "ID of a netdev to use as a backend",
320     .get   = get_netdev,
321     .set   = set_netdev,
322 };
323 
324 
325 void qdev_prop_set_drive(DeviceState *dev, const char *name,
326                          BlockBackend *value, Error **errp)
327 {
328     const char *ref = "";
329 
330     if (value) {
331         ref = blk_name(value);
332         if (!*ref) {
333             const BlockDriverState *bs = blk_bs(value);
334             if (bs) {
335                 ref = bdrv_get_node_name(bs);
336             }
337         }
338     }
339 
340     object_property_set_str(OBJECT(dev), ref, name, errp);
341 }
342 
343 void qdev_prop_set_chr(DeviceState *dev, const char *name,
344                        Chardev *value)
345 {
346     assert(!value || value->label);
347     object_property_set_str(OBJECT(dev),
348                             value ? value->label : "", name, &error_abort);
349 }
350 
351 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
352                           NetClientState *value)
353 {
354     assert(!value || value->name);
355     object_property_set_str(OBJECT(dev),
356                             value ? value->name : "", name, &error_abort);
357 }
358 
359 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
360 {
361     qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
362     if (nd->netdev) {
363         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
364     }
365     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
366         object_property_find(OBJECT(dev), "vectors", NULL)) {
367         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
368     }
369     nd->instantiated = 1;
370 }
371