These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / 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 "qapi/error.h"
12 #include "qemu-common.h"
13 #include "cpu.h"
14 #include "hw/sysbus.h"
15 #include "hw/arm/arm.h"
16 #include "hw/loader.h"
17 #include "elf.h"
18 #include "sysemu/qtest.h"
19 #include "qemu/error-report.h"
20
21 /* Bitbanded IO.  Each word corresponds to a single bit.  */
22
23 /* Get the byte address of the real memory for a bitband access.  */
24 static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
25 {
26     uint32_t res;
27
28     res = *(uint32_t *)opaque;
29     res |= (addr & 0x1ffffff) >> 5;
30     return res;
31
32 }
33
34 static uint32_t bitband_readb(void *opaque, hwaddr offset)
35 {
36     uint8_t v;
37     cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
38     return (v & (1 << ((offset >> 2) & 7))) != 0;
39 }
40
41 static void bitband_writeb(void *opaque, hwaddr offset,
42                            uint32_t value)
43 {
44     uint32_t addr;
45     uint8_t mask;
46     uint8_t v;
47     addr = bitband_addr(opaque, offset);
48     mask = (1 << ((offset >> 2) & 7));
49     cpu_physical_memory_read(addr, &v, 1);
50     if (value & 1)
51         v |= mask;
52     else
53         v &= ~mask;
54     cpu_physical_memory_write(addr, &v, 1);
55 }
56
57 static uint32_t bitband_readw(void *opaque, hwaddr offset)
58 {
59     uint32_t addr;
60     uint16_t mask;
61     uint16_t v;
62     addr = bitband_addr(opaque, offset) & ~1;
63     mask = (1 << ((offset >> 2) & 15));
64     mask = tswap16(mask);
65     cpu_physical_memory_read(addr, &v, 2);
66     return (v & mask) != 0;
67 }
68
69 static void bitband_writew(void *opaque, hwaddr offset,
70                            uint32_t value)
71 {
72     uint32_t addr;
73     uint16_t mask;
74     uint16_t v;
75     addr = bitband_addr(opaque, offset) & ~1;
76     mask = (1 << ((offset >> 2) & 15));
77     mask = tswap16(mask);
78     cpu_physical_memory_read(addr, &v, 2);
79     if (value & 1)
80         v |= mask;
81     else
82         v &= ~mask;
83     cpu_physical_memory_write(addr, &v, 2);
84 }
85
86 static uint32_t bitband_readl(void *opaque, hwaddr offset)
87 {
88     uint32_t addr;
89     uint32_t mask;
90     uint32_t v;
91     addr = bitband_addr(opaque, offset) & ~3;
92     mask = (1 << ((offset >> 2) & 31));
93     mask = tswap32(mask);
94     cpu_physical_memory_read(addr, &v, 4);
95     return (v & mask) != 0;
96 }
97
98 static void bitband_writel(void *opaque, hwaddr offset,
99                            uint32_t value)
100 {
101     uint32_t addr;
102     uint32_t mask;
103     uint32_t v;
104     addr = bitband_addr(opaque, offset) & ~3;
105     mask = (1 << ((offset >> 2) & 31));
106     mask = tswap32(mask);
107     cpu_physical_memory_read(addr, &v, 4);
108     if (value & 1)
109         v |= mask;
110     else
111         v &= ~mask;
112     cpu_physical_memory_write(addr, &v, 4);
113 }
114
115 static const MemoryRegionOps bitband_ops = {
116     .old_mmio = {
117         .read = { bitband_readb, bitband_readw, bitband_readl, },
118         .write = { bitband_writeb, bitband_writew, bitband_writel, },
119     },
120     .endianness = DEVICE_NATIVE_ENDIAN,
121 };
122
123 #define TYPE_BITBAND "ARM,bitband-memory"
124 #define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND)
125
126 typedef struct {
127     /*< private >*/
128     SysBusDevice parent_obj;
129     /*< public >*/
130
131     MemoryRegion iomem;
132     uint32_t base;
133 } BitBandState;
134
135 static int bitband_init(SysBusDevice *dev)
136 {
137     BitBandState *s = BITBAND(dev);
138
139     memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base,
140                           "bitband", 0x02000000);
141     sysbus_init_mmio(dev, &s->iomem);
142     return 0;
143 }
144
145 static void armv7m_bitband_init(void)
146 {
147     DeviceState *dev;
148
149     dev = qdev_create(NULL, TYPE_BITBAND);
150     qdev_prop_set_uint32(dev, "base", 0x20000000);
151     qdev_init_nofail(dev);
152     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000);
153
154     dev = qdev_create(NULL, TYPE_BITBAND);
155     qdev_prop_set_uint32(dev, "base", 0x40000000);
156     qdev_init_nofail(dev);
157     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000);
158 }
159
160 /* Board init.  */
161
162 static void armv7m_reset(void *opaque)
163 {
164     ARMCPU *cpu = opaque;
165
166     cpu_reset(CPU(cpu));
167 }
168
169 /* Init CPU and memory for a v7-M based board.
170    mem_size is in bytes.
171    Returns the NVIC array.  */
172
173 DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
174                       const char *kernel_filename, const char *cpu_model)
175 {
176     ARMCPU *cpu;
177     CPUARMState *env;
178     DeviceState *nvic;
179     int image_size;
180     uint64_t entry;
181     uint64_t lowaddr;
182     int big_endian;
183     MemoryRegion *hack = g_new(MemoryRegion, 1);
184
185     if (cpu_model == NULL) {
186         cpu_model = "cortex-m3";
187     }
188     cpu = cpu_arm_init(cpu_model);
189     if (cpu == NULL) {
190         fprintf(stderr, "Unable to find CPU definition\n");
191         exit(1);
192     }
193     env = &cpu->env;
194
195     armv7m_bitband_init();
196
197     nvic = qdev_create(NULL, "armv7m_nvic");
198     qdev_prop_set_uint32(nvic, "num-irq", num_irq);
199     env->nvic = nvic;
200     qdev_init_nofail(nvic);
201     sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
202                        qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
203
204 #ifdef TARGET_WORDS_BIGENDIAN
205     big_endian = 1;
206 #else
207     big_endian = 0;
208 #endif
209
210     if (!kernel_filename && !qtest_enabled()) {
211         fprintf(stderr, "Guest image must be specified (using -kernel)\n");
212         exit(1);
213     }
214
215     if (kernel_filename) {
216         image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
217                               NULL, big_endian, EM_ARM, 1, 0);
218         if (image_size < 0) {
219             image_size = load_image_targphys(kernel_filename, 0, mem_size);
220             lowaddr = 0;
221         }
222         if (image_size < 0) {
223             error_report("Could not load kernel '%s'", kernel_filename);
224             exit(1);
225         }
226     }
227
228     /* Hack to map an additional page of ram at the top of the address
229        space.  This stops qemu complaining about executing code outside RAM
230        when returning from an exception.  */
231     memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal);
232     vmstate_register_ram_global(hack);
233     memory_region_add_subregion(system_memory, 0xfffff000, hack);
234
235     qemu_register_reset(armv7m_reset, cpu);
236     return nvic;
237 }
238
239 static Property bitband_properties[] = {
240     DEFINE_PROP_UINT32("base", BitBandState, base, 0),
241     DEFINE_PROP_END_OF_LIST(),
242 };
243
244 static void bitband_class_init(ObjectClass *klass, void *data)
245 {
246     DeviceClass *dc = DEVICE_CLASS(klass);
247     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
248
249     k->init = bitband_init;
250     dc->props = bitband_properties;
251 }
252
253 static const TypeInfo bitband_info = {
254     .name          = TYPE_BITBAND,
255     .parent        = TYPE_SYS_BUS_DEVICE,
256     .instance_size = sizeof(BitBandState),
257     .class_init    = bitband_class_init,
258 };
259
260 static void armv7m_register_types(void)
261 {
262     type_register_static(&bitband_info);
263 }
264
265 type_init(armv7m_register_types)