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 "qemu/osdep.h" 11 #include "qapi/error.h" 12 #include "qemu-common.h" 13 #include "cpu.h" 14 #include "hw/sysbus.h" 15 #include "hw/arm/arm.h" 16 #include "hw/loader.h" 17 #include "elf.h" 18 #include "sysemu/qtest.h" 19 #include "qemu/error-report.h" 20 21 /* Bitbanded IO. Each word corresponds to a single bit. */ 22 23 /* Get the byte address of the real memory for a bitband access. */ 24 static inline uint32_t bitband_addr(void * opaque, uint32_t addr) 25 { 26 uint32_t res; 27 28 res = *(uint32_t *)opaque; 29 res |= (addr & 0x1ffffff) >> 5; 30 return res; 31 32 } 33 34 static uint32_t bitband_readb(void *opaque, hwaddr offset) 35 { 36 uint8_t v; 37 cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1); 38 return (v & (1 << ((offset >> 2) & 7))) != 0; 39 } 40 41 static void bitband_writeb(void *opaque, hwaddr offset, 42 uint32_t value) 43 { 44 uint32_t addr; 45 uint8_t mask; 46 uint8_t v; 47 addr = bitband_addr(opaque, offset); 48 mask = (1 << ((offset >> 2) & 7)); 49 cpu_physical_memory_read(addr, &v, 1); 50 if (value & 1) 51 v |= mask; 52 else 53 v &= ~mask; 54 cpu_physical_memory_write(addr, &v, 1); 55 } 56 57 static uint32_t bitband_readw(void *opaque, hwaddr offset) 58 { 59 uint32_t addr; 60 uint16_t mask; 61 uint16_t v; 62 addr = bitband_addr(opaque, offset) & ~1; 63 mask = (1 << ((offset >> 2) & 15)); 64 mask = tswap16(mask); 65 cpu_physical_memory_read(addr, &v, 2); 66 return (v & mask) != 0; 67 } 68 69 static void bitband_writew(void *opaque, hwaddr offset, 70 uint32_t value) 71 { 72 uint32_t addr; 73 uint16_t mask; 74 uint16_t v; 75 addr = bitband_addr(opaque, offset) & ~1; 76 mask = (1 << ((offset >> 2) & 15)); 77 mask = tswap16(mask); 78 cpu_physical_memory_read(addr, &v, 2); 79 if (value & 1) 80 v |= mask; 81 else 82 v &= ~mask; 83 cpu_physical_memory_write(addr, &v, 2); 84 } 85 86 static uint32_t bitband_readl(void *opaque, hwaddr offset) 87 { 88 uint32_t addr; 89 uint32_t mask; 90 uint32_t v; 91 addr = bitband_addr(opaque, offset) & ~3; 92 mask = (1 << ((offset >> 2) & 31)); 93 mask = tswap32(mask); 94 cpu_physical_memory_read(addr, &v, 4); 95 return (v & mask) != 0; 96 } 97 98 static void bitband_writel(void *opaque, hwaddr offset, 99 uint32_t value) 100 { 101 uint32_t addr; 102 uint32_t mask; 103 uint32_t v; 104 addr = bitband_addr(opaque, offset) & ~3; 105 mask = (1 << ((offset >> 2) & 31)); 106 mask = tswap32(mask); 107 cpu_physical_memory_read(addr, &v, 4); 108 if (value & 1) 109 v |= mask; 110 else 111 v &= ~mask; 112 cpu_physical_memory_write(addr, &v, 4); 113 } 114 115 static const MemoryRegionOps bitband_ops = { 116 .old_mmio = { 117 .read = { bitband_readb, bitband_readw, bitband_readl, }, 118 .write = { bitband_writeb, bitband_writew, bitband_writel, }, 119 }, 120 .endianness = DEVICE_NATIVE_ENDIAN, 121 }; 122 123 #define TYPE_BITBAND "ARM,bitband-memory" 124 #define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND) 125 126 typedef struct { 127 /*< private >*/ 128 SysBusDevice parent_obj; 129 /*< public >*/ 130 131 MemoryRegion iomem; 132 uint32_t base; 133 } BitBandState; 134 135 static void bitband_init(Object *obj) 136 { 137 BitBandState *s = BITBAND(obj); 138 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 139 140 memory_region_init_io(&s->iomem, obj, &bitband_ops, &s->base, 141 "bitband", 0x02000000); 142 sysbus_init_mmio(dev, &s->iomem); 143 } 144 145 static void armv7m_bitband_init(void) 146 { 147 DeviceState *dev; 148 149 dev = qdev_create(NULL, TYPE_BITBAND); 150 qdev_prop_set_uint32(dev, "base", 0x20000000); 151 qdev_init_nofail(dev); 152 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); 153 154 dev = qdev_create(NULL, TYPE_BITBAND); 155 qdev_prop_set_uint32(dev, "base", 0x40000000); 156 qdev_init_nofail(dev); 157 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); 158 } 159 160 /* Board init. */ 161 162 static void armv7m_reset(void *opaque) 163 { 164 ARMCPU *cpu = opaque; 165 166 cpu_reset(CPU(cpu)); 167 } 168 169 /* Init CPU and memory for a v7-M based board. 170 mem_size is in bytes. 171 Returns the NVIC array. */ 172 173 DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, 174 const char *kernel_filename, const char *cpu_model) 175 { 176 ARMCPU *cpu; 177 CPUARMState *env; 178 DeviceState *nvic; 179 int image_size; 180 uint64_t entry; 181 uint64_t lowaddr; 182 int big_endian; 183 MemoryRegion *hack = g_new(MemoryRegion, 1); 184 185 if (cpu_model == NULL) { 186 cpu_model = "cortex-m3"; 187 } 188 cpu = cpu_arm_init(cpu_model); 189 if (cpu == NULL) { 190 fprintf(stderr, "Unable to find CPU definition\n"); 191 exit(1); 192 } 193 env = &cpu->env; 194 195 armv7m_bitband_init(); 196 197 nvic = qdev_create(NULL, "armv7m_nvic"); 198 qdev_prop_set_uint32(nvic, "num-irq", num_irq); 199 env->nvic = nvic; 200 qdev_init_nofail(nvic); 201 sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, 202 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); 203 204 #ifdef TARGET_WORDS_BIGENDIAN 205 big_endian = 1; 206 #else 207 big_endian = 0; 208 #endif 209 210 if (!kernel_filename && !qtest_enabled()) { 211 fprintf(stderr, "Guest image must be specified (using -kernel)\n"); 212 exit(1); 213 } 214 215 if (kernel_filename) { 216 image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, 217 NULL, big_endian, EM_ARM, 1, 0); 218 if (image_size < 0) { 219 image_size = load_image_targphys(kernel_filename, 0, mem_size); 220 lowaddr = 0; 221 } 222 if (image_size < 0) { 223 error_report("Could not load kernel '%s'", kernel_filename); 224 exit(1); 225 } 226 } 227 228 /* Hack to map an additional page of ram at the top of the address 229 space. This stops qemu complaining about executing code outside RAM 230 when returning from an exception. */ 231 memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal); 232 vmstate_register_ram_global(hack); 233 memory_region_add_subregion(system_memory, 0xfffff000, hack); 234 235 qemu_register_reset(armv7m_reset, cpu); 236 return nvic; 237 } 238 239 static Property bitband_properties[] = { 240 DEFINE_PROP_UINT32("base", BitBandState, base, 0), 241 DEFINE_PROP_END_OF_LIST(), 242 }; 243 244 static void bitband_class_init(ObjectClass *klass, void *data) 245 { 246 DeviceClass *dc = DEVICE_CLASS(klass); 247 248 dc->props = bitband_properties; 249 } 250 251 static const TypeInfo bitband_info = { 252 .name = TYPE_BITBAND, 253 .parent = TYPE_SYS_BUS_DEVICE, 254 .instance_size = sizeof(BitBandState), 255 .instance_init = bitband_init, 256 .class_init = bitband_class_init, 257 }; 258 259 static void armv7m_register_types(void) 260 { 261 type_register_static(&bitband_info); 262 } 263 264 type_init(armv7m_register_types) 265