armv7m.c 6.6 KB
Newer Older
P
pbrook 已提交
1 2 3 4 5 6
/*
 * ARMV7M System emulation.
 *
 * Copyright (c) 2006-2007 CodeSourcery.
 * Written by Paul Brook
 *
7
 * This code is licensed under the GPL.
P
pbrook 已提交
8 9
 */

10
#include "hw/sysbus.h"
11
#include "hw/arm/arm.h"
12
#include "hw/loader.h"
B
Blue Swirl 已提交
13
#include "elf.h"
14 15
#include "sysemu/qtest.h"
#include "qemu/error-report.h"
P
pbrook 已提交
16 17 18

/* Bitbanded IO.  Each word corresponds to a single bit.  */

19
/* Get the byte address of the real memory for a bitband access.  */
20
static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
P
pbrook 已提交
21 22 23
{
    uint32_t res;

24
    res = *(uint32_t *)opaque;
P
pbrook 已提交
25 26 27 28 29
    res |= (addr & 0x1ffffff) >> 5;
    return res;

}

A
Avi Kivity 已提交
30
static uint32_t bitband_readb(void *opaque, hwaddr offset)
P
pbrook 已提交
31 32
{
    uint8_t v;
33
    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
P
pbrook 已提交
34 35 36
    return (v & (1 << ((offset >> 2) & 7))) != 0;
}

A
Avi Kivity 已提交
37
static void bitband_writeb(void *opaque, hwaddr offset,
P
pbrook 已提交
38 39 40 41 42
                           uint32_t value)
{
    uint32_t addr;
    uint8_t mask;
    uint8_t v;
43
    addr = bitband_addr(opaque, offset);
P
pbrook 已提交
44 45 46 47 48 49 50 51 52
    mask = (1 << ((offset >> 2) & 7));
    cpu_physical_memory_read(addr, &v, 1);
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
    cpu_physical_memory_write(addr, &v, 1);
}

A
Avi Kivity 已提交
53
static uint32_t bitband_readw(void *opaque, hwaddr offset)
P
pbrook 已提交
54 55 56 57
{
    uint32_t addr;
    uint16_t mask;
    uint16_t v;
58
    addr = bitband_addr(opaque, offset) & ~1;
P
pbrook 已提交
59 60
    mask = (1 << ((offset >> 2) & 15));
    mask = tswap16(mask);
S
Stefan Weil 已提交
61
    cpu_physical_memory_read(addr, &v, 2);
P
pbrook 已提交
62 63 64
    return (v & mask) != 0;
}

A
Avi Kivity 已提交
65
static void bitband_writew(void *opaque, hwaddr offset,
P
pbrook 已提交
66 67 68 69 70
                           uint32_t value)
{
    uint32_t addr;
    uint16_t mask;
    uint16_t v;
71
    addr = bitband_addr(opaque, offset) & ~1;
P
pbrook 已提交
72 73
    mask = (1 << ((offset >> 2) & 15));
    mask = tswap16(mask);
S
Stefan Weil 已提交
74
    cpu_physical_memory_read(addr, &v, 2);
P
pbrook 已提交
75 76 77 78
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
S
Stefan Weil 已提交
79
    cpu_physical_memory_write(addr, &v, 2);
P
pbrook 已提交
80 81
}

A
Avi Kivity 已提交
82
static uint32_t bitband_readl(void *opaque, hwaddr offset)
P
pbrook 已提交
83 84 85 86
{
    uint32_t addr;
    uint32_t mask;
    uint32_t v;
87
    addr = bitband_addr(opaque, offset) & ~3;
P
pbrook 已提交
88 89
    mask = (1 << ((offset >> 2) & 31));
    mask = tswap32(mask);
S
Stefan Weil 已提交
90
    cpu_physical_memory_read(addr, &v, 4);
P
pbrook 已提交
91 92 93
    return (v & mask) != 0;
}

A
Avi Kivity 已提交
94
static void bitband_writel(void *opaque, hwaddr offset,
P
pbrook 已提交
95 96 97 98 99
                           uint32_t value)
{
    uint32_t addr;
    uint32_t mask;
    uint32_t v;
100
    addr = bitband_addr(opaque, offset) & ~3;
P
pbrook 已提交
101 102
    mask = (1 << ((offset >> 2) & 31));
    mask = tswap32(mask);
S
Stefan Weil 已提交
103
    cpu_physical_memory_read(addr, &v, 4);
P
pbrook 已提交
104 105 106 107
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
S
Stefan Weil 已提交
108
    cpu_physical_memory_write(addr, &v, 4);
P
pbrook 已提交
109 110
}

A
Avi Kivity 已提交
111 112 113 114 115 116
static const MemoryRegionOps bitband_ops = {
    .old_mmio = {
        .read = { bitband_readb, bitband_readw, bitband_readl, },
        .write = { bitband_writeb, bitband_writew, bitband_writel, },
    },
    .endianness = DEVICE_NATIVE_ENDIAN,
P
pbrook 已提交
117 118
};

119 120 121
#define TYPE_BITBAND "ARM,bitband-memory"
#define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND)

P
Paul Brook 已提交
122
typedef struct {
123 124 125 126
    /*< private >*/
    SysBusDevice parent_obj;
    /*< public >*/

A
Avi Kivity 已提交
127
    MemoryRegion iomem;
P
Paul Brook 已提交
128 129 130
    uint32_t base;
} BitBandState;

