通过/dev/mem只能访问高端内存以下的内核线性地址空间
http://blog.chinaunix.net/uid-20564848-id-74706.html
《/proc/iomem和/proc /ioports对应的fops》
《浅析pc机上如何将vmlinuz- 2.6.31-14-generic解压出vmlinux》
fs_initcall(chr_dev_init);
chr_dev_init
==> register_chrdev(MEM_MAJOR,"mem",&memory_fops); // 建立/dev/mem字符节点
memory_open会根据inode的minor来定位具体的fops,
比如
1,1为mem_fops
1,2为kmem_fops
1,8为random_fops
等等(具体见下面的devlist[])
static const struct file_operations memory_fops = {
.open = memory_open, /* just a selector for the real open */
};
static const struct {
unsigned int minor;
char *name;
umode_t mode;
const struct file_operations *fops;
} devlist[] = { /* list of minor devices */
#ifdef CONFIG_DEVMEM
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
#endif
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
#ifdef CONFIG_DEVPORT
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
{7, "full", S_IRUGO | S_IWUGO, &full_fops},
{8, "random", S_IRUGO | S_IWUSR, &random_fops},
{9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
{11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops},
#ifdef CONFIG_CRASH_DUMP
{12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
#endif
};
static int memory_open(struct inode * inode, struct file * filp)
{
// 根据inode的minor子节点号定位具体功能驱动fops
switch (iminor(inode)) {
#ifdef CONFIG_DEVMEM
case 1:
filp->f_op = &mem_fops;
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
case 2:
filp->f_op = &kmem_fops;
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
#endif
case 3:
filp->f_op = &null_fops;
break;
#ifdef CONFIG_DEVPORT
case 4:
filp->f_op = &port_fops;
break;
#endif
case 5:
filp->f_mapping->backing_dev_info = &zero_bdi;
filp->f_op = &zero_fops;
break;
case 7:
filp->f_op = &full_fops;
break;
case 8:
filp->f_op = &random_fops;
break;
case 9:
filp->f_op = &urandom_fops;
break;
case 11:
filp->f_op = &kmsg_fops;
break;
#ifdef CONFIG_CRASH_DUMP
case 12:
filp->f_op = &oldmem_fops;
break;
#endif
default:
return -ENXIO;
}
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
crw-rw-rw- 1 root root 1, 9 2010-05-16 09:18 urandom
crw-rw-rw- 1 root root 1, 3 2010-05-16 17:17 null
crw-rw-rw- 1 root root 1, 8 2010-05-16 17:17 random
crw-rw-rw- 1 root root 1, 5 2010-05-16 17:17 zero
brw-rw---- 1 root disk 1, 9 2010-05-16 17:17 ram9
brw-rw---- 1 root disk 1, 8 2010-05-16 17:17 ram8
brw-rw---- 1 root disk 1, 7 2010-05-16 17:18 ram7
crw-r----- 1 root kmem 1, 4 2010-05-16 17:18 port
crw-rw---- 1 root root 1, 12 2010-05-16 17:18 oldmem
crw-r----- 1 root kmem 1, 1 2010-05-16 17:18 mem
crw-rw---- 1 root root 1, 11 2010-05-16 17:18 kmsg
crw-rw-rw- 1 root root 1, 7 2010-05-16 17:18 full
我们来看看/dev/mem都能读取到些什么
static const struct file_operations mem_fops = {
.llseek = memory_lseek,
.read = read_mem,
.write = write_mem,
.mmap = mmap_mem,
.open = open_mem,
.get_unmapped_area = get_unmapped_area_mem,
};
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
*/
static ssize_t read_mem(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t read, sz;
char *ptr;
/*
// for arm
int valid_phys_addr_range(unsigned long addr, size_t size)
{
if (addr < PHYS_OFFSET) // 只能CONFIG_DRAM_BASE这个DDR物理内存首地址开始的空间~到高端内存之间内核线性地址
return 0;
if (addr + size > __pa(high_memory))
return 0;
return 1;
}
// for x86
static inline int valid_phys_addr_range(unsigned long addr, size_t count)
{
if (addr + count > __pa(high_memory)) // 只有高端内存以下的地址才能访问.
return 0;
return 1;
}
*/
if (!valid_phys_addr_range(p, count))
return -EFAULT;
read = 0;
#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
/* we don't have page 0 mapped on sparc and m68k.. */
if (p < PAGE_SIZE) {
sz = PAGE_SIZE - p;
if (sz > count)
sz = count;
if (sz > 0) {
if (clear_user(buf, sz))
return -EFAULT;
buf += sz;
p += sz;
count -= sz;
read += sz;
}
}
#endif
while (count > 0) {
/*
* Handle first page in case it's not aligned
*/
if (-p & (PAGE_SIZE - 1))
sz = -p & (PAGE_SIZE - 1);
else
sz = PAGE_SIZE;
sz = min_t(unsigned long, sz, count);
/*
* On ia64 if a page has been mapped somewhere as
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
ptr = xlate_dev_mem_ptr(p); // 将物理地址p转化为内核线性虚拟地址
// #define xlate_dev_mem_ptr(p) __va(p)
// #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
// #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
// #define __PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
// vim arch/x86/configs/i386_defconfig 我们获取的参数[luther.gliethttp]
// CONFIG_PAGE_OFFSET=0xC0000000
if (copy_to_user(buf, ptr, sz))
return -EFAULT;
buf += sz;
p += sz;
count -= sz;
read += sz;
}
*ppos += read;
return read;
}
让我们实际演练演练,我们读取释放到内存中的kernel代码
tatic struct resource code_resource = {
.name = "Kernel code",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
};
start_kernel
==> setup_arch
code_resource.start = virt_to_phys(_text); // _text内核代码相对DDR物理内存的偏移量,也就是内核线性地址偏移量[luther.gliethttp]
code_resource.end = virt_to_phys(_etext)-1;
data_resource.start = virt_to_phys(_etext);
data_resource.end = virt_to_phys(_edata)-1;
bss_resource.start = virt_to_phys(&__bss_start);
bss_resource.end = virt_to_phys(&__bss_stop)-1;
subsys_initcall(request_standard_resources);
request_standard_resources
==> init_iomem_resources(&code_resource, &data_resource, &bss_resource);// 这样/proc/iomem就可以看到这里设置的信息了
request_resource(res, code_resource);
request_resource(res, data_resource);
request_resource(res, bss_resource);
==> request_resource(&iomem_resource, &video_ram_resource);
luther@gliethttp:~$ cat /proc/iomem
00000000-00001fff : System RAM
00002000-00005fff : reserved
00006000-0009dbff : System RAM
0009dc00-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000cefff : Video ROM
000cf000-000d07ff : Adapter ROM
000d2000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-5bf0ffff : System RAM
00100000-00575553 : Kernel code
00575554-0078d307 : Kernel data
0081a000-008a809f : Kernel bss
以上的
00100000-00575553 : Kernel code
就是kernel代码存储区了
0x00100000等于1048576
0x00575553等于5723475
luther@gliethttp:~$ sudo dd bs=1 skip=1048576 count=208 if=/dev/mem 2>/dev/null | xxd -g 1
0000000: f6 86 11 02 00 00 40 75 14 0f 01 15 22 8e 74 00 ......@u....".t.
0000010: b8 18 00 00 00 8e d8 8e c0 8e e0 8e e8 fc 31 c0 ..............1.
0000020: bf 00 a0 81 00 b9 a0 80 8a 00 29 f9 c1 e9 02 f3 ..........).....
0000030: ab bf c0 56 7c 00 b9 00 04 00 00 fc f3 a5 8b 35 ...V|..........5
0000040: e8 58 7c 00 21 f6 74 0c bf e0 2a 7c 00 b9 00 02 .X|.!.t...*|....
0000050: 00 00 f3 a5 66 81 3d c6 58 7c 00 07 02 72 1c a1 ....f.=.X|...r..
0000060: fc 58 7c 00 3d 03 00 00 00 73 0e 8b 04 85 80 22 .X|.=....s....."
0000070: 7c 00 2d 00 00 00 c0 ff e0 0f 0b bf 00 90 8a 00 |.-.............
0000080: ba 00 a0 81 00 b8 03 00 00 00 8d 4f 67 89 0a 89 ...........Og...
0000090: 8a 00 0c 00 00 83 c2 04 b9 00 04 00 00 ab 05 00 ................
00000a0: 10 00 00 e2 f8 bd 03 90 a4 00 39 e8 72 dc 81 c7 ..........9.r...
00000b0: 00 00 00 c0 89 3d 80 a5 74 00 c1 e8 0c a3 84 f0 .....=..t.......
00000c0: 81 00 b8 67 b0 81 00 a3 fc af 81 00 e9 6d 6b 46 ...g.........mkF
通过/dev/mem只能访问高端内存以下的内核线性地址空间的更多相关文章
- Linux内存管理-高端内存(二)
在支持MMU的32位处理器平台上,Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Lin ...
- Linux内核高端内存 转
Linux内核地址映射模型x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通 ...
- Linux用户空间与内核空间(理解高端内存)
Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...
- linux 用户空间与内核空间——高端内存详解
摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...
- Linux内核高端内存
Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通常32位L ...
- kmalloc分配物理内存与高端内存映射--Linux内存管理(十八)
1 前景回顾 1.1 内核映射区 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供 ...
- linux用户空间和内核空间(内核高端内存)_转
转自:Linux用户空间与内核空间(理解高端内存) 参考: 1. 进程内核栈.用户栈 2. 解惑-Linux内核空间 3. linux kernel学习笔记-5 内存管理 Linux 操作系统和驱 ...
- linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】
转自:http://blog.csdn.net/tommy_wxie/article/details/17093307 上一篇微博留下了这几个函数,现在我们来分析它们 sanity_c ...
- Linux用户空间与内核空间(理解高端内存)【转】
转自:http://www.cnblogs.com/wuchanming/p/4360277.html Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递 ...
随机推荐
- 让低版本IE也能正常运行HTML5+CSS3网站的3种解决方案
现在我们可以选择浏览器非常多,所以浏览器的环境也是种类繁多,同一个浏览器也是包含各种不同的版本,不同的版本之间的渲染方法也存在差异,,它们支持的 HTML5.CSS3 特性恐怕也不尽相同.这种情况于是 ...
- Android 资源保护问题——探索
apk文件使用解压工具就能看到drawable等资源,但是有些游戏中的图片资源却是无法看到的. 这个问题探索了许久…… [1]图片资源不放置在drawable文件下,放在assets中(但是解压apk ...
- Python异常处理try...except...finally raise assert
异常处理:try ...except try代码块放置容易发生异常的语句:except代码块放置处理异常的语句try ...except...finally finally代码快是任何时候都会执行的 ...
- Makefile 11——支持头文件目录指定
现在,是时候在对应目录放入对应文件了: /× foo.h */ #ifndef __FOO_H #define __FOO_H void foo(void) #endif/*__FOO_H*/ /* ...
- 关于mysqli_free_result($result)报错
运行原来的一个原生的php写的项目,出现mysqli_free_result($result)的警告 Warning: mysqli_free_result() expects parameter 1 ...
- 跟着百度学PHP[13]-文件上传
PS:上传的时候一定要用POST方法,GET方法不行. 文件上传的entype要改成“mutilpart/form-data”这个编码 <html> <form action=&qu ...
- SpringBoot DataSource 配置说明
DataSource 配置说明 属性 说明 spring.dao.exceptiontranslation.enabled 是否开启PersistenceExceptionTranslationPos ...
- 虚拟机和Docker的异同
[摘要]各种虚拟机技术开启了云计算时代:而Docker,作为下一代虚拟化技术,正在改变我们开发.测试.部署应用的方式.那虚拟机与Docker究竟有何不同呢? 首先,大家需要明确一点,Docker容器不 ...
- log4cplus基本用法
说起日志系统,不得不提大名鼎鼎的Log4j.特别是使用Java的人们,能够说是无人不知无人不晓无人不用. Log4j以其简单的使用方式(引入一个jar包.一行代码就可以调用).灵活(可通过配置文件任意 ...
- 使用css全面美化input标签
做网站时经常有这样那样的需要,要美化input ,于是CSS的美化必不可少.和程序人生的站长交流,他发给我这个. 下面是CSS样式 input { border:1px solid #B3D6EF; ...