1 #include "qemu/osdep.h"
2 #include "hw/qdev-properties.h"
3 #include "qapi/error.h"
4 #include "qapi/qapi-types-misc.h"
5 #include "qapi/qapi-visit-common.h"
6 #include "qobject/qlist.h"
7 #include "qemu/ctype.h"
8 #include "qemu/error-report.h"
9 #include "qapi/visitor.h"
10 #include "qemu/units.h"
11 #include "qemu/cutils.h"
12 #include "qdev-prop-internal.h"
13 #include "qom/qom-qobject.h"
14
qdev_prop_set_after_realize(DeviceState * dev,const char * name,Error ** errp)15 void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
16 Error **errp)
17 {
18 if (dev->id) {
19 error_setg(errp, "Attempt to set property '%s' on device '%s' "
20 "(type '%s') after it was realized", name, dev->id,
21 object_get_typename(OBJECT(dev)));
22 } else {
23 error_setg(errp, "Attempt to set property '%s' on anonymous device "
24 "(type '%s') after it was realized", name,
25 object_get_typename(OBJECT(dev)));
26 }
27 }
28
29 /* returns: true if property is allowed to be set, false otherwise */
qdev_prop_allow_set(Object * obj,const char * name,const PropertyInfo * info,Error ** errp)30 static bool qdev_prop_allow_set(Object *obj, const char *name,
31 const PropertyInfo *info, Error **errp)
32 {
33 DeviceState *dev = DEVICE(obj);
34
35 if (dev->realized && !info->realized_set_allowed) {
36 qdev_prop_set_after_realize(dev, name, errp);
37 return false;
38 }
39 return true;
40 }
41
qdev_prop_allow_set_link_before_realize(const Object * obj,const char * name,Object * val,Error ** errp)42 void qdev_prop_allow_set_link_before_realize(const Object *obj,
43 const char *name,
44 Object *val, Error **errp)
45 {
46 DeviceState *dev = DEVICE(obj);
47
48 if (dev->realized) {
49 error_setg(errp, "Attempt to set link property '%s' on device '%s' "
50 "(type '%s') after it was realized",
51 name, dev->id, object_get_typename(obj));
52 }
53 }
54
object_field_prop_ptr(Object * obj,const Property * prop)55 void *object_field_prop_ptr(Object *obj, const Property *prop)
56 {
57 void *ptr = obj;
58 ptr += prop->offset;
59 return ptr;
60 }
61
field_prop_get(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)62 static void field_prop_get(Object *obj, Visitor *v, const char *name,
63 void *opaque, Error **errp)
64 {
65 const Property *prop = opaque;
66 return prop->info->get(obj, v, name, opaque, errp);
67 }
68
69 /**
70 * field_prop_getter: Return getter function to be used for property
71 *
72 * Return value can be NULL if @info has no getter function.
73 */
field_prop_getter(const PropertyInfo * info)74 static ObjectPropertyAccessor *field_prop_getter(const PropertyInfo *info)
75 {
76 return info->get ? field_prop_get : NULL;
77 }
78
field_prop_set(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)79 static void field_prop_set(Object *obj, Visitor *v, const char *name,
80 void *opaque, Error **errp)
81 {
82 const Property *prop = opaque;
83
84 if (!qdev_prop_allow_set(obj, name, prop->info, errp)) {
85 return;
86 }
87
88 return prop->info->set(obj, v, name, opaque, errp);
89 }
90
91 /**
92 * field_prop_setter: Return setter function to be used for property
93 *
94 * Return value can be NULL if @info has not setter function.
95 */
field_prop_setter(const PropertyInfo * info)96 static ObjectPropertyAccessor *field_prop_setter(const PropertyInfo *info)
97 {
98 return info->set ? field_prop_set : NULL;
99 }
100
qdev_propinfo_get_enum(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)101 void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
102 void *opaque, Error **errp)
103 {
104 const Property *prop = opaque;
105 int *ptr = object_field_prop_ptr(obj, prop);
106
107 visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
108 }
109
qdev_propinfo_set_enum(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)110 void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name,
111 void *opaque, Error **errp)
112 {
113 const Property *prop = opaque;
114 int *ptr = object_field_prop_ptr(obj, prop);
115
116 visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
117 }
118
qdev_propinfo_set_default_value_enum(ObjectProperty * op,const Property * prop)119 void qdev_propinfo_set_default_value_enum(ObjectProperty *op,
120 const Property *prop)
121 {
122 object_property_set_default_str(op,
123 qapi_enum_lookup(prop->info->enum_table, prop->defval.i));
124 }
125
126 /* Bit */
127
qdev_get_prop_mask(const Property * prop)128 static uint32_t qdev_get_prop_mask(const Property *prop)
129 {
130 assert(prop->info == &qdev_prop_bit);
131 return 0x1 << prop->bitnr;
132 }
133
bit_prop_set(Object * obj,const Property * props,bool val)134 static void bit_prop_set(Object *obj, const Property *props, bool val)
135 {
136 uint32_t *p = object_field_prop_ptr(obj, props);
137 uint32_t mask = qdev_get_prop_mask(props);
138 if (val) {
139 *p |= mask;
140 } else {
141 *p &= ~mask;
142 }
143 }
144
prop_get_bit(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)145 static void prop_get_bit(Object *obj, Visitor *v, const char *name,
146 void *opaque, Error **errp)
147 {
148 const Property *prop = opaque;
149 uint32_t *p = object_field_prop_ptr(obj, prop);
150 bool value = (*p & qdev_get_prop_mask(prop)) != 0;
151
152 visit_type_bool(v, name, &value, errp);
153 }
154
prop_set_bit(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)155 static void prop_set_bit(Object *obj, Visitor *v, const char *name,
156 void *opaque, Error **errp)
157 {
158 const Property *prop = opaque;
159 bool value;
160
161 if (!visit_type_bool(v, name, &value, errp)) {
162 return;
163 }
164 bit_prop_set(obj, prop, value);
165 }
166
set_default_value_bool(ObjectProperty * op,const Property * prop)167 static void set_default_value_bool(ObjectProperty *op, const Property *prop)
168 {
169 object_property_set_default_bool(op, prop->defval.u);
170 }
171
172 const PropertyInfo qdev_prop_bit = {
173 .type = "bool",
174 .description = "on/off",
175 .get = prop_get_bit,
176 .set = prop_set_bit,
177 .set_default_value = set_default_value_bool,
178 };
179
180 /* Bit64 */
181
qdev_get_prop_mask64(const Property * prop)182 static uint64_t qdev_get_prop_mask64(const Property *prop)
183 {
184 assert(prop->info == &qdev_prop_bit64 ||
185 prop->info == &qdev_prop_on_off_auto_bit64);
186 return 0x1ull << prop->bitnr;
187 }
188
bit64_prop_set(Object * obj,const Property * props,bool val)189 static void bit64_prop_set(Object *obj, const Property *props, bool val)
190 {
191 uint64_t *p = object_field_prop_ptr(obj, props);
192 uint64_t mask = qdev_get_prop_mask64(props);
193 if (val) {
194 *p |= mask;
195 } else {
196 *p &= ~mask;
197 }
198 }
199
prop_get_bit64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)200 static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
201 void *opaque, Error **errp)
202 {
203 const Property *prop = opaque;
204 uint64_t *p = object_field_prop_ptr(obj, prop);
205 bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
206
207 visit_type_bool(v, name, &value, errp);
208 }
209
prop_set_bit64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)210 static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
211 void *opaque, Error **errp)
212 {
213 const Property *prop = opaque;
214 bool value;
215
216 if (!visit_type_bool(v, name, &value, errp)) {
217 return;
218 }
219 bit64_prop_set(obj, prop, value);
220 }
221
222 const PropertyInfo qdev_prop_bit64 = {
223 .type = "bool",
224 .description = "on/off",
225 .get = prop_get_bit64,
226 .set = prop_set_bit64,
227 .set_default_value = set_default_value_bool,
228 };
229
prop_get_on_off_auto_bit64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)230 static void prop_get_on_off_auto_bit64(Object *obj, Visitor *v,
231 const char *name, void *opaque,
232 Error **errp)
233 {
234 Property *prop = opaque;
235 OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop);
236 OnOffAuto value;
237 uint64_t mask = qdev_get_prop_mask64(prop);
238
239 if (p->auto_bits & mask) {
240 value = ON_OFF_AUTO_AUTO;
241 } else if (p->on_bits & mask) {
242 value = ON_OFF_AUTO_ON;
243 } else {
244 value = ON_OFF_AUTO_OFF;
245 }
246
247 visit_type_OnOffAuto(v, name, &value, errp);
248 }
249
prop_set_on_off_auto_bit64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)250 static void prop_set_on_off_auto_bit64(Object *obj, Visitor *v,
251 const char *name, void *opaque,
252 Error **errp)
253 {
254 Property *prop = opaque;
255 OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop);
256 OnOffAuto value;
257 uint64_t mask = qdev_get_prop_mask64(prop);
258
259 if (!visit_type_OnOffAuto(v, name, &value, errp)) {
260 return;
261 }
262
263 switch (value) {
264 case ON_OFF_AUTO_AUTO:
265 p->on_bits &= ~mask;
266 p->auto_bits |= mask;
267 break;
268
269 case ON_OFF_AUTO_ON:
270 p->on_bits |= mask;
271 p->auto_bits &= ~mask;
272 break;
273
274 case ON_OFF_AUTO_OFF:
275 p->on_bits &= ~mask;
276 p->auto_bits &= ~mask;
277 break;
278
279 case ON_OFF_AUTO__MAX:
280 g_assert_not_reached();
281 }
282 }
283
284 const PropertyInfo qdev_prop_on_off_auto_bit64 = {
285 .type = "OnOffAuto",
286 .description = "on/off/auto",
287 .enum_table = &OnOffAuto_lookup,
288 .get = prop_get_on_off_auto_bit64,
289 .set = prop_set_on_off_auto_bit64,
290 .set_default_value = qdev_propinfo_set_default_value_enum,
291 };
292
293 /* --- bool --- */
294
get_bool(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)295 static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
296 Error **errp)
297 {
298 const Property *prop = opaque;
299 bool *ptr = object_field_prop_ptr(obj, prop);
300
301 visit_type_bool(v, name, ptr, errp);
302 }
303
set_bool(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)304 static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
305 Error **errp)
306 {
307 const Property *prop = opaque;
308 bool *ptr = object_field_prop_ptr(obj, prop);
309
310 visit_type_bool(v, name, ptr, errp);
311 }
312
313 const PropertyInfo qdev_prop_bool = {
314 .type = "bool",
315 .description = "on/off",
316 .get = get_bool,
317 .set = set_bool,
318 .set_default_value = set_default_value_bool,
319 };
320
321 /* --- 8bit integer --- */
322
get_uint8(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)323 static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
324 Error **errp)
325 {
326 const Property *prop = opaque;
327 uint8_t *ptr = object_field_prop_ptr(obj, prop);
328
329 visit_type_uint8(v, name, ptr, errp);
330 }
331
set_uint8(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)332 static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
333 Error **errp)
334 {
335 const Property *prop = opaque;
336 uint8_t *ptr = object_field_prop_ptr(obj, prop);
337
338 visit_type_uint8(v, name, ptr, errp);
339 }
340
qdev_propinfo_set_default_value_int(ObjectProperty * op,const Property * prop)341 void qdev_propinfo_set_default_value_int(ObjectProperty *op,
342 const Property *prop)
343 {
344 object_property_set_default_int(op, prop->defval.i);
345 }
346
qdev_propinfo_set_default_value_uint(ObjectProperty * op,const Property * prop)347 void qdev_propinfo_set_default_value_uint(ObjectProperty *op,
348 const Property *prop)
349 {
350 object_property_set_default_uint(op, prop->defval.u);
351 }
352
353 const PropertyInfo qdev_prop_uint8 = {
354 .type = "uint8",
355 .get = get_uint8,
356 .set = set_uint8,
357 .set_default_value = qdev_propinfo_set_default_value_uint,
358 };
359
360 /* --- 16bit integer --- */
361
get_uint16(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)362 static void get_uint16(Object *obj, Visitor *v, const char *name,
363 void *opaque, Error **errp)
364 {
365 const Property *prop = opaque;
366 uint16_t *ptr = object_field_prop_ptr(obj, prop);
367
368 visit_type_uint16(v, name, ptr, errp);
369 }
370
set_uint16(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)371 static void set_uint16(Object *obj, Visitor *v, const char *name,
372 void *opaque, Error **errp)
373 {
374 const Property *prop = opaque;
375 uint16_t *ptr = object_field_prop_ptr(obj, prop);
376
377 visit_type_uint16(v, name, ptr, errp);
378 }
379
380 const PropertyInfo qdev_prop_uint16 = {
381 .type = "uint16",
382 .get = get_uint16,
383 .set = set_uint16,
384 .set_default_value = qdev_propinfo_set_default_value_uint,
385 };
386
387 /* --- 32bit integer --- */
388
get_uint32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)389 static void get_uint32(Object *obj, Visitor *v, const char *name,
390 void *opaque, Error **errp)
391 {
392 const Property *prop = opaque;
393 uint32_t *ptr = object_field_prop_ptr(obj, prop);
394
395 visit_type_uint32(v, name, ptr, errp);
396 }
397
set_uint32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)398 static void set_uint32(Object *obj, Visitor *v, const char *name,
399 void *opaque, Error **errp)
400 {
401 const Property *prop = opaque;
402 uint32_t *ptr = object_field_prop_ptr(obj, prop);
403
404 visit_type_uint32(v, name, ptr, errp);
405 }
406
qdev_propinfo_get_int32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)407 void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
408 void *opaque, Error **errp)
409 {
410 const Property *prop = opaque;
411 int32_t *ptr = object_field_prop_ptr(obj, prop);
412
413 visit_type_int32(v, name, ptr, errp);
414 }
415
set_int32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)416 static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
417 Error **errp)
418 {
419 const Property *prop = opaque;
420 int32_t *ptr = object_field_prop_ptr(obj, prop);
421
422 visit_type_int32(v, name, ptr, errp);
423 }
424
425 const PropertyInfo qdev_prop_uint32 = {
426 .type = "uint32",
427 .get = get_uint32,
428 .set = set_uint32,
429 .set_default_value = qdev_propinfo_set_default_value_uint,
430 };
431
432 const PropertyInfo qdev_prop_int32 = {
433 .type = "int32",
434 .get = qdev_propinfo_get_int32,
435 .set = set_int32,
436 .set_default_value = qdev_propinfo_set_default_value_int,
437 };
438
439 /* --- 64bit integer --- */
440
get_uint64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)441 static void get_uint64(Object *obj, Visitor *v, const char *name,
442 void *opaque, Error **errp)
443 {
444 const Property *prop = opaque;
445 uint64_t *ptr = object_field_prop_ptr(obj, prop);
446
447 visit_type_uint64(v, name, ptr, errp);
448 }
449
set_uint64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)450 static void set_uint64(Object *obj, Visitor *v, const char *name,
451 void *opaque, Error **errp)
452 {
453 const Property *prop = opaque;
454 uint64_t *ptr = object_field_prop_ptr(obj, prop);
455
456 visit_type_uint64(v, name, ptr, errp);
457 }
458
get_int64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)459 static void get_int64(Object *obj, Visitor *v, const char *name,
460 void *opaque, Error **errp)
461 {
462 const Property *prop = opaque;
463 int64_t *ptr = object_field_prop_ptr(obj, prop);
464
465 visit_type_int64(v, name, ptr, errp);
466 }
467
set_int64(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)468 static void set_int64(Object *obj, Visitor *v, const char *name,
469 void *opaque, Error **errp)
470 {
471 const Property *prop = opaque;
472 int64_t *ptr = object_field_prop_ptr(obj, prop);
473
474 visit_type_int64(v, name, ptr, errp);
475 }
476
477 const PropertyInfo qdev_prop_uint64 = {
478 .type = "uint64",
479 .get = get_uint64,
480 .set = set_uint64,
481 .set_default_value = qdev_propinfo_set_default_value_uint,
482 };
483
484 const PropertyInfo qdev_prop_int64 = {
485 .type = "int64",
486 .get = get_int64,
487 .set = set_int64,
488 .set_default_value = qdev_propinfo_set_default_value_int,
489 };
490
set_uint64_checkmask(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)491 static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name,
492 void *opaque, Error **errp)
493 {
494 const Property *prop = opaque;
495 uint64_t *ptr = object_field_prop_ptr(obj, prop);
496
497 visit_type_uint64(v, name, ptr, errp);
498 if (*ptr & ~prop->bitmask) {
499 error_setg(errp, "Property value for '%s' has bits outside mask '0x%" PRIx64 "'",
500 name, prop->bitmask);
501 }
502 }
503
504 const PropertyInfo qdev_prop_uint64_checkmask = {
505 .type = "uint64",
506 .get = get_uint64,
507 .set = set_uint64_checkmask,
508 };
509
510 /* --- pointer-size integer --- */
511
get_usize(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)512 static void get_usize(Object *obj, Visitor *v, const char *name, void *opaque,
513 Error **errp)
514 {
515 const Property *prop = opaque;
516
517 #if HOST_LONG_BITS == 32
518 uint32_t *ptr = object_field_prop_ptr(obj, prop);
519 visit_type_uint32(v, name, ptr, errp);
520 #else
521 uint64_t *ptr = object_field_prop_ptr(obj, prop);
522 visit_type_uint64(v, name, ptr, errp);
523 #endif
524 }
525
set_usize(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)526 static void set_usize(Object *obj, Visitor *v, const char *name, void *opaque,
527 Error **errp)
528 {
529 const Property *prop = opaque;
530
531 #if HOST_LONG_BITS == 32
532 uint32_t *ptr = object_field_prop_ptr(obj, prop);
533 visit_type_uint32(v, name, ptr, errp);
534 #else
535 uint64_t *ptr = object_field_prop_ptr(obj, prop);
536 visit_type_uint64(v, name, ptr, errp);
537 #endif
538 }
539
540 const PropertyInfo qdev_prop_usize = {
541 .type = "usize",
542 .get = get_usize,
543 .set = set_usize,
544 .set_default_value = qdev_propinfo_set_default_value_uint,
545 };
546
547 /* --- string --- */
548
release_string(Object * obj,const char * name,void * opaque)549 static void release_string(Object *obj, const char *name, void *opaque)
550 {
551 const Property *prop = opaque;
552 g_free(*(char **)object_field_prop_ptr(obj, prop));
553 }
554
get_string(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)555 static void get_string(Object *obj, Visitor *v, const char *name,
556 void *opaque, Error **errp)
557 {
558 const Property *prop = opaque;
559 char **ptr = object_field_prop_ptr(obj, prop);
560
561 if (!*ptr) {
562 char *str = (char *)"";
563 visit_type_str(v, name, &str, errp);
564 } else {
565 visit_type_str(v, name, ptr, errp);
566 }
567 }
568
set_string(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)569 static void set_string(Object *obj, Visitor *v, const char *name,
570 void *opaque, Error **errp)
571 {
572 const Property *prop = opaque;
573 char **ptr = object_field_prop_ptr(obj, prop);
574 char *str;
575
576 if (!visit_type_str(v, name, &str, errp)) {
577 return;
578 }
579 g_free(*ptr);
580 *ptr = str;
581 }
582
583 const PropertyInfo qdev_prop_string = {
584 .type = "str",
585 .release = release_string,
586 .get = get_string,
587 .set = set_string,
588 };
589
590 /* --- on/off/auto --- */
591
592 const PropertyInfo qdev_prop_on_off_auto = {
593 .type = "OnOffAuto",
594 .description = "on/off/auto",
595 .enum_table = &OnOffAuto_lookup,
596 .get = qdev_propinfo_get_enum,
597 .set = qdev_propinfo_set_enum,
598 .set_default_value = qdev_propinfo_set_default_value_enum,
599 };
600
601 /* --- 32bit unsigned int 'size' type --- */
602
qdev_propinfo_get_size32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)603 void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
604 void *opaque, Error **errp)
605 {
606 const Property *prop = opaque;
607 uint32_t *ptr = object_field_prop_ptr(obj, prop);
608 uint64_t value = *ptr;
609
610 visit_type_size(v, name, &value, errp);
611 }
612
set_size32(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)613 static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
614 Error **errp)
615 {
616 const Property *prop = opaque;
617 uint32_t *ptr = object_field_prop_ptr(obj, prop);
618 uint64_t value;
619
620 if (!visit_type_size(v, name, &value, errp)) {
621 return;
622 }
623
624 if (value > UINT32_MAX) {
625 error_setg(errp,
626 "Property %s.%s doesn't take value %" PRIu64
627 " (maximum: %u)",
628 object_get_typename(obj), name, value, UINT32_MAX);
629 return;
630 }
631
632 *ptr = value;
633 }
634
635 const PropertyInfo qdev_prop_size32 = {
636 .type = "size",
637 .get = qdev_propinfo_get_size32,
638 .set = set_size32,
639 .set_default_value = qdev_propinfo_set_default_value_uint,
640 };
641
642 /* --- support for array properties --- */
643
644 typedef struct ArrayElementList ArrayElementList;
645
646 struct ArrayElementList {
647 ArrayElementList *next;
648 void *value;
649 };
650
651 /*
652 * Given an array property @parent_prop in @obj, return a Property for a
653 * specific element of the array. Arrays are backed by an uint32_t length field
654 * and an element array. @elem points at an element in this element array.
655 */
array_elem_prop(Object * obj,const Property * parent_prop,const char * name,char * elem)656 static Property array_elem_prop(Object *obj, const Property *parent_prop,
657 const char *name, char *elem)
658 {
659 return (Property) {
660 .info = parent_prop->arrayinfo,
661 .name = name,
662 /*
663 * This ugly piece of pointer arithmetic sets up the offset so
664 * that when the underlying release hook calls qdev_get_prop_ptr
665 * they get the right answer despite the array element not actually
666 * being inside the device struct.
667 */
668 .offset = (uintptr_t)elem - (uintptr_t)obj,
669 };
670 }
671
672 /*
673 * Object property release callback for array properties: We call the
674 * underlying element's property release hook for each element.
675 *
676 * Note that it is the responsibility of the individual device's deinit
677 * to free the array proper.
678 */
release_prop_array(Object * obj,const char * name,void * opaque)679 static void release_prop_array(Object *obj, const char *name, void *opaque)
680 {
681 const Property *prop = opaque;
682 uint32_t *alenptr = object_field_prop_ptr(obj, prop);
683 void **arrayptr = (void *)obj + prop->arrayoffset;
684 char *elem = *arrayptr;
685 int i;
686
687 if (!prop->arrayinfo->release) {
688 return;
689 }
690
691 for (i = 0; i < *alenptr; i++) {
692 Property elem_prop = array_elem_prop(obj, prop, name, elem);
693 prop->arrayinfo->release(obj, NULL, &elem_prop);
694 elem += prop->arrayfieldsize;
695 }
696 }
697
698 /*
699 * Setter for an array property. This sets both the array length (which
700 * is technically the property field in the object) and the array itself
701 * (a pointer to which is stored in the additional field described by
702 * prop->arrayoffset).
703 */
set_prop_array(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)704 static void set_prop_array(Object *obj, Visitor *v, const char *name,
705 void *opaque, Error **errp)
706 {
707 ERRP_GUARD();
708 const Property *prop = opaque;
709 uint32_t *alenptr = object_field_prop_ptr(obj, prop);
710 void **arrayptr = (void *)obj + prop->arrayoffset;
711 ArrayElementList *list, *elem, *next;
712 const size_t size = sizeof(*list);
713 char *elemptr;
714 bool ok = true;
715
716 if (*alenptr) {
717 error_setg(errp, "array size property %s may not be set more than once",
718 name);
719 return;
720 }
721
722 if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) {
723 return;
724 }
725
726 /* Read the whole input into a temporary list */
727 elem = list;
728 while (elem) {
729 Property elem_prop;
730
731 elem->value = g_malloc0(prop->arrayfieldsize);
732 elem_prop = array_elem_prop(obj, prop, name, elem->value);
733 prop->arrayinfo->set(obj, v, NULL, &elem_prop, errp);
734 if (*errp) {
735 ok = false;
736 goto out_obj;
737 }
738 if (*alenptr == INT_MAX) {
739 error_setg(errp, "array is too big");
740 return;
741 }
742 (*alenptr)++;
743 elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem,
744 size);
745 }
746
747 ok = visit_check_list(v, errp);
748 out_obj:
749 visit_end_list(v, (void**) &list);
750
751 if (!ok) {
752 for (elem = list; elem; elem = next) {
753 Property elem_prop = array_elem_prop(obj, prop, name,
754 elem->value);
755 if (prop->arrayinfo->release) {
756 prop->arrayinfo->release(obj, NULL, &elem_prop);
757 }
758 next = elem->next;
759 g_free(elem->value);
760 g_free(elem);
761 }
762 return;
763 }
764
765 /*
766 * Now that we know how big the array has to be, move the data over to a
767 * linear array and free the temporary list.
768 */
769 *arrayptr = g_malloc_n(*alenptr, prop->arrayfieldsize);
770 elemptr = *arrayptr;
771 for (elem = list; elem; elem = next) {
772 memcpy(elemptr, elem->value, prop->arrayfieldsize);
773 elemptr += prop->arrayfieldsize;
774 next = elem->next;
775 g_free(elem->value);
776 g_free(elem);
777 }
778 }
779
get_prop_array(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)780 static void get_prop_array(Object *obj, Visitor *v, const char *name,
781 void *opaque, Error **errp)
782 {
783 ERRP_GUARD();
784 const Property *prop = opaque;
785 uint32_t *alenptr = object_field_prop_ptr(obj, prop);
786 void **arrayptr = (void *)obj + prop->arrayoffset;
787 char *elemptr = *arrayptr;
788 ArrayElementList *list = NULL, *elem;
789 ArrayElementList **tail = &list;
790 const size_t size = sizeof(*list);
791 int i;
792 bool ok;
793
794 /* At least the string output visitor needs a real list */
795 for (i = 0; i < *alenptr; i++) {
796 elem = g_new0(ArrayElementList, 1);
797 elem->value = elemptr;
798 elemptr += prop->arrayfieldsize;
799
800 *tail = elem;
801 tail = &elem->next;
802 }
803
804 if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) {
805 return;
806 }
807
808 elem = list;
809 while (elem) {
810 Property elem_prop = array_elem_prop(obj, prop, name, elem->value);
811 prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
812 if (*errp) {
813 goto out_obj;
814 }
815 elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem,
816 size);
817 }
818
819 /* visit_check_list() can only fail for input visitors */
820 ok = visit_check_list(v, errp);
821 assert(ok);
822
823 out_obj:
824 visit_end_list(v, (void**) &list);
825
826 while (list) {
827 elem = list;
828 list = elem->next;
829 g_free(elem);
830 }
831 }
832
default_prop_array(ObjectProperty * op,const Property * prop)833 static void default_prop_array(ObjectProperty *op, const Property *prop)
834 {
835 object_property_set_default_list(op);
836 }
837
838 const PropertyInfo qdev_prop_array = {
839 .type = "list",
840 .get = get_prop_array,
841 .set = set_prop_array,
842 .release = release_prop_array,
843 .set_default_value = default_prop_array,
844 };
845
846 /* --- public helpers --- */
847
qdev_prop_walk(DeviceClass * cls,const char * name)848 static const Property *qdev_prop_walk(DeviceClass *cls, const char *name)
849 {
850 for (int i = 0, n = cls->props_count_; i < n; ++i) {
851 const Property *prop = &cls->props_[i];
852 if (strcmp(prop->name, name) == 0) {
853 return prop;
854 }
855 }
856 return NULL;
857 }
858
qdev_prop_find(DeviceState * dev,const char * name)859 static const Property *qdev_prop_find(DeviceState *dev, const char *name)
860 {
861 ObjectClass *class;
862 const Property *prop;
863
864 /* device properties */
865 class = object_get_class(OBJECT(dev));
866 do {
867 prop = qdev_prop_walk(DEVICE_CLASS(class), name);
868 if (prop) {
869 return prop;
870 }
871 class = object_class_get_parent(class);
872 } while (class != object_class_by_name(TYPE_DEVICE));
873
874 return NULL;
875 }
876
error_set_from_qdev_prop_error(Error ** errp,int ret,Object * obj,const char * name,const char * value)877 void error_set_from_qdev_prop_error(Error **errp, int ret, Object *obj,
878 const char *name, const char *value)
879 {
880 switch (ret) {
881 case -EEXIST:
882 error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
883 object_get_typename(obj), name, value);
884 break;
885 default:
886 case -EINVAL:
887 error_setg(errp, "Property '%s.%s' doesn't take value '%s'",
888 object_get_typename(obj), name, value);
889 break;
890 case -ENOENT:
891 error_setg(errp, "Property '%s.%s' can't find value '%s'",
892 object_get_typename(obj), name, value);
893 break;
894 case 0:
895 break;
896 }
897 }
898
qdev_prop_set_bit(DeviceState * dev,const char * name,bool value)899 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
900 {
901 object_property_set_bool(OBJECT(dev), name, value, &error_abort);
902 }
903
qdev_prop_set_uint8(DeviceState * dev,const char * name,uint8_t value)904 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
905 {
906 object_property_set_int(OBJECT(dev), name, value, &error_abort);
907 }
908
qdev_prop_set_uint16(DeviceState * dev,const char * name,uint16_t value)909 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
910 {
911 object_property_set_int(OBJECT(dev), name, value, &error_abort);
912 }
913
qdev_prop_set_uint32(DeviceState * dev,const char * name,uint32_t value)914 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
915 {
916 object_property_set_int(OBJECT(dev), name, value, &error_abort);
917 }
918
qdev_prop_set_int32(DeviceState * dev,const char * name,int32_t value)919 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
920 {
921 object_property_set_int(OBJECT(dev), name, value, &error_abort);
922 }
923
qdev_prop_set_uint64(DeviceState * dev,const char * name,uint64_t value)924 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
925 {
926 object_property_set_int(OBJECT(dev), name, value, &error_abort);
927 }
928
qdev_prop_set_string(DeviceState * dev,const char * name,const char * value)929 void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
930 {
931 object_property_set_str(OBJECT(dev), name, value, &error_abort);
932 }
933
qdev_prop_set_enum(DeviceState * dev,const char * name,int value)934 void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
935 {
936 const Property *prop;
937
938 prop = qdev_prop_find(dev, name);
939 object_property_set_str(OBJECT(dev), name,
940 qapi_enum_lookup(prop->info->enum_table, value),
941 &error_abort);
942 }
943
qdev_prop_set_array(DeviceState * dev,const char * name,QList * values)944 void qdev_prop_set_array(DeviceState *dev, const char *name, QList *values)
945 {
946 object_property_set_qobject(OBJECT(dev), name, QOBJECT(values),
947 &error_abort);
948 qobject_unref(values);
949 }
950
global_props(void)951 static GPtrArray *global_props(void)
952 {
953 static GPtrArray *gp;
954
955 if (!gp) {
956 gp = g_ptr_array_new();
957 }
958
959 return gp;
960 }
961
qdev_prop_register_global(GlobalProperty * prop)962 void qdev_prop_register_global(GlobalProperty *prop)
963 {
964 g_ptr_array_add(global_props(), prop);
965 }
966
qdev_find_global_prop(Object * obj,const char * name)967 const GlobalProperty *qdev_find_global_prop(Object *obj,
968 const char *name)
969 {
970 GPtrArray *props = global_props();
971 const GlobalProperty *p;
972 int i;
973
974 for (i = 0; i < props->len; i++) {
975 p = g_ptr_array_index(props, i);
976 if (object_dynamic_cast(obj, p->driver)
977 && !strcmp(p->property, name)) {
978 return p;
979 }
980 }
981 return NULL;
982 }
983
qdev_prop_check_globals(void)984 int qdev_prop_check_globals(void)
985 {
986 int i, ret = 0;
987
988 for (i = 0; i < global_props()->len; i++) {
989 GlobalProperty *prop;
990 ObjectClass *oc;
991 DeviceClass *dc;
992
993 prop = g_ptr_array_index(global_props(), i);
994 if (prop->used) {
995 continue;
996 }
997 oc = object_class_by_name(prop->driver);
998 oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
999 if (!oc) {
1000 warn_report("global %s.%s has invalid class name",
1001 prop->driver, prop->property);
1002 ret = 1;
1003 continue;
1004 }
1005 dc = DEVICE_CLASS(oc);
1006 if (!dc->hotpluggable && !prop->used) {
1007 warn_report("global %s.%s=%s not used",
1008 prop->driver, prop->property, prop->value);
1009 ret = 1;
1010 continue;
1011 }
1012 }
1013 return ret;
1014 }
1015
qdev_prop_set_globals(DeviceState * dev)1016 void qdev_prop_set_globals(DeviceState *dev)
1017 {
1018 object_apply_global_props(OBJECT(dev), global_props(),
1019 dev->hotplugged ? NULL : &error_fatal);
1020 }
1021
1022 /* --- 64bit unsigned int 'size' type --- */
1023
get_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1024 static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
1025 Error **errp)
1026 {
1027 const Property *prop = opaque;
1028 uint64_t *ptr = object_field_prop_ptr(obj, prop);
1029
1030 visit_type_size(v, name, ptr, errp);
1031 }
1032
set_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1033 static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
1034 Error **errp)
1035 {
1036 const Property *prop = opaque;
1037 uint64_t *ptr = object_field_prop_ptr(obj, prop);
1038
1039 visit_type_size(v, name, ptr, errp);
1040 }
1041
1042 const PropertyInfo qdev_prop_size = {
1043 .type = "size",
1044 .get = get_size,
1045 .set = set_size,
1046 .set_default_value = qdev_propinfo_set_default_value_uint,
1047 };
1048
1049 /* --- object link property --- */
1050
create_link_property(ObjectClass * oc,const char * name,const Property * prop)1051 static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
1052 const Property *prop)
1053 {
1054 return object_class_property_add_link(oc, name, prop->link_type,
1055 prop->offset,
1056 qdev_prop_allow_set_link_before_realize,
1057 OBJ_PROP_LINK_STRONG);
1058 }
1059
1060 const PropertyInfo qdev_prop_link = {
1061 .type = "link",
1062 .create = create_link_property,
1063 };
1064
qdev_property_add_static(DeviceState * dev,const Property * prop)1065 void qdev_property_add_static(DeviceState *dev, const Property *prop)
1066 {
1067 Object *obj = OBJECT(dev);
1068 ObjectProperty *op;
1069
1070 assert(!prop->info->create);
1071
1072 op = object_property_add(obj, prop->name, prop->info->type,
1073 field_prop_getter(prop->info),
1074 field_prop_setter(prop->info),
1075 prop->info->release,
1076 (Property *)prop);
1077
1078 object_property_set_description(obj, prop->name,
1079 prop->info->description);
1080
1081 if (prop->set_default) {
1082 prop->info->set_default_value(op, prop);
1083 if (op->init) {
1084 op->init(obj, op);
1085 }
1086 }
1087 }
1088
qdev_class_add_property(DeviceClass * klass,const char * name,const Property * prop)1089 static void qdev_class_add_property(DeviceClass *klass, const char *name,
1090 const Property *prop)
1091 {
1092 ObjectClass *oc = OBJECT_CLASS(klass);
1093 ObjectProperty *op;
1094
1095 if (prop->info->create) {
1096 op = prop->info->create(oc, name, prop);
1097 } else {
1098 op = object_class_property_add(oc,
1099 name, prop->info->type,
1100 field_prop_getter(prop->info),
1101 field_prop_setter(prop->info),
1102 prop->info->release,
1103 (Property *)prop);
1104 }
1105 if (prop->set_default) {
1106 prop->info->set_default_value(op, prop);
1107 }
1108 object_class_property_set_description(oc, name, prop->info->description);
1109 }
1110
1111 /**
1112 * Legacy property handling
1113 */
1114
qdev_get_legacy_property(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1115 static void qdev_get_legacy_property(Object *obj, Visitor *v,
1116 const char *name, void *opaque,
1117 Error **errp)
1118 {
1119 const Property *prop = opaque;
1120
1121 char buffer[1024];
1122 char *ptr = buffer;
1123
1124 prop->info->print(obj, prop, buffer, sizeof(buffer));
1125 visit_type_str(v, name, &ptr, errp);
1126 }
1127
1128 /**
1129 * qdev_class_add_legacy_property:
1130 * @dev: Device to add the property to.
1131 * @prop: The qdev property definition.
1132 *
1133 * Add a legacy QOM property to @dev for qdev property @prop.
1134 *
1135 * Legacy properties are string versions of QOM properties. The format of
1136 * the string depends on the property type. Legacy properties are only
1137 * needed for "info qtree".
1138 *
1139 * Do not use this in new code! QOM Properties added through this interface
1140 * will be given names in the "legacy" namespace.
1141 */
qdev_class_add_legacy_property(DeviceClass * dc,const Property * prop)1142 static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
1143 {
1144 g_autofree char *name = NULL;
1145
1146 /* Register pointer properties as legacy properties */
1147 if (!prop->info->print && prop->info->get) {
1148 return;
1149 }
1150
1151 name = g_strdup_printf("legacy-%s", prop->name);
1152 object_class_property_add(OBJECT_CLASS(dc), name, "str",
1153 prop->info->print ? qdev_get_legacy_property : prop->info->get,
1154 NULL, NULL, (Property *)prop);
1155 }
1156
device_class_set_props_n(DeviceClass * dc,const Property * props,size_t n)1157 void device_class_set_props_n(DeviceClass *dc, const Property *props, size_t n)
1158 {
1159 /* We used a hole in DeviceClass because that's still a lot. */
1160 assert(n <= UINT16_MAX);
1161 assert(n != 0);
1162
1163 dc->props_ = props;
1164 dc->props_count_ = n;
1165
1166 for (size_t i = 0; i < n; ++i) {
1167 const Property *prop = &props[i];
1168 assert(prop->name);
1169 qdev_class_add_legacy_property(dc, prop);
1170 qdev_class_add_property(dc, prop->name, prop);
1171 }
1172 }
1173
qdev_alias_all_properties(DeviceState * target,Object * source)1174 void qdev_alias_all_properties(DeviceState *target, Object *source)
1175 {
1176 ObjectClass *class;
1177 ObjectPropertyIterator iter;
1178 ObjectProperty *prop;
1179
1180 class = object_get_class(OBJECT(target));
1181
1182 object_class_property_iter_init(&iter, class);
1183 while ((prop = object_property_iter_next(&iter))) {
1184 if (object_property_find(source, prop->name)) {
1185 continue; /* skip duplicate properties */
1186 }
1187
1188 object_property_add_alias(source, prop->name,
1189 OBJECT(target), prop->name);
1190 }
1191 }
1192