]> Git Repo - qemu.git/blob - hw/arm/armv7m.c
armv7m: Use QOMified armv7m object in armv7m_init()
[qemu.git] / hw / arm / armv7m.c
1 /*
2  * ARMV7M System emulation.
3  *
4  * Copyright (c) 2006-2007 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licensed under the GPL.
8  */
9
10 #include "qemu/osdep.h"
11 #include "hw/arm/armv7m.h"
12 #include "qapi/error.h"
13 #include "qemu-common.h"
14 #include "cpu.h"
15 #include "hw/sysbus.h"
16 #include "hw/arm/arm.h"
17 #include "hw/loader.h"
18 #include "elf.h"
19 #include "sysemu/qtest.h"
20 #include "qemu/error-report.h"
21
22 /* Bitbanded IO.  Each word corresponds to a single bit.  */
23
24 /* Get the byte address of the real memory for a bitband access.  */
25 static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
26 {
27     uint32_t res;
28
29     res = *(uint32_t *)opaque;
30     res |= (addr & 0x1ffffff) >> 5;
31     return res;
32
33 }
34
35 static uint32_t bitband_readb(void *opaque, hwaddr offset)
36 {
37     uint8_t v;
38     cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
39     return (v & (1 << ((offset >> 2) & 7))) != 0;
40 }
41
42 static void bitband_writeb(void *opaque, hwaddr offset,
43                            uint32_t value)
44 {
45     uint32_t addr;
46     uint8_t mask;
47     uint8_t v;
48     addr = bitband_addr(opaque, offset);
49     mask = (1 << ((offset >> 2) & 7));
50     cpu_physical_memory_read(addr, &v, 1);
51     if (value & 1)
52         v |= mask;
53     else
54         v &= ~mask;
55     cpu_physical_memory_write(addr, &v, 1);
56 }
57
58 static uint32_t bitband_readw(void *opaque, hwaddr offset)
59 {
60     uint32_t addr;
61     uint16_t mask;
62     uint16_t v;
63     addr = bitband_addr(opaque, offset) & ~1;
64     mask = (1 << ((offset >> 2) & 15));
65     mask = tswap16(mask);
66     cpu_physical_memory_read(addr, &v, 2);
67     return (v & mask) != 0;
68 }
69
70 static void bitband_writew(void *opaque, hwaddr offset,
71                            uint32_t value)
72 {
73     uint32_t addr;
74     uint16_t mask;
75     uint16_t v;
76     addr = bitband_addr(opaque, offset) & ~1;
77     mask = (1 << ((offset >> 2) & 15));
78     mask = tswap16(mask);
79     cpu_physical_memory_read(addr, &v, 2);
80     if (value & 1)
81         v |= mask;
82     else
83         v &= ~mask;
84     cpu_physical_memory_write(addr, &v, 2);
85 }
86
87 static uint32_t bitband_readl(void *opaque, hwaddr offset)
88 {
89     uint32_t addr;
90     uint32_t mask;
91     uint32_t v;
92     addr = bitband_addr(opaque, offset) & ~3;
93     mask = (1 << ((offset >> 2) & 31));
94     mask = tswap32(mask);
95     cpu_physical_memory_read(addr, &v, 4);
96     return (v & mask) != 0;
97 }
98
99 static void bitband_writel(void *opaque, hwaddr offset,
100                            uint32_t value)
101 {
102     uint32_t addr;
103     uint32_t mask;
104     uint32_t v;
105     addr = bitband_addr(opaque, offset) & ~3;
106     mask = (1 << ((offset >> 2) & 31));
107     mask = tswap32(mask);
108     cpu_physical_memory_read(addr, &v, 4);
109     if (value & 1)
110         v |= mask;
111     else
112         v &= ~mask;
113     cpu_physical_memory_write(addr, &v, 4);
114 }
115
116 static const MemoryRegionOps bitband_ops = {
117     .old_mmio = {
118         .read = { bitband_readb, bitband_readw, bitband_readl, },
119         .write = { bitband_writeb, bitband_writew, bitband_writel, },
120     },
121     .endianness = DEVICE_NATIVE_ENDIAN,
122 };
123
124 static void bitband_init(Object *obj)
125 {
126     BitBandState *s = BITBAND(obj);
127     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
128
129     memory_region_init_io(&s->iomem, obj, &bitband_ops, &s->base,
130                           "bitband", 0x02000000);
131     sysbus_init_mmio(dev, &s->iomem);
132 }
133
134 /* Board init.  */
135
136 static const hwaddr bitband_input_addr[ARMV7M_NUM_BITBANDS] = {
137     0x20000000, 0x40000000
138 };
139
140 static const hwaddr bitband_output_addr[ARMV7M_NUM_BITBANDS] = {
141     0x22000000, 0x42000000
142 };
143
144 static void armv7m_instance_init(Object *obj)
145 {
146     ARMv7MState *s = ARMV7M(obj);
147     int i;
148
149     /* Can't init the cpu here, we don't yet know which model to use */
150
151     object_initialize(&s->nvic, sizeof(s->nvic), "armv7m_nvic");
152     qdev_set_parent_bus(DEVICE(&s->nvic), sysbus_get_default());
153     object_property_add_alias(obj, "num-irq",
154                               OBJECT(&s->nvic), "num-irq", &error_abort);
155
156     for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
157         object_initialize(&s->bitband[i], sizeof(s->bitband[i]), TYPE_BITBAND);
158         qdev_set_parent_bus(DEVICE(&s->bitband[i]), sysbus_get_default());
159     }
160 }
161
162 static void armv7m_realize(DeviceState *dev, Error **errp)
163 {
164     ARMv7MState *s = ARMV7M(dev);
165     Error *err = NULL;
166     int i;
167     char **cpustr;
168     ObjectClass *oc;
169     const char *typename;
170     CPUClass *cc;
171
172     cpustr = g_strsplit(s->cpu_model, ",", 2);
173
174     oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
175     if (!oc) {
176         error_setg(errp, "Unknown CPU model %s", cpustr[0]);
177         g_strfreev(cpustr);
178         return;
179     }
180
181     cc = CPU_CLASS(oc);
182     typename = object_class_get_name(oc);
183     cc->parse_features(typename, cpustr[1], &err);
184     g_strfreev(cpustr);
185     if (err) {
186         error_propagate(errp, err);
187         return;
188     }
189
190     s->cpu = ARM_CPU(object_new(typename));
191     if (!s->cpu) {
192         error_setg(errp, "Unknown CPU model %s", s->cpu_model);
193         return;
194     }
195
196     object_property_set_bool(OBJECT(s->cpu), true, "realized", &err);
197     if (err != NULL) {
198         error_propagate(errp, err);
199         return;
200     }
201
202     /* Note that we must realize the NVIC after the CPU */
203     object_property_set_bool(OBJECT(&s->nvic), true, "realized", &err);
204     if (err != NULL) {
205         error_propagate(errp, err);
206         return;
207     }
208
209     /* Alias the NVIC's input and output GPIOs as our own so the board
210      * code can wire them up. (We do this in realize because the
211      * NVIC doesn't create the input GPIO array until realize.)
212      */
213     qdev_pass_gpios(DEVICE(&s->nvic), dev, NULL);
214     qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ");
215
216     /* Wire the NVIC up to the CPU */
217     sysbus_connect_irq(SYS_BUS_DEVICE(&s->nvic), 0,
218                        qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
219     s->cpu->env.nvic = &s->nvic;
220
221     for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
222         Object *obj = OBJECT(&s->bitband[i]);
223         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]);
224
225         object_property_set_int(obj, bitband_input_addr[i], "base", &err);
226         if (err != NULL) {
227             error_propagate(errp, err);
228             return;
229         }
230         object_property_set_bool(obj, true, "realized", &err);
231         if (err != NULL) {
232             error_propagate(errp, err);
233             return;
234         }
235
236         sysbus_mmio_map(sbd, 0, bitband_output_addr[i]);
237     }
238 }
239
240 static Property armv7m_properties[] = {
241     DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model),
242     DEFINE_PROP_END_OF_LIST(),
243 };
244
245 static void armv7m_class_init(ObjectClass *klass, void *data)
246 {
247     DeviceClass *dc = DEVICE_CLASS(klass);
248
249     dc->realize = armv7m_realize;
250     dc->props = armv7m_properties;
251 }
252
253 static const TypeInfo armv7m_info = {
254     .name = TYPE_ARMV7M,
255     .parent = TYPE_SYS_BUS_DEVICE,
256     .instance_size = sizeof(ARMv7MState),
257     .instance_init = armv7m_instance_init,
258     .class_init = armv7m_class_init,
259 };
260
261 static void armv7m_reset(void *opaque)
262 {
263     ARMCPU *cpu = opaque;
264
265     cpu_reset(CPU(cpu));
266 }
267
268 /* Init CPU and memory for a v7-M based board.
269    mem_size is in bytes.
270    Returns the ARMv7M device.  */
271
272 DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
273                       const char *kernel_filename, const char *cpu_model)
274 {
275     DeviceState *armv7m;
276
277     if (cpu_model == NULL) {
278         cpu_model = "cortex-m3";
279     }
280
281     armv7m = qdev_create(NULL, "armv7m");
282     qdev_prop_set_uint32(armv7m, "num-irq", num_irq);
283     qdev_prop_set_string(armv7m, "cpu-model", cpu_model);
284     /* This will exit with an error if the user passed us a bad cpu_model */
285     qdev_init_nofail(armv7m);
286
287     armv7m_load_kernel(ARM_CPU(first_cpu), kernel_filename, mem_size);
288     return armv7m;
289 }
290
291 void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
292 {
293     int image_size;
294     uint64_t entry;
295     uint64_t lowaddr;
296     int big_endian;
297
298 #ifdef TARGET_WORDS_BIGENDIAN
299     big_endian = 1;
300 #else
301     big_endian = 0;
302 #endif
303
304     if (!kernel_filename && !qtest_enabled()) {
305         fprintf(stderr, "Guest image must be specified (using -kernel)\n");
306         exit(1);
307     }
308
309     if (kernel_filename) {
310         image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
311                               NULL, big_endian, EM_ARM, 1, 0);
312         if (image_size < 0) {
313             image_size = load_image_targphys(kernel_filename, 0, mem_size);
314             lowaddr = 0;
315         }
316         if (image_size < 0) {
317             error_report("Could not load kernel '%s'", kernel_filename);
318             exit(1);
319         }
320     }
321
322     /* CPU objects (unlike devices) are not automatically reset on system
323      * reset, so we must always register a handler to do so. Unlike
324      * A-profile CPUs, we don't need to do anything special in the
325      * handler to arrange that it starts correctly.
326      * This is arguably the wrong place to do this, but it matches the
327      * way A-profile does it. Note that this means that every M profile
328      * board must call this function!
329      */
330     qemu_register_reset(armv7m_reset, cpu);
331 }
332
333 static Property bitband_properties[] = {
334     DEFINE_PROP_UINT32("base", BitBandState, base, 0),
335     DEFINE_PROP_END_OF_LIST(),
336 };
337
338 static void bitband_class_init(ObjectClass *klass, void *data)
339 {
340     DeviceClass *dc = DEVICE_CLASS(klass);
341
342     dc->props = bitband_properties;
343 }
344
345 static const TypeInfo bitband_info = {
346     .name          = TYPE_BITBAND,
347     .parent        = TYPE_SYS_BUS_DEVICE,
348     .instance_size = sizeof(BitBandState),
349     .instance_init = bitband_init,
350     .class_init    = bitband_class_init,
351 };
352
353 static void armv7m_register_types(void)
354 {
355     type_register_static(&bitband_info);
356     type_register_static(&armv7m_info);
357 }
358
359 type_init(armv7m_register_types)
This page took 0.043625 seconds and 4 git commands to generate.