From patchwork Thu Jun 3 18:33:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 12297829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4991DC47096 for ; Thu, 3 Jun 2021 18:34:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F481613E3 for ; Thu, 3 Jun 2021 18:34:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229906AbhFCSfq (ORCPT ); Thu, 3 Jun 2021 14:35:46 -0400 Received: from mail.kernel.org ([198.145.29.99]:51172 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229817AbhFCSfo (ORCPT ); Thu, 3 Jun 2021 14:35:44 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 9B51D613DC; Thu, 3 Jun 2021 18:33:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1622745240; bh=8rzvn6RTUZ+Fwle5zCQTw7SSxwCeA8VzLr8wda4TNzA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=knMwvqEDfg1TqKq+8mJzto8ZkP9NHA83kO8aFVRApvuOlPy9xFn72QrTIAgylo6Ma 3v6ZqrpoCULuBEn8DmxDjf1InP1TggNgxD1zfvlh8Om1ATNdLqijRLa+F4MVdQsQEC d1Dud6Nte9sawAg+6/fFb37Y2xITBxlb7HbBFoZi/ouDnQglK6DIiH4fs2oAmIFIQ4 KYlAhqnNYpCVRKpKMJrwt0K02poML1UyEJASdpEsCJe5m9sdWJiY9UcOl5iaJn3U/d 899ah8ctyb0RvqKAFoXKS0tbkSuiTzr+JVK4q7wbodfJ+ZkAetwAykwg9/9knRGtUK 8alKJHF/yy/2A== From: Will Deacon To: kvmarm@lists.cs.columbia.edu Cc: Will Deacon , Marc Zyngier , James Morse , Alexandru Elisei , Suzuki K Poulose , Mark Rutland , Christoffer Dall , Paolo Bonzini , Fuad Tabba , Quentin Perret , Sean Christopherson , David Brazdil , kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/4] KVM: arm64: Ignore 'kvm-arm.mode=protected' when using VHE Date: Thu, 3 Jun 2021 19:33:44 +0100 Message-Id: <20210603183347.1695-2-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210603183347.1695-1-will@kernel.org> References: <20210603183347.1695-1-will@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Ignore 'kvm-arm.mode=protected' when using VHE so that kvm_get_mode() only returns KVM_MODE_PROTECTED on systems where the feature is available. Cc: David Brazdil Signed-off-by: Will Deacon Acked-by: Mark Rutland --- Documentation/admin-guide/kernel-parameters.txt | 1 - arch/arm64/kernel/cpufeature.c | 10 +--------- arch/arm64/kvm/arm.c | 6 +++++- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..e85dbdf1ee8e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2300,7 +2300,6 @@ protected: nVHE-based mode with support for guests whose state is kept private from the host. - Not valid if the kernel is running in EL2. Defaults to VHE/nVHE based on hardware support. diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index efed2830d141..dc1f2e747828 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1773,15 +1773,7 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap) #ifdef CONFIG_KVM static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, int __unused) { - if (kvm_get_mode() != KVM_MODE_PROTECTED) - return false; - - if (is_kernel_in_hyp_mode()) { - pr_warn("Protected KVM not available with VHE\n"); - return false; - } - - return true; + return kvm_get_mode() == KVM_MODE_PROTECTED; } #endif /* CONFIG_KVM */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 1cb39c0803a4..8d5e23198dfd 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2121,7 +2121,11 @@ static int __init early_kvm_mode_cfg(char *arg) return -EINVAL; if (strcmp(arg, "protected") == 0) { - kvm_mode = KVM_MODE_PROTECTED; + if (!is_kernel_in_hyp_mode()) + kvm_mode = KVM_MODE_PROTECTED; + else + pr_warn_once("Protected KVM not available with VHE\n"); + return 0; } From patchwork Thu Jun 3 18:33:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 12297831 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E76CAC47096 for ; Thu, 3 Jun 2021 18:34:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CFF40613D7 for ; Thu, 3 Jun 2021 18:34:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229955AbhFCSfs (ORCPT ); Thu, 3 Jun 2021 14:35:48 -0400 Received: from mail.kernel.org ([198.145.29.99]:51224 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229902AbhFCSfr (ORCPT ); Thu, 3 Jun 2021 14:35:47 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7F2C8613B8; Thu, 3 Jun 2021 18:34:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1622745242; bh=osyrOd8rLcVCMiPHAeJKLzTGdMUBbbPPNLLfrYOVNtE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fOt+VKmNu2qb7NlmlC8F8f7NZks31mqaTKoFAcQTxTnnIZsP99bm4KVUW3Fy5BRvN k2jFjdJeC1Ex6aXIlzQTS6Z+2nmuqbXQ5BCBEDUFJ2hXtvBa2kF4PGG8m6Ug2xCo0Q 2mkPnUbq1g9fcBSTNR1e0d8gzL2CvA8qU1mdCLwmONsEdMYiX9MBJPQUtdKpSzTkEr ei3Ud1mbQSStGuUhg7+ec20zSiVnEUYt0Fyd7Ylz0JXyoDEzLq6C2N7S8fN7v4J9dy l0CBMMnNmYEK9oOkkz2xWN2Ub6RyqV+ey0y9/m+fBqIL12YAOOv7nPK2CygTSFZayc TwB4LD/lrL5yg== From: Will Deacon To: kvmarm@lists.cs.columbia.edu Cc: Will Deacon , Marc Zyngier , James Morse , Alexandru Elisei , Suzuki K Poulose , Mark Rutland , Christoffer Dall , Paolo Bonzini , Fuad Tabba , Quentin Perret , Sean Christopherson , David Brazdil , kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 2/4] KVM: arm64: Extend comment in has_vhe() Date: Thu, 3 Jun 2021 19:33:45 +0100 Message-Id: <20210603183347.1695-3-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210603183347.1695-1-will@kernel.org> References: <20210603183347.1695-1-will@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org has_vhe() expands to a compile-time constant when evaluated from the VHE or nVHE code, alternatively checking a static key when called from elsewhere in the kernel. On face value, this looks like a case of premature optimization, but in fact this allows symbol references on VHE-specific code paths to be dropped from the nVHE object. Expand the comment in has_vhe() to make this clearer, hopefully discouraging anybody from simplifying the code. Cc: David Brazdil Signed-off-by: Will Deacon Acked-by: Mark Rutland --- arch/arm64/include/asm/virt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index 7379f35ae2c6..3218ca17f819 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -111,6 +111,9 @@ static __always_inline bool has_vhe(void) /* * Code only run in VHE/NVHE hyp context can assume VHE is present or * absent. Otherwise fall back to caps. + * This allows the compiler to discard VHE-specific code from the + * nVHE object, reducing the number of external symbol references + * needed to link. */ if (is_vhe_hyp_code()) return true; From patchwork Thu Jun 3 18:33:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 12297833 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D81CC47096 for ; Thu, 3 Jun 2021 18:34:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 35274613F4 for ; Thu, 3 Jun 2021 18:34:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229976AbhFCSfv (ORCPT ); Thu, 3 Jun 2021 14:35:51 -0400 Received: from mail.kernel.org ([198.145.29.99]:51304 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229902AbhFCSfu (ORCPT ); Thu, 3 Jun 2021 14:35:50 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5F0D2613B1; Thu, 3 Jun 2021 18:34:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1622745245; bh=aoxTolk8dCsad1y8K8HR18m0JTWcLPqsOTFqONlive0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N+fw/PVVPGRXMhC3TkqOpBuQgwJeHdfZr1v4uMmj+INdOrG/Rc2e8I+n2gO+kVOAM W3Bz9jK+g+A1y6utCu9QY+iI5vEtqMqFX3d4t3RicZ7tHp5ujp2iURHRLSRfPHFEdu hFhwHAlia7zxZ4ez9Skwa219IlitvrpqG9CDvrhk2kiRz31z0/GkXTmw19iFAVedPw bov/6bSX1dx1JQ2B5LPyUMmC0xG+lU3DvFEL2k2RyPgY/lAvlCYalCl+bpL6vv0Cjo 0c7C/43WkPYg2w4mvktVhA2MI3vr3PWTrsdZ2ytpP4C5xGEpkzpC5sMTNXZ7FHiOOF aV/49OEId7zsw== From: Will Deacon To: kvmarm@lists.cs.columbia.edu Cc: Will Deacon , Marc Zyngier , James Morse , Alexandru Elisei , Suzuki K Poulose , Mark Rutland , Christoffer Dall , Paolo Bonzini , Fuad Tabba , Quentin Perret , Sean Christopherson , David Brazdil , kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 3/4] KVM: arm64: Parse reserved-memory node for pkvm guest firmware region Date: Thu, 3 Jun 2021 19:33:46 +0100 Message-Id: <20210603183347.1695-4-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210603183347.1695-1-will@kernel.org> References: <20210603183347.1695-1-will@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add support for a "linux,pkvm-guest-firmware-memory" reserved memory region, which can be used to identify a firmware image for protected VMs. Signed-off-by: Will Deacon --- arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/pkvm.c | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/kvm/pkvm.c diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 589921392cb1..61e054411831 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -14,7 +14,7 @@ kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \ $(KVM)/vfio.o $(KVM)/irqchip.o \ arm.o mmu.o mmio.o psci.o perf.o hypercalls.o pvtime.o \ inject_fault.o va_layout.o handle_exit.o \ - guest.o debug.o reset.o sys_regs.o \ + guest.o debug.o pkvm.o reset.o sys_regs.o \ vgic-sys-reg-v3.o fpsimd.o pmu.o \ arch_timer.o trng.o\ vgic/vgic.o vgic/vgic-init.o \ diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c new file mode 100644 index 000000000000..7af5d03a3941 --- /dev/null +++ b/arch/arm64/kvm/pkvm.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KVM host (EL1) interface to Protected KVM (pkvm) code at EL2. + * + * Copyright (C) 2021 Google LLC + * Author: Will Deacon + */ + +#include +#include +#include +#include + +static struct reserved_mem *pkvm_firmware_mem; + +static int __init pkvm_firmware_rmem_err(struct reserved_mem *rmem, + const char *reason) +{ + phys_addr_t end = rmem->base + rmem->size; + + kvm_err("Ignoring pkvm guest firmware memory reservation [%pa - %pa]: %s\n", + &rmem->base, &end, reason); + return -EINVAL; +} + +static int __init pkvm_firmware_rmem_init(struct reserved_mem *rmem) +{ + unsigned long node = rmem->fdt_node; + + if (kvm_get_mode() != KVM_MODE_PROTECTED) + return pkvm_firmware_rmem_err(rmem, "protected mode not enabled"); + + if (pkvm_firmware_mem) + return pkvm_firmware_rmem_err(rmem, "duplicate reservation"); + + if (!of_get_flat_dt_prop(node, "no-map", NULL)) + return pkvm_firmware_rmem_err(rmem, "missing \"no-map\" property"); + + if (of_get_flat_dt_prop(node, "reusable", NULL)) + return pkvm_firmware_rmem_err(rmem, "\"reusable\" property unsupported"); + + if (!PAGE_ALIGNED(rmem->base)) + return pkvm_firmware_rmem_err(rmem, "base is not page-aligned"); + + if (!PAGE_ALIGNED(rmem->size)) + return pkvm_firmware_rmem_err(rmem, "size is not page-aligned"); + + pkvm_firmware_mem = rmem; + return 0; +} +RESERVEDMEM_OF_DECLARE(pkvm_firmware, "linux,pkvm-guest-firmware-memory", + pkvm_firmware_rmem_init); From patchwork Thu Jun 3 18:33:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 12297835 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6810AC47082 for ; Thu, 3 Jun 2021 18:34:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B9C8613DA for ; Thu, 3 Jun 2021 18:34:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230004AbhFCSfy (ORCPT ); Thu, 3 Jun 2021 14:35:54 -0400 Received: from mail.kernel.org ([198.145.29.99]:51340 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229963AbhFCSfx (ORCPT ); Thu, 3 Jun 2021 14:35:53 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 3FE1A613F3; Thu, 3 Jun 2021 18:34:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1622745248; bh=xvTd7Eh6umCswsc6DntHBSUyT9ZXtV7p9wb3U520Nms=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YbmolTxsINqDJRKpXnKvaan3EZOi0N0pFb/5O+IK+bS73V05Bny1/Oy1f4uLzaRGN gX3ndoG3PLWnw5aASPq+xY02dNNUUvnFuW7rZ9i8w3qbucWQjA6SNS5uoXBEJg5g1r nJP6CqdgpJ8bLv2Yv9PSDZnapB/wUyMB9zZxkHOFWe/TOM5+gS+VudZqbZ/orjfy8t vKFkxnkTN6UvSFHdocjTCsdb+aVoAcscwyw/Dmrw9QJXxEPiBDoVpPMBEL1VABSoQL 2zheck0pvOUTlJH8SEiZenpBfdAOk7o0Qgi/X5/Q/dZJ7rLdHFC+GOOvKpG6EiD44C GS0QqYVWvXrKg== From: Will Deacon To: kvmarm@lists.cs.columbia.edu Cc: Will Deacon , Marc Zyngier , James Morse , Alexandru Elisei , Suzuki K Poulose , Mark Rutland , Christoffer Dall , Paolo Bonzini , Fuad Tabba , Quentin Perret , Sean Christopherson , David Brazdil , kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 4/4] KVM: arm64: Introduce KVM_CAP_ARM_PROTECTED_VM Date: Thu, 3 Jun 2021 19:33:47 +0100 Message-Id: <20210603183347.1695-5-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210603183347.1695-1-will@kernel.org> References: <20210603183347.1695-1-will@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Introduce a new VM capability, KVM_CAP_ARM_PROTECTED_VM, which can be used to isolate guest memory from the host. For now, the EL2 portion is missing, so this documents and exposes the user ABI for the host. Signed-off-by: Will Deacon --- Documentation/virt/kvm/api.rst | 69 ++++++++++++++++++++ arch/arm64/include/asm/kvm_host.h | 10 +++ arch/arm64/include/uapi/asm/kvm.h | 9 +++ arch/arm64/kvm/arm.c | 18 +++--- arch/arm64/kvm/mmu.c | 3 + arch/arm64/kvm/pkvm.c | 104 ++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 7 files changed, 205 insertions(+), 9 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 7fcb2fd38f42..dfbaf905c435 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6362,6 +6362,75 @@ default. See Documentation/x86/sgx/2.Kernel-internals.rst for more details. +7.26 KVM_CAP_ARM_PROTECTED_VM +----------------------------- + +:Architectures: arm64 +:Target: VM +:Parameters: flags is a single KVM_CAP_ARM_PROTECTED_VM_FLAGS_* value + +The presence of this capability indicates that KVM supports running in a +configuration where the host Linux kernel does not have access to guest memory. +On such a system, a small hypervisor layer at EL2 can configure the stage-2 +page tables for both the CPU and any DMA-capable devices to protect guest +memory pages so that they are inaccessible to the host unless access is granted +explicitly by the guest. + +The 'flags' parameter is defined as follows: + +7.26.1 KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE +-------------------------------------------- + +:Capability: 'flag' parameter to KVM_CAP_ARM_PROTECTED_VM +:Architectures: arm64 +:Target: VM +:Parameters: args[0] contains memory slot ID to hold guest firmware +:Returns: 0 on success; negative error code on failure + +Enabling this capability causes all memory slots of the specified VM to be +unmapped from the host system and put into a state where they are no longer +configurable. The memory slot corresponding to the ID passed in args[0] is +populated with the guest firmware image provided by the host firmware. + +The first vCPU to enter the guest is defined to be the primary vCPU. All other +vCPUs belonging to the VM are secondary vCPUs. + +All vCPUs belonging to a VM with this capability enabled are initialised to a +pre-determined reset state irrespective of any prior configuration according to +the KVM_ARM_VCPU_INIT ioctl, with the following exceptions for the primary +vCPU: + + =========== =========== + Register(s) Reset value + =========== =========== + X0-X14: Preserved (see KVM_SET_ONE_REG) + X15: Boot protocol version (0) + X16-X30: Reserved (0) + PC: IPA base of firmware memory slot + SP: IPA end of firmware memory slot + =========== =========== + +Secondary vCPUs belonging to a VM with this capability enabled will return +-EPERM in response to a KVM_RUN ioctl() if the vCPU was not initialised with +the KVM_ARM_VCPU_POWER_OFF feature. + +There is no support for AArch32 at any exception level. + +It is an error to enable this capability on a VM after issuing a KVM_RUN +ioctl() on one of its vCPUs. + +7.26.2 KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO +------------------------------------------ + +:Capability: 'flag' parameter to KVM_CAP_ARM_PROTECTED_VM +:Architectures: arm64 +:Target: VM +:Parameters: args[0] contains pointer to 'struct kvm_protected_vm_info' +:Returns: 0 on success; negative error code on failure + +Populates the 'struct kvm_protected_vm_info' pointed to by args[0] with +information about the protected environment for the VM. + 8. Other capabilities. ====================== diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7cd7d5c8c4bc..5645af2a1431 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -100,6 +100,11 @@ struct kvm_s2_mmu { struct kvm_arch_memory_slot { }; +struct kvm_protected_vm { + bool enabled; + struct kvm_memory_slot *firmware_slot; +}; + struct kvm_arch { struct kvm_s2_mmu mmu; @@ -132,6 +137,8 @@ struct kvm_arch { u8 pfr0_csv2; u8 pfr0_csv3; + + struct kvm_protected_vm pkvm; }; struct kvm_vcpu_fault_info { @@ -763,6 +770,9 @@ void kvm_arch_free_vm(struct kvm *kvm); int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type); +int kvm_arm_vm_ioctl_pkvm(struct kvm *kvm, struct kvm_enable_cap *cap); +#define kvm_vm_is_protected(kvm) (kvm->arch.pkvm.enabled) + int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature); bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 24223adae150..cdb3298ba8ae 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -402,6 +402,15 @@ struct kvm_vcpu_events { #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED +/* Protected KVM */ +#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE 0 +#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO 1 + +struct kvm_protected_vm_info { + __u64 firmware_size; + __u64 __reserved[7]; +}; + #endif #endif /* __ARM_KVM_H__ */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 8d5e23198dfd..186a0adf6391 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -83,22 +83,19 @@ int kvm_arch_check_processor_compat(void *opaque) int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) { - int r; - - if (cap->flags) - return -EINVAL; - switch (cap->cap) { case KVM_CAP_ARM_NISV_TO_USER: - r = 0; + if (cap->flags) + return -EINVAL; kvm->arch.return_nisv_io_abort_to_user = true; break; + case KVM_CAP_ARM_PROTECTED_VM: + return kvm_arm_vm_ioctl_pkvm(kvm, cap); default: - r = -EINVAL; - break; + return -EINVAL; } - return r; + return 0; } static int kvm_arm_default_max_vcpus(void) @@ -265,6 +262,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_PTRAUTH_GENERIC: r = system_has_full_ptr_auth(); break; + case KVM_CAP_ARM_PROTECTED_VM: + r = is_protected_kvm_enabled(); + break; default: r = 0; } diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index c5d1f3c87dbd..e1d4a87d18e4 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1349,6 +1349,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, bool writable = !(mem->flags & KVM_MEM_READONLY); int ret = 0; + if (kvm_vm_is_protected(kvm)) + return -EPERM; + if (change != KVM_MR_CREATE && change != KVM_MR_MOVE && change != KVM_MR_FLAGS_ONLY) return 0; diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 7af5d03a3941..cf624350fb27 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -50,3 +50,107 @@ static int __init pkvm_firmware_rmem_init(struct reserved_mem *rmem) } RESERVEDMEM_OF_DECLARE(pkvm_firmware, "linux,pkvm-guest-firmware-memory", pkvm_firmware_rmem_init); + +static int pkvm_init_el2_context(struct kvm *kvm) +{ + kvm_pr_unimpl("Stage-2 protection is not yet implemented\n"); + return -EINVAL; +} + +static int pkvm_init_firmware_slot(struct kvm *kvm, u64 slotid) +{ + struct kvm_memslots *slots; + struct kvm_memory_slot *slot; + + if (slotid >= KVM_MEM_SLOTS_NUM || !pkvm_firmware_mem) + return -EINVAL; + + slots = kvm_memslots(kvm); + if (!slots) + return -ENOENT; + + slot = id_to_memslot(slots, slotid); + if (!slot) + return -ENOENT; + + if (slot->flags) + return -EINVAL; + + if ((slot->npages << PAGE_SHIFT) < pkvm_firmware_mem->size) + return -ENOMEM; + + kvm->arch.pkvm.firmware_slot = slot; + return 0; +} + +static void pkvm_teardown_firmware_slot(struct kvm *kvm) +{ + kvm->arch.pkvm.firmware_slot = NULL; +} + +static int pkvm_enable(struct kvm *kvm, u64 slotid) +{ + int ret; + + ret = pkvm_init_firmware_slot(kvm, slotid); + if (ret) + return ret; + + ret = pkvm_init_el2_context(kvm); + if (ret) + pkvm_teardown_firmware_slot(kvm); + + return ret; +} + +static int pkvm_vm_ioctl_enable(struct kvm *kvm, u64 slotid) +{ + int ret = 0; + + mutex_lock(&kvm->lock); + if (kvm_vm_is_protected(kvm)) { + ret = -EPERM; + goto out_kvm_unlock; + } + + mutex_lock(&kvm->slots_lock); + ret = pkvm_enable(kvm, slotid); + if (ret) + goto out_slots_unlock; + + kvm->arch.pkvm.enabled = true; +out_slots_unlock: + mutex_unlock(&kvm->slots_lock); +out_kvm_unlock: + mutex_unlock(&kvm->lock); + return ret; +} + +static int pkvm_vm_ioctl_info(struct kvm *kvm, + struct kvm_protected_vm_info __user *info) +{ + struct kvm_protected_vm_info kinfo = { + .firmware_size = pkvm_firmware_mem ? + pkvm_firmware_mem->size : + 0, + }; + + return copy_to_user(info, &kinfo, sizeof(kinfo)) ? -EFAULT : 0; +} + +int kvm_arm_vm_ioctl_pkvm(struct kvm *kvm, struct kvm_enable_cap *cap) +{ + if (cap->args[1] || cap->args[2] || cap->args[3]) + return -EINVAL; + + switch (cap->flags) { + case KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE: + return pkvm_vm_ioctl_enable(kvm, cap->args[0]); + case KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO: + return pkvm_vm_ioctl_info(kvm, (void __user *)cap->args[0]); + default: + return -EINVAL; + } + + return 0; +} diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 3fd9a7e9d90c..58ab8508be5e 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1082,6 +1082,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SGX_ATTRIBUTE 196 #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197 #define KVM_CAP_PTP_KVM 198 +#define KVM_CAP_ARM_PROTECTED_VM 199 #ifdef KVM_CAP_IRQ_ROUTING