git: 2eeb95ccf39a - main - bhyve: make most of the iommu_ops interfaces return error
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 06 Apr 2025 03:25:55 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=2eeb95ccf39ac5d79326c4482112b6b7dd5fc8b2
commit 2eeb95ccf39ac5d79326c4482112b6b7dd5fc8b2
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-12-19 15:41:32 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-04-06 03:25:38 +0000
bhyve: make most of the iommu_ops interfaces return error
and change create_mapping()/remove_mapping() to allow shorten results.
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D49629
---
sys/amd64/vmm/amd/amdvi_hw.c | 39 +++++++-------
sys/amd64/vmm/intel/vtd.c | 28 ++++++----
sys/amd64/vmm/io/iommu.c | 119 +++++++++++++++++++++++++------------------
sys/amd64/vmm/io/iommu.h | 26 +++++-----
sys/amd64/vmm/io/ppt.c | 33 ++++++++----
sys/amd64/vmm/vmm.c | 22 ++++----
6 files changed, 159 insertions(+), 108 deletions(-)
diff --git a/sys/amd64/vmm/amd/amdvi_hw.c b/sys/amd64/vmm/amd/amdvi_hw.c
index 87283325600c..831c31277570 100644
--- a/sys/amd64/vmm/amd/amdvi_hw.c
+++ b/sys/amd64/vmm/amd/amdvi_hw.c
@@ -1155,9 +1155,9 @@ amdvi_update_mapping(struct amdvi_domain *domain, vm_paddr_t gpa,
return (mapped);
}
-static uint64_t
+static int
amdvi_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa,
- uint64_t len)
+ uint64_t len, uint64_t *res_len)
{
struct amdvi_domain *domain;
@@ -1165,7 +1165,7 @@ amdvi_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa,
if (domain->id && !domain->ptp) {
printf("ptp is NULL");
- return (-1);
+ return (EINVAL);
}
/*
@@ -1173,13 +1173,14 @@ amdvi_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa,
* table set-up.
*/
if (domain->ptp)
- return (amdvi_update_mapping(domain, gpa, hpa, len, true));
+ *res_len = amdvi_update_mapping(domain, gpa, hpa, len, true);
else
- return (len);
+ *res_len = len;
+ return (0);
}
-static uint64_t
-amdvi_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
+static int
+amdvi_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len, uint64_t *res_len)
{
struct amdvi_domain *domain;
@@ -1189,9 +1190,10 @@ amdvi_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
* table set-up.
*/
if (domain->ptp)
- return (amdvi_update_mapping(domain, gpa, 0, len, false));
- return
- (len);
+ *res_len = amdvi_update_mapping(domain, gpa, 0, len, false);
+ else
+ *res_len = len;
+ return (0);
}
static struct amdvi_softc *
@@ -1268,8 +1270,8 @@ amdvi_inv_device(struct amdvi_softc *softc, uint16_t devid)
amdvi_wait(softc);
}
-static void
-amdvi_add_device(void *arg, uint16_t devid)
+static int
+amdvi_add_device(void *arg, device_t dev __unused, uint16_t devid)
{
struct amdvi_domain *domain;
struct amdvi_softc *softc;
@@ -1282,13 +1284,14 @@ amdvi_add_device(void *arg, uint16_t devid)
#endif
softc = amdvi_find_iommu(devid);
if (softc == NULL)
- return;
+ return (ENXIO);
amdvi_set_dte(domain, softc, devid, true);
amdvi_inv_device(softc, devid);
+ return (0);
}
-static void
-amdvi_remove_device(void *arg, uint16_t devid)
+static int
+amdvi_remove_device(void *arg, device_t dev __unused, uint16_t devid)
{
struct amdvi_domain *domain;
struct amdvi_softc *softc;
@@ -1300,9 +1303,10 @@ amdvi_remove_device(void *arg, uint16_t devid)
#endif
softc = amdvi_find_iommu(devid);
if (softc == NULL)
- return;
+ return (ENXIO);
amdvi_set_dte(domain, softc, devid, false);
amdvi_inv_device(softc, devid);
+ return (0);
}
static void
@@ -1357,7 +1361,7 @@ amdvi_disable(void)
}
}
-static void
+static int
amdvi_invalidate_tlb(void *arg)
{
struct amdvi_domain *domain;
@@ -1365,6 +1369,7 @@ amdvi_invalidate_tlb(void *arg)
domain = (struct amdvi_domain *)arg;
KASSERT(domain, ("domain is NULL"));
amdvi_do_inv_domain(domain->id, false);
+ return (0);
}
const struct iommu_ops iommu_ops_amd = {
diff --git a/sys/amd64/vmm/intel/vtd.c b/sys/amd64/vmm/intel/vtd.c
index 72cedeca6ec1..b56541290a9d 100644
--- a/sys/amd64/vmm/intel/vtd.c
+++ b/sys/amd64/vmm/intel/vtd.c
@@ -431,8 +431,8 @@ vtd_disable(void)
}
}
-static void
-vtd_add_device(void *arg, uint16_t rid)
+static int
+vtd_add_device(void *arg, device_t dev __unused, uint16_t rid)
{
int idx;
uint64_t *ctxp;
@@ -475,10 +475,11 @@ vtd_add_device(void *arg, uint16_t rid)
* 'Not Present' entries are not cached in either the Context Cache
* or in the IOTLB, so there is no need to invalidate either of them.
*/
+ return (0);
}
-static void
-vtd_remove_device(void *arg, uint16_t rid)
+static int
+vtd_remove_device(void *arg, device_t dev __unused, uint16_t rid)
{
int i, idx;
uint64_t *ctxp;
@@ -506,6 +507,7 @@ vtd_remove_device(void *arg, uint16_t rid)
vtd_ctx_global_invalidate(vtdmap);
vtd_iotlb_global_invalidate(vtdmap);
}
+ return (0);
}
#define CREATE_MAPPING 0
@@ -600,21 +602,24 @@ vtd_update_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len,
return (1UL << ptpshift);
}
-static uint64_t
-vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
+static int
+vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len,
+ uint64_t *res_len)
{
- return (vtd_update_mapping(arg, gpa, hpa, len, CREATE_MAPPING));
+ *res_len = vtd_update_mapping(arg, gpa, hpa, len, CREATE_MAPPING);
+ return (0);
}
-static uint64_t
-vtd_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
+static int
+vtd_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len, uint64_t *res_len)
{
- return (vtd_update_mapping(arg, gpa, 0, len, REMOVE_MAPPING));
+ *res_len = vtd_update_mapping(arg, gpa, 0, len, REMOVE_MAPPING);
+ return (0);
}
-static void
+static int
vtd_invalidate_tlb(void *dom)
{
int i;
@@ -628,6 +633,7 @@ vtd_invalidate_tlb(void *dom)
vtdmap = vtdmaps[i];
vtd_iotlb_global_invalidate(vtdmap);
}
+ return (0);
}
static void *
diff --git a/sys/amd64/vmm/io/iommu.c b/sys/amd64/vmm/io/iommu.c
index dc4a0de94bb6..bd86ac37a83e 100644
--- a/sys/amd64/vmm/io/iommu.c
+++ b/sys/amd64/vmm/io/iommu.c
@@ -58,6 +58,8 @@ static const struct iommu_ops *ops;
static void *host_domain;
static eventhandler_tag add_tag, delete_tag;
+static void iommu_cleanup_int(bool iommu_disable);
+
static __inline int
IOMMU_INIT(void)
{
@@ -92,48 +94,51 @@ IOMMU_DESTROY_DOMAIN(void *dom)
(*ops->destroy_domain)(dom);
}
-static __inline uint64_t
-IOMMU_CREATE_MAPPING(void *domain, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
+static __inline int
+IOMMU_CREATE_MAPPING(void *domain, vm_paddr_t gpa, vm_paddr_t hpa,
+ uint64_t len, uint64_t *res_len)
{
if (ops != NULL && iommu_avail)
- return ((*ops->create_mapping)(domain, gpa, hpa, len));
- else
- return (len); /* XXX */
+ return ((*ops->create_mapping)(domain, gpa, hpa, len, res_len));
+ return (EOPNOTSUPP);
}
static __inline uint64_t
-IOMMU_REMOVE_MAPPING(void *domain, vm_paddr_t gpa, uint64_t len)
+IOMMU_REMOVE_MAPPING(void *domain, vm_paddr_t gpa, uint64_t len,
+ uint64_t *res_len)
{
if (ops != NULL && iommu_avail)
- return ((*ops->remove_mapping)(domain, gpa, len));
- else
- return (len); /* XXX */
+ return ((*ops->remove_mapping)(domain, gpa, len, res_len));
+ return (EOPNOTSUPP);
}
-static __inline void
-IOMMU_ADD_DEVICE(void *domain, uint16_t rid)
+static __inline int
+IOMMU_ADD_DEVICE(void *domain, device_t dev, uint16_t rid)
{
if (ops != NULL && iommu_avail)
- (*ops->add_device)(domain, rid);
+ return ((*ops->add_device)(domain, dev, rid));
+ return (EOPNOTSUPP);
}
-static __inline void
-IOMMU_REMOVE_DEVICE(void *domain, uint16_t rid)
+static __inline int
+IOMMU_REMOVE_DEVICE(void *domain, device_t dev, uint16_t rid)
{
if (ops != NULL && iommu_avail)
- (*ops->remove_device)(domain, rid);
+ return ((*ops->remove_device)(domain, dev, rid));
+ return (EOPNOTSUPP);
}
-static __inline void
+static __inline int
IOMMU_INVALIDATE_TLB(void *domain)
{
if (ops != NULL && iommu_avail)
- (*ops->invalidate_tlb)(domain);
+ return ((*ops->invalidate_tlb)(domain));
+ return (0);
}
static __inline void
@@ -157,14 +162,14 @@ iommu_pci_add(void *arg, device_t dev)
{
/* Add new devices to the host domain. */
- iommu_add_device(host_domain, pci_get_rid(dev));
+ iommu_add_device(host_domain, dev, pci_get_rid(dev));
}
static void
iommu_pci_delete(void *arg, device_t dev)
{
- iommu_remove_device(host_domain, pci_get_rid(dev));
+ iommu_remove_device(host_domain, dev, pci_get_rid(dev));
}
static void
@@ -230,17 +235,20 @@ iommu_init(void)
* Everything else belongs to the host
* domain.
*/
- iommu_add_device(host_domain,
+ error = iommu_add_device(host_domain, dev,
pci_get_rid(dev));
+ if (error != 0) {
+ iommu_cleanup_int(false);
+ return;
+ }
}
}
}
IOMMU_ENABLE();
-
}
-void
-iommu_cleanup(void)
+static void
+iommu_cleanup_int(bool iommu_disable)
{
if (add_tag != NULL) {
@@ -251,12 +259,19 @@ iommu_cleanup(void)
EVENTHANDLER_DEREGISTER(pci_delete_device, delete_tag);
delete_tag = NULL;
}
- IOMMU_DISABLE();
+ if (iommu_disable)
+ IOMMU_DISABLE();
IOMMU_DESTROY_DOMAIN(host_domain);
host_domain = NULL;
IOMMU_CLEANUP();
}
+void
+iommu_cleanup(void)
+{
+ iommu_cleanup_int(true);
+}
+
void *
iommu_create_domain(vm_paddr_t maxaddr)
{
@@ -280,33 +295,39 @@ iommu_destroy_domain(void *dom)
IOMMU_DESTROY_DOMAIN(dom);
}
-void
+int
iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa, size_t len)
{
uint64_t mapped, remaining;
-
- remaining = len;
-
- while (remaining > 0) {
- mapped = IOMMU_CREATE_MAPPING(dom, gpa, hpa, remaining);
- gpa += mapped;
- hpa += mapped;
- remaining -= mapped;
+ int error;
+
+ for (remaining = len; remaining > 0; gpa += mapped, hpa += mapped,
+ remaining -= mapped) {
+ error = IOMMU_CREATE_MAPPING(dom, gpa, hpa, remaining,
+ &mapped);
+ if (error != 0) {
+ /* XXXKIB rollback */
+ return (error);
+ }
}
+ return (0);
}
-void
+int
iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len)
{
uint64_t unmapped, remaining;
-
- remaining = len;
-
- while (remaining > 0) {
- unmapped = IOMMU_REMOVE_MAPPING(dom, gpa, remaining);
- gpa += unmapped;
- remaining -= unmapped;
+ int error;
+
+ for (remaining = len; remaining > 0; gpa += unmapped,
+ remaining -= unmapped) {
+ error = IOMMU_REMOVE_MAPPING(dom, gpa, remaining, &unmapped);
+ if (error != 0) {
+ /* XXXKIB ? */
+ return (error);
+ }
}
+ return (0);
}
void *
@@ -316,23 +337,23 @@ iommu_host_domain(void)
return (host_domain);
}
-void
-iommu_add_device(void *dom, uint16_t rid)
+int
+iommu_add_device(void *dom, device_t dev, uint16_t rid)
{
- IOMMU_ADD_DEVICE(dom, rid);
+ return (IOMMU_ADD_DEVICE(dom, dev, rid));
}
-void
-iommu_remove_device(void *dom, uint16_t rid)
+int
+iommu_remove_device(void *dom, device_t dev, uint16_t rid)
{
- IOMMU_REMOVE_DEVICE(dom, rid);
+ return (IOMMU_REMOVE_DEVICE(dom, dev, rid));
}
-void
+int
iommu_invalidate_tlb(void *domain)
{
- IOMMU_INVALIDATE_TLB(domain);
+ return (IOMMU_INVALIDATE_TLB(domain));
}
diff --git a/sys/amd64/vmm/io/iommu.h b/sys/amd64/vmm/io/iommu.h
index c2891b62b5f2..5294a9d92a6b 100644
--- a/sys/amd64/vmm/io/iommu.h
+++ b/sys/amd64/vmm/io/iommu.h
@@ -35,13 +35,13 @@ typedef void (*iommu_enable_func_t)(void);
typedef void (*iommu_disable_func_t)(void);
typedef void *(*iommu_create_domain_t)(vm_paddr_t maxaddr);
typedef void (*iommu_destroy_domain_t)(void *domain);
-typedef uint64_t (*iommu_create_mapping_t)(void *domain, vm_paddr_t gpa,
- vm_paddr_t hpa, uint64_t len);
-typedef uint64_t (*iommu_remove_mapping_t)(void *domain, vm_paddr_t gpa,
- uint64_t len);
-typedef void (*iommu_add_device_t)(void *domain, uint16_t rid);
-typedef void (*iommu_remove_device_t)(void *dom, uint16_t rid);
-typedef void (*iommu_invalidate_tlb_t)(void *dom);
+typedef int (*iommu_create_mapping_t)(void *domain, vm_paddr_t gpa,
+ vm_paddr_t hpa, uint64_t len, uint64_t *res_len);
+typedef int (*iommu_remove_mapping_t)(void *domain, vm_paddr_t gpa,
+ uint64_t len, uint64_t *res_len);
+typedef int (*iommu_add_device_t)(void *domain, device_t dev, uint16_t rid);
+typedef int (*iommu_remove_device_t)(void *dom, device_t dev, uint16_t rid);
+typedef int (*iommu_invalidate_tlb_t)(void *dom);
struct iommu_ops {
iommu_init_func_t init; /* module wide */
@@ -65,10 +65,10 @@ void iommu_cleanup(void);
void *iommu_host_domain(void);
void *iommu_create_domain(vm_paddr_t maxaddr);
void iommu_destroy_domain(void *dom);
-void iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa,
- size_t len);
-void iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len);
-void iommu_add_device(void *dom, uint16_t rid);
-void iommu_remove_device(void *dom, uint16_t rid);
-void iommu_invalidate_tlb(void *domain);
+int iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa,
+ size_t len);
+int iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len);
+int iommu_add_device(void *dom, device_t dev, uint16_t rid);
+int iommu_remove_device(void *dom, device_t dev, uint16_t rid);
+int iommu_invalidate_tlb(void *domain);
#endif
diff --git a/sys/amd64/vmm/io/ppt.c b/sys/amd64/vmm/io/ppt.c
index 3b043c64fbde..c3b2b57da988 100644
--- a/sys/amd64/vmm/io/ppt.c
+++ b/sys/amd64/vmm/io/ppt.c
@@ -151,14 +151,19 @@ static int
ppt_attach(device_t dev)
{
struct pptdev *ppt;
- uint16_t cmd;
+ uint16_t cmd, cmd1;
+ int error;
ppt = device_get_softc(dev);
- cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+ cmd1 = cmd = pci_read_config(dev, PCIR_COMMAND, 2);
cmd &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, cmd, 2);
- iommu_remove_device(iommu_host_domain(), pci_get_rid(dev));
+ error = iommu_remove_device(iommu_host_domain(), dev, pci_get_rid(dev));
+ if (error != 0) {
+ pci_write_config(dev, PCIR_COMMAND, cmd1, 2);
+ return (error);
+ }
num_pptdevs++;
TAILQ_INSERT_TAIL(&pptdev_list, ppt, next);
ppt->dev = dev;
@@ -173,17 +178,23 @@ static int
ppt_detach(device_t dev)
{
struct pptdev *ppt;
+ int error;
ppt = device_get_softc(dev);
if (ppt->vm != NULL)
return (EBUSY);
+ if (iommu_host_domain() != NULL) {
+ error = iommu_add_device(iommu_host_domain(), dev,
+ pci_get_rid(dev));
+ } else {
+ error = 0;
+ }
+ if (error != 0)
+ return (error);
num_pptdevs--;
TAILQ_REMOVE(&pptdev_list, ppt, next);
- if (iommu_host_domain() != NULL)
- iommu_add_device(iommu_host_domain(), pci_get_rid(dev));
-
return (0);
}
@@ -410,8 +421,11 @@ ppt_assign_device(struct vm *vm, int bus, int slot, int func)
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
+ error = iommu_add_device(vm_iommu_domain(vm), ppt->dev,
+ pci_get_rid(ppt->dev));
+ if (error != 0)
+ return (error);
ppt->vm = vm;
- iommu_add_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
cmd = pci_read_config(ppt->dev, PCIR_COMMAND, 2);
cmd |= PCIM_CMD_BUSMASTEREN | ppt_bar_enables(ppt);
pci_write_config(ppt->dev, PCIR_COMMAND, cmd, 2);
@@ -438,9 +452,10 @@ ppt_unassign_device(struct vm *vm, int bus, int slot, int func)
ppt_unmap_all_mmio(vm, ppt);
ppt_teardown_msi(ppt);
ppt_teardown_msix(ppt);
- iommu_remove_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
+ error = iommu_remove_device(vm_iommu_domain(vm), ppt->dev,
+ pci_get_rid(ppt->dev));
ppt->vm = NULL;
- return (0);
+ return (error);
}
int
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 1d410835be88..bd703f63b557 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -745,12 +745,12 @@ vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len)
return (0);
}
-static void
+static int
vm_iommu_map(struct vm *vm)
{
vm_paddr_t gpa, hpa;
struct vm_mem_map *mm;
- int i;
+ int error, i;
sx_assert(&vm->mem.mem_segs_lock, SX_LOCKED);
@@ -789,15 +789,16 @@ vm_iommu_map(struct vm *vm)
}
}
- iommu_invalidate_tlb(iommu_host_domain());
+ error = iommu_invalidate_tlb(iommu_host_domain());
+ return (error);
}
-static void
+static int
vm_iommu_unmap(struct vm *vm)
{
vm_paddr_t gpa;
struct vm_mem_map *mm;
- int i;
+ int error, i;
sx_assert(&vm->mem.mem_segs_lock, SX_LOCKED);
@@ -826,7 +827,8 @@ vm_iommu_unmap(struct vm *vm)
* Invalidate the cached translations associated with the domain
* from which pages were removed.
*/
- iommu_invalidate_tlb(vm->iommu);
+ error = iommu_invalidate_tlb(vm->iommu);
+ return (error);
}
int
@@ -839,9 +841,9 @@ vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func)
return (error);
if (ppt_assigned_devices(vm) == 0)
- vm_iommu_unmap(vm);
+ error = vm_iommu_unmap(vm);
- return (0);
+ return (error);
}
int
@@ -858,10 +860,12 @@ vm_assign_pptdev(struct vm *vm, int bus, int slot, int func)
vm->iommu = iommu_create_domain(maxaddr);
if (vm->iommu == NULL)
return (ENXIO);
- vm_iommu_map(vm);
}
error = ppt_assign_device(vm, bus, slot, func);
+ if (error != 0)
+ return (error);
+ error = vm_iommu_map(vm);
return (error);
}