mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
ANDROID: arm64: ioremap/iounmap use stage-2 granule size
When MMIO guard is queried, it advertises the guard granule size it uses. Use that value. Fixes: arm64: Implement ioremap/iounmap hooks calling into KVM's MMIO guard Bug: 251432016 Change-Id: Iff4dcb6229bf89aef832a29a98fecc041a1aec1b Signed-off-by: Fuad Tabba <tabba@google.com> Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
committed by
Quentin Perret
parent
9720e4d374
commit
eb0f5f7486
@@ -59,6 +59,8 @@ static DEFINE_STATIC_KEY_FALSE(ioremap_guard_key);
|
||||
static DEFINE_XARRAY(ioremap_guard_array);
|
||||
static DEFINE_MUTEX(ioremap_guard_lock);
|
||||
|
||||
static size_t guard_granule;
|
||||
|
||||
static bool ioremap_guard;
|
||||
static int __init ioremap_guard_setup(char *str)
|
||||
{
|
||||
@@ -82,6 +84,7 @@ static void fixup_fixmap(void)
|
||||
void kvm_init_ioremap_services(void)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
size_t granule;
|
||||
|
||||
if (!ioremap_guard)
|
||||
return;
|
||||
@@ -95,12 +98,18 @@ void kvm_init_ioremap_services(void)
|
||||
|
||||
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID,
|
||||
0, 0, 0, &res);
|
||||
if (res.a0 != PAGE_SIZE)
|
||||
granule = res.a0;
|
||||
if (granule > PAGE_SIZE || !granule || (granule & (granule - 1))) {
|
||||
pr_warn("KVM MMIO guard initialization failed: "
|
||||
"guard granule (%lu), page size (%lu)\n",
|
||||
granule, PAGE_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID,
|
||||
&res);
|
||||
if (res.a0 == SMCCC_RET_SUCCESS) {
|
||||
guard_granule = granule;
|
||||
static_branch_enable(&ioremap_guard_key);
|
||||
fixup_fixmap();
|
||||
pr_info("Using KVM MMIO guard for ioremap\n");
|
||||
@@ -111,20 +120,24 @@ void kvm_init_ioremap_services(void)
|
||||
|
||||
void ioremap_phys_range_hook(phys_addr_t phys_addr, size_t size, pgprot_t prot)
|
||||
{
|
||||
int guard_shift;
|
||||
|
||||
if (!static_branch_unlikely(&ioremap_guard_key))
|
||||
return;
|
||||
|
||||
guard_shift = __builtin_ctzl(guard_granule);
|
||||
|
||||
mutex_lock(&ioremap_guard_lock);
|
||||
|
||||
while (size) {
|
||||
u64 pfn = phys_addr >> PAGE_SHIFT;
|
||||
u64 guard_fn = phys_addr >> guard_shift;
|
||||
struct ioremap_guard_ref *ref;
|
||||
struct arm_smccc_res res;
|
||||
|
||||
if (pfn_valid(__phys_to_pfn(phys_addr)))
|
||||
goto next;
|
||||
|
||||
ref = xa_load(&ioremap_guard_array, pfn);
|
||||
ref = xa_load(&ioremap_guard_array, guard_fn);
|
||||
if (ref) {
|
||||
refcount_inc(&ref->count);
|
||||
goto next;
|
||||
@@ -141,7 +154,7 @@ void ioremap_phys_range_hook(phys_addr_t phys_addr, size_t size, pgprot_t prot)
|
||||
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
|
||||
if (ref) {
|
||||
refcount_set(&ref->count, 1);
|
||||
if (xa_err(xa_store(&ioremap_guard_array, pfn, ref,
|
||||
if (xa_err(xa_store(&ioremap_guard_array, guard_fn, ref,
|
||||
GFP_KERNEL))) {
|
||||
kfree(ref);
|
||||
ref = NULL;
|
||||
@@ -153,14 +166,14 @@ void ioremap_phys_range_hook(phys_addr_t phys_addr, size_t size, pgprot_t prot)
|
||||
if (res.a0 != SMCCC_RET_SUCCESS) {
|
||||
pr_warn_ratelimited("Failed to register %llx\n",
|
||||
phys_addr);
|
||||
xa_erase(&ioremap_guard_array, pfn);
|
||||
xa_erase(&ioremap_guard_array, guard_fn);
|
||||
kfree(ref);
|
||||
goto out;
|
||||
}
|
||||
|
||||
next:
|
||||
size -= PAGE_SIZE;
|
||||
phys_addr += PAGE_SIZE;
|
||||
size -= guard_granule;
|
||||
phys_addr += guard_granule;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&ioremap_guard_lock);
|
||||
@@ -168,19 +181,22 @@ out:
|
||||
|
||||
void iounmap_phys_range_hook(phys_addr_t phys_addr, size_t size)
|
||||
{
|
||||
int guard_shift;
|
||||
|
||||
if (!static_branch_unlikely(&ioremap_guard_key))
|
||||
return;
|
||||
|
||||
VM_BUG_ON(phys_addr & ~PAGE_MASK || size & ~PAGE_MASK);
|
||||
guard_shift = __builtin_ctzl(guard_granule);
|
||||
|
||||
mutex_lock(&ioremap_guard_lock);
|
||||
|
||||
while (size) {
|
||||
u64 pfn = phys_addr >> PAGE_SHIFT;
|
||||
u64 guard_fn = phys_addr >> guard_shift;
|
||||
struct ioremap_guard_ref *ref;
|
||||
struct arm_smccc_res res;
|
||||
|
||||
ref = xa_load(&ioremap_guard_array, pfn);
|
||||
ref = xa_load(&ioremap_guard_array, guard_fn);
|
||||
if (!ref) {
|
||||
pr_warn_ratelimited("%llx not tracked, left mapped\n",
|
||||
phys_addr);
|
||||
@@ -190,7 +206,7 @@ void iounmap_phys_range_hook(phys_addr_t phys_addr, size_t size)
|
||||
if (!refcount_dec_and_test(&ref->count))
|
||||
goto next;
|
||||
|
||||
xa_erase(&ioremap_guard_array, pfn);
|
||||
xa_erase(&ioremap_guard_array, guard_fn);
|
||||
kfree(ref);
|
||||
|
||||
arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID,
|
||||
@@ -202,8 +218,8 @@ void iounmap_phys_range_hook(phys_addr_t phys_addr, size_t size)
|
||||
}
|
||||
|
||||
next:
|
||||
size -= PAGE_SIZE;
|
||||
phys_addr += PAGE_SIZE;
|
||||
size -= guard_granule;
|
||||
phys_addr += guard_granule;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&ioremap_guard_lock);
|
||||
|
||||
Reference in New Issue
Block a user