gpa_t scb_gpa; /* 0x0258 */
/* the shadow gmap in use by the vsie_page */
struct gmap_cache gmap_cache; /* 0x0260 */
- __u8 reserved[0x0700 - 0x0278]; /* 0x0278 */
- struct kvm_s390_crypto_cb crycb; /* 0x0700 */
- __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
+ __u8 reserved[0x06f8 - 0x0278]; /* 0x0278 */
+ struct kvm_s390_crypto_cb crycb; /* 0x06f8 */
+ __u8 fac[8 + S390_ARCH_FAC_LIST_SIZE_BYTE];/* 0x07f8 */
};
static_assert(sizeof(struct vsie_page) == PAGE_SIZE);
return 0;
}
+static int handle_stfle_2(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, u32 fac_list_origin)
+{
+ struct kvm_s390_flcb2 *flcb_s = (struct kvm_s390_flcb2 *)vsie_page->fac;
+ struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+ u64 len;
+
+ if (read_guest_real(vcpu, fac_list_origin, &len, sizeof(len)))
+ return set_validity_icpt(scb_s, 0x1090U);
+
+ /* discard reserved bits */
+ len = (len & U8_MAX);
+ flcb_s->header_val = len;
+ len += 1;
+
+ if (read_guest_real(vcpu, fac_list_origin + offsetof(struct kvm_s390_flcb2, facilities),
+ &flcb_s->facilities, len * sizeof(u64)))
+ return set_validity_icpt(scb_s, 0x1090U);
+
+ scb_s->fac = (u32)virt_to_phys(&vsie_page->fac) | S390_ARCH_FAC_FORMAT_2;
+ return 0;
+}
+
/*
* Try to shadow + enable the guest 2 provided facility list.
* Retry instruction execution if enabled for and provided by guest 2.
int format_mask, format;
u32 origin;
+ /* assert no overflow with maximum len */
+ BUILD_BUG_ON(sizeof(vsie_page->fac) < ((S390_ARCH_FAC_LIST_SIZE_U64 + 1) * sizeof(u64)));
BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct vsie_page, fac), 8));
if (fac && test_kvm_facility(vcpu->kvm, 7)) {
case 0:
return handle_stfle_0(vcpu, vsie_page, origin);
case 1:
+ return set_validity_icpt(&vsie_page->scb_s, 0x1330U);
case 2:
+ return handle_stfle_2(vcpu, vsie_page, origin);
case 3:
- unreachable();
+ return set_validity_icpt(&vsie_page->scb_s, 0x1330U);
}
}
return 0;