205
}
206
}
207
208
+static int handle_diag320_query_vcsi(S390CPU *cpu, uint64_t addr, uint64_t r1,
209
+ uintptr_t ra, S390IPLCertificateStore *cs)
210
+{
211
+ g_autofree VCStorageSizeBlock *vcssb = NULL;
212
+
213
+ vcssb = g_new0(VCStorageSizeBlock, 1);
214
+ if (s390_cpu_virt_mem_read(cpu, addr, r1, vcssb, sizeof(*vcssb))) {
215
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
216
+ return -1;
217
+ }
218
+
219
+ if (be32_to_cpu(vcssb->length) != VCSSB_LEN_VALID) {
220
+ return DIAG_320_RC_INVAL_VCSSB_LEN;
221
+ }
222
+
223
+ if (!cs->count) {
224
+ vcssb->length = cpu_to_be32(VCSSB_NO_VC);
225
+ } else {
226
+ vcssb->version = 0;
227
+ vcssb->total_vc_ct = cpu_to_be16(cs->count);
228
+ vcssb->max_vc_ct = cpu_to_be16(MAX_CERTIFICATES);
229
+ vcssb->max_single_vcb_len = cpu_to_be32(sizeof(VCBlockHeader) +
230
+ sizeof(VCEntryHeader) +
231
+ cs->largest_cert_size);
232
+ vcssb->total_vcb_len = cpu_to_be32(sizeof(VCBlockHeader) +
233
+ cs->count * sizeof(VCEntryHeader) +
234
+ cs->total_bytes);
235
+ }
236
+
237
+ if (s390_cpu_virt_mem_write(cpu, addr, r1, vcssb, be32_to_cpu(vcssb->length))) {
238
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
239
+ return -1;
240
+ }
241
+ return DIAG_320_RC_OK;
242
+}
243
+
244
+QEMU_BUILD_BUG_MSG(sizeof(VCStorageSizeBlock) != VCSSB_LEN_VALID,
245
+ "size of VCStorageSizeBlock is wrong");
246
+
247
void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
248
{
249
S390CPU *cpu = env_archcpu(env);
250
+ S390IPLCertificateStore *cs = s390_ipl_get_certificate_store();
251
uint64_t subcode = env->regs[r3];
252
uint64_t addr = env->regs[r1];
253
uint32_t ism_word0;
254
+ int rc;
255
256
if (env->psw.mask & PSW_MASK_PSTATE) {
257
s390_program_interrupt(env, PGM_PRIVILEGED, ra);
272
* but the current set of subcodes can fit within a single word
273
* for now.
274
*/
234
- ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES);
275
+ ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES |
276
+ DIAG_320_ISM_QUERY_VCSI);
277
278
if (s390_cpu_virt_mem_write(cpu, addr, r1, &ism_word0, sizeof(ism_word0))) {
279
s390_cpu_virt_mem_handle_exc(cpu, ra);
282
283
env->regs[r1 + 1] = DIAG_320_RC_OK;
284
break;
285
+ case DIAG_320_SUBC_QUERY_VCSI:
286
+ if (addr & 0x7) {
287
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
288
+ return;
289
+ }
290
+
291
+ if (!diag_parm_addr_valid(addr, sizeof(VCStorageSizeBlock), true)) {
292
+ s390_program_interrupt(env, PGM_ADDRESSING, ra);
293
+ return;
294
+ }
295
+
296
+ rc = handle_diag320_query_vcsi(cpu, addr, r1, ra, cs);
297
+ if (rc == -1) {
298
+ return;
299
+ }
300
+ env->regs[r1 + 1] = rc;
301
+ break;
302
default:
303
env->regs[r1 + 1] = DIAG_320_RC_NOT_SUPPORTED;
304
break;