]> Git Repo - qemu.git/blob - hw/armv7m.c
Merge remote-tracking branch 'aneesh/for-upstream-2' 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_region(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(int flash_size, int sram_size,
160                       const char *kernel_filename, const char *cpu_model)
161 {
162     CPUState *env;
163     DeviceState *nvic;
164     /* FIXME: make this local state.  */
165     static qemu_irq pic[64];
166     qemu_irq *cpu_pic;
167     int image_size;
168     uint64_t entry;
169     uint64_t lowaddr;
170     int i;
171     int big_endian;
172
173     flash_size *= 1024;
174     sram_size *= 1024;
175
176     if (!cpu_model)
177         cpu_model = "cortex-m3";
178     env = cpu_init(cpu_model);
179     if (!env) {
180         fprintf(stderr, "Unable to find CPU definition\n");
181         exit(1);
182     }
183
184 #if 0
185     /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
186        We don't have proper commandline options, so allocate half of memory
187        as SRAM, up to a maximum of 32Mb, and the rest as code.  */
188     if (ram_size > (512 + 32) * 1024 * 1024)
189         ram_size = (512 + 32) * 1024 * 1024;
190     sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
191     if (sram_size > 32 * 1024 * 1024)
192         sram_size = 32 * 1024 * 1024;
193     code_size = ram_size - sram_size;
194 #endif
195
196     /* Flash programming is done via the SCU, so pretend it is ROM.  */
197     cpu_register_physical_memory(0, flash_size,
198                                  qemu_ram_alloc(NULL, "armv7m.flash",
199                                                 flash_size) | IO_MEM_ROM);
200     cpu_register_physical_memory(0x20000000, sram_size,
201                                  qemu_ram_alloc(NULL, "armv7m.sram",
202                                                 sram_size) | IO_MEM_RAM);
203     armv7m_bitband_init();
204
205     nvic = qdev_create(NULL, "armv7m_nvic");
206     env->nvic = nvic;
207     qdev_init_nofail(nvic);
208     cpu_pic = arm_pic_init_cpu(env);
209     sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
210     for (i = 0; i < 64; i++) {
211         pic[i] = qdev_get_gpio_in(nvic, i);
212     }
213
214 #ifdef TARGET_WORDS_BIGENDIAN
215     big_endian = 1;
216 #else
217     big_endian = 0;
218 #endif
219
220     image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
221                           NULL, big_endian, ELF_MACHINE, 1);
222     if (image_size < 0) {
223         image_size = load_image_targphys(kernel_filename, 0, flash_size);
224         lowaddr = 0;
225     }
226     if (image_size < 0) {
227         fprintf(stderr, "qemu: could not load kernel '%s'\n",
228                 kernel_filename);
229         exit(1);
230     }
231
232     /* Hack to map an additional page of ram at the top of the address
233        space.  This stops qemu complaining about executing code outside RAM
234        when returning from an exception.  */
235     cpu_register_physical_memory(0xfffff000, 0x1000,
236                                  qemu_ram_alloc(NULL, "armv7m.hack", 
237                                                 0x1000) | IO_MEM_RAM);
238
239     qemu_register_reset(armv7m_reset, env);
240     return pic;
241 }
242
243 static SysBusDeviceInfo bitband_info = {
244     .init = bitband_init,
245     .qdev.name  = "ARM,bitband-memory",
246     .qdev.size  = sizeof(BitBandState),
247     .qdev.props = (Property[]) {
248         DEFINE_PROP_UINT32("base", BitBandState, base, 0),
249         DEFINE_PROP_END_OF_LIST(),
250     }
251 };
252
253 static void armv7m_register_devices(void)
254 {
255     sysbus_register_withprop(&bitband_info);
256 }
257
258 device_init(armv7m_register_devices)
This page took 0.037637 seconds and 4 git commands to generate.