131
static int bitband_init(SysBusDevice *dev)
P
pbrook 已提交
132
{
133
    BitBandState *s = BITBAND(dev);
P
pbrook 已提交
134

135 136
    memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base,
                          "bitband", 0x02000000);
137
    sysbus_init_mmio(dev, &s->iomem);
138
    return 0;
P
Paul Brook 已提交
139 140 141 142 143 144
}

static void armv7m_bitband_init(void)
{
    DeviceState *dev;

145
    dev = qdev_create(NULL, TYPE_BITBAND);
G
Gerd Hoffmann 已提交
146
    qdev_prop_set_uint32(dev, "base", 0x20000000);
M
Markus Armbruster 已提交
147
    qdev_init_nofail(dev);
148
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000);
P
Paul Brook 已提交
149

150
    dev = qdev_create(NULL, TYPE_BITBAND);
G
Gerd Hoffmann 已提交
151
    qdev_prop_set_uint32(dev, "base", 0x40000000);
M
Markus Armbruster 已提交
152
    qdev_init_nofail(dev);
153
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000);
P
pbrook 已提交
154 155 156
}

/* Board init.  */
P
Paul Brook 已提交
157 158 159

static void armv7m_reset(void *opaque)
{
160 161 162
    ARMCPU *cpu = opaque;

    cpu_reset(CPU(cpu));
P
Paul Brook 已提交
163 164
}

P
pbrook 已提交
165
/* Init CPU and memory for a v7-M based board.
166
   mem_size is in bytes.
P
pbrook 已提交
167 168
   Returns the NVIC array.  */

169
DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
P
pbrook 已提交
170 171
                      const char *kernel_filename, const char *cpu_model)
{
172
    ARMCPU *cpu;
A
Andreas Färber 已提交
173
    CPUARMState *env;
P
Paul Brook 已提交
174
    DeviceState *nvic;
P
pbrook 已提交
175 176 177
    int image_size;
    uint64_t entry;
    uint64_t lowaddr;
B
Blue Swirl 已提交
178
    int big_endian;
A
Avi Kivity 已提交
179
    MemoryRegion *hack = g_new(MemoryRegion, 1);
P
pbrook 已提交
180

181
    if (cpu_model == NULL) {
P
pbrook 已提交
182
	cpu_model = "cortex-m3";
183 184 185
    }
    cpu = cpu_arm_init(cpu_model);
    if (cpu == NULL) {
P
pbrook 已提交
186 187 188
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
189
    env = &cpu->env;
P
pbrook 已提交
190 191 192

    armv7m_bitband_init();

P
Paul Brook 已提交
193
    nvic = qdev_create(NULL, "armv7m_nvic");
194
    qdev_prop_set_uint32(nvic, "num-irq", num_irq);
P
Paul Brook 已提交
195
    env->nvic = nvic;
M
Markus Armbruster 已提交
196
    qdev_init_nofail(nvic);
197 198
    sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
                       qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
P
pbrook 已提交
199

B
Blue Swirl 已提交
200 201 202 203 204 205
#ifdef TARGET_WORDS_BIGENDIAN
    big_endian = 1;
#else
    big_endian = 0;
#endif

206
    if (!kernel_filename && !qtest_enabled()) {
207 208 209 210
        fprintf(stderr, "Guest image must be specified (using -kernel)\n");
        exit(1);
    }

211 212
    if (kernel_filename) {
        image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
213
                              NULL, big_endian, EM_ARM, 1);
214
        if (image_size < 0) {
215
            image_size = load_image_targphys(kernel_filename, 0, mem_size);
216 217 218 219 220 221
            lowaddr = 0;
        }
        if (image_size < 0) {
            error_report("Could not load kernel '%s'", kernel_filename);
            exit(1);
        }
P
pbrook 已提交
222 223 224 225 226
    }

    /* Hack to map an additional page of ram at the top of the address
       space.  This stops qemu complaining about executing code outside RAM
       when returning from an exception.  */
227
    memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal);
228
    vmstate_register_ram_global(hack);
229
    memory_region_add_subregion(system_memory, 0xfffff000, hack);
P
pbrook 已提交
230

231
    qemu_register_reset(armv7m_reset, cpu);
232
    return nvic;
P
pbrook 已提交
233
}
P
Paul Brook 已提交
234

235 236 237 238 239 240 241
static Property bitband_properties[] = {
    DEFINE_PROP_UINT32("base", BitBandState, base, 0),
    DEFINE_PROP_END_OF_LIST(),
};

static void bitband_class_init(ObjectClass *klass, void *data)
{
242
    DeviceClass *dc = DEVICE_CLASS(klass);
243 244 245
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = bitband_init;
246
    dc->props = bitband_properties;
247 248
}

249
static const TypeInfo bitband_info = {
250
    .name          = TYPE_BITBAND,
251 252 253
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(BitBandState),
    .class_init    = bitband_class_init,
G
Gerd Hoffmann 已提交
254 255
};

A
Andreas Färber 已提交
256
static void armv7m_register_types(void)
P
Paul Brook 已提交
257
{
258
    type_register_static(&bitband_info);
P
Paul Brook 已提交
259 260
}

A
Andreas Färber 已提交
261
type_init(armv7m_register_types)