Я пытаюсь получить доступ к физической памяти напрямую для проекта встроенного Linux, но я не уверен, как лучше всего определить память для моего использования.
Если я регулярно загружаю свое устройство и получаю доступ к / dev / mem, я могу легко читать и писать практически в любом месте, где захочу. Однако в этом я получаю доступ к памяти, которая может быть легко выделена для любого процесса; что я не хочу делать
Мой код для / dev / mem (все проверки ошибок и т. Д. Удалены):
mem_fd = open("/dev/mem", O_RDWR));
mem_p = malloc(SIZE + (PAGE_SIZE - 1));
if ((unsigned long) mem_p % PAGE_SIZE) {
mem_p += PAGE_SIZE - ((unsigned long) mem_p % PAGE_SIZE);
}
mem_p = (unsigned char *) mmap(mem_p, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, mem_fd, BASE_ADDRESS);
И это работает. Тем не менее, я бы хотел использовать память, которую больше никто не тронет. Я попытался ограничить объем памяти, который видит ядро, загрузившись с mem = XXXm, а затем установив BASE_ADDRESS на что-то выше этого (но ниже физической памяти), но, похоже, он не обращается к той же памяти последовательно.
Исходя из того, что я видел в Интернете, я подозреваю, что мне может понадобиться модуль ядра (который в порядке), который использует либо ioremap () или remap_pfn_range () (или оба ???), но я абсолютно не знаю, как ; кто-нибудь может помочь?
EDIT:
Я хочу, чтобы всегда был доступ к одной и той же физической памяти (скажем, 1,5 МБ), и откладывали эту память в сторону, чтобы ядро не выделяло ее для какого-либо другого процесса.
Я пытаюсь воспроизвести систему, которая была у нас в других ОС (без управления памятью), с помощью которой я мог бы выделить пространство в памяти через компоновщик и получить к нему доступ, используя что-то вроде
*(unsigned char *)0x12345678
EDIT2:
Я полагаю, я должен предоставить более подробную информацию. Это пространство памяти будет использоваться для буфера ОЗУ для высокопроизводительного решения для ведения журнала для встроенного приложения. В наших системах нет ничего, что очищало бы или скремблировало физическую память во время мягкой перезагрузки. Таким образом, если я записываю бит в физический адрес X и перезагружаю систему, тот же бит все равно будет установлен после перезагрузки. Это было проверено на том же оборудовании, на котором работает VxWorks (эта логика также хорошо работает в Nucleus RTOS и OS20 на разных платформах, FWIW). Моя идея состояла в том, чтобы попробовать то же самое в Linux, напрямую обращаясь к физической памяти; поэтому важно, чтобы я получал одинаковые адреса при каждой загрузке.
Я должен пояснить, что это для ядра 2.6.12 и новее.
EDIT3:
Вот мой код, сначала для модуля ядра, затем для пользовательского приложения.
Чтобы использовать его, я загружаюсь с mem = 95m, затем insmod foo-module.ko, затем mknod mknod / dev / foo c 32 0, затем запускаю foo-user, где он умирает. Запуск под GDB показывает, что он умирает при назначении, хотя в GDB я не могу разыменовать адрес, полученный от mmap (хотя printf может)
Foo-module.c
#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/io.h>
#define VERSION_STR "1.0.0"
#define FOO_BUFFER_SIZE (1u*1024u*1024u)
#define FOO_BUFFER_OFFSET (95u*1024u*1024u)
#define FOO_MAJOR 32
#define FOO_NAME "foo"
static const char *foo_version = "@(#) foo Support version " VERSION_STR " " __DATE__ " " __TIME__;
static void *pt = NULL;
static int foo_release(struct inode *inode, struct file *file);
static int foo_open(struct inode *inode, struct file *file);
static int foo_mmap(struct file *filp, struct vm_area_struct *vma);
struct file_operations foo_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = NULL,
.write = NULL,
.readdir = NULL,
.poll = NULL,
.ioctl = NULL,
.mmap = foo_mmap,
.open = foo_open,
.flush = NULL,
.release = foo_release,
.fsync = NULL,
.fasync = NULL,
.lock = NULL,
.readv = NULL,
.writev = NULL,
};
static int __init foo_init(void)
{
int i;
printk(KERN_NOTICE "Loading foo support module\n");
printk(KERN_INFO "Version %s\n", foo_version);
printk(KERN_INFO "Preparing device /dev/foo\n");
i = register_chrdev(FOO_MAJOR, FOO_NAME, &foo_fops);
if (i != 0) {
return -EIO;
printk(KERN_ERR "Device couldn't be registered!");
}
printk(KERN_NOTICE "Device ready.\n");
printk(KERN_NOTICE "Make sure to run mknod /dev/foo c %d 0\n", FOO_MAJOR);
printk(KERN_INFO "Allocating memory\n");
pt = ioremap(FOO_BUFFER_OFFSET, FOO_BUFFER_SIZE);
if (pt == NULL) {
printk(KERN_ERR "Unable to remap memory\n");
return 1;
}
printk(KERN_INFO "ioremap returned %p\n", pt);
return 0;
}
static void __exit foo_exit(void)
{
printk(KERN_NOTICE "Unloading foo support module\n");
unregister_chrdev(FOO_MAJOR, FOO_NAME);
if (pt != NULL) {
printk(KERN_INFO "Unmapping memory at %p\n", pt);
iounmap(pt);
} else {
printk(KERN_WARNING "No memory to unmap!\n");
}
return;
}
static int foo_open(struct inode *inode, struct file *file)
{
printk("foo_open\n");
return 0;
}
static int foo_release(struct inode *inode, struct file *file)
{
printk("foo_release\n");
return 0;
}
static int foo_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
if (pt == NULL) {
printk(KERN_ERR "Memory not mapped!\n");
return -EAGAIN;
}
if ((vma->vm_end - vma->vm_start) != FOO_BUFFER_SIZE) {
printk(KERN_ERR "Error: sizes don't match (buffer size = %d, requested size = %lu)\n", FOO_BUFFER_SIZE, vma->vm_end - vma->vm_start);
return -EAGAIN;
}
ret = remap_pfn_range(vma, vma->vm_start, (unsigned long) pt, vma->vm_end - vma->vm_start, PAGE_SHARED);
if (ret != 0) {
printk(KERN_ERR "Error in calling remap_pfn_range: returned %d\n", ret);
return -EAGAIN;
}
return 0;
}
module_init(foo_init);
module_exit(foo_exit);
MODULE_AUTHOR("Mike Miller");
MODULE_LICENSE("NONE");
MODULE_VERSION(VERSION_STR);
MODULE_DESCRIPTION("Provides support for foo to access direct memory");
Foo-user.c
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main(void)
{
int fd;
char *mptr;
fd = open("/dev/foo", O_RDWR | O_SYNC);
if (fd == -1) {
printf("open error...\n");
return 1;
}
mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
printf("On start, mptr points to 0x%lX.\n",(unsigned long) mptr);
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr, *mptr);
mptr[0] = 'a';
mptr[1] = 'b';
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr, *mptr);
close(fd);
return 0;
}