Tôi đang cố gắng truy cập bộ nhớ vật lý trực tiếp cho một dự án Linux được nhúng, nhưng tôi không chắc chắn làm cách nào để có thể chỉ định bộ nhớ tốt nhất cho việc sử dụng của mình.Truy cập bộ nhớ trực tiếp trong Linux
Nếu tôi khởi động thiết bị của mình thường xuyên và truy cập/dev/mem, tôi có thể dễ dàng đọc và ghi vào bất kỳ nơi nào tôi muốn. Tuy nhiên, trong này, tôi đang truy cập vào bộ nhớ có thể dễ dàng được phân bổ cho bất kỳ quá trình nào; mà tôi không muốn làm
Mã của tôi cho/dev/mem là (tất cả các kiểm tra lỗi, vv loại bỏ):
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);
Và công trình này. Tuy nhiên, tôi muốn sử dụng bộ nhớ mà không ai khác sẽ chạm vào. Tôi đã thử giới hạn số lượng bộ nhớ mà hạt nhân nhìn thấy bằng cách khởi động với mem = XXXm, và sau đó thiết lập BASE_ADDRESS thành một cái gì đó ở trên (nhưng bên dưới bộ nhớ vật lý), nhưng dường như không thể truy cập cùng một bộ nhớ một cách nhất quán.
Dựa trên những gì tôi đã xem trực tuyến, tôi nghi ngờ có thể cần một mô-đun hạt nhân (OK) sử dụng ioremap() hoặc remap_pfn_range() (hoặc cả hai ???), nhưng tôi hoàn toàn không có ý tưởng làm sao; có ai giúp được không?
EDIT: Điều tôi muốn là cách luôn truy cập cùng một bộ nhớ vật lý (giả sử 1,5MB) và đặt bộ nhớ sang một bên sao cho hạt nhân sẽ không cấp phát cho bất kỳ quá trình nào khác.
Tôi đang cố gắng để tái tạo một hệ thống chúng tôi đã có trong hệ điều hành khác (không có quản lý bộ nhớ) nhờ đó mà tôi có thể bố trí một không gian trong bộ nhớ thông qua mối liên kết và truy cập nó bằng cách sử cái gì đó như
*(unsigned char *)0x12345678
EDIT2: Tôi đoán tôi nên cung cấp thêm một số chi tiết. Không gian bộ nhớ này sẽ được sử dụng cho bộ đệm RAM cho giải pháp ghi nhật ký hiệu suất cao cho một ứng dụng nhúng. Trong các hệ thống chúng tôi có, không có gì xóa hoặc xáo trộn bộ nhớ vật lý trong khi khởi động lại mềm. Vì vậy, nếu tôi viết một chút vào một địa chỉ vật lý X, và khởi động lại hệ thống, cùng một bit sẽ vẫn được thiết lập sau khi khởi động lại. Điều này đã được thử nghiệm trên cùng một phần cứng chạy VxWorks (logic này cũng hoạt động tốt trong Nucleus RTOS và OS20 trên các nền tảng khác nhau, FWIW). Ý tưởng của tôi là thử cùng một thứ trong Linux bằng cách giải quyết trực tiếp bộ nhớ vật lý; do đó, điều quan trọng là tôi nhận được cùng một địa chỉ mỗi lần khởi động.
Tôi có lẽ nên làm rõ rằng đây là hạt nhân 2.6.12 và mới hơn.
EDIT3: Đây là mã của tôi, trước tiên cho mô-đun hạt nhân, sau đó cho ứng dụng không gian người dùng.
Để sử dụng nó, tôi khởi động với mem = 95m, sau đó insmod foo-module.ko, sau đó mknod mknod/dev/foo c 32 0, sau đó chạy foo-user, nơi nó chết. Chạy theo gdb cho thấy rằng nó chết tại nhiệm vụ, mặc dù trong gdb, tôi có thể không dereference địa chỉ tôi nhận được từ mmap (mặc dù printf thể)
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;
}
Để làm rõ, bạn muốn (trong mô-đun) trả về một không gian địa chỉ cho không gian người dùng được mua qua vmalloc(), không phải là kmalloc(), đúng không? Bạn cần bao nhiêu bộ nhớ? –
Điều này có thể được thực hiện dễ dàng nhất với kmalloc(), những gì bạn muốn làm là thiết lập 1,5 MB không gian hạt nhân ngoài và đưa nó vào không gian người dùng. Nếu đó là những gì bạn muốn làm, tôi sẽ làm mới bản thân mình trên một vài hạt nhân bên trong và cố gắng trả lời. –
Lưu ý, làm điều này với vmalloc() có thể là một nhiệm vụ cực kỳ đáng ghét. Số tiền bạn thực sự cần để ánh xạ ảnh hưởng đến câu trả lời, vì vậy bạn chắc chắn 1,5 MB hoặc ít hơn? –