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