Skip to content

Instantly share code, notes, and snippets.

@shivaprasadbhat
Created September 10, 2024 06:20
Show Gist options
  • Select an option

  • Save shivaprasadbhat/e9f890aa674d40d88de5223d17cb934d to your computer and use it in GitHub Desktop.

Select an option

Save shivaprasadbhat/e9f890aa674d40d88de5223d17cb934d to your computer and use it in GitHub Desktop.
Example Gist
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/iommufd.h>
#include <linux/vfio.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#define MEMORY_SIZE (1024 * 1024) // 1 MB
int main() {
int cdev_fd, iommufd;
struct vfio_device_bind_iommufd bind;
struct iommu_ioas_alloc alloc_data = {0};
struct iommu_ioas_iova_ranges iova_ranges = {0};
struct iommu_iova_range allowed_iovas;
struct iommu_ioas_map map = {0};
struct iommu_ioas_unmap unmap = {0};
struct iommu_hwpt_alloc hwpt_alloc = {0};
void *user_va;
__aligned_u64 iova_alignment;
// Open the VFIO device
cdev_fd = open("/dev/vfio/devices/vfio0", O_RDWR); // Adjust path as needed
if (cdev_fd < 0) {
perror("Failed to open VFIO device");
return EXIT_FAILURE;
}
// Open the IOMMU FD
iommufd = open("/dev/iommu", O_RDWR);
if (iommufd < 0) {
perror("Failed to open IOMMU FD");
close(cdev_fd);
return EXIT_FAILURE;
}
// Bind the VFIO device to the IOMMU FD
bind.argsz = sizeof(bind);
bind.iommufd = iommufd;
bind.flags = 0;
if (ioctl(cdev_fd, VFIO_DEVICE_BIND_IOMMUFD, &bind) < 0) {
perror("Failed to bind VFIO device to IOMMU FD");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
// Allocate an IOAS
alloc_data.size = sizeof(alloc_data);
alloc_data.flags = 0;
if (ioctl(iommufd, IOMMU_IOAS_ALLOC, &alloc_data) < 0) {
perror("Failed to allocate IOAS");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
// Query IOVA ranges
/* iova_ranges.size = sizeof(iova_ranges);
iova_ranges.ioas_id = alloc_data.out_ioas_id;
iova_ranges.num_iovas = 1; // Initial guess; can be adjusted if needed
iova_ranges.allowed_iovas = (__aligned_u64)&allowed_iovas;
iova_ranges.out_iova_alignment = 0; // Query for alignment
if (ioctl(iommufd, IOMMU_IOAS_IOVA_RANGES, &iova_ranges) < 0) {
perror("Failed to query IOVA ranges");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
// Set allowed IOVAs (if needed)
// For simplicity, assume we have one range; adjust as needed
struct iommu_ioas_allow_iovas allow_iovas = {0};
allow_iovas.size = sizeof(allow_iovas);
allow_iovas.ioas_id = alloc_data.out_ioas_id;
allow_iovas.num_iovas = 1;
allow_iovas.allowed_iovas = (__aligned_u64)&allowed_iovas;
if (ioctl(iommufd, IOMMU_IOAS_ALLOW_IOVAS, &allow_iovas) < 0) {
perror("Failed to set allowed IOVAs");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
} */
// Allocate HWPT
hwpt_alloc.size = sizeof(hwpt_alloc);
hwpt_alloc.flags = 0; // No special flags
hwpt_alloc.dev_id = bind.out_devid; // Device ID, adjust as needed
hwpt_alloc.pt_id = alloc_data.out_ioas_id; // Connect HWPT to the allocated IOAS
hwpt_alloc.out_hwpt_id = 0; // Output parameter, should be filled by the ioctl
hwpt_alloc.__reserved = 0;
hwpt_alloc.data_type = IOMMU_HWPT_DATA_NONE; // Using default data type
hwpt_alloc.data_len = 0;
hwpt_alloc.data_uptr = 0;
if (ioctl(iommufd, IOMMU_HWPT_ALLOC, &hwpt_alloc) < 0) {
perror("Failed to allocate HWPT");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
// Allocate some space and setup a DMA mapping
user_va = mmap(NULL, MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (user_va == MAP_FAILED) {
perror("Failed to mmap user space memory");
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
map.size = sizeof(map);
map.flags = IOMMU_IOAS_MAP_READABLE | IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_FIXED_IOVA;
map.ioas_id = alloc_data.out_ioas_id;
map.user_va = (__aligned_u64)user_va;
map.length = MEMORY_SIZE;
map.iova = 0; // Use fixed IOVA (set to 0 for automatic)
if (ioctl(iommufd, IOMMU_IOAS_MAP, &map) < 0) {
perror("Failed to map IOAS");
munmap(user_va, MEMORY_SIZE);
close(iommufd);
close(cdev_fd);
return EXIT_FAILURE;
}
// Optionally, you could perform operations with the mapped memory here...
// Unmap the IOAS
unmap.size = sizeof(unmap);
unmap.ioas_id = alloc_data.out_ioas_id;
unmap.iova = map.iova;
unmap.length = MEMORY_SIZE;
if (ioctl(iommufd, IOMMU_IOAS_UNMAP, &unmap) < 0) {
perror("Failed to unmap IOAS");
}
// Clean up
munmap(user_va, MEMORY_SIZE);
close(iommufd);
close(cdev_fd);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment