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