As in title I need to allocate at least 32MB block of physical memory. I have a hardware that saves it's trace data with 32MB blocks at given physical address. So I thought of allocating enough space with virtual address and translating it's address but I've forgot that pages at physical memory are not stored next to the other.
Right now I have this code.
#define MEGABYTE 1048576
#include <fcntl.h> /* open */
#include <stdint.h> /* uint64_t */
#include <stdio.h> /* printf */
#include <stdlib.h> /* size_t */
#include <unistd.h> /* pread, sysconf */
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
typedef struct {
uint64_t pfn : 54;
unsigned int soft_dirty : 1;
unsigned int file_page : 1;
unsigned int swapped : 1;
unsigned int present : 1;
} PagemapEntry;
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)
{
size_t nread;
ssize_t ret;
uint64_t data;
uintptr_t vpn;
vpn = vaddr / sysconf(_SC_PAGE_SIZE);
nread = 0;
while (nread < sizeof(data)) {
ret = pread(pagemap_fd, &data, sizeof(data) - nread,
vpn * sizeof(data) + nread);
nread += ret;
if (ret <= 0) {
return 1;
}
}
entry->pfn = data & (((uint64_t)1 << 54) - 1);
entry->soft_dirty = (data >> 54) & 1;
entry->file_page = (data >> 61) & 1;
entry->swapped = (data >> 62) & 1;
entry->present = (data >> 63) & 1;
return 0;
}
/* Convert the given virtual address to physical using /proc/PID/pagemap.
*
* @param[out] paddr physical address
* @param[in] pid process to convert for
* @param[in] vaddr virtual address to get entry for
* @return 0 for success, 1 for failure
*/
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr)
{
char pagemap_file[BUFSIZ];
int pagemap_fd;
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
pagemap_fd = open(pagemap_file, O_RDONLY);
if (pagemap_fd < 0) {
return 1;
}
PagemapEntry entry;
if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
return 1;
}
close(pagemap_fd);
*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
return 0;
}
int is_changed(uint8_t *pBuffer, uint64_t size)
{
printf("size = %ld\n", size);
for (uint64_t i = 0; i < size; i++)
{
if(pBuffer[i] != 'A')
{
printf("Found it!!!\n");
printf("Index = %ld\n",i);
return 1;
}
}
printf("Nothing found!\n");
return 0;
}
uint8_t *virtual_mem_addr = NULL;
uint8_t *physical_mem_addr = NULL;
uint64_t mem_size = 0;
pid_t pid = 0;
char* vaddr = NULL;
uintptr_t paddr = 0;
FILE *f = NULL;
int main(int argc, char const *argv[])
{
uint64_t pFile;
struct stat statbuf;
unsigned char *mmapPointer;
uint32_t file_size = 0;
pid = getpid();
if (argc < 2)
{
printf("Usage %s <filename>\n", argv[0]);
return 1;
}
pFile = open(argv[1], O_RDWR | O_SYNC);
if(pFile <= 0)
{
printf("Error opening %s.\n", argv[1]);
return 1;
}
if(fstat(pFile,&statbuf) < 0)
{
printf("fstat error\n");
return 1;
}
mmapPointer = mmap(NULL,statbuf.st_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, pFile,0);
printf("mmapPointer = %p\n",mmapPointer);
printf("pid %ju\n", (uintmax_t)pid);
printf("%c\n",mmapPointer[0]);
printf("mmapPointer After loop = %p\n",mmapPointer);
if (virt_to_phys_user(&paddr, pid,(uintptr_t)mmapPointer))
{
fprintf(stderr, "error: virt_to_phys_user\n");
return EXIT_FAILURE;
};
printf("paddr = 0x%jx\n", (uintmax_t)paddr);
//WAITING FOR CHANGE
printf("Press key to continue.\n");
getchar();
// //CHECK IF SOMETHING HAS CHANGED
is_changed(mmapPointer, 32*MEGABYTE);
if(munmap(mmapPointer,statbuf.st_size) < 0)
{
perror("Error un-mapping the file\n");
close(pFile);
return 1;
}
close(pFile);
return EXIT_SUCCESS;
}
It allocates virtual memory for buffer file(64MB file full of 'A' bytes) with mmap() and with virt_to_phys() it translates it's virtual address to physical address. Next when there's "WAITING FOR CHANGE" comment I'm trying to save some bytes to this address with another program. I've tested it with busybox devmem right now, and when reading first 16KB of memory I've read what's inside my buffer file, but after that it reads some gibberish data, so that confirms, that physical memory allocated next page somewhere else in the memory.
So my question is how can I allocate 32MB block of memory that is next to the other in physical memory space. Better question is: Is it even possible?