1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "hw/sysbus.h"
22#include "qapi/error.h"
23#include "monitor/monitor.h"
24#include "exec/address-spaces.h"
25
26#include "hw/fdt_generic_util.h"
27
28static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
29static char *sysbus_get_fw_dev_path(DeviceState *dev);
30
31typedef struct SysBusFind {
32 void *opaque;
33 FindSysbusDeviceFunc *func;
34} SysBusFind;
35
36
37static int find_sysbus_device(Object *obj, void *opaque)
38{
39 SysBusFind *find = opaque;
40 Object *dev;
41 SysBusDevice *sbdev;
42
43 dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
44 sbdev = (SysBusDevice *)dev;
45
46 if (!sbdev) {
47
48 return object_child_foreach(obj, find_sysbus_device, opaque);
49 }
50
51 find->func(sbdev, find->opaque);
52
53 return 0;
54}
55
56
57
58
59
60void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
61{
62 Object *container;
63 SysBusFind find = {
64 .func = func,
65 .opaque = opaque,
66 };
67
68
69 container = container_get(qdev_get_machine(), "/peripheral");
70 find_sysbus_device(container, &find);
71 container = container_get(qdev_get_machine(), "/peripheral-anon");
72 find_sysbus_device(container, &find);
73}
74
75
76static void system_bus_class_init(ObjectClass *klass, void *data)
77{
78 BusClass *k = BUS_CLASS(klass);
79
80 k->print_dev = sysbus_dev_print;
81 k->get_fw_dev_path = sysbus_get_fw_dev_path;
82}
83
84static const TypeInfo system_bus_info = {
85 .name = TYPE_SYSTEM_BUS,
86 .parent = TYPE_BUS,
87 .instance_size = sizeof(BusState),
88 .class_init = system_bus_class_init,
89};
90
91
92bool sysbus_has_irq(SysBusDevice *dev, int n)
93{
94 char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n);
95 ObjectProperty *r;
96
97 r = object_property_find(OBJECT(dev), prop, NULL);
98 g_free(prop);
99
100 return (r != NULL);
101}
102
103bool sysbus_is_irq_connected(SysBusDevice *dev, int n)
104{
105 return !!sysbus_get_connected_irq(dev, n);
106}
107
108qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
109{
110 DeviceState *d = DEVICE(dev);
111 return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n);
112}
113
114void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
115{
116 SysBusDeviceClass *sbd = SYS_BUS_DEVICE_GET_CLASS(dev);
117
118 qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
119
120 if (sbd->connect_irq_notifier) {
121 sbd->connect_irq_notifier(dev, irq);
122 }
123}
124
125
126bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n)
127{
128 return (n < dev->num_mmio);
129}
130
131static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
132 bool may_overlap, int priority)
133{
134 MemoryRegion *mr;
135 assert(n >= 0);
136
137 mr = sysbus_mmio_get_region(dev, n);
138 assert(mr);
139
140 object_property_set_link(OBJECT(mr), OBJECT(get_system_memory()),
141 "container", &error_abort);
142 if (may_overlap) {
143 object_property_set_bool(OBJECT(mr), may_overlap, "may-overlap",
144 &error_abort);
145 }
146 object_property_set_int(OBJECT(mr), priority, "priority", &error_abort);
147 object_property_set_int(OBJECT(mr), addr, "addr", &error_abort);
148}
149
150void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
151{
152 sysbus_mmio_map_common(dev, n, addr, false, 0);
153}
154
155void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
156 int priority)
157{
158 sysbus_mmio_map_common(dev, n, addr, true, priority);
159}
160
161
162void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
163{
164 qdev_init_gpio_out_named(DEVICE(dev), p, SYSBUS_DEVICE_GPIO_IRQ, 1);
165}
166
167
168void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
169{
170 qdev_pass_gpios(DEVICE(target), DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ);
171}
172
173void sysbus_init_mmio_n(SysBusDevice *dev, MemoryRegion *memory, int n)
174{
175 char *propname = g_strdup_printf("sysbus-mr-%d", n);
176 MemoryRegion **mem_ptr = g_malloc0(sizeof(*mem_ptr));
177
178 object_property_add_link(OBJECT(dev), propname, TYPE_MEMORY_REGION,
179 (Object **)mem_ptr,
180 object_property_allow_set_link,
181 OBJ_PROP_LINK_UNREF_ON_RELEASE,
182 &error_abort);
183
184
185
186#if 0
187 object_property_set_link(OBJECT(dev), OBJECT(memory), propname,
188 &error_abort);
189#endif
190 *mem_ptr = memory;
191 g_free(propname);
192}
193
194void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory)
195{
196 int i;
197
198 for (i = 0; sysbus_mmio_get_region(dev, i); ++i);
199 sysbus_init_mmio_n(dev, memory, i);
200}
201
202MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
203{
204 MemoryRegion *ret;
205 char *propname = g_strdup_printf("sysbus-mr-%d", n);
206 bool early = false;
207 Object *dev_obj = OBJECT(dev);
208
209
210 if (!dev_obj->parent) {
211 early = true;
212 object_property_add_child(qdev_get_machine(), "__dummy__",
213 dev_obj, &error_abort);
214 }
215 ret = MEMORY_REGION(object_property_get_link(OBJECT(dev), propname,
216 NULL));
217 if (early) {
218 object_unparent(dev_obj);
219 }
220 g_free(propname);
221 return ret;
222}
223
224void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size)
225{
226 uint32_t i;
227
228 for (i = 0; i < size; i++) {
229 assert(dev->num_pio < QDEV_MAX_PIO);
230 dev->pio[dev->num_pio++] = ioport++;
231 }
232}
233
234static int sysbus_device_init(DeviceState *dev)
235{
236 SysBusDevice *sd = SYS_BUS_DEVICE(dev);
237 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
238
239 if (!sbc->init) {
240 return 0;
241 }
242 return sbc->init(sd);
243}
244
245DeviceState *sysbus_create_varargs(const char *name,
246 hwaddr addr, ...)
247{
248 DeviceState *dev;
249 SysBusDevice *s;
250 va_list va;
251 qemu_irq irq;
252 int n;
253
254 dev = qdev_create(NULL, name);
255 s = SYS_BUS_DEVICE(dev);
256 qdev_init_nofail(dev);
257 if (addr != (hwaddr)-1) {
258 sysbus_mmio_map(s, 0, addr);
259 }
260 va_start(va, addr);
261 n = 0;
262 while (1) {
263 irq = va_arg(va, qemu_irq);
264 if (!irq) {
265 break;
266 }
267 sysbus_connect_irq(s, n, irq);
268 n++;
269 }
270 va_end(va);
271 return dev;
272}
273
274DeviceState *sysbus_try_create_varargs(const char *name,
275 hwaddr addr, ...)
276{
277 DeviceState *dev;
278 SysBusDevice *s;
279 va_list va;
280 qemu_irq irq;
281 int n;
282
283 dev = qdev_try_create(NULL, name);
284 if (!dev) {
285 return NULL;
286 }
287 s = SYS_BUS_DEVICE(dev);
288 qdev_init_nofail(dev);
289 if (addr != (hwaddr)-1) {
290 sysbus_mmio_map(s, 0, addr);
291 }
292 va_start(va, addr);
293 n = 0;
294 while (1) {
295 irq = va_arg(va, qemu_irq);
296 if (!irq) {
297 break;
298 }
299 sysbus_connect_irq(s, n, irq);
300 n++;
301 }
302 va_end(va);
303 return dev;
304}
305
306static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
307{
308 SysBusDevice *s = SYS_BUS_DEVICE(dev);
309 hwaddr size;
310 int i;
311
312 for (i = 0;; i++) {
313 MemoryRegion *mr = sysbus_mmio_get_region(s, i);
314
315 if (!mr) {
316 break;
317 }
318 hwaddr addr = object_property_get_int(OBJECT(mr), "addr", &error_abort);
319 size = memory_region_size(mr);
320 monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
321 indent, "", addr, size);
322 }
323}
324
325static char *sysbus_get_fw_dev_path(DeviceState *dev)
326{
327 SysBusDevice *s = SYS_BUS_DEVICE(dev);
328 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(s);
329
330 char *addr, *fw_dev_path;
331
332 if (s->num_mmio) {
333 return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev),
334 s->mmio[0].addr);
335 }
336 if (s->num_pio) {
337 return g_strdup_printf("%s@i%04x", qdev_fw_name(dev), s->pio[0]);
338 }
339 if (sbc->explicit_ofw_unit_address) {
340 addr = sbc->explicit_ofw_unit_address(s);
341 if (addr) {
342 fw_dev_path = g_strdup_printf("%s@%s", qdev_fw_name(dev), addr);
343 g_free(addr);
344 return fw_dev_path;
345 }
346 }
347 return g_strdup(qdev_fw_name(dev));
348}
349
350void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
351 MemoryRegion *mem)
352{
353 memory_region_add_subregion(get_system_io(), addr, mem);
354}
355
356MemoryRegion *sysbus_address_space(SysBusDevice *dev)
357{
358 return get_system_memory();
359}
360
361static bool sysbus_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
362 Error **errp) {
363 int i;
364
365 for (i = 0; i < reg.n; ++i) {
366 MemoryRegion *mr_parent = (MemoryRegion *)
367 object_dynamic_cast(reg.parents[i], TYPE_MEMORY_REGION);
368 if (!mr_parent) {
369
370 mr_parent = get_system_memory();
371 }
372 memory_region_add_subregion_overlap(mr_parent, reg.a[i],
373 sysbus_mmio_get_region(SYS_BUS_DEVICE(obj), i),
374 reg.p[i]);
375 }
376 return false;
377}
378
379static void sysbus_device_pwr_hlt_cntrl(void *opaque)
380{
381 DeviceState *dev = DEVICE(opaque);
382 SysBusDevice *s = SYS_BUS_DEVICE(opaque);
383 int i;
384
385 for (i = 0;; i++) {
386 MemoryRegion *mr = sysbus_mmio_get_region(s, i);
387 if (!mr) {
388 break;
389 }
390 memory_region_set_enabled(mr, dev->ps.active);
391 }
392}
393static void sysbus_device_pwr_cntrl(void *opaque, int n, int level)
394{
395 DeviceClass *dc_parent = DEVICE_CLASS(SYS_BUS_DEVICE_PARENT_CLASS);
396
397 dc_parent->pwr_cntrl(opaque, n, level);
398 sysbus_device_pwr_hlt_cntrl(opaque);
399}
400
401static void sysbus_device_hlt_cntrl(void *opaque, int n, int level)
402{
403 DeviceClass *dc_parent = DEVICE_CLASS(SYS_BUS_DEVICE_PARENT_CLASS);
404
405 dc_parent->hlt_cntrl(opaque, n, level);
406 sysbus_device_pwr_hlt_cntrl(opaque);
407}
408
409static void sysbus_device_class_init(ObjectClass *klass, void *data)
410{
411 DeviceClass *k = DEVICE_CLASS(klass);
412 FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(klass);
413
414 k->init = sysbus_device_init;
415 k->bus_type = TYPE_SYSTEM_BUS;
416 k->pwr_cntrl = sysbus_device_pwr_cntrl;
417 k->hlt_cntrl = sysbus_device_hlt_cntrl;
418 fmc->parse_reg = sysbus_parse_reg;
419}
420
421static const TypeInfo sysbus_device_type_info = {
422 .name = TYPE_SYS_BUS_DEVICE,
423 .parent = TYPE_DEVICE,
424 .instance_size = sizeof(SysBusDevice),
425 .abstract = true,
426 .class_size = sizeof(SysBusDeviceClass),
427 .class_init = sysbus_device_class_init,
428 .interfaces = (InterfaceInfo[]) {
429 { TYPE_FDT_GENERIC_MMAP },
430 { },
431 },
432};
433
434
435static BusState *main_system_bus;
436
437static void main_system_bus_create(void)
438{
439
440
441 main_system_bus = g_malloc0(system_bus_info.instance_size);
442 qbus_create_inplace(main_system_bus, system_bus_info.instance_size,
443 TYPE_SYSTEM_BUS, NULL, "main-system-bus");
444 OBJECT(main_system_bus)->free = g_free;
445 object_property_add_child(container_get(qdev_get_machine(),
446 "/unattached"),
447 "sysbus", OBJECT(main_system_bus), NULL);
448}
449
450BusState *sysbus_get_default(void)
451{
452 if (!main_system_bus) {
453 main_system_bus_create();
454 }
455 return main_system_bus;
456}
457
458static void sysbus_register_types(void)
459{
460 type_register_static(&system_bus_info);
461 type_register_static(&sysbus_device_type_info);
462}
463
464type_init(sysbus_register_types)
465