blob: 2bc901bf9b583abfa6c2e683da51687111819ee3 [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023 Google LLC
* Author: Mostafa Saleh <smostafa@google.com>
*
* pKVM provides mutual distrust between host kernel and protected VMs(pVM)
* One solution to provide DMA isolation in this model, is to move the IOMMU
* control to the hypervisor and para-virtualize the IOMMU interface for
* the host and guest kernel. (none of them have direct access to IOMMU
* programming interface).
* In the case of device assignement, the host can't map memory in for the
* guest kernel (as it is not trusted).
* So, what mainly needs to be done is to assign a blocking domain, when
* VFIO assigns the device to user space, so it can't issue any DMA, and
* when the guest take control it can program the IOMMU through hypervisor
* with collapsed translation (IOVA->PA directly).
* This looks similar to noiommu but with one main difference is that
* group->type is VFIO_IOMMU, which attaches the groups to a blocking domain.
*/
#include <linux/module.h>
#include <linux/vfio.h>
#include "vfio.h"
static void *pkvm_iommu_open(unsigned long arg)
{
if (arg != VFIO_PKVM_IOMMU)
return ERR_PTR(-EINVAL);
return NULL;
}
static void pkvm_iommu_release(void *iommu_data)
{
}
static long pkvm_iommu_ioctl(void *iommu_data,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case VFIO_CHECK_EXTENSION:
return arg == VFIO_PKVM_IOMMU;
case VFIO_IOMMU_MAP_DMA:
case VFIO_IOMMU_UNMAP_DMA:
return -EOPNOTSUPP;
}
return -ENOTTY;
}
static int pkvm_iommu_attach_group(void *iommu_data,
struct iommu_group *iommu_group,
enum vfio_group_type type)
{
/*
* VFIO already calls iommu_group_claim_dma_owner() which attaches
* the group to a blocking domain.
*/
return 0;
}
static void pkvm_iommu_detach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
/*
* VFIO calls iommu_group_release_dma_owner().
*/
}
static const struct vfio_iommu_driver_ops pkvm_iommu_ops = {
.name = "vfio-pkvm-iommu",
.owner = THIS_MODULE,
.open = pkvm_iommu_open,
.release = pkvm_iommu_release,
.ioctl = pkvm_iommu_ioctl,
.attach_group = pkvm_iommu_attach_group,
.detach_group = pkvm_iommu_detach_group,
};
static int __init pkvm_iommu_init(void)
{
return vfio_register_iommu_driver(&pkvm_iommu_ops);
}
static void __exit pkvm_iommu_exit(void)
{
vfio_unregister_iommu_driver(&pkvm_iommu_ops);
}
module_init(pkvm_iommu_init);
module_exit(pkvm_iommu_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("smostafa@google.com");
MODULE_DESCRIPTION("VFIO IOMMU for pKVM pvIOMMU");