ANDROID: KVM: arm64: Restore memcache representation Recently, order was added to memcache, and the idea was to encode the order in the PAGE_SIZE bits as memcache is always page aligned. However, due to wrong usage of FIELD_*, now the address is shifted by PAGE_SIZE, which can cause address corruption under some configurations. Also, the naming of the macros make things confusing, just use PAGE_MASK as it make things more clear. Bug: 357781595 Bug: 333874255 Bug: 277989609 Bug: 278749606 Change-Id: I2782f8995b7230300b524e2197b607426b2ed250 Signed-off-by: Mostafa Saleh <smostafa@google.com>
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 84029d0..f7c47d39 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h
@@ -85,8 +85,6 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu); void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu); /* Head holds page head and it's order. */ -#define HYP_MC_PTR_MASK GENMASK_ULL(63, PAGE_SHIFT) -#define HYP_MC_ORDER_MASK GENMASK_ULL(PAGE_SHIFT - 1, 0) struct kvm_hyp_memcache { phys_addr_t head; unsigned long nr_pages; @@ -99,8 +97,8 @@ static inline void push_hyp_memcache(struct kvm_hyp_memcache *mc, unsigned long order) { *p = mc->head; - mc->head = FIELD_PREP(HYP_MC_PTR_MASK, to_pa(p)) | - FIELD_PREP(HYP_MC_ORDER_MASK, order); + mc->head = (to_pa(p) & PAGE_MASK) | + FIELD_PREP(~PAGE_MASK, order); mc->nr_pages++; } @@ -108,12 +106,12 @@ static inline void *pop_hyp_memcache(struct kvm_hyp_memcache *mc, void *(*to_va)(phys_addr_t phys), unsigned long *order) { - phys_addr_t *p = to_va(FIELD_GET(HYP_MC_PTR_MASK, mc->head)); + phys_addr_t *p = to_va(mc->head & PAGE_MASK); if (!mc->nr_pages) return NULL; - *order = FIELD_GET(HYP_MC_ORDER_MASK, mc->head); + *order = FIELD_GET(~PAGE_MASK, mc->head); mc->head = *p; mc->nr_pages--;
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 9bab9a2..86ab719 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -478,10 +478,10 @@ static void *admit_host_page(void *arg, unsigned long order) if (!host_mc->nr_pages) return NULL; - mc_order = FIELD_GET(HYP_MC_ORDER_MASK, host_mc->head); + mc_order = FIELD_GET(~PAGE_MASK, host_mc->head); BUG_ON(order != mc_order); - p = FIELD_GET(HYP_MC_PTR_MASK, host_mc->head); + p = host_mc->head & PAGE_MASK; /* * The host still owns the pages in its memcache, so we need to go * through a full host-to-hyp donation cycle to change it. Fortunately, @@ -529,7 +529,7 @@ int refill_hyp_pool(struct hyp_pool *pool, struct kvm_hyp_memcache *host_mc) void *p; while (host_mc->nr_pages) { - order = host_mc->head & (PAGE_SIZE - 1); + order = FIELD_GET(~PAGE_MASK, host_mc->head); p = admit_host_page(host_mc, order); if (!p) return -EINVAL;