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