Http://blog.chinaunix.net/uid-20564848-id-74706.html
The FoPs of/proc/iomem and/proc/ioports
Analysis on how to extract vmlinuz-2.6.31-14-generic from Vmlinux on PC
Fs_initcall (Chr_dev_init);
Chr_dev_init
==> Register_chrdev (mem_major, "MEM", &memory_fops); Establishing a/DEV/MEM character node
Memory_open will be based on the minor of the inode to locate the specific fops,
Like what
To Mem_fops
For Kmem_fops
1,8 to Random_fops
And so on (see devlist[below for details)
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},
{One, "kmsg", S_irugo | S_IWUSR, &kmsg_fops},
#ifdef Config_crash_dump
{Oldmem, S_IRUSR | S_IWUSR | S_irgrp, &oldmem_fops},
#endif
};
static int Memory_open (struct inode * inode, struct file * Filp)
{
Locate the specific function driven fops based on the Inode's minor sub-node number
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, 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, 2010-05-16 17:18 kmsg
Crw-rw-rw-1 root root 1, 7 2010-05-16 17:18 full
Let's see what/dev/mem can read.
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)//can only config_dram_base the first address of this DDR physical memory start space ~ to high-end memory between the kernel linear address
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))//Only the address below the high-end memory can be accessed.
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 is accessed uncached
* By the kernel or data corruption may occur
*/
ptr = Xlate_dev_mem_ptr (p); Convert Physical address p to kernel linear virtual address
#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 The parameters we get [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;
}
Let's actually walk through the walkthrough, we read the kernel code released into memory
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 The offset of the kernel code relative to the DDR physical memory, that is, the kernel linear address offset [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);//So/proc/ Iomem can see the information set up here.
Request_resource (res, code_resource);
Request_resource (res, data_resource);
Request_resource (res, bss_resource);
==> Request_resource (&iomem_resource, &video_ram_resource);
[Email protected]:~$ 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
Above the
00100000-00575553:kernel Code
is the kernel code store.
0x00100000 equals 1048576.
0x00575553 equals 5723475.
[Email protected]:~$ sudo dd bs=1 skip=1048576 count=208 if=/dev/mem 2>/dev/null | Xxd-g 1
0000000:f6-All-in-one, 0f, 8e (email protected). T.
0000010:b8 8e D8 8e C0 8e E0 8e E8 FC to C0 ......... 1.
0000020:BF A0 Bayi B9 A0 8a xx F9 C1 E9, F3 ......) .....
0000030:ab BF c0 7c B9 xx xx FC F3 A5 8b 35 ... V| ..... 5
0000040:e8 7c f6 0c BF e0 2a 7c xx b9 00 02. x|.!. T...*| ....
0000050:00 f3 A5, Bayi 3d C6 7c, Geneva, A1 1c f.= .... X|...R.
0000060:FC (7c) 3d (22) (0e 8b 04 85 80). X|. =....s ... "
0000070:7c 2d xx c0 ff E0 0f 0b BF 00 | -.............
0000080:ba A0 Bayi xx B8, xx xx 8d 4f, 89, 0a, ..... Og ...
0000090:8a 0c xx C2 b9 xx xx 00, AB 05 ............
00000A0:10 XX E2 f8 BD a4 xx E8, DC, C7 ...... 9.R ...
00000b0:00 xx C0 3d a5 c1 e8 0c A3 ....... T.......
00000c0:81 B8 b0 a3 FC af Bayi XX E9 6d 6b ... g.........mkf
Only kernel linear address space below high-end memory can be accessed via/dev/mem