armv7m: QOMify the armv7m container
[qemu/kevin.git] / hw / arm / armv7m.c
blobfca85b2e733ee840716a4d3b37cbd91c53640ae2
1 /*
2 * ARMV7M System emulation.
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
8 */
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"
22 /* Bitbanded IO. Each word corresponds to a single bit. */
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)
27 uint32_t res;
29 res = *(uint32_t *)opaque;
30 res |= (addr & 0x1ffffff) >> 5;
31 return res;
35 static uint32_t bitband_readb(void *opaque, hwaddr offset)
37 uint8_t v;
38 cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
39 return (v & (1 << ((offset >> 2) & 7))) != 0;
42 static void bitband_writeb(void *opaque, hwaddr offset,
43 uint32_t value)
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);
58 static uint32_t bitband_readw(void *opaque, hwaddr offset)
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;
70 static void bitband_writew(void *opaque, hwaddr offset,
71 uint32_t value)
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);
87 static uint32_t bitband_readl(void *opaque, hwaddr offset)
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;
99 static void bitband_writel(void *opaque, hwaddr offset,
100 uint32_t value)
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);
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, },
121 .endianness = DEVICE_NATIVE_ENDIAN,
124 static void bitband_init(Object *obj)
126 BitBandState *s = BITBAND(obj);
127 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
129 memory_region_init_io(&s->iomem, obj, &bitband_ops, &s->base,
130 "bitband", 0x02000000);
131 sysbus_init_mmio(dev, &s->iomem);
134 static void armv7m_bitband_init(void)
136 DeviceState *dev;
138 dev = qdev_create(NULL, TYPE_BITBAND);
139 qdev_prop_set_uint32(dev, "base", 0x20000000);
140 qdev_init_nofail(dev);
141 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000);
143 dev = qdev_create(NULL, TYPE_BITBAND);
144 qdev_prop_set_uint32(dev, "base", 0x40000000);
145 qdev_init_nofail(dev);
146 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000);
149 /* Board init. */
151 static const hwaddr bitband_input_addr[ARMV7M_NUM_BITBANDS] = {
152 0x20000000, 0x40000000
155 static const hwaddr bitband_output_addr[ARMV7M_NUM_BITBANDS] = {
156 0x22000000, 0x42000000
159 static void armv7m_instance_init(Object *obj)
161 ARMv7MState *s = ARMV7M(obj);
162 int i;
164 /* Can't init the cpu here, we don't yet know which model to use */
166 object_initialize(&s->nvic, sizeof(s->nvic), "armv7m_nvic");
167 qdev_set_parent_bus(DEVICE(&s->nvic), sysbus_get_default());
168 object_property_add_alias(obj, "num-irq",
169 OBJECT(&s->nvic), "num-irq", &error_abort);
171 for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
172 object_initialize(&s->bitband[i], sizeof(s->bitband[i]), TYPE_BITBAND);
173 qdev_set_parent_bus(DEVICE(&s->bitband[i]), sysbus_get_default());
177 static void armv7m_realize(DeviceState *dev, Error **errp)
179 ARMv7MState *s = ARMV7M(dev);
180 Error *err = NULL;
181 int i;
182 char **cpustr;
183 ObjectClass *oc;
184 const char *typename;
185 CPUClass *cc;
187 cpustr = g_strsplit(s->cpu_model, ",", 2);
189 oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
190 if (!oc) {
191 error_setg(errp, "Unknown CPU model %s", cpustr[0]);
192 g_strfreev(cpustr);
193 return;
196 cc = CPU_CLASS(oc);
197 typename = object_class_get_name(oc);
198 cc->parse_features(typename, cpustr[1], &err);
199 g_strfreev(cpustr);
200 if (err) {
201 error_propagate(errp, err);
202 return;
205 s->cpu = ARM_CPU(object_new(typename));
206 if (!s->cpu) {
207 error_setg(errp, "Unknown CPU model %s", s->cpu_model);
208 return;
211 object_property_set_bool(OBJECT(s->cpu), true, "realized", &err);
212 if (err != NULL) {
213 error_propagate(errp, err);
214 return;
217 /* Note that we must realize the NVIC after the CPU */
218 object_property_set_bool(OBJECT(&s->nvic), true, "realized", &err);
219 if (err != NULL) {
220 error_propagate(errp, err);
221 return;
224 /* Alias the NVIC's input and output GPIOs as our own so the board
225 * code can wire them up. (We do this in realize because the
226 * NVIC doesn't create the input GPIO array until realize.)
228 qdev_pass_gpios(DEVICE(&s->nvic), dev, NULL);
229 qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ");
231 /* Wire the NVIC up to the CPU */
232 sysbus_connect_irq(SYS_BUS_DEVICE(&s->nvic), 0,
233 qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
234 s->cpu->env.nvic = &s->nvic;
236 for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
237 Object *obj = OBJECT(&s->bitband[i]);
238 SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]);
240 object_property_set_int(obj, bitband_input_addr[i], "base", &err);
241 if (err != NULL) {
242 error_propagate(errp, err);
243 return;
245 object_property_set_bool(obj, true, "realized", &err);
246 if (err != NULL) {
247 error_propagate(errp, err);
248 return;
251 sysbus_mmio_map(sbd, 0, bitband_output_addr[i]);
255 static Property armv7m_properties[] = {
256 DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model),
257 DEFINE_PROP_END_OF_LIST(),
260 static void armv7m_class_init(ObjectClass *klass, void *data)
262 DeviceClass *dc = DEVICE_CLASS(klass);
264 dc->realize = armv7m_realize;
265 dc->props = armv7m_properties;
268 static const TypeInfo armv7m_info = {
269 .name = TYPE_ARMV7M,
270 .parent = TYPE_SYS_BUS_DEVICE,
271 .instance_size = sizeof(ARMv7MState),
272 .instance_init = armv7m_instance_init,
273 .class_init = armv7m_class_init,
276 static void armv7m_reset(void *opaque)
278 ARMCPU *cpu = opaque;
280 cpu_reset(CPU(cpu));
283 /* Init CPU and memory for a v7-M based board.
284 mem_size is in bytes.
285 Returns the NVIC array. */
287 DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
288 const char *kernel_filename, const char *cpu_model)
290 ARMCPU *cpu;
291 CPUARMState *env;
292 DeviceState *nvic;
294 if (cpu_model == NULL) {
295 cpu_model = "cortex-m3";
297 cpu = cpu_arm_init(cpu_model);
298 if (cpu == NULL) {
299 fprintf(stderr, "Unable to find CPU definition\n");
300 exit(1);
302 env = &cpu->env;
304 armv7m_bitband_init();
306 nvic = qdev_create(NULL, "armv7m_nvic");
307 qdev_prop_set_uint32(nvic, "num-irq", num_irq);
308 env->nvic = nvic;
309 qdev_init_nofail(nvic);
310 sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
311 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
312 armv7m_load_kernel(cpu, kernel_filename, mem_size);
313 return nvic;
316 void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
318 int image_size;
319 uint64_t entry;
320 uint64_t lowaddr;
321 int big_endian;
323 #ifdef TARGET_WORDS_BIGENDIAN
324 big_endian = 1;
325 #else
326 big_endian = 0;
327 #endif
329 if (!kernel_filename && !qtest_enabled()) {
330 fprintf(stderr, "Guest image must be specified (using -kernel)\n");
331 exit(1);
334 if (kernel_filename) {
335 image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
336 NULL, big_endian, EM_ARM, 1, 0);
337 if (image_size < 0) {
338 image_size = load_image_targphys(kernel_filename, 0, mem_size);
339 lowaddr = 0;
341 if (image_size < 0) {
342 error_report("Could not load kernel '%s'", kernel_filename);
343 exit(1);
347 /* CPU objects (unlike devices) are not automatically reset on system
348 * reset, so we must always register a handler to do so. Unlike
349 * A-profile CPUs, we don't need to do anything special in the
350 * handler to arrange that it starts correctly.
351 * This is arguably the wrong place to do this, but it matches the
352 * way A-profile does it. Note that this means that every M profile
353 * board must call this function!
355 qemu_register_reset(armv7m_reset, cpu);
358 static Property bitband_properties[] = {
359 DEFINE_PROP_UINT32("base", BitBandState, base, 0),
360 DEFINE_PROP_END_OF_LIST(),
363 static void bitband_class_init(ObjectClass *klass, void *data)
365 DeviceClass *dc = DEVICE_CLASS(klass);
367 dc->props = bitband_properties;
370 static const TypeInfo bitband_info = {
371 .name = TYPE_BITBAND,
372 .parent = TYPE_SYS_BUS_DEVICE,
373 .instance_size = sizeof(BitBandState),
374 .instance_init = bitband_init,
375 .class_init = bitband_class_init,
378 static void armv7m_register_types(void)
380 type_register_static(&bitband_info);
381 type_register_static(&armv7m_info);
384 type_init(armv7m_register_types)