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