123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // SPDX-License-Identifier: GPL-2.0-only
- #define pr_fmt(fmt) "ioremap: " fmt
- #include <linux/mm.h>
- #include <linux/io.h>
- #include <linux/arm-smccc.h>
- #include <linux/slab.h>
- #include <asm/fixmap.h>
- #include <asm/tlbflush.h>
- #include <asm/hypervisor.h>
- #ifndef ARM_SMCCC_KVM_FUNC_MMIO_GUARD_INFO
- #define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_INFO 5
- #define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID \
- ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
- ARM_SMCCC_SMC_64, \
- ARM_SMCCC_OWNER_VENDOR_HYP, \
- ARM_SMCCC_KVM_FUNC_MMIO_GUARD_INFO)
- #endif /* ARM_SMCCC_KVM_FUNC_MMIO_GUARD_INFO */
- #ifndef ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL
- #define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL 6
- #define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID \
- ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
- ARM_SMCCC_SMC_64, \
- ARM_SMCCC_OWNER_VENDOR_HYP, \
- ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL)
- #endif /* ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL */
- #ifndef ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP
- #define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP 7
- #define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID \
- ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
- ARM_SMCCC_SMC_64, \
- ARM_SMCCC_OWNER_VENDOR_HYP, \
- ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP)
- #endif /* ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP */
- #ifndef ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP
- #define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP 8
- #define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID \
- ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
- ARM_SMCCC_SMC_64, \
- ARM_SMCCC_OWNER_VENDOR_HYP, \
- ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP)
- #endif /* ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP */
- struct ioremap_guard_ref {
- refcount_t count;
- };
- 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)
- {
- ioremap_guard = true;
- return 0;
- }
- early_param("ioremap_guard", ioremap_guard_setup);
- void kvm_init_ioremap_services(void)
- {
- struct arm_smccc_res res;
- size_t granule;
- if (!ioremap_guard)
- return;
- /* We need all the functions to be implemented */
- if (!kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_INFO) ||
- !kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL) ||
- !kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP) ||
- !kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP))
- return;
- arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID,
- 0, 0, 0, &res);
- 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);
- pr_info("Using KVM MMIO guard for ioremap\n");
- } else {
- pr_warn("KVM MMIO guard registration failed (%ld)\n", res.a0);
- }
- }
- 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 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, guard_fn);
- if (ref) {
- refcount_inc(&ref->count);
- goto next;
- }
- /*
- * It is acceptable for the allocation to fail, specially
- * if trying to ioremap something very early on, like with
- * earlycon, which happens long before kmem_cache_init.
- * This page will be permanently accessible, similar to a
- * saturated refcount.
- */
- if (slab_is_available())
- ref = kzalloc(sizeof(*ref), GFP_KERNEL);
- if (ref) {
- refcount_set(&ref->count, 1);
- if (xa_err(xa_store(&ioremap_guard_array, guard_fn, ref,
- GFP_KERNEL))) {
- kfree(ref);
- ref = NULL;
- }
- }
- arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID,
- phys_addr, prot, &res);
- if (res.a0 != SMCCC_RET_SUCCESS) {
- pr_warn_ratelimited("Failed to register %llx\n",
- phys_addr);
- xa_erase(&ioremap_guard_array, guard_fn);
- kfree(ref);
- goto out;
- }
- next:
- size -= guard_granule;
- phys_addr += guard_granule;
- }
- out:
- mutex_unlock(&ioremap_guard_lock);
- }
- 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 guard_fn = phys_addr >> guard_shift;
- struct ioremap_guard_ref *ref;
- struct arm_smccc_res res;
- ref = xa_load(&ioremap_guard_array, guard_fn);
- if (!ref) {
- pr_warn_ratelimited("%llx not tracked, left mapped\n",
- phys_addr);
- goto next;
- }
- if (!refcount_dec_and_test(&ref->count))
- goto next;
- xa_erase(&ioremap_guard_array, guard_fn);
- kfree(ref);
- arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID,
- phys_addr, &res);
- if (res.a0 != SMCCC_RET_SUCCESS) {
- pr_warn_ratelimited("Failed to unregister %llx\n",
- phys_addr);
- goto out;
- }
- next:
- size -= guard_granule;
- phys_addr += guard_granule;
- }
- out:
- mutex_unlock(&ioremap_guard_lock);
- }
- bool ioremap_allowed(phys_addr_t phys_addr, size_t size, unsigned long prot)
- {
- unsigned long last_addr = phys_addr + size - 1;
- /* Don't allow outside PHYS_MASK */
- if (last_addr & ~PHYS_MASK)
- return false;
- /* Don't allow RAM to be mapped. */
- if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr))))
- return false;
- return true;
- }
- /*
- * Must be called after early_fixmap_init
- */
- void __init early_ioremap_init(void)
- {
- early_ioremap_setup();
- }
- bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
- unsigned long flags)
- {
- unsigned long pfn = PHYS_PFN(offset);
- return pfn_is_map_memory(pfn);
- }
|