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 <qperret@google.com>
This commit is contained in:
Quentin Perret
2022-12-12 18:47:56 +00:00
parent 51a84221b1
commit 9d56fc7890
5 changed files with 64 additions and 1 deletions

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -9,6 +9,7 @@
#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/sort.h>
@@ -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();