From 9d56fc78909afe95f69d5496a74295b8deb8bbe1 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Mon, 12 Dec 2022 18:47:56 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Specify stage-2-protected regions in DT Parse the devicetree during pKVM init to find nodes with the "pkvm,protected-region" compatible string. These nodes specify a physical address range in reg that must alway be mapped as invalid in the host stage-2 page table when running under pKVM. Example DT: pkvm_prot_reg: pkvm_prot_reg@80000000 { compatible = "pkvm,protected-region"; reg = <0x00 0x80000000 0x00 0x200000>; }; Bug: 244543039 Bug: 244373730 Change-Id: I102cd16c91d96e5283cdd1a4fa58836cc4834eac Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pkvm.h | 1 + arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 4 ++- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 13 ++++++++++ arch/arm64/kvm/hyp/nvhe/setup.c | 21 +++++++++++++++ arch/arm64/kvm/pkvm.c | 26 +++++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index 49aa99fad1b3..6cd974fc584f 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -244,6 +244,7 @@ static inline int pkvm_get_max_wrps(void) enum pkvm_moveable_reg_type { PKVM_MREG_MEMORY, + PKVM_MREG_PROTECTED_RANGE, }; struct pkvm_moveable_reg { diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index 751f860770ac..6c7419abd54d 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -60,7 +60,8 @@ enum pkvm_component_id { PKVM_ID_HYP, PKVM_ID_GUEST, PKVM_ID_FFA, - PKVM_ID_MAX = PKVM_ID_FFA, + PKVM_ID_PROTECTED, + PKVM_ID_MAX = PKVM_ID_PROTECTED, }; extern unsigned long hyp_nr_cpus; @@ -87,6 +88,7 @@ bool addr_is_memory(phys_addr_t phys); int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot, bool update_iommu); int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, enum pkvm_component_id owner_id); +int host_stage2_protect_pages_locked(phys_addr_t addr, u64 size); int host_stage2_unmap_reg_locked(phys_addr_t start, u64 size); int kvm_host_prepare_stage2(void *pgt_pool_base); int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd); diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index c1f457a56176..a0107f99abfa 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -2235,3 +2235,16 @@ bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu) return ret; } + +int host_stage2_protect_pages_locked(phys_addr_t addr, u64 size) +{ + int ret; + + hyp_assert_lock_held(&host_mmu.lock); + + ret = __host_check_page_state_range(addr, size, PKVM_PAGE_OWNED); + if (!ret) + ret = host_stage2_set_owner_locked(addr, size, PKVM_ID_PROTECTED); + + return ret; +} diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 5e379f03fcca..a3f787859fa5 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -303,6 +303,23 @@ static int fix_hyp_pgtable_refcnt(void) &walker); } +static int unmap_protected_regions(void) +{ + struct pkvm_moveable_reg *reg; + int i, ret; + + for (i = 0; i < pkvm_moveable_regs_nr; i++) { + reg = &pkvm_moveable_regs[i]; + if (reg->type != PKVM_MREG_PROTECTED_RANGE) + continue; + ret = host_stage2_protect_pages_locked(reg->start, reg->size); + if (ret) + return ret; + } + + return 0; +} + void __noreturn __pkvm_init_finalise(void) { struct kvm_host_data *host_data = this_cpu_ptr(&kvm_host_data); @@ -344,6 +361,10 @@ void __noreturn __pkvm_init_finalise(void) if (ret) goto out; + ret = unmap_protected_regions(); + if (ret) + goto out; + ret = hyp_ffa_init(ffa_proxy_pages); if (ret) goto out; diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index c2979cc77804..2ff0eb18a57d 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,7 @@ static void __init sort_moveable_regs(void) static int __init register_moveable_regions(void) { struct memblock_region *reg; + struct device_node *np; int i = 0; for_each_mem_region(reg) { @@ -107,6 +109,30 @@ static int __init register_moveable_regions(void) moveable_regs[i].type = PKVM_MREG_MEMORY; i++; } + + for_each_compatible_node(np, NULL, "pkvm,protected-region") { + struct resource res; + u64 start, size; + int ret; + + if (i >= PKVM_NR_MOVEABLE_REGS) + return -ENOMEM; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + start = res.start; + size = resource_size(&res); + if (!PAGE_ALIGNED(start) || !PAGE_ALIGNED(size)) + return -EINVAL; + + moveable_regs[i].start = start; + moveable_regs[i].size = size; + moveable_regs[i].type = PKVM_MREG_PROTECTED_RANGE; + i++; + } + kvm_nvhe_sym(pkvm_moveable_regs_nr) = i; sort_moveable_regs();