From patchwork Thu Jul 26 19:54:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Borntraeger X-Patchwork-Id: 10546391 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 47570174A for ; Thu, 26 Jul 2018 19:55:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2BB9928801 for ; Thu, 26 Jul 2018 19:55:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1FCEA2BD26; Thu, 26 Jul 2018 19:55:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 58BE428801 for ; Thu, 26 Jul 2018 19:55:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732049AbeGZVN0 (ORCPT ); Thu, 26 Jul 2018 17:13:26 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:52326 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732036AbeGZVN0 (ORCPT ); Thu, 26 Jul 2018 17:13:26 -0400 Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w6QJsIft105062 for ; Thu, 26 Jul 2018 15:55:03 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2kfkkeu2gs-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 26 Jul 2018 15:55:02 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 26 Jul 2018 20:55:00 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Thu, 26 Jul 2018 20:54:57 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w6QJstmB34603254 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 26 Jul 2018 19:54:55 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D7AEC4C046; Thu, 26 Jul 2018 22:55:09 +0100 (BST) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B61114C040; Thu, 26 Jul 2018 22:55:09 +0100 (BST) Received: from tuxmaker.boeblingen.de.ibm.com (unknown [9.152.85.9]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTPS; Thu, 26 Jul 2018 22:55:09 +0100 (BST) Received: by tuxmaker.boeblingen.de.ibm.com (Postfix, from userid 25651) id DCC2020F5B5; Thu, 26 Jul 2018 21:54:54 +0200 (CEST) From: Christian Borntraeger To: Janosch Frank , alex.williamson@redhat.com, Kirti Wankhede Cc: KVM , Cornelia Huck , Christian Borntraeger , David Hildenbrand , linux-s390@vger.kernel.org, freude@de.ibm.com, schwidefsky@de.ibm.com, pmorel@linux.vnet.ibm.com, Halil Pasic , Tony Krowiak , Michael Mueller , buendgen@de.ibm.com, Boris Fiuczynski , jjherne@linux.ibm.com, Farhan Ali , berrange@redhat.com Subject: [PATCH v7 20/22] KVM: s390: Handling of Cypto control block in VSIE Date: Thu, 26 Jul 2018 21:54:27 +0200 X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180726195429.31960-1-borntraeger@de.ibm.com> References: <20180726195429.31960-1-borntraeger@de.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18072619-0020-0000-0000-000002AC7915 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18072619-0021-0000-0000-000020F8807C Message-Id: <20180726195429.31960-21-borntraeger@de.ibm.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2018-07-26_05:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1806210000 definitions=main-1807260204 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Pierre Morel Shadowing the crypto control block now supports APCB shadowing. AP instruction interpretation for guest 3 through ECA.28 is shadowed when guest 2 ECA.28 is set. CRYCB is shadowed for APCB and wrapping keys. CRYCB format 0 is now supported for both guests 2 and 3. Shadow CRYCB always uses the guest 2 CRYCB format and it follows that: * Guest 3 CRYCB format 0 is supported with guest 2 CRYCB format 0,1 or 2 * Guest 3 CRYCB format 1 is supported with guest 2 CRYCB format 1 or 2 * Guest 3 CRYCB format 2 is supported with guest 2 CRYCB format 2 Signed-off-by: Pierre Morel Reviewed-by: Tony Krowiak Acked-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 224 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 200 insertions(+), 24 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 84c89cb9636f..25c8cccaa976 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -136,17 +136,8 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return 0; } -/* - * Create a shadow copy of the crycb block and setup key wrapping, if - * requested for guest 3 and enabled for guest 2. - * - * We only accept format-1 (no AP in g2), but convert it into format-2 - * There is nothing to do for format-0. - * - * Returns: - 0 if shadowed or nothing to do - * - > 0 if control has to be given to guest 2 - */ -static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) +/* Copy keys into shadow crycb, is only called if MSA3 is available. */ +static int copy_key_masks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; @@ -155,30 +146,17 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) unsigned long *b1, *b2; u8 ecb3_flags; - scb_s->crycbd = 0; - if (!(crycbd_o & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) - return 0; - /* format-1 is supported with message-security-assist extension 3 */ - if (!test_kvm_facility(vcpu->kvm, 76)) - return 0; /* we may only allow it if enabled for guest 2 */ ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 & (ECB3_AES | ECB3_DEA); if (!ecb3_flags) return 0; - if ((crycb_addr & PAGE_MASK) != ((crycb_addr + 128) & PAGE_MASK)) - return set_validity_icpt(scb_s, 0x003CU); - else if (!crycb_addr) - return set_validity_icpt(scb_s, 0x0039U); - /* copy only the wrapping keys */ if (read_guest_real(vcpu, crycb_addr + 72, &vsie_page->crycb, 56)) return set_validity_icpt(scb_s, 0x0035U); scb_s->ecb3 |= ecb3_flags; - scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT1 | - CRYCB_FORMAT2; /* xor both blocks in one run */ b1 = (unsigned long *) vsie_page->crycb.dea_wrapping_key_mask; @@ -189,6 +167,204 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return 0; } +/* Copy masks into apcb when g2 and g3 use format 1 */ +static int copy_apcb1(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) +{ + struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd); + const u32 crycb_o = crycbd_o & 0x7ffffff8U; + struct kvm_s390_crypto_cb *crycb_h = &vcpu->kvm->arch.sie_page2->crycb; + struct kvm_s390_crypto_cb *crycb_s = &vsie_page->crycb; + unsigned long *apcb_s = (unsigned long *) &crycb_s->apcb1; + unsigned long *apcb_h = (unsigned long *) &crycb_h->apcb1; + int i; + u32 src; + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb1); + if (read_guest_real(vcpu, src, apcb_s, sizeof(struct kvm_s390_apcb1))) + return set_validity_icpt(scb_s, 0x0035U); + + for (i = 0; i < sizeof(struct kvm_s390_apcb1); i += sizeof(*apcb_s)) + *apcb_s &= *apcb_h; + + return 0; +} + +/* + * Copy masks into apcb when g2 use format 1 and g3 use format 0 + * In this case the shadow APCB uses format 1 + */ +static int copy_apcb01(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) +{ + struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd); + const u32 crycb_o = crycbd_o & 0x7ffffff8U; + struct kvm_s390_apcb1 *apcb_h = &vcpu->kvm->arch.sie_page2->crycb.apcb1; + struct kvm_s390_apcb1 *apcb_s = &vsie_page->crycb.apcb1; + u32 src; + + memset(apcb_s, 0, sizeof(*apcb_s)); + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.apm[0]); + if (read_guest_real(vcpu, src, &apcb_s->apm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.aqm[0]); + if (read_guest_real(vcpu, src, &apcb_s->aqm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.adm[0]); + if (read_guest_real(vcpu, src, &apcb_s->adm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + apcb_s->apm[0] &= apcb_h->apm[0]; + apcb_s->aqm[0] &= apcb_h->aqm[0]; + apcb_s->adm[0] &= apcb_h->adm[0]; + + return 0; +} + +/* Copy masks into apcb when g2 and g3 use format 0 */ +static int copy_apcb0(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) +{ + struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd); + const u32 crycb_o = crycbd_o & 0x7ffffff8U; + struct kvm_s390_apcb0 *apcb_h = &vcpu->kvm->arch.sie_page2->crycb.apcb0; + struct kvm_s390_apcb0 *apcb_s = &vsie_page->crycb.apcb0; + u32 src; + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.apm[0]); + if (read_guest_real(vcpu, src, &apcb_s->apm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.aqm[0]); + if (read_guest_real(vcpu, src, &apcb_s->aqm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + src = crycb_o + offsetof(struct kvm_s390_crypto_cb, apcb0.adm[0]); + if (read_guest_real(vcpu, src, &apcb_s->adm[0], sizeof(__u64))) + return set_validity_icpt(scb_s, 0x0035U); + + apcb_s->apm[0] &= apcb_h->apm[0]; + apcb_s->aqm[0] &= apcb_h->aqm[0]; + apcb_s->adm[0] &= apcb_h->adm[0]; + + return 0; +} + +/* Shadowing APCB depends on G2 and G3 CRYCB format */ +static int copy_apcb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, + int g2_fmt, int g3_fmt) +{ + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + int ret = 0; + + switch (g2_fmt) { + case CRYCB_FORMAT0: + switch (g3_fmt) { + case CRYCB_FORMAT0: + ret = copy_apcb0(vcpu, vsie_page); + break; + default: + return set_validity_icpt(scb_s, 0x0020U); + } + break; + case CRYCB_FORMAT1: + switch (g3_fmt) { + case CRYCB_FORMAT1: + case CRYCB_FORMAT0: /* Fall through to copy APCB */ + ret = copy_apcb0(vcpu, vsie_page); + break; + default: + return set_validity_icpt(scb_s, 0x0020U); + } + break; + case CRYCB_FORMAT2: + switch (g3_fmt) { + case CRYCB_FORMAT0: + case CRYCB_FORMAT1: + ret = copy_apcb01(vcpu, vsie_page); + break; + case CRYCB_FORMAT2: + ret = copy_apcb1(vcpu, vsie_page); + break; + } + break; + default: + /* + * Guest 2 format is valid or we can not get to here. + */ + break; + } + + return ret; +} + +/* + * Create a shadow copy of the crycb block. + * - Setup key wrapping, if requested for guest 3 and enabled for guest 2. + * - Shadow APCB if requested by guest 3 and enabled for guest 2 through + * ECA_APIE. + * + * We only accept format-1 (no AP in g2), but convert it into format-2 + * There is nothing to do for format-0. + * + * Returns: - 0 if shadowed or nothing to do + * - > 0 if control has to be given to guest 2 + * - < 0 if something went wrong on copy + */ +#define ECA_APIE 0x00000008 +static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) +{ + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd); + const u32 crycb_addr = crycbd_o & 0x7ffffff8U; + int g2_fmt = vcpu->arch.sie_block->crycbd & CRYCB_FORMAT_MASK; + int g3_fmt = crycbd_o & CRYCB_FORMAT_MASK; + int g2_apie, g2_msa3, g3_apie, g3_msa3; + int size, ret; + + /* crycb should not cross a page boundary */ + size = (g3_fmt == CRYCB_FORMAT2) ? 0x100 : 0x80; + if ((crycb_addr & PAGE_MASK) != ((crycb_addr + size) & PAGE_MASK)) + return set_validity_icpt(scb_s, 0x003CU); + + g2_apie = vcpu->arch.sie_block->eca & ECA_APIE; + g3_apie = scb_o->eca & g2_apie; + + g2_msa3 = test_kvm_facility(vcpu->kvm, 76); + g3_msa3 = (g3_fmt != CRYCB_FORMAT0) & g2_msa3; + + scb_s->crycbd = 0; + /* If no AP instructions and no keys we just set crycbd to 0 */ + if (!(g3_apie || g3_msa3)) + return 0; + + if (!crycb_addr) + return set_validity_icpt(scb_s, 0x0039U); + + if (g3_apie) { + ret = copy_apcb(vcpu, vsie_page, g2_fmt, g3_fmt); + if (ret) + goto out; + scb_s->eca |= g3_apie; + } + + if (g3_msa3) + ret = copy_key_masks(vcpu, vsie_page); + + if (!ret) + scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | g2_fmt; + +out: + return ret; +} + /* shadow (round up/down) the ibc to avoid validity icpt */ static void prepare_ibc(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) {