ANDROID: KVM: arm64: Unmap S2MPU MMIO registers from host stage-2

The S2MPU driver needs to protect its MMIO registers from the host.
Implement the host_stage2_adjust_mmio_range callback and restrict
the address range that is about to be mapped in to avoid the known
S2MPU MMIO regions.

Test: builds, boots
Bug: 190463801
Change-Id: Ib46f5dd651b9368c31940035e4c28a7324fc4160
Signed-off-by: David Brazdil <dbrazdil@google.com>
(cherry picked from commit 8f23406153)
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
David Brazdil
2021-10-13 11:13:00 +01:00
committed by Quentin Perret
parent 877e4ee079
commit 8c2b04dc1b
2 changed files with 40 additions and 0 deletions

View File

@@ -270,6 +270,34 @@ static void s2mpu_host_stage2_set_owner(phys_addr_t addr, size_t size, u32 owner
hyp_spin_unlock(&s2mpu_lock);
}
static int s2mpu_host_stage2_adjust_mmio_range(phys_addr_t addr, phys_addr_t *start,
phys_addr_t *end)
{
struct s2mpu *dev;
phys_addr_t dev_start, dev_end, int_start, int_end;
/* Find the PA interval in the non-empty, sorted list of S2MPUs. */
int_start = 0;
for_each_s2mpu(dev) {
dev_start = dev->pa;
dev_end = dev_start + S2MPU_MMIO_SIZE;
int_end = dev_start;
if (dev_start <= addr && addr < dev_end)
return -EPERM;
if (int_start <= addr && addr < int_end)
break;
int_start = dev_end;
int_end = PA_MAX;
}
*start = max(*start, int_start);
*end = min(*end, int_end);
return 0;
}
static bool s2mpu_host_smc_handler(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(u64, fn, host_ctxt, 0);
@@ -432,4 +460,5 @@ const struct kvm_iommu_ops kvm_s2mpu_ops = (struct kvm_iommu_ops){
.host_smc_handler = s2mpu_host_smc_handler,
.host_mmio_dabt_handler = s2mpu_host_mmio_dabt_handler,
.host_stage2_set_owner = s2mpu_host_stage2_set_owner,
.host_stage2_adjust_mmio_range = s2mpu_host_stage2_adjust_mmio_range,
};

View File

@@ -8,6 +8,7 @@
#include <linux/kvm_host.h>
#include <linux/list.h>
#include <linux/of_platform.h>
#include <linux/sort.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_s2mpu.h>
@@ -279,6 +280,13 @@ static void free_s2mpu_array(struct s2mpu *array)
free_pages((unsigned long)array, order);
}
static int cmp_s2mpu(const void *p1, const void *p2)
{
const struct s2mpu *a = p1, *b = p2;
return (a->pa > b->pa) - (a->pa < b->pa);
}
static int create_s2mpu_array(struct s2mpu **array)
{
struct s2mpu_list_entry *entry, *tmp;
@@ -297,6 +305,9 @@ static int create_s2mpu_array(struct s2mpu **array)
}
WARN_ON(i != kvm_hyp_nr_s2mpus);
/* Searching through the list assumes that it is sorted. */
sort(*array, kvm_hyp_nr_s2mpus, sizeof(struct s2mpu), cmp_s2mpu, NULL);
kvm_hyp_s2mpus = kern_hyp_va(*array);
return 0;
}