Dynamically passes the physical address and size of the kernel space to user space. This article also demonstrates two common methods that can be used for communication between kernel space and user space: Proc file system and Mmap shared memory.
The entire kernel module, when the module inserts, establishes the proc file, allocates the memory. When the module is unloaded, the content written by the user space is printed.
Here is the code for the kernel module and the test code for user space.
/*this program are used to allocate memory in kernel and pass the physical address to userspace through proc file.*/
#include <linux/version.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/mm.h>
#define PROC_MEMSHARE_DIR "Memshare" #define PROC_MEMSHARE_PHYADDR "Phymem_addr" #define PROC_MEMSHARE_SIZE "Phymem_size"
/*alloc one page. 4096 bytes*/ #define Page_order 0 /*this value can get from page_order*/ #define PAGES_NUMBER 1
struct Proc_dir_entry *proc_memshare_dir; unsigned long kernel_memaddr = 0; unsigned long kernel_memsize= 0;
static int proc_read_phymem_addr (char *page, Char **start, off_t off, int count) { return sprintf (page, "%08lx/n", __pa (KERNEL_MEMADDR)); } static int proc_read_phymem_size (char *page, Char **start, off_t off, int count) { return sprintf (page, "%lu/n", kernel_memsize); }
static int __init init (void) { /*build proc dir "Memshare" and two proc files:phymem_addr, phymem_size in the dir*/ Proc_memshare_dir = Proc_mkdir (Proc_memshare_dir, NULL); Create_proc_info_entry (proc_memshare_phyaddr, 0, Proc_memshare_dir, proc_read_phymem_addr); Create_proc_info_entry (proc_memshare_size, 0, Proc_memshare_dir, proc_read_phymem_size);
/*alloc One page*/ Kernel_memaddr =__get_free_pages (Gfp_kernel, Page_order); if (!KERNEL_MEMADDR) { PRINTK ("Allocate memory failure!/n"); } Else { Setpagereserved (Virt_to_page (KERNEL_MEMADDR)); In the kernel after the application to the page, to call the setpagereserved, the equivalent of telling the system, this page I already accounted for. You should do this for every page you apply to.
Kernel_memsize = Pages_number * page_size; PRINTK ("Allocate memory success!.") The PHY mem addr=%08lx, size=%lu/n ", __pa (KERNEL_MEMADDR), kernel_memsize); } return 0; }
static void __exit fini (void) { PRINTK ("The content written by user is:%s/n", (unsigned char *) kernel_memaddr); Clearpagereserved (Virt_to_page (KERNEL_MEMADDR)); Free_pages (KERNEL_MEMADDR, Page_order); Remove_proc_entry (PROC_MEMSHARE_PHYADDR, Proc_memshare_dir); Remove_proc_entry (Proc_memshare_size, Proc_memshare_dir); Remove_proc_entry (Proc_memshare_dir, NULL);
Return } Module_init (init); Module_exit (fini); Module_license ("GPL"); Module_author ("Godbach ([Email]nylzhaowei@163.com[/email])"); Module_description ("Kernel memory Share module."); |
Test code for User space:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/mman.h>
int main (int argc, char* argv[]) { if (argc!= 2) { printf ("Usage:%s string/n", argv[0]); return 0; }
unsigned long phymem_addr, phymem_size; Char *map_addr; Char s[256]; int FD;
/*get the physical address of allocated memory in kernel*/ FD = open ("/proc/memshare/phymem_addr", o_rdonly); if (FD < 0) { printf ("Cannot open file/proc/memshare/phymem_addr/n"); return 0; } Read (fd, S, sizeof (s)); SSCANF (S, "%LX", &phymem_addr); Close (FD);
/*get the size of allocated memory in kernel*/ FD = open ("/proc/memshare/phymem_size", o_rdonly); if (FD < 0) { printf ("Cannot open file/proc/memshare/phymem_size/n"); return 0; } Read (fd, S, sizeof (s)); SSCANF (S, "%lu", &phymem_size); Close (FD);
printf ("Phymem_addr=%lx, phymem_size=%lu/n", phymem_addr, phymem_size); /*memory map*/ int map_fd = open ("/dev/mem", O_RDWR); if (MAP_FD < 0) { printf ("Cannot open file/dev/mem/n"); return 0; }
map_addr = mmap (0, Phymem_size, prot_read| Prot_write, map_shared, MAP_FD, phymem_addr); strcpy (MAP_ADDR, argv[1]); Munmap (MAP_ADDR, phymem_size); Close (MAP_FD); return 0;
} |
The kernel of the test is 2.6.25. The following are the results of the execution.
debian:/home/km/memshare# Insmod Memshare_kernel.ko debian:/home/km/memshare#./memshare_user ' hello,world! ' phymem_addr=e64e000, phymem_size=4096 debian:/home/km/memshare# cat/proc/memshare/phymem_addr 0e64e000 debian:/home/km/memshare# cat/proc/memshare/phymem_size 4096 debian:/home/km/memshare# Rmmod Memshare_kernel debian:/home/km/memshare# tail/var/log/messages Sep 18:14:24 Debian kernel: [50527.567931] Allocate memory success!. The PHY mem addr=0e64e000, size=4096 Sep 18:15:31 Debian kernel: [50592.570986] The content written by user is:hello,world! |
In this way, you want to apply for 4M of memory,
static int __init init (void)
{
char * PADDR;
int order = 0;
int offset = 0;
int tmp = 0;
/*build proc dir "Memshare" and two proc files:phymem_addr, phymem_size in the dir*/
Proc_memshare_dir = Proc_mkdir (Proc_memshare_dir, NULL);
Create_proc_info_entry (proc_memshare_phyaddr, 0, Proc_memshare_dir, proc_read_phymem_addr);
Create_proc_info_entry (proc_memshare_size, 0, Proc_memshare_dir, proc_read_phymem_size);
/*alloc One page*/
Kernel_memaddr =__get_free_pages (Gfp_kernel, Page_order);
[Color=royalblue] order = Get_order (4000000);
Kernel_memaddr =__get_free_pages (Gfp_kernel, order);
[/color]
if (!KERNEL_MEMADDR)
{
PRINTK ("Allocate memory failure!/n");
}
Else
{
Setpagereserved (Virt_to_page (KERNEL_MEMADDR));
Kernel_memsize = Pages_number * page_size;
[Color=royalblue] kernel_memsize = ((4000000-1) >> page_shift) * page_size; [/color]
[Color= #4169e1] [/color]
[Color=black] ... [/color]
[Color=black]} [/color]
[Color=black] [/color]
[Color=black] [/color]
I write the data to the first page (4k range) in the kernel, which can be read in the user state, but if you write the data to another page in the future, the user state will not be able to attend it.
This is also true for user state writes.
needs to be performed on each 4k page: setpagereserved (Virt_to_page (KERNEL_MEMADDR));
In the kernel after the application to the page, to call the setpagereserved, the equivalent of telling the system, this page I already accounted for. You should do this for every page you apply to.