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 "hw/hw.h" 31 #include "sysemu/sysemu.h" 32 #include "hw/sysbus.h" 33 #include "sysemu/kvm.h" 34 35 #define MAX_CPUS 32 36 37 typedef struct spin_info { 38 uint64_t addr; 39 uint64_t r3; 40 uint32_t resv; 41 uint32_t pir; 42 uint64_t reserved; 43 } QEMU_PACKED SpinInfo; 44 45 #define TYPE_E500_SPIN "e500-spin" 46 #define E500_SPIN(obj) OBJECT_CHECK(SpinState, (obj), TYPE_E500_SPIN) 47 48 typedef struct SpinState { 49 SysBusDevice parent_obj; 50 51 MemoryRegion iomem; 52 SpinInfo spin[MAX_CPUS]; 53 } SpinState; 54 55 typedef struct spin_kick { 56 PowerPCCPU *cpu; 57 SpinInfo *spin; 58 } SpinKick; 59 60 static void spin_reset(void *opaque) 61 { 62 SpinState *s = opaque; 63 int i; 64 65 for (i = 0; i < MAX_CPUS; i++) { 66 SpinInfo *info = &s->spin[i]; 67 68 stl_p(&info->pir, i); 69 stq_p(&info->r3, i); 70 stq_p(&info->addr, 1); 71 } 72 } 73 74 /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ 75 static inline hwaddr booke206_page_size_to_tlb(uint64_t size) 76 { 77 return ctz32(size >> 10) >> 1; 78 } 79 80 static void mmubooke_create_initial_mapping(CPUPPCState *env, 81 target_ulong va, 82 hwaddr pa, 83 hwaddr len) 84 { 85 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); 86 hwaddr size; 87 88 size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); 89 tlb->mas1 = MAS1_VALID | size; 90 tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; 91 tlb->mas7_3 = pa & TARGET_PAGE_MASK; 92 tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 93 env->tlb_dirty = true; 94 } 95 96 static void spin_kick(void *data) 97 { 98 SpinKick *kick = data; 99 CPUState *cpu = CPU(kick->cpu); 100 CPUPPCState *env = &kick->cpu->env; 101 SpinInfo *curspin = kick->spin; 102 hwaddr map_size = 64 * 1024 * 1024; 103 hwaddr map_start; 104 105 cpu_synchronize_state(cpu); 106 stl_p(&curspin->pir, env->spr[SPR_PIR]); 107 env->nip = ldq_p(&curspin->addr) & (map_size - 1); 108 env->gpr[3] = ldq_p(&curspin->r3); 109 env->gpr[4] = 0; 110 env->gpr[5] = 0; 111 env->gpr[6] = 0; 112 env->gpr[7] = map_size; 113 env->gpr[8] = 0; 114 env->gpr[9] = 0; 115 116 map_start = ldq_p(&curspin->addr) & ~(map_size - 1); 117 mmubooke_create_initial_mapping(env, 0, map_start, map_size); 118 119 cpu->halted = 0; 120 cpu->exception_index = -1; 121 cpu->stopped = false; 122 qemu_cpu_kick(cpu); 123 } 124 125 static void spin_write(void *opaque, hwaddr addr, uint64_t value, 126 unsigned len) 127 { 128 SpinState *s = opaque; 129 int env_idx = addr / sizeof(SpinInfo); 130 CPUState *cpu; 131 SpinInfo *curspin = &s->spin[env_idx]; 132 uint8_t *curspin_p = (uint8_t*)curspin; 133 134 cpu = qemu_get_cpu(env_idx); 135 if (cpu == NULL) { 136 /* Unknown CPU */ 137 return; 138 } 139 140 if (cpu->cpu_index == 0) { 141 /* primary CPU doesn't spin */ 142 return; 143 } 144 145 curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; 146 switch (len) { 147 case 1: 148 stb_p(curspin_p, value); 149 break; 150 case 2: 151 stw_p(curspin_p, value); 152 break; 153 case 4: 154 stl_p(curspin_p, value); 155 break; 156 } 157 158 if (!(ldq_p(&curspin->addr) & 1)) { 159 /* run CPU */ 160 SpinKick kick = { 161 .cpu = POWERPC_CPU(cpu), 162 .spin = curspin, 163 }; 164 165 run_on_cpu(cpu, spin_kick, &kick); 166 } 167 } 168 169 static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) 170 { 171 SpinState *s = opaque; 172 uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; 173 174 switch (len) { 175 case 1: 176 return ldub_p(spin_p); 177 case 2: 178 return lduw_p(spin_p); 179 case 4: 180 return ldl_p(spin_p); 181 default: 182 hw_error("ppce500: unexpected %s with len = %u", __func__, len); 183 } 184 } 185 186 static const MemoryRegionOps spin_rw_ops = { 187 .read = spin_read, 188 .write = spin_write, 189 .endianness = DEVICE_BIG_ENDIAN, 190 }; 191 192 static int ppce500_spin_initfn(SysBusDevice *dev) 193 { 194 SpinState *s = E500_SPIN(dev); 195 196 memory_region_init_io(&s->iomem, OBJECT(s), &spin_rw_ops, s, 197 "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS); 198 sysbus_init_mmio(dev, &s->iomem); 199 200 qemu_register_reset(spin_reset, s); 201 202 return 0; 203 } 204 205 static void ppce500_spin_class_init(ObjectClass *klass, void *data) 206 { 207 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 208 209 k->init = ppce500_spin_initfn; 210 } 211 212 static const TypeInfo ppce500_spin_info = { 213 .name = TYPE_E500_SPIN, 214 .parent = TYPE_SYS_BUS_DEVICE, 215 .instance_size = sizeof(SpinState), 216 .class_init = ppce500_spin_class_init, 217 }; 218 219 static void ppce500_spin_register_types(void) 220 { 221 type_register_static(&ppce500_spin_info); 222 } 223 224 type_init(ppce500_spin_register_types) 225