Virtual Turn Physical Address Virt_to_phys (*ADDR);
Physical to Virtual address phys_to_virt (*ADDR);
Such as:
Long Pprotectva; phys_addr_t protectpa; = Pprotectva; = Virt_to_phys ((void *) pprotectva);
-------------------------------------------------
The/dev/mem driver provided in the Linux kernel provides a channel for us to read and write memory physical addresses. Here are 2 ways to use MEM device files to read and write physical addresses, one is device-driven, the other is the method of system invocation.
First we look at the mem this device file,/dev/mem is a character device under Linux, the source file is ~/DRIVERS/CHAR/MEM.C, this device file is specifically used to read and write physical address. The contents are the address of all physical memory and the content information. Typically, only the root user has read and write access to it.
1. Device-driven methods
The following is the file_operations structure defined in the MEM.C file, which provides methods such as Llseek,read,write,mmap and open.
static struct File_operations mem_fops =
{
. Llseek = Memory_lseek,
. Read = Read_mem,
. write = Write_mem,
. mmap = Mmap_mem,
. open = Open_mem,
};
Therefore, we can use the general driving method to treat memory as a device completely. The application is as follows:
#include <stdio.h>
#include <fcntl.h>
int main (void)
{
int FD;
Char *rdbuf;
char *wrbuf = "Butterfly";
int i;
FD = open ("/dev/mem", O_RDWR);
if (FD < 0)
{
printf ("Open/dev/mem failed.");
}
Read (fd,rdbuf,10);
for (i = 0;i < 10;i++)
{
printf ("Old mem[%d]:%c\n", i,* (Rdbuf + i));
}
Lseek (fd,5,0);
Write (fd,wrbuf,10);
Lseek (fd,0,0);//move F_ops to the front
Read (fd,rdbuf,10);
for (i = 0;i < 10;i++)
{
printf ("New mem[%d]:%c\n", i,* (Rdbuf + i));
}
return 0;
}
The execution results are as follows: Replace the contents of the first 10 bytes of memory.
[email protected] app]#./memtest
Old Mem[0]:b
Old Mem[1]:u
Old Mem[2]:t
Old Mem[3]:t
Old Mem[4]:e
Old Mem[5]:r
Old Mem[6]:f
Old Mem[7]:l
Old Mem[8]:y
Old mem[9]:!
New MEM[0]:B
New Mem[1]:u
New Mem[2]:t
New Mem[3]:t
New Mem[4]:e
New MEM[5]:B
New Mem[6]:u
New Mem[7]:t
New Mem[8]:t
New Mem[9]:e
2. Method of System call
Careful you may find, since you said that the file is stored in the memory of the address and content information, then I can directly see it, the answer is: yes. The developer of the Linux kernel provides us with a command HexEdit to display the contents of the/dev/mem (if you use Cat/dev/mem, you will see garbled characters), and the results of the Hexedit/dev/mem execution are as follows:
00000000----------------------6C butterfly!
00000010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00000020 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00000030 6F EF F0 6F ef F0 (EF) F0 6F ef xx F0 o...o ... W...O ...
00000040 C0 4D F8 xx F0, F8 xx F0 .... M... A... 4 ...
00000050 E7 (F0) F8 F0 2E E8 xx F0 D2 EF F0 9...Y .....
00000060 A4 E7 xx F0 F2 E6 xx F0 6E FE F0 (FF) F0 ... n ... S ...
00000070-F0 A4 F0 F0 C7 EF F0 1C C0 S ....., ..... B..
From the visible, the leftmost display is the address, the next 24 columns display the ASCII code information of the contents of each memory byte cell, the rightmost display is the corresponding character information. It is gratifying that this file can be directly modified, press the TAB key to enter the modified mode, the changes in the process will be displayed in bold, press F2 saved after the bold disappears. The above butterfly is modified in this way.
Since the memory address and the content information are all stored in the MEM device file, then we can think of another way to achieve the physical address read and write. This is the use of MEM device files and mmap system calls together, the physical memory address in the file map to the address space of the process, so as to achieve the physical address of the memory to read and write. Let's talk about the mmap system call.
The function prototype for mmap is: void *mmap (void *start,size_t length,int prot,int flags,int fd,off_t offset), which is defined in/usr/include/sys/ Mman.h, when used to include: #include <sys/mman.h>,mmap () is used to map the contents of a file to the address space of the process, access to that space is read and write to the contents of the file. The parameters are described as follows:
Start: The starting address of the address space to which you want to map, usually set to null or 0. Indicates that the system automatically selects the address and the address is returned after the mapping is successful.
Length: Indicates the size of the mapped file content, in bytes.
Prot: Represents the protected mode of a mapped area, with the following four combinations:
The--prot_exec map area can be executed,
--prot_read map area is readable,
The--prot_write map area is writable,
--prot_none map area cannot be accessed
Flags: Some of the features of the map area, mainly:
--map_fixed If the mapping is unsuccessful, an error is returned,
--map_shared write data to the mapped area will be written back to the original file
--map_private write data to the mapped region will not be written back to the original file
--map_anonymous
--map_denywrite only allow write operations to mapped regions, other operations that write directly to the file will be rejected
--map_locked Lock Map Area
When calling Mmap (), you must specify Map_shared or Map_private.
Fd:open () returns the file descriptor.
Offset: The number of offsets for the mapped file, indicating where to start the mapping from where the file is, typically set to 0, which indicates that the mapping starts at the beginning of the file. Offset must be an integer multiple of the paging size (4096 bytes).
The application is as follows:
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>//mmap head file
int main (void)
{
int i;
int FD;
Char *start;
Char *buf = "butterfly!";
Open/dev/mem with Read and write mode
FD = open ("/dev/mem", O_RDWR);
if (FD < 0)
{
printf ("Cannot open/dev/mem.");
return-1;
}
Map Physical Memory 0-10 bytes
Start = (char *) mmap (0, Prot_read | Prot_write, map_shared, FD, 0);
if (Start < 0)
{
printf ("Mmap failed.");
return-1;
}
Read old value
for (i = 0; i <; i++)
{
printf ("Old mem[%d]:%c\n", I, * (start + i));
}
Write memory
memcpy (Start, buf, 10);
Read New Value
for (i = 0;i < 10;i++)
{
printf ("New mem[%d]:%c\n", i,* (start + i));
}
Munmap (start, 10); Destroy map memory
Close (FD); Close File
return 0;
}
The results of the program execution are as follows:
[email protected] app]#./rwphy
Old Mem[0]:b
Old Mem[1]:u
Old Mem[2]:t
Old Mem[3]:t
Old Mem[4]:e
Old Mem[5]:b
Old Mem[6]:u
Old Mem[7]:t
Old Mem[8]:t
Old Mem[9]:e
New MEM[0]:B
New Mem[1]:u
New Mem[2]:t
New Mem[3]:t
New Mem[4]:e
New Mem[5]:r
New Mem[6]:f
New Mem[7]:l
New Mem[8]:y
New mem[9]:!
"/dev/mem is a fun thing to do and you can access physical memory directly. This is very magical under Linux, this feeling like a thief intended to steal a bank, but the bank is heavily guarded, just as the thief had no countermeasures, suddenly found in a humble place there is a back door, the back door can be directly to the bank's coffers. ”
The difference between/dev/mem and/dev/kmem under Linux:
/dev/mem: Full mirroring of physical memory. Can be used to access physical memory.
/dev/kmem:kernel See the full image of the virtual memory. Can be used to access the content of kernel.
Role:
The/DEV/MEM is used to access physical IO devices, such as the physical memory used by x to access the graphics card, or to access the Gpio in embedded. The usage is usually open, then mmap, then you can use the address after map to access the physical memory. This is actually a way to implement user-driven space.
/dev/kmem The latter can generally be used to view kernel variables, or as rootkits. References 1 and 2 describe the problem used to view the kernel variable.
/dev/mem Usage Examples:
such as the drive (kernel space)
VIR_ADDR = Kmalloc (size, Gfp_kernel | GFP_DMA)
PHY_ADDR = __pa (VIR_ADDR);
Request a memory, then get __pa () to get its physical address, and then upload the physical address to the user space
Then in the application (user space)
int map_fd = open ("/dev/mem", O_RDWR);
map_addr = mmap (0, size, prot_read| Prot_write, map_shared, MAP_FD, phy_addr);
This gives you a pointer to the memory requested in the application's access driver map_addr, enabling applications and drivers to access the same segment of memory, save overhead, and implement memory sharing
This is a way to map kernel-space memory to user space, kernel-space memory--Physical Address (PA)--User space through/dev/mem and system calls Mmap
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include < fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h > #include <sys/poll.h> #include <sys/mman.h>int page_size #define PAGE_SIZE page_size#define Page_mask (~ (page_size-1)) void Get_var (unsigned long addr) {off_t ptr = addr & ~ (page_mask); off_t offset = addr & Page_mask ; int i = 0;char *map;static int kfd = -1;KFD = Open ("/dev/kmem", o_rdonly), if (KFD < 0) {perror ("open"); exit (0);} Map = mmap (Null,page_size,prot_read,map_shared,kfd,offset), if (MAP = = map_failed) {perror ("mmap"); exit (-1);} printf ("%s\n", map+ptr); return;} int main (int argc, char **argv) {FILE *fp;char addr_str[11]= "0x"; char var[51];unsigned long Addr;char ch;int r;if (argc! = 2) {fprintf (stderr, "Usage:%s system.map\n", argv[0]); exit (-1);} if (fp = fopen (Argv[1], "r")) = = NULL) {perror ("fopen"); exit (-1);} do {r = fscanf (FP, "%8s%c%50s\n", &addr_str[2],&ch,var); if (strcmp (Var, "Modprobe_path") ==0) break;} while (R > 0), if (R < 0) {printf ("Could not find modprobe_path\n"); exit (-1);} Page_size = GetPageSize (); addr = Strtoul (addr_str,null,16);p rintf ("Found Modprobe_path at (%s)%08lx\n", addr_str,addr) ; Get_var (addr);}
[CPP]View PlainCopy
- A piece of code in a foreign project:
- if (Fdmem = open ("/dev/mem", O_RDWR | O_sync)) = =-1)
- {
- fprintf (stderr, "Unable to open The/dev/mem interface!\n");
- return;
- }
- Map_base = mmap (0, map_size, Prot_read | Prot_write, map_shared, Fdmem, Gpio_addr & ~map_mask);
- if (map_base = = (void *)-1)
- {
- fprintf (stderr, "Unable to map 0x%08x address\n", gpio_addr);
- Close (FDMEM);
- return;
- }
- //ADD offset for init (VD0) = PORTC8
- VIRT_ADDR = Map_base + 0x20;
- //Configure GPIO
- Read_result = * ((unsigned long *) virt_addr);
- Read_result &= (~ (0x03 << 16));
- Read_result |= 0x01 << 16;
- * ((unsigned long *) virt_addr) = Read_result;
- //ADD offset for VD0
- VIRT_ADDR = Map_base + 0x24;
Direct read and write physical address memory under Linux