highmem内存在内核的映射问题?

发布于 2022-10-03 21:03:58 字数 443 浏览 16 评论 0

我写了一个内核模块程序,通过在内核模块中,可以得到cr3寄存器的值,再通过页面的二级映射关系,我可以在程序中实现将一个用户空间>
的线性地址转换成物理地址。这一点在我的pc机(i386,512M内存)中已经得到验证。

可同样的程序在服务器上(2G内存,i386,估计打开了pte highmem选项),总是发生oops错误。
我的理解是这样:
当物理内存小于896M时,在内核中可以直接将物理内存+3G作为线性地址访问。
可当某一个物理地址大于896M时,在内核中如何访问这个物理地址中对应的内容呢?

请大虾门指教!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤独岁月 2022-10-10 21:03:58

估计跟我前几天遇到的问题一样。偶是给了代码有人帮忙解决的,你不给代码就只能象偶一样慢慢郁闷了。

风吹短裙飘 2022-10-10 21:03:58

以下是那个内核模块程序,在2.6内核下能用

#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/version.h>

#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/poll.h>

#include <asm/io.h>

static int cr3_major = 0;
unsigned long int ch,ch1;

module_param(cr3_major, int, 0);
MODULE_AUTHOR("linuxman");
MODULE_LICENSE("Dual BSD/GPL");

int cr3_open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "kernel_get_cr3: cr3_open called!n");
return 0;
}

int cr3_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "kernel_get_cr3: cr3_release called!n");
return 0;
}

ssize_t cr3_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
static unsigned long int cr3_value;
ssize_t retval=0;

printk(KERN_INFO "kernel_get_cr3: cr3_read called!n");

__asm__ __volatile__(" movl %%cr3,%0":"=r"(cr3_value)); //read CR3 register

if (copy_to_user(buf,&cr3_value,sizeof(unsigned long int))) {
printk(KERN_INFO "kernel_get_cr3: cr3_read: copy_to_user failed!n");
retval = -EFAULT;
}
return retval;
}

ssize_t cr3_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
unsigned long int cr3_value;
unsigned long int pgd_basic;
unsigned long int pgd_offset;
unsigned long int pte_basic;
unsigned long int pte_offset;
unsigned long int page_basic;
unsigned long int page_offset;

unsigned long int *tmp_pointer;
unsigned long int tmp_data;

ssize_t retval=0;

char *ch_tmp;

printk(KERN_INFO "kernel_get_cr3: cr3_write called!n");

__asm__ __volatile__(" movl %%cr3,%0":"=r"(cr3_value)); //read CR3 register. user process context?
printk(KERN_INFO "get_cr3: write: with asm, cr3 register(with physical addr) is : %8lx n", cr3_value);

if (copy_from_user(&ch,buf,sizeof(unsigned long int))) {
printk(KERN_INFO "kernel_get_cr3: cr3_write: copy_from_user failed!n");
retval = -EFAULT;
}

printk(KERN_INFO "kernel_get_cr3: string linear addr for user space is %8lx .n", ch);

ch_tmp = (char *)ch;
*ch_tmp = 'x'; //change the first letter of user-level string through linear addr

printk(KERN_INFO "get_cr3: write: with current, cr3 register(with physical addr) is : %8lx n",
(unsigned long int)current->mm->pgd);

ch1 = ch;
pgd_basic = cr3_value & 0xfffff000;
pgd_offset = (ch1 >> 22) & 0x000003ff;
tmp_data = pgd_basic + pgd_offset*4 + PAGE_OFFSET; //physical addr to linear addr
printk(KERN_INFO "pgd entry physical addr is : %8lx n", (unsigned long int)tmp_data);
tmp_pointer = (unsigned long int *)tmp_data;
tmp_data = *tmp_pointer;

printk(KERN_INFO "with cr3, pte starting physical addr is : %8lx n", (unsigned long int)tmp_data);

ch1 = ch;
pte_basic = tmp_data & 0xfffff000;
pte_offset = (ch1 & 0x003ff000) >> 12;
tmp_data = pte_basic + pte_offset*4 + PAGE_OFFSET; //physical addr to linear addr
printk(KERN_INFO "pte entry physical addr is : %8lx n", (unsigned long int)tmp_data);
tmp_pointer = (unsigned long int *)tmp_data;
tmp_data = *tmp_pointer;

printk(KERN_INFO "page starting physical addr is : %8lx n", (unsigned long int)tmp_data);

ch1 = ch;
page_basic = tmp_data & 0xfffff000;
page_offset = ch1 & 0x00000FFF;
tmp_data = page_basic + page_offset; //already real physical addr

printk(KERN_INFO "kernel_get_cr3: string physical addr(with mapping) is : %8lx n", (unsigned long int)tmp_data);

ch_tmp = (char *)(tmp_data + PAGE_OFFSET); //no need to *4
printk(KERN_INFO "kernel_get_cr3: string linear addr(with mapping) is : %8lx n", (unsigned long int)ch_tmp);
*ch_tmp = 'y'; //change the first letter of user-level string through cr3 manner
*(ch_tmp+1) = 'a'; //change the first letter of user-level string through cr3 manner
*(ch_tmp+2) = 'h'; //change the first letter of user-level string through cr3 manner
*(ch_tmp+3) = 'o'; //change the first letter of user-level string through cr3 manner
*(ch_tmp+4) = 'o'; //change the first letter of user-level string through cr3 manner
*(ch_tmp+5) = '!'; //change the first letter of user-level string through cr3 manner

return retval;
}

unsigned int cr3_poll(struct file *filp, poll_table *wait)
{
return 0;
}

struct file_operations cr3_fops = {
.read = cr3_read,
.write = cr3_write,
.poll = cr3_poll,
.open = cr3_open,
.release = cr3_release,
.owner = THIS_MODULE
};

int cr3_init(void)
{
int result;

unsigned long int cr3_value;

result = register_chrdev(cr3_major, "cr3", &cr3_fops);

if (result < 0) {
printk(KERN_INFO "kernel_get_cr3: can't get cr3 char device major numbern");
return result;
}
printk(KERN_INFO "kernel_get_cr3: init ok!n");

if (cr3_major == 0)
cr3_major = result;

__asm__ __volatile__(" movl %%cr3,%0":"=r"(cr3_value)); //read CR3 register, insmod process context?
printk(KERN_INFO "get_cr3: init:cr3 register(with physical addr) is : %8lx n", cr3_value);

return 0;
}

module_init(cr3_init);
module_exit(cr3_cleanup);

仙女山的月亮 2022-10-10 21:03:58

以下是用户进程的程序。

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

char str[100]="linuxmanisalinuxfan";

int main(void)
{
int i;
int cr3_fd;
unsigned long int str_addr;

if( -1 == (cr3_fd = open("/dev/cr3",O_RDWR)) ) {
printf("cannot open /dev/cr3 module!n");
return -1;
}

str_addr = (unsigned long int)str;

printf("linear addr is %8lxn", str);
printf("string is:%sn",str);

write(cr3_fd, &str_addr, sizeof(int));

for(i=0;i<1000;i++) {
printf("string is:%sn",str);
sleep(1);
}

close(cr3_fd);

}

战皆罪 2022-10-10 21:03:58

先将内核模块执行程序insmod,在执行user程序。就会发现,user进程中的字符串被内核模块程序所修改。
再执行user之前,还要
mknod /dev/cr3 c 254 0

254是查看/proc/devices 文件中cr3对应的值

修改的途径是通过二次页面映射完成。

这2个程序在我的i386的pc机(512M内存)上能很好的执行。但在2G内存的i386服务器上容易出现oops错误。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文