Skip to content

Instantly share code, notes, and snippets.

@abelardojarab
Created January 26, 2023 17:36
Show Gist options
  • Save abelardojarab/c326f9c41f40abb7e5bf7fef51475cd4 to your computer and use it in GitHub Desktop.
Save abelardojarab/c326f9c41f40abb7e5bf7fef51475cd4 to your computer and use it in GitHub Desktop.
Allocate DMA pages
#include <iostream>
#include <memory>
#include <regex>
#include <cassert>
#include <experimental/filesystem>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
#include <poll.h>
#include <unistd.h>
#include <termios.h>
#define MB 1024
#define GB 1024*1024
#ifndef MAP_HUGETLB
#define MAP_HUGETLB 0X400000
#endif
#ifndef MAP_HUGE_SHIFT
#define MAP_HUGE_SHIFT 26
#endif
#define MAP_1G_HUGEPAGE (0x1e << MAP_HUGE_SHIFT)
#define ADDR (void *)(0x0UL)
#define FLAGS_4K (MAP_PRIVATE | MAP_ANONYMOUS)
#define FLAGS_2M (FLAGS_4K | MAP_HUGETLB)
#define FLAGS_1G (FLAGS_2M | MAP_1G_HUGEPAGE)
// sudo bash -c "echo 30 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"
// sudo bash -c "echo 1 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages"
// echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
namespace fs = std::experimental::filesystem;
struct dma_heap_allocation_data {
uint64_t len;
uint32_t fd;
uint32_t fd_flags;
uint64_t heap_flags;
};
struct HugePage
{
using Ref = std::shared_ptr<HugePage>;
void *virt; // Virtual address
uintptr_t phy; // Physical address
std::size_t size; // Size (in bytes)
HugePage(void *v, uintptr_t p, std::size_t sz)
: virt(v), phy(p), size(sz) {
}
~HugePage() {
int rc;
rc = munlock(virt, size);
assert(rc != -1);
rc = munmap(virt, size);
assert(rc != -1);
}
};
#define BIT(n) (1ULL << (n))
static uintptr_t virtual_to_physical(const void *vaddr) {
auto page_size = sysconf(_SC_PAGESIZE);
int fd = ::open("/proc/self/pagemap", O_RDONLY);
assert(fd != -1);
int res = ::lseek64(fd,
(uintptr_t)vaddr / page_size * sizeof(uintptr_t),
SEEK_SET);
assert(res != -1);
uintptr_t phy = 0;
res = ::read(fd, &phy, sizeof(uintptr_t));
assert(res == sizeof(uintptr_t));
::close(fd);
assert((phy & BIT(63)) != 0);
return (phy & 0x7fffffffffffffULL) * page_size +
(uintptr_t)vaddr % page_size;
}
HugePage::Ref allocate(size_t size) {
// Map a hugepage into memory
void* vaddr = NULL;
if (size > 2 * MB)
vaddr = (void *)mmap(ADDR, size,
PROT_READ | PROT_WRITE,
FLAGS_1G,
-1, 0);
else
vaddr = (void *)mmap(ADDR, size,
PROT_READ | PROT_WRITE,
FLAGS_2M,
-1, 0);
assert (vaddr != MAP_FAILED);
auto lock_result = mlock(vaddr, size);
assert (lock_result != -1);
return std::make_shared<HugePage>(vaddr,
virtual_to_physical(vaddr),
size);
}
class virtio_console {
public:
virtio_console();
~virtio_console();
void close(void);
int open(std::string name);
int write(const void *ptr, size_t len);
int read(void *ptr, size_t count);
private:
int port_fd;
struct termios settings_orig;
struct termios settings;
};
int main(int argc, char *argv[])
{
auto buffer1 = allocate(2 * MB);
std::cout << "Virtual memory: " << buffer1->virt << std::endl;
std::cout << "Physical memory: " << (void *)buffer1->phy << std::endl;
auto buffer2 = allocate(2 * MB);
std::cout << "Virtual memory: " << buffer2->virt << std::endl;
std::cout << "Physical memory: " << (void *)buffer2->phy << std::endl;
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment