highmem内存在内核的映射问题?
我写了一个内核模块程序,通过在内核模块中,可以得到cr3寄存器的值,再通过页面的二级映射关系,我可以在程序中实现将一个用户空间>
的线性地址转换成物理地址。这一点在我的pc机(i386,512M内存)中已经得到验证。
可同样的程序在服务器上(2G内存,i386,估计打开了pte highmem选项),总是发生oops错误。
我的理解是这样:
当物理内存小于896M时,在内核中可以直接将物理内存+3G作为线性地址访问。
可当某一个物理地址大于896M时,在内核中如何访问这个物理地址中对应的内容呢?
请大虾门指教!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
估计跟我前几天遇到的问题一样。偶是给了代码有人帮忙解决的,你不给代码就只能象偶一样慢慢郁闷了。
以下是那个内核模块程序,在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);
以下是用户进程的程序。
#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);
}
先将内核模块执行程序insmod,在执行user程序。就会发现,user进程中的字符串被内核模块程序所修改。
再执行user之前,还要
mknod /dev/cr3 c 254 0
254是查看/proc/devices 文件中cr3对应的值
修改的途径是通过二次页面映射完成。
这2个程序在我的i386的pc机(512M内存)上能很好的执行。但在2G内存的i386服务器上容易出现oops错误。