diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-16 06:55:07 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-16 06:55:07 +0200 |
commit | 114143a595895c03fbefccfd8346fc51fb4908ed (patch) | |
tree | 161f753ad69a2aabe7cd7ac7cc493c3678dbd760 /drivers/virt | |
parent | 8617d7d6298f54dfef4038281863270b5864fe83 (diff) | |
parent | 75078ba2b38a38d94017bd334f71aaed205e30a4 (diff) | |
download | lwn-114143a595895c03fbefccfd8346fc51fb4908ed.tar.gz lwn-114143a595895c03fbefccfd8346fc51fb4908ed.zip |
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Will Deacon:
"The highlights are support for Arm's "Permission Overlay Extension"
using memory protection keys, support for running as a protected guest
on Android as well as perf support for a bunch of new interconnect
PMUs.
Summary:
ACPI:
- Enable PMCG erratum workaround for HiSilicon HIP10 and 11
platforms.
- Ensure arm64-specific IORT header is covered by MAINTAINERS.
CPU Errata:
- Enable workaround for hardware access/dirty issue on Ampere-1A
cores.
Memory management:
- Define PHYSMEM_END to fix a crash in the amdgpu driver.
- Avoid tripping over invalid kernel mappings on the kexec() path.
- Userspace support for the Permission Overlay Extension (POE) using
protection keys.
Perf and PMUs:
- Add support for the "fixed instruction counter" extension in the
CPU PMU architecture.
- Extend and fix the event encodings for Apple's M1 CPU PMU.
- Allow LSM hooks to decide on SPE permissions for physical
profiling.
- Add support for the CMN S3 and NI-700 PMUs.
Confidential Computing:
- Add support for booting an arm64 kernel as a protected guest under
Android's "Protected KVM" (pKVM) hypervisor.
Selftests:
- Fix vector length issues in the SVE/SME sigreturn tests
- Fix build warning in the ptrace tests.
Timers:
- Add support for PR_{G,S}ET_TSC so that 'rr' can deal with
non-determinism arising from the architected counter.
Miscellaneous:
- Rework our IPI-based CPU stopping code to try NMIs if regular IPIs
don't succeed.
- Minor fixes and cleanups"
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (94 commits)
perf: arm-ni: Fix an NULL vs IS_ERR() bug
arm64: hibernate: Fix warning for cast from restricted gfp_t
arm64: esr: Define ESR_ELx_EC_* constants as UL
arm64: pkeys: remove redundant WARN
perf: arm_pmuv3: Use BR_RETIRED for HW branch event if enabled
MAINTAINERS: List Arm interconnect PMUs as supported
perf: Add driver for Arm NI-700 interconnect PMU
dt-bindings/perf: Add Arm NI-700 PMU
perf/arm-cmn: Improve format attr printing
perf/arm-cmn: Clean up unnecessary NUMA_NO_NODE check
arm64/mm: use lm_alias() with addresses passed to memblock_free()
mm: arm64: document why pte is not advanced in contpte_ptep_set_access_flags()
arm64: Expose the end of the linear map in PHYSMEM_END
arm64: trans_pgd: mark PTEs entries as valid to avoid dead kexec()
arm64/mm: Delete __init region from memblock.reserved
perf/arm-cmn: Support CMN S3
dt-bindings: perf: arm-cmn: Add CMN S3
perf/arm-cmn: Refactor DTC PMU register access
perf/arm-cmn: Make cycle counts less surprising
perf/arm-cmn: Improve build-time assertion
...
Diffstat (limited to 'drivers/virt')
-rw-r--r-- | drivers/virt/coco/Kconfig | 2 | ||||
-rw-r--r-- | drivers/virt/coco/Makefile | 1 | ||||
-rw-r--r-- | drivers/virt/coco/pkvm-guest/Kconfig | 10 | ||||
-rw-r--r-- | drivers/virt/coco/pkvm-guest/Makefile | 2 | ||||
-rw-r--r-- | drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 127 |
5 files changed, 142 insertions, 0 deletions
diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig index 87d142c1f932..d9ff676bf48d 100644 --- a/drivers/virt/coco/Kconfig +++ b/drivers/virt/coco/Kconfig @@ -9,6 +9,8 @@ config TSM_REPORTS source "drivers/virt/coco/efi_secret/Kconfig" +source "drivers/virt/coco/pkvm-guest/Kconfig" + source "drivers/virt/coco/sev-guest/Kconfig" source "drivers/virt/coco/tdx-guest/Kconfig" diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile index 18c1aba5edb7..b69c30c1c720 100644 --- a/drivers/virt/coco/Makefile +++ b/drivers/virt/coco/Makefile @@ -4,5 +4,6 @@ # obj-$(CONFIG_TSM_REPORTS) += tsm.o obj-$(CONFIG_EFI_SECRET) += efi_secret/ +obj-$(CONFIG_ARM_PKVM_GUEST) += pkvm-guest/ obj-$(CONFIG_SEV_GUEST) += sev-guest/ obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/ diff --git a/drivers/virt/coco/pkvm-guest/Kconfig b/drivers/virt/coco/pkvm-guest/Kconfig new file mode 100644 index 000000000000..d2f344f1f98f --- /dev/null +++ b/drivers/virt/coco/pkvm-guest/Kconfig @@ -0,0 +1,10 @@ +config ARM_PKVM_GUEST + bool "Arm pKVM protected guest driver" + depends on ARM64 + help + Protected guests running under the pKVM hypervisor on arm64 + are isolated from the host and must issue hypercalls to enable + interaction with virtual devices. This driver implements + support for probing and issuing these hypercalls. + + If unsure, say 'N'. diff --git a/drivers/virt/coco/pkvm-guest/Makefile b/drivers/virt/coco/pkvm-guest/Makefile new file mode 100644 index 000000000000..4bee24579423 --- /dev/null +++ b/drivers/virt/coco/pkvm-guest/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_ARM_PKVM_GUEST) += arm-pkvm-guest.o diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c new file mode 100644 index 000000000000..56a3859dda8a --- /dev/null +++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Support for the hypercall interface exposed to protected guests by + * pKVM. + * + * Author: Will Deacon <will@kernel.org> + * Copyright (C) 2024 Google LLC + */ + +#include <linux/arm-smccc.h> +#include <linux/array_size.h> +#include <linux/io.h> +#include <linux/mem_encrypt.h> +#include <linux/mm.h> +#include <linux/pgtable.h> + +#include <asm/hypervisor.h> + +static size_t pkvm_granule; + +static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys) +{ + phys_addr_t end = phys + PAGE_SIZE; + + while (phys < end) { + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res); + if (res.a0 != SMCCC_RET_SUCCESS) + return -EPERM; + + phys += pkvm_granule; + } + + return 0; +} + +static int __set_memory_range(u32 func_id, unsigned long start, int numpages) +{ + void *addr = (void *)start, *end = addr + numpages * PAGE_SIZE; + + while (addr < end) { + int err; + + err = arm_smccc_do_one_page(func_id, virt_to_phys(addr)); + if (err) + return err; + + addr += PAGE_SIZE; + } + + return 0; +} + +static int pkvm_set_memory_encrypted(unsigned long addr, int numpages) +{ + return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID, + addr, numpages); +} + +static int pkvm_set_memory_decrypted(unsigned long addr, int numpages) +{ + return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID, + addr, numpages); +} + +static const struct arm64_mem_crypt_ops pkvm_crypt_ops = { + .encrypt = pkvm_set_memory_encrypted, + .decrypt = pkvm_set_memory_decrypted, +}; + +static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size, + pgprot_t *prot) +{ + phys_addr_t end; + pteval_t protval = pgprot_val(*prot); + + /* + * We only expect MMIO emulation for regions mapped with device + * attributes. + */ + if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE) + return 0; + + phys = PAGE_ALIGN_DOWN(phys); + end = phys + PAGE_ALIGN(size); + + while (phys < end) { + const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID; + int err; + + err = arm_smccc_do_one_page(func_id, phys); + if (err) + return err; + + phys += PAGE_SIZE; + } + + return 0; +} + +void pkvm_init_hyp_services(void) +{ + int i; + struct arm_smccc_res res; + const u32 funcs[] = { + ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, + ARM_SMCCC_KVM_FUNC_MEM_SHARE, + ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, + }; + + for (i = 0; i < ARRAY_SIZE(funcs); ++i) { + if (!kvm_arm_hyp_service_available(funcs[i])) + return; + } + + arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID, + 0, 0, 0, &res); + if (res.a0 > PAGE_SIZE) /* Includes error codes */ + return; + + pkvm_granule = res.a0; + arm64_mem_crypt_ops_register(&pkvm_crypt_ops); + + if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD)) + arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook); +} |