sdk/userspace/fpga_libs/fpga_dma/fpga_dma_mem.c (106 lines of code) (raw):

#include <fpga_dma_mem.h> #include <fcntl.h> #include <hal/fpga_common.h> #include <stdio.h> #include <sys/mman.h> #include <utils/log.h> #define __USE_LARGEFILE64 #include <sys/types.h> #include <unistd.h> #define BIT(b) (1LL << (b)) /* pagemap bits */ #define PAGE_FRAME_NUM (BIT(55) - 1) #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SIZE - 1) static int get_pagemap(uint64_t page_frame_number, uint64_t* pagemap) { int ret = FPGA_ERR_FAIL; fail_on_with_code(pagemap == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "page_map is NULL"); char pagemap_file_path[128]; snprintf(pagemap_file_path, sizeof(pagemap_file_path), "/proc/%d/pagemap", getpid()); int fd = open(pagemap_file_path, 0); fail_on_with_code(fd == -1, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "open(%s) failed: %m", pagemap_file_path); lseek64(fd, page_frame_number * 8, SEEK_SET); size_t bytes_read = read(fd, pagemap, sizeof(*pagemap)); fail_on_with_code( bytes_read != sizeof(*pagemap), cleanup, ret, FPGA_ERR_SOFTWARE_PROBLEM, "read(%s) failed: %m", pagemap_file_path); return FPGA_ERR_OK; cleanup: close(fd); err: return ret; } static int get_physical_address(void* virtual_address, uint64_t* physical_address) { int ret = FPGA_ERR_FAIL; fail_on_with_code(virtual_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "virtual_address is NULL"); uint64_t virtual_page_frame_number = ((uintptr_t) virtual_address) >> PAGE_SHIFT; uint64_t pagemap; ret = get_pagemap(virtual_page_frame_number, &pagemap); fail_on_with_code(ret != FPGA_ERR_OK, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "get_pagemap failed"); uint64_t physical_page_frame_number = (uintptr_t) pagemap & PAGE_FRAME_NUM; uint64_t offset = ((uintptr_t) virtual_address) & PAGE_MASK; *physical_address = (physical_page_frame_number * PAGE_SIZE) | offset; err: return ret; } static int map_page(int fd, size_t size_bytes, int flags, uint64_t* virtual_address, uint64_t* physical_address) { int ret = 0; int prot = PROT_READ | PROT_WRITE; void *va = mmap(NULL, size_bytes, prot, flags, fd, 0); fail_on_with_code(va == MAP_FAILED, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "mmap failed"); *virtual_address = (uint64_t) va; *(uint32_t *) va = 0; ret = mlockall(MCL_CURRENT); fail_on_with_code(ret != FPGA_ERR_OK, cleanup, ret, FPGA_ERR_SOFTWARE_PROBLEM, "mlockall failed"); ret = get_physical_address(va, physical_address); fail_on_with_code(ret != FPGA_ERR_OK, cleanup, ret, FPGA_ERR_SOFTWARE_PROBLEM, "get_physical_address failed"); err: return ret; cleanup: munmap(va, size_bytes); return ret; } int fpga_dma_mem_map(int fd, size_t size_bytes, uint64_t* virtual_address, uint64_t* physical_address) { int ret = 0; fail_on_with_code(virtual_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "virtual_address is NULL"); fail_on_with_code(physical_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "physical_address is NULL"); fail_on_with_code(size_bytes == 0, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "size_bytes is 0"); int flags = MAP_SHARED; ret = map_page(fd, size_bytes, flags, virtual_address, physical_address); fail_on_with_code(ret != FPGA_ERR_OK, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "map_page failed"); log_info("size_bytes = %zu, virtual_address = 0x%lx, physical_address = 0x%lx", size_bytes, *virtual_address, *physical_address); err: return ret; } int fpga_dma_mem_map_anon(size_t size_bytes, uint64_t* virtual_address, uint64_t* physical_address) { int ret = 0; fail_on_with_code(virtual_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "virtual_address is NULL"); fail_on_with_code(physical_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "physical_address is NULL"); fail_on_with_code(size_bytes == 0, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "size_bytes is 0"); int flags = MAP_PRIVATE | MAP_ANONYMOUS; ret = map_page(-1, size_bytes, flags, virtual_address, physical_address); fail_on_with_code(ret != FPGA_ERR_OK, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "map_page failed"); log_info("size_bytes = %zu, virtual_address = 0x%lx, physical_address = 0x%lx", size_bytes, *virtual_address, *physical_address); err: return ret; } int fpga_dma_mem_map_huge(uint64_t* virtual_address, uint64_t* physical_address) { int ret = 0; fail_on_with_code(virtual_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "virtual_address is NULL"); fail_on_with_code(physical_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "physical_address is NULL"); int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB; size_t default_hugepage_bytes = 2 * 1024 * 1024; ret = map_page(-1, default_hugepage_bytes, flags, virtual_address, physical_address); fail_on_with_code(ret != FPGA_ERR_OK, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "map_page failed"); log_info("hugepage_size = %zu, virtual_address = 0x%lx, physical_address = 0x%lx", default_hugepage_bytes, *virtual_address, *physical_address); err: return ret; } int fpga_dma_mem_unmap(uint64_t* virtual_address, size_t size_bytes) { int ret = FPGA_ERR_FAIL; fail_on_with_code(virtual_address == NULL, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "virtual_address is NULL"); fail_on_with_code(size_bytes == 0, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "size_bytes is 0"); ret = munmap((void *) *virtual_address, size_bytes); fail_on_with_code(ret != FPGA_ERR_OK, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "munmap failed"); *virtual_address = 0; err: return ret; }