ANDROID: KVM: arm64: devices: Add reset handler for devices

Many devices must be reset before and after assignment, and as the
host can't be trusted to do this, we have to do it from the
hypervisor, and as we only deal with MMIO(platform) devices, which
has not standard interface, we provide a function to register
reset handler to modules, that can be registered with the MMIO base
address of the device with pkvm_device_register_reset.

Bug: 357781595
Bug: 348382247
Change-Id: Ie700aacf440caa6f1ffee85086a1edecdc104a5a
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2024-07-08 18:25:03 +00:00
committed by Treehugger Robot
parent b86926ac85
commit 44f9c10361
5 changed files with 60 additions and 0 deletions
+17
View File
@@ -11,6 +11,7 @@ typedef void (*dyn_hcall_t)(struct user_pt_regs *);
struct kvm_hyp_iommu;
struct iommu_iotlb_gather;
struct kvm_hyp_iommu_domain;
struct pkvm_device;
#ifdef CONFIG_MODULES
enum pkvm_psci_notification {
@@ -169,6 +170,20 @@ enum pkvm_psci_notification {
* @iommu_donate_pages_atomic: Allocate memory from IOMMU identity pool.
* @iommu_reclaim_pages_atomic: Reclaim memory from iommu_donate_pages_atomic()
* @hyp_smp_processor_id: Current CPU id
* @device_register_reset: Register a reset callback for devices that is called
* before/after devices are assigned. Only one callback
* can be registered per device.
* Devices are identified by the base address of the MMIO
* as defined in the device tree.
* Reset is expected to clear any state/secrets on the
* device and put it in quiescent state, where it can't
* trigger any DMA.
* If reset fails at device assignment to guest, the
* device won't be assigned.
* Or if it fails on the guest teardown path, that would
* panic to avoid leaking any information.
* Direction of assignment can be deduced from pkvm_device::ctxt
* where NULL means host to guest and vice versa.
*/
struct pkvm_module_ops {
int (*create_private_mapping)(phys_addr_t phys, size_t size,
@@ -235,6 +250,8 @@ struct pkvm_module_ops {
void * (*iommu_donate_pages_atomic)(u8 order);
void (*iommu_reclaim_pages_atomic)(void *p, u8 order);
int (*hyp_smp_processor_id)(void);
int (*device_register_reset)(u64 phys, void *cookie,
int (*cb)(void *cookie, bool host_to_guest));
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
+2
View File
@@ -190,5 +190,7 @@ int pkvm_init_devices(void);
int pkvm_device_hyp_assign_mmio(u64 pfn, u64 nr_pages);
int pkvm_device_reclaim_mmio(u64 pfn, u64 nr_pages);
int pkvm_host_map_guest_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 pfn, u64 gfn);
int pkvm_device_register_reset(u64 phys, void *cookie,
int (*cb)(void *cookie, bool host_to_guest));
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */
+38
View File
@@ -148,6 +148,17 @@ out_unlock:
return ret;
}
static int pkvm_device_reset(struct pkvm_device *dev, bool host_to_guest)
{
hyp_assert_lock_held(&device_spinlock);
/* Reset is mandatory. */
if (!dev->reset_handler)
return -ENODEV;
return dev->reset_handler(dev->cookie, host_to_guest);
}
static int __pkvm_device_assign(struct pkvm_device *dev, struct pkvm_hyp_vm *vm)
{
int i;
@@ -163,6 +174,10 @@ static int __pkvm_device_assign(struct pkvm_device *dev, struct pkvm_hyp_vm *vm)
return ret;
}
ret = pkvm_device_reset(dev, true);
if (ret)
return ret;
dev->ctxt = vm;
return 0;
}
@@ -326,6 +341,7 @@ void pkvm_devices_teardown(struct pkvm_hyp_vm *vm)
if (dev->ctxt != vm)
continue;
WARN_ON(pkvm_device_reset(dev, false));
dev->ctxt = NULL;
pkvm_devices_reclaim_device(dev);
}
@@ -380,3 +396,25 @@ void pkvm_devices_put_context(u64 iommu_id, u32 endpoint_id)
hyp_spin_unlock(&device_spinlock);
}
int pkvm_device_register_reset(u64 phys, void *cookie,
int (*cb)(void *cookie, bool host_to_guest))
{
struct pkvm_device *dev;
int ret = 0;
dev = pkvm_get_device_by_addr(phys);
if (!dev)
return -ENODEV;
hyp_spin_lock(&device_spinlock);
if (!dev->reset_handler) {
dev->reset_handler = cb;
dev->cookie = cookie;
} else {
ret = -EBUSY;
}
hyp_spin_unlock(&device_spinlock);
return ret;
}
+1
View File
@@ -265,6 +265,7 @@ const struct pkvm_module_ops module_ops = {
.iommu_donate_pages_atomic = kvm_iommu_donate_pages_atomic,
.iommu_reclaim_pages_atomic = kvm_iommu_reclaim_pages_atomic,
.hyp_smp_processor_id = __hyp_smp_processor_id,
.device_register_reset = pkvm_device_register_reset,
};
static void *pkvm_module_hyp_va(struct pkvm_el2_module *mod, void *kern_va)
+2
View File
@@ -38,6 +38,8 @@ struct pkvm_device {
u32 group_id;
void *ctxt; /* Current context of the device*/
unsigned short refcount;
int (*reset_handler)(void *cookie, bool host_to_guest);
void *cookie; /* cookie from drivers. */
};
#endif /* #ifndef __KVM_DEVICE_H */