]> git.proxmox.com Git - mirror_qemu.git/blame - hw/armv7m.c
vmstate, memory: decouple vmstate from memory API
[mirror_qemu.git] / hw / 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
fe7e8758 10#include "sysbus.h"
87ecb68b 11#include "arm-misc.h"
ca20cf32
BS
12#include "loader.h"
13#include "elf.h"
9ee6e8bb
PB
14
15/* Bitbanded IO. Each word corresponds to a single bit. */
16
2167f7bc 17/* Get the byte address of the real memory for a bitband access. */
8da3ff18 18static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
9ee6e8bb
PB
19{
20 uint32_t res;
21
8da3ff18 22 res = *(uint32_t *)opaque;
9ee6e8bb
PB
23 res |= (addr & 0x1ffffff) >> 5;
24 return res;
25
26}
27
c227f099 28static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
9ee6e8bb
PB
29{
30 uint8_t v;
8da3ff18 31 cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
9ee6e8bb
PB
32 return (v & (1 << ((offset >> 2) & 7))) != 0;
33}
34
c227f099 35static void bitband_writeb(void *opaque, target_phys_addr_t offset,
9ee6e8bb
PB
36 uint32_t value)
37{
38 uint32_t addr;
39 uint8_t mask;
40 uint8_t v;
8da3ff18 41 addr = bitband_addr(opaque, offset);
9ee6e8bb
PB
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
c227f099 51static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
9ee6e8bb
PB
52{
53 uint32_t addr;
54 uint16_t mask;
55 uint16_t v;
8da3ff18 56 addr = bitband_addr(opaque, offset) & ~1;
9ee6e8bb
PB
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
c227f099 63static void bitband_writew(void *opaque, target_phys_addr_t offset,
9ee6e8bb
PB
64 uint32_t value)
65{
66 uint32_t addr;
67 uint16_t mask;
68 uint16_t v;
8da3ff18 69 addr = bitband_addr(opaque, offset) & ~1;
9ee6e8bb
PB
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
c227f099 80static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
9ee6e8bb
PB
81{
82 uint32_t addr;
83 uint32_t mask;
84 uint32_t v;
8da3ff18 85 addr = bitband_addr(opaque, offset) & ~3;
9ee6e8bb
PB
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
c227f099 92static void bitband_writel(void *opaque, target_phys_addr_t offset,
9ee6e8bb
PB
93 uint32_t value)
94{
95 uint32_t addr;
96 uint32_t mask;
97 uint32_t v;
8da3ff18 98 addr = bitband_addr(opaque, offset) & ~3;
9ee6e8bb
PB
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
f69bf9d4
AK
109static 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,
9ee6e8bb
PB
115};
116
40905a6a
PB
117typedef struct {
118 SysBusDevice busdev;
f69bf9d4 119 MemoryRegion iomem;
40905a6a
PB
120 uint32_t base;
121} BitBandState;
122
81a322d4 123static int bitband_init(SysBusDevice *dev)
9ee6e8bb 124{
40905a6a 125 BitBandState *s = FROM_SYSBUS(BitBandState, dev);
9ee6e8bb 126
f69bf9d4
AK
127 memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband",
128 0x02000000);
750ecd44 129 sysbus_init_mmio(dev, &s->iomem);
81a322d4 130 return 0;
40905a6a
PB
131}
132
133static void armv7m_bitband_init(void)
134{
135 DeviceState *dev;
136
137 dev = qdev_create(NULL, "ARM,bitband-memory");
ee6847d1 138 qdev_prop_set_uint32(dev, "base", 0x20000000);
e23a1b33 139 qdev_init_nofail(dev);
40905a6a
PB
140 sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
141
142 dev = qdev_create(NULL, "ARM,bitband-memory");
ee6847d1 143 qdev_prop_set_uint32(dev, "base", 0x40000000);
e23a1b33 144 qdev_init_nofail(dev);
40905a6a 145 sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
9ee6e8bb
PB
146}
147
148/* Board init. */
983fe826
PB
149
150static void armv7m_reset(void *opaque)
151{
152 cpu_reset((CPUState *)opaque);
153}
154
9ee6e8bb
PB
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
7d6f78cf
AK
159qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
160 int flash_size, int sram_size,
9ee6e8bb
PB
161 const char *kernel_filename, const char *cpu_model)
162{
163 CPUState *env;
fe7e8758
PB
164 DeviceState *nvic;
165 /* FIXME: make this local state. */
166 static qemu_irq pic[64];
167 qemu_irq *cpu_pic;
9ee6e8bb
PB
168 int image_size;
169 uint64_t entry;
170 uint64_t lowaddr;
fe7e8758 171 int i;
ca20cf32 172 int big_endian;
7d6f78cf
AK
173 MemoryRegion *sram = g_new(MemoryRegion, 1);
174 MemoryRegion *flash = g_new(MemoryRegion, 1);
175 MemoryRegion *hack = g_new(MemoryRegion, 1);
9ee6e8bb
PB
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. */
c5705a77
AK
201 memory_region_init_ram(flash, "armv7m.flash", flash_size);
202 vmstate_register_ram_global(flash);
7d6f78cf
AK
203 memory_region_set_readonly(flash, true);
204 memory_region_add_subregion(address_space_mem, 0, flash);
c5705a77
AK
205 memory_region_init_ram(sram, "armv7m.sram", sram_size);
206 vmstate_register_ram_global(sram);
7d6f78cf 207 memory_region_add_subregion(address_space_mem, 0x20000000, sram);
9ee6e8bb
PB
208 armv7m_bitband_init();
209
fe7e8758 210 nvic = qdev_create(NULL, "armv7m_nvic");
983fe826 211 env->nvic = nvic;
e23a1b33 212 qdev_init_nofail(nvic);
fe7e8758
PB
213 cpu_pic = arm_pic_init_cpu(env);
214 sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
215 for (i = 0; i < 64; i++) {
067a3ddc 216 pic[i] = qdev_get_gpio_in(nvic, i);
fe7e8758 217 }
9ee6e8bb 218
ca20cf32
BS
219#ifdef TARGET_WORDS_BIGENDIAN
220 big_endian = 1;
221#else
222 big_endian = 0;
223#endif
224
409dbce5
AJ
225 image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
226 NULL, big_endian, ELF_MACHINE, 1);
9ee6e8bb 227 if (image_size < 0) {
dcac9679 228 image_size = load_image_targphys(kernel_filename, 0, flash_size);
9ee6e8bb
PB
229 lowaddr = 0;
230 }
231 if (image_size < 0) {
232 fprintf(stderr, "qemu: could not load kernel '%s'\n",
233 kernel_filename);
234 exit(1);
235 }
236
9ee6e8bb
PB
237 /* Hack to map an additional page of ram at the top of the address
238 space. This stops qemu complaining about executing code outside RAM
239 when returning from an exception. */
c5705a77
AK
240 memory_region_init_ram(hack, "armv7m.hack", 0x1000);
241 vmstate_register_ram_global(hack);
7d6f78cf 242 memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
9ee6e8bb 243
983fe826 244 qemu_register_reset(armv7m_reset, env);
9ee6e8bb
PB
245 return pic;
246}
40905a6a 247
ee6847d1
GH
248static SysBusDeviceInfo bitband_info = {
249 .init = bitband_init,
250 .qdev.name = "ARM,bitband-memory",
251 .qdev.size = sizeof(BitBandState),
252 .qdev.props = (Property[]) {
1832efa2
GH
253 DEFINE_PROP_UINT32("base", BitBandState, base, 0),
254 DEFINE_PROP_END_OF_LIST(),
ee6847d1
GH
255 }
256};
257
40905a6a
PB
258static void armv7m_register_devices(void)
259{
ee6847d1 260 sysbus_register_withprop(&bitband_info);
40905a6a
PB
261}
262
263device_init(armv7m_register_devices)