首页 > 解决方案 > 如何分配物理内存块?

问题描述

如标题所示,我需要分配至少 32MB 的物理内存块。我有一个硬件,可以在给定的物理地址保存它的跟踪数据,其中包含 32MB 块。所以我想用虚拟地址分配足够的空间并翻译它的地址,但我忘记了物理内存中的页面没有存储在另一个旁边。

现在我有这个代码。

#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;
}

它使用 mmap() 为缓冲区文件(充满“A”字节的 64MB 文件)分配虚拟内存,并使用 virt_to_phys() 将其虚拟地址转换为物理地址。接下来,当有“WAITING FOR CHANGE”评论时,我试图用另一个程序将一些字节保存到这个地址。我现在已经用busybox devmem对其进行了测试,当读取前16KB的内存时,我已经读取了缓冲区文件中的内容,但之后它读取了一些乱码数据,因此可以确认物理内存在其他地方分配了下一页记忆。

所以我的问题是如何分配物理内存空间中相邻的 32MB 内存块。更好的问题是:这甚至可能吗?

标签: cmemorymmapmemory-address

解决方案


推荐阅读