1 /* 2 * QEMU PowerPC e500v2 ePAPR spinning code 3 * 4 * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. 5 * 6 * Author: Alexander Graf, <agraf@suse.de> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 20 * 21 * This code is not really a device, but models an interface that usually 22 * firmware takes care of. It's used when QEMU plays the role of firmware. 23 * 24 * Specification: 25 * 26 * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf 27 * 28 */ 29 30 #include "qemu/osdep.h" 31 #include "hw/hw.h" 32 #include "sysemu/sysemu.h" 33 #include "hw/sysbus.h" 34 #include "sysemu/kvm.h" 35 36 #define MAX_CPUS 32 37 38 typedef struct spin_info { 39 uint64_t addr; 40 uint64_t r3; 41 uint32_t resv; 42 uint32_t pir; 43 uint64_t reserved; 44 } QEMU_PACKED SpinInfo; 45 46 #define TYPE_E500_SPIN "e500-spin" 47 #define E500_SPIN(obj) OBJECT_CHECK(SpinState, (obj), TYPE_E500_SPIN) 48 49 typedef struct SpinState { 50 SysBusDevice parent_obj; 51 52 MemoryRegion iomem; 53 SpinInfo spin[MAX_CPUS]; 54 } SpinState; 55 56 typedef struct spin_kick { 57 PowerPCCPU *cpu; 58 SpinInfo *spin; 59 } SpinKick; 60 61 static void spin_reset(void *opaque) 62 { 63 SpinState *s = opaque; 64 int i; 65 66 for (i = 0; i < MAX_CPUS; i++) { 67 SpinInfo *info = &s->spin[i]; 68 69 stl_p(&info->pir, i); 70 stq_p(&info->r3, i); 71 stq_p(&info->addr, 1); 72 } 73 } 74 75 /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ 76 static inline hwaddr booke206_page_size_to_tlb(uint64_t size) 77 { 78 return ctz32(size >> 10) >> 1; 79 } 80 81 static void mmubooke_create_initial_mapping(CPUPPCState *env, 82 target_ulong va, 83 hwaddr pa, 84 hwaddr len) 85 { 86 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); 87 hwaddr size; 88 89 size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); 90 tlb->mas1 = MAS1_VALID | size; 91 tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; 92 tlb->mas7_3 = pa & TARGET_PAGE_MASK; 93 tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 94 env->tlb_dirty = true; 95 } 96 97 static void spin_kick(void *data) 98 { 99 SpinKick *kick = data; 100 CPUState *cpu = CPU(kick->cpu); 101 CPUPPCState *env = &kick->cpu->env; 102 SpinInfo *curspin = kick->spin; 103 hwaddr map_size = 64 * 1024 * 1024; 104 hwaddr map_start; 105 106 cpu_synchronize_state(cpu); 107 stl_p(&curspin->pir, env->spr[SPR_PIR]); 108 env->nip = ldq_p(&curspin->addr) & (map_size - 1); 109 env->gpr[3] = ldq_p(&curspin->r3); 110 env->gpr[4] = 0; 111 env->gpr[5] = 0; 112 env->gpr[6] = 0; 113 env->gpr[7] = map_size; 114 env->gpr[8] = 0; 115 env->gpr[9] = 0; 116 117 map_start = ldq_p(&curspin->addr) & ~(map_size - 1); 118 mmubooke_create_initial_mapping(env, 0, map_start, map_size); 119 120 cpu->halted = 0; 121 cpu->exception_index = -1; 122 cpu->stopped = false; 123 qemu_cpu_kick(cpu); 124 } 125 126 static void spin_write(void *opaque, hwaddr addr, uint64_t value, 127 unsigned len) 128 { 129 SpinState *s = opaque; 130 int env_idx = addr / sizeof(SpinInfo); 131 CPUState *cpu; 132 SpinInfo *curspin = &s->spin[env_idx]; 133 uint8_t *curspin_p = (uint8_t*)curspin; 134 135 cpu = qemu_get_cpu(env_idx); 136 if (cpu == NULL) { 137 /* Unknown CPU */ 138 return; 139 } 140 141 if (cpu->cpu_index == 0) { 142 /* primary CPU doesn't spin */ 143 return; 144 } 145 146 curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; 147 switch (len) { 148 case 1: 149 stb_p(curspin_p, value); 150 break; 151 case 2: 152 stw_p(curspin_p, value); 153 break; 154 case 4: 155 stl_p(curspin_p, value); 156 break; 157 } 158 159 if (!(ldq_p(&curspin->addr) & 1)) { 160 /* run CPU */ 161 SpinKick kick = { 162 .cpu = POWERPC_CPU(cpu), 163 .spin = curspin, 164 }; 165 166 run_on_cpu(cpu, spin_kick, &kick); 167 } 168 } 169 170 static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) 171 { 172 SpinState *s = opaque; 173 uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; 174 175 switch (len) { 176 case 1: 177 return ldub_p(spin_p); 178 case 2: 179 return lduw_p(spin_p); 180 case 4: 181 return ldl_p(spin_p); 182 default: 183 hw_error("ppce500: unexpected %s with len = %u", __func__, len); 184 } 185 } 186 187 static const MemoryRegionOps spin_rw_ops = { 188 .read = spin_read, 189 .write = spin_write, 190 .endianness = DEVICE_BIG_ENDIAN, 191 }; 192 193 static int ppce500_spin_initfn(SysBusDevice *dev) 194 { 195 SpinState *s = E500_SPIN(dev); 196 197 memory_region_init_io(&s->iomem, OBJECT(s), &spin_rw_ops, s, 198 "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS); 199 sysbus_init_mmio(dev, &s->iomem); 200 201 qemu_register_reset(spin_reset, s); 202 203 return 0; 204 } 205 206 static void ppce500_spin_class_init(ObjectClass *klass, void *data) 207 { 208 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 209 210 k->init = ppce500_spin_initfn; 211 } 212 213 static const TypeInfo ppce500_spin_info = { 214 .name = TYPE_E500_SPIN, 215 .parent = TYPE_SYS_BUS_DEVICE, 216 .instance_size = sizeof(SpinState), 217 .class_init = ppce500_spin_class_init, 218 }; 219 220 static void ppce500_spin_register_types(void) 221 { 222 type_register_static(&ppce500_spin_info); 223 } 224 225 type_init(ppce500_spin_register_types) 226