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 | |
18 | #define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \ |
19 | [S390_FEAT_##_FEAT] = { \ |
20 | .name = _NAME, \ |
21 | .type = S390_FEAT_TYPE_##_TYPE, \ |
22 | .bit = _BIT, \ |
23 | .desc = _DESC, \ |
24 | }, |
25 | static const S390FeatDef s390_features[S390_FEAT_MAX] = { |
26 | #include "cpu_features_def.inc.h" |
27 | }; |
28 | #undef DEF_FEAT |
29 | |
30 | const S390FeatDef *s390_feat_def(S390Feat feat) |
31 | { |
32 | return &s390_features[feat]; |
33 | } |
34 | |
35 | S390Feat s390_feat_by_type_and_bit(S390FeatType type, int bit) |
36 | { |
37 | S390Feat feat; |
38 | |
39 | for (feat = 0; feat < ARRAY_SIZE(s390_features); feat++) { |
40 | if (s390_features[feat].type == type && |
41 | s390_features[feat].bit == bit) { |
42 | return feat; |
43 | } |
44 | } |
45 | return S390_FEAT_MAX; |
46 | } |
47 | |
48 | void s390_init_feat_bitmap(const S390FeatInit init, S390FeatBitmap bitmap) |
49 | { |
50 | int i, j; |
51 | |
52 | for (i = 0; i < (S390_FEAT_MAX / 64 + 1); i++) { |
53 | if (init[i]) { |
54 | for (j = 0; j < 64; j++) { |
55 | if (init[i] & 1ULL << j) { |
56 | set_bit(i * 64 + j, bitmap); |
57 | } |
58 | } |
59 | } |
60 | } |
61 | } |
62 | |
63 | void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type, |
64 | uint8_t *data) |
65 | { |
66 | S390Feat feat; |
67 | int bit_nr; |
68 | |
69 | switch (type) { |
70 | case S390_FEAT_TYPE_STFL: |
71 | if (test_bit(S390_FEAT_ZARCH, features)) { |
72 | /* Features that are always active */ |
73 | set_be_bit(2, data); /* z/Architecture */ |
74 | set_be_bit(138, data); /* Configuration-z-architectural-mode */ |
75 | } |
76 | break; |
77 | case S390_FEAT_TYPE_PTFF: |
78 | case S390_FEAT_TYPE_KMAC: |
79 | case S390_FEAT_TYPE_KMC: |
80 | case S390_FEAT_TYPE_KM: |
81 | case S390_FEAT_TYPE_KIMD: |
82 | case S390_FEAT_TYPE_KLMD: |
83 | case S390_FEAT_TYPE_PCKMO: |
84 | case S390_FEAT_TYPE_KMCTR: |
85 | case S390_FEAT_TYPE_KMF: |
86 | case S390_FEAT_TYPE_KMO: |
87 | case S390_FEAT_TYPE_PCC: |
88 | case S390_FEAT_TYPE_PPNO: |
89 | case S390_FEAT_TYPE_KMA: |
90 | case S390_FEAT_TYPE_KDSA: |
91 | case S390_FEAT_TYPE_SORTL: |
92 | case S390_FEAT_TYPE_DFLTCC: |
93 | set_be_bit(0, data); /* query is always available */ |
94 | break; |
95 | default: |
96 | break; |
97 | }; |
98 | |
99 | feat = find_first_bit(features, S390_FEAT_MAX); |
100 | while (feat < S390_FEAT_MAX) { |
101 | if (s390_features[feat].type == type) { |
102 | bit_nr = s390_features[feat].bit; |
103 | /* big endian on uint8_t array */ |
104 | set_be_bit(bit_nr, data); |
105 | } |
106 | feat = find_next_bit(features, S390_FEAT_MAX, feat + 1); |
107 | } |
108 | } |
109 | |
110 | void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type, |
111 | uint8_t *data) |
112 | { |
113 | int nr_bits, le_bit; |
114 | |
115 | switch (type) { |
116 | case S390_FEAT_TYPE_STFL: |
117 | nr_bits = 16384; |
118 | break; |
119 | case S390_FEAT_TYPE_PLO: |
120 | case S390_FEAT_TYPE_SORTL: |
121 | case S390_FEAT_TYPE_DFLTCC: |
122 | nr_bits = 256; |
123 | break; |
124 | default: |
125 | /* all cpu subfunctions have 128 bit */ |
126 | nr_bits = 128; |
127 | }; |
128 | |
129 | le_bit = find_first_bit((unsigned long *) data, nr_bits); |
130 | while (le_bit < nr_bits) { |
131 | /* convert the bit number to a big endian bit nr */ |
132 | S390Feat feat = s390_feat_by_type_and_bit(type, BE_BIT_NR(le_bit)); |
133 | /* ignore unknown bits */ |
134 | if (feat < S390_FEAT_MAX) { |
135 | set_bit(feat, features); |
136 | } |
137 | le_bit = find_next_bit((unsigned long *) data, nr_bits, le_bit + 1); |
138 | } |
139 | } |
140 | |
141 | void s390_feat_bitmap_to_ascii(const S390FeatBitmap features, void *opaque, |
142 | void (*fn)(const char *name, void *opaque)) |
143 | { |
144 | S390FeatBitmap bitmap, tmp; |
145 | S390FeatGroup group; |
146 | S390Feat feat; |
147 | |
148 | bitmap_copy(bitmap, features, S390_FEAT_MAX); |
149 | |
150 | /* process whole groups first */ |
151 | for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { |
152 | const S390FeatGroupDef *def = s390_feat_group_def(group); |
153 | |
154 | bitmap_and(tmp, bitmap, def->feat, S390_FEAT_MAX); |
155 | if (bitmap_equal(tmp, def->feat, S390_FEAT_MAX)) { |
156 | bitmap_andnot(bitmap, bitmap, def->feat, S390_FEAT_MAX); |
157 | fn(def->name, opaque); |
158 | } |
159 | } |
160 | |
161 | /* report leftovers as separate features */ |
162 | feat = find_first_bit(bitmap, S390_FEAT_MAX); |
163 | while (feat < S390_FEAT_MAX) { |
164 | fn(s390_feat_def(feat)->name, opaque); |
165 | feat = find_next_bit(bitmap, S390_FEAT_MAX, feat + 1); |
166 | }; |
167 | } |
168 | |
169 | #define FEAT_GROUP_INIT(_name, _group, _desc) \ |
170 | { \ |
171 | .name = _name, \ |
172 | .desc = _desc, \ |
173 | .init = { S390_FEAT_GROUP_LIST_ ## _group }, \ |
174 | } |
175 | |
176 | /* indexed by feature group number for easy lookup */ |
177 | static S390FeatGroupDef s390_feature_groups[] = { |
178 | FEAT_GROUP_INIT("plo" , PLO, "Perform-locked-operation facility" ), |
179 | FEAT_GROUP_INIT("tods" , TOD_CLOCK_STEERING, "Tod-clock-steering facility" ), |
180 | FEAT_GROUP_INIT("gen13ptff" , GEN13_PTFF, "PTFF enhancements introduced with z13" ), |
181 | FEAT_GROUP_INIT("msa" , MSA, "Message-security-assist facility" ), |
182 | FEAT_GROUP_INIT("msa1" , MSA_EXT_1, "Message-security-assist-extension 1 facility" ), |
183 | FEAT_GROUP_INIT("msa2" , MSA_EXT_2, "Message-security-assist-extension 2 facility" ), |
184 | FEAT_GROUP_INIT("msa3" , MSA_EXT_3, "Message-security-assist-extension 3 facility" ), |
185 | FEAT_GROUP_INIT("msa4" , MSA_EXT_4, "Message-security-assist-extension 4 facility" ), |
186 | FEAT_GROUP_INIT("msa5" , MSA_EXT_5, "Message-security-assist-extension 5 facility" ), |
187 | FEAT_GROUP_INIT("msa6" , MSA_EXT_6, "Message-security-assist-extension 6 facility" ), |
188 | FEAT_GROUP_INIT("msa7" , MSA_EXT_7, "Message-security-assist-extension 7 facility" ), |
189 | FEAT_GROUP_INIT("msa8" , MSA_EXT_8, "Message-security-assist-extension 8 facility" ), |
190 | FEAT_GROUP_INIT("msa9" , MSA_EXT_9, "Message-security-assist-extension 9 facility" ), |
191 | FEAT_GROUP_INIT("msa9_pckmo" , MSA_EXT_9_PCKMO, "Message-security-assist-extension 9 PCKMO subfunctions" ), |
192 | FEAT_GROUP_INIT("mepochptff" , MULTIPLE_EPOCH_PTFF, "PTFF enhancements introduced with Multiple-epoch facility" ), |
193 | FEAT_GROUP_INIT("esort" , ENH_SORT, "Enhanced-sort facility" ), |
194 | FEAT_GROUP_INIT("deflate" , DEFLATE_CONVERSION, "Deflate-conversion facility" ), |
195 | }; |
196 | |
197 | const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group) |
198 | { |
199 | return &s390_feature_groups[group]; |
200 | } |
201 | |
202 | static void init_groups(void) |
203 | { |
204 | int i; |
205 | |
206 | /* init all bitmaps from gnerated data initially */ |
207 | for (i = 0; i < ARRAY_SIZE(s390_feature_groups); i++) { |
208 | s390_init_feat_bitmap(s390_feature_groups[i].init, |
209 | s390_feature_groups[i].feat); |
210 | } |
211 | } |
212 | |
213 | type_init(init_groups) |
214 | |