【问题标题】:How do I directly access reserved memory with a kernel module?如何使用内核模块直接访问保留内存?
【发布时间】:2015-06-30 14:24:25
【问题描述】:

我正在尝试将操作系统(Ubuntu Server 15.04)限制为一定的内存使用量并保留其余部分,但编写一个内核模块来读取/写入保留的内存。我想出了如何使用内核参数“mem=4G memmap=4G@0 memmap=4G$4G”来限制使用/保留内存(操作系统为 4GB,保留 4GB,在 4GB 处拆分)但我不知道如何对保留内存的 DMA 与内核模块一起使用。我想只创建一个 proc 文件,但我不确定您是否可以在操作系统分配的内存之外创建一个。

有什么建议吗?谢谢!

编辑:这是为了研究,所以它不需要“很好”

更新: 也许我不需要编写内核模块。我刚刚找到了这个,我要试一试: http://elinux.org/Memory_Management#Reserving_.28and_accessing.29_the_top_of_memory_on_startup

更新: 我尝试了上面的链接,但每当我尝试写作时都会出现段错误。这是我的代码:

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mann.h>

    #define RESERVED_MEMORY_SIZE 0x100000000

    int main() {
            int fd;
            char *reserved_memory;

            fd = open("/dev/mem", O_RDWR | O_SYNC);
            reserved_memory = (char *) mmap(0, RESERVED_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
            reserved_memory[0] = 'a';
            return 0;
    }

dmesg 显示:

    a.out[1167]: segfault at ffffffffffffffff ip 00000000004005d7 sp 00007ffeffccbd80 error 7 in a.out[400000+1000]

为了好玩,我尝试了 reserved_memory[1]:

    a.out[1180]: segfault at 0 ip 00000000004005db sp 00007ffc388d77b0 error 6 in a.out[400000+1000]

我将研究这些消息的格式,以便弄清楚它在告诉我什么。

更新:

我发现这个问题是由与我有相同问题的人提出的,但唯一的解决方案似乎是内核重建。我将尽量避免这种情况,所以也许我最好的选择是再次自定义内核模块。 accessing mmaped /dev/mem?

【问题讨论】:

  • 您确定您使用的mmap 正确吗?当您请求从偏移量 4096 开始映射 4GiB 区域时,它似乎返回错误(-1 数值),并且根据您的问题,系统没有 4GiB+4096Byte 内存(因为您拆分为 4GiB)。也许你交换了第二个和最后一个论点?另外我不知道 /dev/mem 是否可用于访问整个(内存)地址空间或仅用于访问可用 RAM 占用的部分。
  • @knm241 我刚刚添加了对 mmap 的返回值的检查,看起来它失败了。好决定!我想我不明白偏移参数是什么。我认为那是物理地址开始的地方,它将在 4GB 点(保留内存的开始)。
  • /dev/mem 是一个文件。读第一个字节就是读物理地址0x0,读第二个字节就是读0x1,读第100个字节就是读地址0x63。 offset 参数告诉mmap 从哪个字节开始读取/dev/mem。所以如果要从4GiB开始映射内存,偏移量必须是0x100000000。第二个参数是要映射多少字节,可以是4096。
  • 好的,有道理。我将该行更改为reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0x100000000);,但仍然无法映射。
  • 查看here 以获取可能的错误列表。包含errno.h 标头并打印errno 左值的值(即printf("%d\n", errno)。我的猜测是您无法映射操作系统不知道的内存。

标签: c linux memory-management linux-kernel


【解决方案1】:

好的,我想我解决了。原来我只是不明白 mmap 是如何工作的,我猜如果内核在保留内存中,它对写入/读取 /dev/mem 没有限制。下面是两个程序,它们将写入我在内存中的保留位置并从中读取。

写“Hello World!”:

    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/mman.h>

    #define RESERVED_MEMORY_OFFSET  0x100000000     /* Offset is 4GB */

    int main() {
            int fd;
            char *reserved_memory;
            char *buffer = "Hello World!";

            fd = open("/dev/mem", O_RDWR | O_SYNC):
            /* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
            reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
            if (reserved_memory == MAP_FAILED) {
                    printf("Failed to creating mapping.\n");
                    printf("ERRNO: %s\n", strerror(errno));
                    return -1;
            }
            sprintf(reserved_memory, "%s", buffer);
            return 0;
    }

从保留内存的开头读取:

    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/mman.h>

    #define RESERVED_MEMORY_OFFSET  0x100000000     /* Offset is 4GB */

    int main() {
            int fd;
            char *reserved_memory;
            char buffer[13];

            fd = open("/dev/mem", O_RDWR | O_SYNC):
            /* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
            reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
            if (reserved_memory == MAP_FAILED) {
                    printf("Failed to creating mapping.\n");
                    printf("ERRNO: %s\n", strerror(errno));
                    return -1;
            }
            snprintf(buffer, 13, "%s", reserved_memory);
            printf("%s\n", buffer);
            return 0;
    }

特别感谢@knm241!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-05
    • 2018-05-20
    • 2012-12-28
    • 2018-06-23
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多