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