| 1 | /* |
| 2 | * CPU features/facilities for s390x |
| 3 | * |
| 4 | * Copyright IBM Corp. 2016, 2018 |
| 5 | * Copyright Red Hat, Inc. 2019 |
| 6 | * |
| 7 | * Author(s): David Hildenbrand <david@redhat.com> |
| 8 | * |
| 9 | * This work is licensed under the terms of the GNU GPL, version 2 or (at |
| 10 | * your option) any later version. See the COPYING file in the top-level |
| 11 | * directory. |
| 12 | */ |
| 13 | |
| 14 | #include "qemu/osdep.h" |
| 15 | #include "qemu/module.h" |
| 16 | #include "cpu_features.h" |
| 17 | #ifndef CONFIG_USER_ONLY |
| 18 | #include "target/s390x/kvm/pv.h" |
| 19 | #endif |
| 20 | |
| 21 | #define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \ |
| 22 | [S390_FEAT_##_FEAT] = { \ |
| 23 | .name = _NAME, \ |
| 24 | .type = S390_FEAT_TYPE_##_TYPE, \ |
| 25 | .bit = _BIT, \ |
| 26 | .desc = _DESC, \ |
| 27 | }, |
| 28 | static const S390FeatDef s390_features[S390_FEAT_MAX] = { |
| 29 | #include "cpu_features_def.h.inc" |
| 30 | }; |
| 31 | #undef DEF_FEAT |
| 32 | |
| 33 | const S390FeatDef *s390_feat_def(S390Feat feat) |
| 34 | { |
| 35 | return &s390_features[feat]; |
| 36 | } |
| 37 | |
| 38 | S390Feat s390_feat_by_type_and_bit(S390FeatType type, int bit) |
| 39 | { |
| 40 | S390Feat feat; |
| 41 | |
| 42 | for (feat = 0; feat < ARRAY_SIZE(s390_features); feat++) { |
| 43 | if (s390_features[feat].type == type && |
| 44 | s390_features[feat].bit == bit) { |
| 45 | return feat; |
| 46 | } |
| 47 | } |
| 48 | return S390_FEAT_MAX; |
| 49 | } |
| 50 | |
| 51 | void s390_init_feat_bitmap(const S390FeatInit init, S390FeatBitmap bitmap) |
| 52 | { |
| 53 | int i, j; |
| 54 | |
| 55 | for (i = 0; i < (S390_FEAT_MAX / 64 + 1); i++) { |
| 56 | if (init[i]) { |
| 57 | for (j = 0; j < 64; j++) { |
| 58 | if (init[i] & 1ULL << j) { |
| 59 | set_bit(i * 64 + j, bitmap); |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type, |
| 67 | uint8_t *data) |
| 68 | { |
| 69 | S390Feat feat; |
| 70 | int bit_nr; |
| 71 | |
| 72 | switch (type) { |
| 73 | case S390_FEAT_TYPE_STFL: |
| 74 | if (test_bit(S390_FEAT_ZARCH, features)) { |
| 75 | /* Features that are always active */ |
| 76 | set_be_bit(2, data); /* z/Architecture */ |
| 77 | set_be_bit(138, data); /* Configuration-z-architectural-mode */ |
| 78 | } |
| 79 | break; |
| 80 | case S390_FEAT_TYPE_PTFF: |
| 81 | case S390_FEAT_TYPE_KMAC: |
| 82 | case S390_FEAT_TYPE_KMC: |
| 83 | case S390_FEAT_TYPE_KM: |
| 84 | case S390_FEAT_TYPE_KIMD: |
| 85 | case S390_FEAT_TYPE_KLMD: |
| 86 | case S390_FEAT_TYPE_PCKMO: |
| 87 | case S390_FEAT_TYPE_KMCTR: |
| 88 | case S390_FEAT_TYPE_KMF: |
| 89 | case S390_FEAT_TYPE_KMO: |
| 90 | case S390_FEAT_TYPE_PCC: |
| 91 | case S390_FEAT_TYPE_PPNO: |
| 92 | case S390_FEAT_TYPE_KMA: |
| 93 | case S390_FEAT_TYPE_KDSA: |
| 94 | case S390_FEAT_TYPE_SORTL: |
| 95 | case S390_FEAT_TYPE_DFLTCC: |
| 96 | case S390_FEAT_TYPE_PFCR: |
| 97 | set_be_bit(0, data); /* query is always available */ |
| 98 | break; |
| 99 | default: |
| 100 | break; |
| 101 | }; |
| 102 | |
| 103 | feat = find_first_bit(features, S390_FEAT_MAX); |
| 104 | while (feat < S390_FEAT_MAX) { |
| 105 | if (s390_features[feat].type == type) { |
| 106 | bit_nr = s390_features[feat].bit; |
| 107 | /* big endian on uint8_t array */ |
| 108 | set_be_bit(bit_nr, data); |
| 109 | } |
| 110 | feat = find_next_bit(features, S390_FEAT_MAX, feat + 1); |
| 111 | } |
| 112 | |
| 113 | #ifndef CONFIG_USER_ONLY |
| 114 | if (!s390_is_pv()) { |
| 115 | return; |
| 116 | } |
| 117 | |
| 118 | /* |
| 119 | * Some facilities are not available for CPUs in protected mode: |
| 120 | * - All SIE facilities because SIE is not available |
| 121 | * - DIAG318 |
| 122 | * - Secure IPL Facility |
| 123 | * - Secure IPL Code Loading Attributes Facility |
| 124 | * |
| 125 | * As VMs can move in and out of protected mode the CPU model |
| 126 | * doesn't protect us from that problem because it is only |
| 127 | * validated at the start of the VM. |
| 128 | */ |
| 129 | switch (type) { |
| 130 | case S390_FEAT_TYPE_SCLP_CPU: |
| 131 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_F2)->bit, data); |
| 132 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_SKEY)->bit, data); |
| 133 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_GPERE)->bit, data); |
| 134 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_SIIF)->bit, data); |
| 135 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_SIGPIF)->bit, data); |
| 136 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_IB)->bit, data); |
| 137 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_CEI)->bit, data); |
| 138 | break; |
| 139 | case S390_FEAT_TYPE_SCLP_CONF_CHAR: |
| 140 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_GSLS)->bit, data); |
| 141 | clear_be_bit(s390_feat_def(S390_FEAT_HPMA2)->bit, data); |
| 142 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_KSS)->bit, data); |
| 143 | break; |
| 144 | case S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT: |
| 145 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_64BSCAO)->bit, data); |
| 146 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_CMMA)->bit, data); |
| 147 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_PFMFI)->bit, data); |
| 148 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_IBS)->bit, data); |
| 149 | break; |
| 150 | case S390_FEAT_TYPE_SCLP_FAC134: |
| 151 | clear_be_bit(s390_feat_def(S390_FEAT_DIAG_318)->bit, data); |
| 152 | clear_be_bit(s390_feat_def(S390_FEAT_CERT_STORE)->bit, data); |
| 153 | break; |
| 154 | case S390_FEAT_TYPE_SCLP_FAC_IPL: |
| 155 | clear_be_bit(s390_feat_def(S390_FEAT_SIPL)->bit, data); |
| 156 | clear_be_bit(s390_feat_def(S390_FEAT_SCLAF)->bit, data); |
| 157 | break; |
| 158 | case S390_FEAT_TYPE_SCLP_FAC139: |
| 159 | clear_be_bit(s390_feat_def(S390_FEAT_SIE_ASTFLEIE2)->bit, data); |
| 160 | break; |
| 161 | default: |
| 162 | return; |
| 163 | } |
| 164 | #endif |
| 165 | } |
| 166 | |
| 167 | void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type, |
| 168 | uint8_t *data) |
| 169 | { |
| 170 | int nr_bits, le_bit; |
| 171 | |
| 172 | switch (type) { |
| 173 | case S390_FEAT_TYPE_STFL: |
| 174 | nr_bits = 16384; |
| 175 | break; |
| 176 | case S390_FEAT_TYPE_PLO: |
| 177 | case S390_FEAT_TYPE_SORTL: |
| 178 | case S390_FEAT_TYPE_DFLTCC: |
| 179 | nr_bits = 256; |
| 180 | break; |
| 181 | default: |
| 182 | /* all cpu subfunctions have 128 bit */ |
| 183 | nr_bits = 128; |
| 184 | }; |
| 185 | |
| 186 | le_bit = find_first_bit((unsigned long *) data, nr_bits); |
| 187 | while (le_bit < nr_bits) { |
| 188 | /* convert the bit number to a big endian bit nr */ |
| 189 | S390Feat feat = s390_feat_by_type_and_bit(type, BE_BIT_NR(le_bit)); |
| 190 | /* ignore unknown bits */ |
| 191 | if (feat < S390_FEAT_MAX) { |
| 192 | set_bit(feat, features); |
| 193 | } |
| 194 | le_bit = find_next_bit((unsigned long *) data, nr_bits, le_bit + 1); |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | void s390_feat_bitmap_to_ascii(const S390FeatBitmap features, void *opaque, |
| 199 | void (*fn)(const char *name, void *opaque)) |
| 200 | { |
| 201 | S390FeatBitmap bitmap, tmp; |
| 202 | S390FeatGroup group; |
| 203 | S390Feat feat; |
| 204 | |
| 205 | bitmap_copy(bitmap, features, S390_FEAT_MAX); |
| 206 | |
| 207 | /* process whole groups first */ |
| 208 | for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { |
| 209 | const S390FeatGroupDef *def = s390_feat_group_def(group); |
| 210 | |
| 211 | bitmap_and(tmp, bitmap, def->feat, S390_FEAT_MAX); |
| 212 | if (bitmap_equal(tmp, def->feat, S390_FEAT_MAX)) { |
| 213 | bitmap_andnot(bitmap, bitmap, def->feat, S390_FEAT_MAX); |
| 214 | fn(def->name, opaque); |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | /* report leftovers as separate features */ |
| 219 | feat = find_first_bit(bitmap, S390_FEAT_MAX); |
| 220 | while (feat < S390_FEAT_MAX) { |
| 221 | fn(s390_feat_def(feat)->name, opaque); |
| 222 | feat = find_next_bit(bitmap, S390_FEAT_MAX, feat + 1); |
| 223 | }; |
| 224 | } |
| 225 | |
| 226 | void s390_get_deprecated_features(S390FeatBitmap features) |
| 227 | { |
| 228 | static const int feats[] = { |
| 229 | /* CSSKE is deprecated on newer generations */ |
| 230 | S390_FEAT_CONDITIONAL_SSKE, |
| 231 | S390_FEAT_BPB, |
| 232 | /* Deprecated on z16 */ |
| 233 | S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE, |
| 234 | S390_FEAT_TRANSACTIONAL_EXE |
| 235 | }; |
| 236 | int i; |
| 237 | |
| 238 | for (i = 0; i < ARRAY_SIZE(feats); i++) { |
| 239 | set_bit(feats[i], features); |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | #define FEAT_GROUP_INIT(_name, _group, _desc) \ |
| 244 | { \ |
| 245 | .name = _name, \ |
| 246 | .desc = _desc, \ |
| 247 | .init = { S390_FEAT_GROUP_LIST_ ## _group }, \ |
| 248 | } |
| 249 | |
| 250 | /* indexed by feature group number for easy lookup */ |
| 251 | static S390FeatGroupDef s390_feature_groups[] = { |
| 252 | FEAT_GROUP_INIT("plo", PLO, "Perform-locked-operation facility"), |
| 253 | FEAT_GROUP_INIT("plo_ext", PLO_EXT, "PLO-extension facility"), |
| 254 | FEAT_GROUP_INIT("tods", TOD_CLOCK_STEERING, "Tod-clock-steering facility"), |
| 255 | FEAT_GROUP_INIT("gen13ptff", GEN13_PTFF, "PTFF enhancements introduced with z13"), |
| 256 | FEAT_GROUP_INIT("gen17ptff", GEN17_PTFF, "PTFF enhancements introduced with gen17"), |
| 257 | FEAT_GROUP_INIT("msa", MSA, "Message-security-assist facility"), |
| 258 | FEAT_GROUP_INIT("msa1", MSA_EXT_1, "Message-security-assist-extension 1 facility"), |
| 259 | FEAT_GROUP_INIT("msa2", MSA_EXT_2, "Message-security-assist-extension 2 facility"), |
| 260 | FEAT_GROUP_INIT("msa3", MSA_EXT_3, "Message-security-assist-extension 3 facility"), |
| 261 | FEAT_GROUP_INIT("msa4", MSA_EXT_4, "Message-security-assist-extension 4 facility"), |
| 262 | FEAT_GROUP_INIT("msa5", MSA_EXT_5, "Message-security-assist-extension 5 facility"), |
| 263 | FEAT_GROUP_INIT("msa6", MSA_EXT_6, "Message-security-assist-extension 6 facility"), |
| 264 | FEAT_GROUP_INIT("msa7", MSA_EXT_7, "Message-security-assist-extension 7 facility"), |
| 265 | FEAT_GROUP_INIT("msa8", MSA_EXT_8, "Message-security-assist-extension 8 facility"), |
| 266 | FEAT_GROUP_INIT("msa9", MSA_EXT_9, "Message-security-assist-extension 9 facility"), |
| 267 | FEAT_GROUP_INIT("msa9_pckmo", MSA_EXT_9_PCKMO, "Message-security-assist-extension 9 PCKMO subfunctions"), |
| 268 | FEAT_GROUP_INIT("msa10", MSA_EXT_10, "Message-security-assist-extension 10 facility"), |
| 269 | FEAT_GROUP_INIT("msa10_pckmo", MSA_EXT_10_PCKMO, "Message-security-assist-extension 10 PCKMO subfunctions"), |
| 270 | FEAT_GROUP_INIT("msa11", MSA_EXT_11, "Message-security-assist-extension 11 facility"), |
| 271 | FEAT_GROUP_INIT("msa11_pckmo", MSA_EXT_11_PCKMO, "Message-security-assist-extension 11 PCKMO subfunctions"), |
| 272 | FEAT_GROUP_INIT("msa12", MSA_EXT_12, "Message-security-assist-extension 12 facility"), |
| 273 | FEAT_GROUP_INIT("msa13", MSA_EXT_13, "Message-security-assist-extension 13 facility"), |
| 274 | FEAT_GROUP_INIT("msa13_pckmo", MSA_EXT_13_PCKMO, "Message-security-assist-extension 13 PCKMO subfunctions"), |
| 275 | FEAT_GROUP_INIT("mepochptff", MULTIPLE_EPOCH_PTFF, "PTFF enhancements introduced with Multiple-epoch facility"), |
| 276 | FEAT_GROUP_INIT("esort", ENH_SORT, "Enhanced-sort facility"), |
| 277 | FEAT_GROUP_INIT("deflate", DEFLATE_CONVERSION, "Deflate-conversion facility"), |
| 278 | FEAT_GROUP_INIT("ccf", CONCURRENT_FUNCTIONS, "Concurrent-functions facility"), |
| 279 | }; |
| 280 | |
| 281 | const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group) |
| 282 | { |
| 283 | return &s390_feature_groups[group]; |
| 284 | } |
| 285 | |
| 286 | static void init_groups(void) |
| 287 | { |
| 288 | int i; |
| 289 | |
| 290 | /* init all bitmaps from generated data initially */ |
| 291 | for (i = 0; i < ARRAY_SIZE(s390_feature_groups); i++) { |
| 292 | s390_init_feat_bitmap(s390_feature_groups[i].init, |
| 293 | s390_feature_groups[i].feat); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | type_init(init_groups) |