Created
September 10, 2024 06:20
-
-
Save shivaprasadbhat/e9f890aa674d40d88de5223d17cb934d to your computer and use it in GitHub Desktop.
Example Gist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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