]> Git Repo - qemu.git/blob - hw/armv7m.c
Merge remote-tracking branch 'kwolf/for-anthony' into staging
[qemu.git] / hw / 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 "sysbus.h"
11 #include "arm-misc.h"
12 #include "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, target_phys_addr_t 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, target_phys_addr_t 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, target_phys_addr_t 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, (uint8_t *)&v, 2);
60     return (v & mask) != 0;
61 }
62
63 static void bitband_writew(void *opaque, target_phys_addr_t 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, (uint8_t *)&v, 2);
73     if (value & 1)
74         v |= mask;
75     else
76         v &= ~mask;
77     cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
78 }
79
80 static uint32_t bitband_readl(void *opaque, target_phys_addr_t 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, (uint8_t *)&v, 4);
89     return (v & mask) != 0;
90 }
91
92 static void bitband_writel(void *opaque, target_phys_addr_t 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, (uint8_t *)&v, 4);
102     if (value & 1)
103         v |= mask;
104     else
105         v &= ~mask;
106     cpu_physical_memory_write(addr, (uint8_t *)&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 typedef struct {
118     SysBusDevice busdev;
119     MemoryRegion iomem;
120     uint32_t base;
121 } BitBandState;
122
123 static int bitband_init(SysBusDevice *dev)
124 {
125     BitBandState *s = FROM_SYSBUS(BitBandState, dev);
126
127     memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband",
128                           0x02000000);
129     sysbus_init_mmio(dev, &s->iomem);
130     return 0;
131 }
132
133 static void armv7m_bitband_init(void)
134 {
135     DeviceState *dev;
136
137     dev = qdev_create(NULL, "ARM,bitband-memory");
138     qdev_prop_set_uint32(dev, "base", 0x20000000);
139     qdev_init_nofail(dev);
140     sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
141
142     dev = qdev_create(NULL, "ARM,bitband-memory");
143     qdev_prop_set_uint32(dev, "base", 0x40000000);
144     qdev_init_nofail(dev);
145     sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
146 }
147
148 /* Board init.  */
149
150 static void armv7m_reset(void *opaque)
151 {
152     cpu_reset((CPUState *)opaque);
153 }
154
155 /* Init CPU and memory for a v7-M based board.
156    flash_size and sram_size are in kb.
157    Returns the NVIC array.  */
158
159 qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
160                       int flash_size, int sram_size,
161                       const char *kernel_filename, const char *cpu_model)
162 {
163     CPUState *env;
164     DeviceState *nvic;
165     /* FIXME: make this local state.  */
166     static qemu_irq pic[64];
167     qemu_irq *cpu_pic;
168     int image_size;
169     uint64_t entry;
170     uint64_t lowaddr;
171     int i;
172     int big_endian;
173     MemoryRegion *sram = g_new(MemoryRegion, 1);
174     MemoryRegion *flash = g_new(MemoryRegion, 1);
175     MemoryRegion *hack = g_new(MemoryRegion, 1);
176
177     flash_size *= 1024;
178     sram_size *= 1024;
179
180     if (!cpu_model)
181         cpu_model = "cortex-m3";
182     env = cpu_init(cpu_model);
183     if (!env) {
184         fprintf(stderr, "Unable to find CPU definition\n");
185         exit(1);
186     }
187
188 #if 0
189     /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
190        We don't have proper commandline options, so allocate half of memory
191        as SRAM, up to a maximum of 32Mb, and the rest as code.  */
192     if (ram_size > (512 + 32) * 1024 * 1024)
193         ram_size = (512 + 32) * 1024 * 1024;
194     sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
195     if (sram_size > 32 * 1024 * 1024)
196         sram_size = 32 * 1024 * 1024;
197     code_size = ram_size - sram_size;
198 #endif
199
200     /* Flash programming is done via the SCU, so pretend it is ROM.  */
201     memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size);
202     memory_region_set_readonly(flash, true);
203     memory_region_add_subregion(address_space_mem, 0, flash);
204     memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size);
205     memory_region_add_subregion(address_space_mem, 0x20000000, sram);
206     armv7m_bitband_init();
207
208     nvic = qdev_create(NULL, "armv7m_nvic");
209     env->nvic = nvic;
210     qdev_init_nofail(nvic);
211     cpu_pic = arm_pic_init_cpu(env);
212     sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
213     for (i = 0; i < 64; i++) {
214         pic[i] = qdev_get_gpio_in(nvic, i);
215     }
216
217 #ifdef TARGET_WORDS_BIGENDIAN
218     big_endian = 1;
219 #else
220     big_endian = 0;
221 #endif
222
223     image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
224                           NULL, big_endian, ELF_MACHINE, 1);
225     if (image_size < 0) {
226         image_size = load_image_targphys(kernel_filename, 0, flash_size);
227         lowaddr = 0;
228     }
229     if (image_size < 0) {
230         fprintf(stderr, "qemu: could not load kernel '%s'\n",
231                 kernel_filename);
232         exit(1);
233     }
234
235     /* Hack to map an additional page of ram at the top of the address
236        space.  This stops qemu complaining about executing code outside RAM
237        when returning from an exception.  */
238     memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000);
239     memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
240
241     qemu_register_reset(armv7m_reset, env);
242     return pic;
243 }
244
245 static SysBusDeviceInfo bitband_info = {
246     .init = bitband_init,
247     .qdev.name  = "ARM,bitband-memory",
248     .qdev.size  = sizeof(BitBandState),
249     .qdev.props = (Property[]) {
250         DEFINE_PROP_UINT32("base", BitBandState, base, 0),
251         DEFINE_PROP_END_OF_LIST(),
252     }
253 };
254
255 static void armv7m_register_devices(void)
256 {
257     sysbus_register_withprop(&bitband_info);
258 }
259
260 device_init(armv7m_register_devices)
This page took 0.040375 seconds and 4 git commands to generate.