Statistics
| Branch: | Revision:

root / hw / arm / armv7m.c @ 3bd88451

History | View | Annotate | Download (7.6 kB)

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