| | | +---------------------------------------------+
| | | | ``INVALID_PARAMETER (-3)`` |
+---------------------+----------+----+---------------------------------------------+
+
+``ARM_SMCCC_KVM_FUNC_MMIO_GUARD``
+----------------------------------
+
+Request that a given memory region is handled as MMIO by the hypervisor,
+allowing accesses to this region to be emulated by the KVM host. The size of the
+region is equal to the memory protection granule advertised by
+``ARM_SMCCC_KVM_FUNC_HYP_MEMINFO``.
+
++---------------------+-------------------------------------------------------------+
+| Presence: | Optional; pKVM protected guests only. |
++---------------------+-------------------------------------------------------------+
+| Calling convention: | HVC64 |
++---------------------+----------+--------------------------------------------------+
+| Function ID: | (uint32) | 0xC6000007 |
++---------------------+----------+----+---------------------------------------------+
+| Arguments: | (uint64) | R1 | Base IPA of MMIO memory region |
+| +----------+----+---------------------------------------------+
+| | (uint64) | R2 | Reserved / Must be zero |
+| +----------+----+---------------------------------------------+
+| | (uint64) | R3 | Reserved / Must be zero |
++---------------------+----------+----+---------------------------------------------+
+| Return Values: | (int64) | R0 | ``SUCCESS (0)`` |
+| | | +---------------------------------------------+
+| | | | ``INVALID_PARAMETER (-3)`` |
++---------------------+----------+----+---------------------------------------------+
#include <linux/arm-smccc.h>
#include <linux/array_size.h>
+#include <linux/io.h>
#include <linux/mem_encrypt.h>
#include <linux/mm.h>
+#include <linux/pgtable.h>
#include <asm/hypervisor.h>
.decrypt = pkvm_set_memory_decrypted,
};
+static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
+ pgprot_t *prot)
+{
+ phys_addr_t end;
+ pteval_t protval = pgprot_val(*prot);
+
+ /*
+ * We only expect MMIO emulation for regions mapped with device
+ * attributes.
+ */
+ if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)
+ return 0;
+
+ phys = PAGE_ALIGN_DOWN(phys);
+ end = phys + PAGE_ALIGN(size);
+
+ while (phys < end) {
+ const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
+ int err;
+
+ err = arm_smccc_do_one_page(func_id, phys);
+ if (err)
+ return err;
+
+ phys += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
void pkvm_init_hyp_services(void)
{
int i;
pkvm_granule = res.a0;
arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
+
+ if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
+ arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook);
}
#define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO 2
#define ARM_SMCCC_KVM_FUNC_MEM_SHARE 3
#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE 4
+#define ARM_SMCCC_KVM_FUNC_MMIO_GUARD 7
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
#define ARM_SMCCC_KVM_NUM_FUNCS 128
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)
+#define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_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)
+
/* ptp_kvm counter type ID */
#define KVM_PTP_VIRT_COUNTER 0
#define KVM_PTP_PHYS_COUNTER 1