1 /* 2 * PowerPC CPU initialization for qemu. 3 * 4 * Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "sysemu/kvm.h" 22 #include "kvm_ppc.h" 23 #include "sysemu/cpus.h" 24 #include "qemu/error-report.h" 25 #include "qapi/error.h" 26 #include "cpu-models.h" 27 28 typedef struct { 29 uint32_t pvr; 30 uint64_t pcr; 31 uint64_t pcr_level; 32 int max_threads; 33 } CompatInfo; 34 35 static const CompatInfo compat_table[] = { 36 /* 37 * Ordered from oldest to newest - the code relies on this 38 */ 39 { /* POWER6, ISA2.05 */ 40 .pvr = CPU_POWERPC_LOGICAL_2_05, 41 .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05 42 | PCR_TM_DIS | PCR_VSX_DIS, 43 .pcr_level = PCR_COMPAT_2_05, 44 .max_threads = 2, 45 }, 46 { /* POWER7, ISA2.06 */ 47 .pvr = CPU_POWERPC_LOGICAL_2_06, 48 .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, 49 .pcr_level = PCR_COMPAT_2_06, 50 .max_threads = 4, 51 }, 52 { 53 .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS, 54 .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, 55 .pcr_level = PCR_COMPAT_2_06, 56 .max_threads = 4, 57 }, 58 { /* POWER8, ISA2.07 */ 59 .pvr = CPU_POWERPC_LOGICAL_2_07, 60 .pcr = PCR_COMPAT_2_07, 61 .pcr_level = PCR_COMPAT_2_07, 62 .max_threads = 8, 63 }, 64 }; 65 66 static const CompatInfo *compat_by_pvr(uint32_t pvr) 67 { 68 int i; 69 70 for (i = 0; i < ARRAY_SIZE(compat_table); i++) { 71 if (compat_table[i].pvr == pvr) { 72 return &compat_table[i]; 73 } 74 } 75 return NULL; 76 } 77 78 bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, 79 uint32_t min_compat_pvr, uint32_t max_compat_pvr) 80 { 81 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 82 const CompatInfo *compat = compat_by_pvr(compat_pvr); 83 const CompatInfo *min = compat_by_pvr(min_compat_pvr); 84 const CompatInfo *max = compat_by_pvr(max_compat_pvr); 85 86 #if !defined(CONFIG_USER_ONLY) 87 g_assert(cpu->vhyp); 88 #endif 89 g_assert(!min_compat_pvr || min); 90 g_assert(!max_compat_pvr || max); 91 92 if (!compat) { 93 /* Not a recognized logical PVR */ 94 return false; 95 } 96 if ((min && (compat < min)) || (max && (compat > max))) { 97 /* Outside specified range */ 98 return false; 99 } 100 if (!(pcc->pcr_supported & compat->pcr_level)) { 101 /* Not supported by this CPU */ 102 return false; 103 } 104 return true; 105 } 106 107 void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) 108 { 109 const CompatInfo *compat = compat_by_pvr(compat_pvr); 110 CPUPPCState *env = &cpu->env; 111 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 112 uint64_t pcr; 113 114 if (!compat_pvr) { 115 pcr = 0; 116 } else if (!compat) { 117 error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr); 118 return; 119 } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) { 120 error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU", 121 compat_pvr); 122 return; 123 } else { 124 pcr = compat->pcr; 125 } 126 127 cpu->compat_pvr = compat_pvr; 128 env->spr[SPR_PCR] = pcr & pcc->pcr_mask; 129 130 if (kvm_enabled()) { 131 int ret = kvmppc_set_compat(cpu, cpu->compat_pvr); 132 if (ret < 0) { 133 error_setg_errno(errp, -ret, 134 "Unable to set CPU compatibility mode in KVM"); 135 } 136 } 137 } 138 139 int ppc_compat_max_threads(PowerPCCPU *cpu) 140 { 141 const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr); 142 int n_threads = CPU(cpu)->nr_threads; 143 144 if (cpu->compat_pvr) { 145 g_assert(compat); 146 n_threads = MIN(n_threads, compat->max_threads); 147 } 148 149 return n_threads; 150 } 151