免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: woimm
打印 上一主题 下一主题

linux内存管理问题求助 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2011-10-31 20:19 |只看该作者
给你个例子,这种东西ldd3的例子里有很多

另外,你的题目不准确,这个顶多是内核一个功能的应用,还谈不上是内存管理的问题


// Linux Device Driver Template/Skeleton with mmap
// Kernel Module

#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#include <linux/wrapper.h>
#endif
#define SKELETON_MAJOR 240
#define SKELETON_NAME "skeleton"
#define CASE1 1
#define CASE2 2
static unsigned int counter = 0;
static char string [128];
static int data;
//#define USEASCII
#ifdef USEASCII
static char *kmalloc_area = NULL;
static char *kmalloc_ptr = NULL;
#else
static unsigned int *kmalloc_area = NULL;
static unsigned int *kmalloc_ptr = NULL;
#endif
#define LEN (64*1024)
unsigned long virt_addr;
DECLARE_WAIT_QUEUE_HEAD(skeleton_wait);
static int data_not_ready = 0;
// open function - called when the "file" /dev/skeleton is opened in userspace
static int skeleton_open (struct inode *inode, struct file *file) {
printk("skeleton_openn";
// we could do some checking on the flags supplied by "open"
// i.e. O_NONBLOCK
// -> set some flag to disable interruptible_sleep_on in skeleton_read
return 0;
}
// close function - called when the "file" /dev/skeleton is closed in userspace  
static int skeleton_release (struct inode *inode, struct file *file) {
printk("skeleton_releasen";
return 0;
}
// read function called when from /dev/skeleton is read
static ssize_t skeleton_read (struct file *file, char *buf,
  size_t count, loff_t *ppos) {
int len, err;

// check if we have data - if not, sleep
// wake up in interrupt_handler
while (data_not_ready) {
  interruptible_sleep_on(&skeleton_wait);
}
//data_not_ready = 1;

if( counter <= 0 )
  return 0;
err = copy_to_user(buf,string,counter);
if (err != 0)
  return -EFAULT;
len  = counter;
counter = 0;
return len;
}
// write function called when to /dev/skeleton is written
static ssize_t skeleton_write (struct file *file, const char *buf,
  size_t count, loff_t *ppos) {
int err;
err = copy_from_user(string,buf,count);
if (err != 0)
  return -EFAULT;
counter += count;
return count;
}
// ioctl - I/O control
static int skeleton_ioctl(struct inode *inode, struct file *file,
  unsigned int cmd, unsigned long arg) {
int retval = 0;
switch ( cmd ) {
  case CASE1:/* for writing data to arg */
   if (copy_from_user(&data, (int *)arg, sizeof(int)))
   return -EFAULT;
   break;
  case CASE2:/* for reading data from arg */
   if (copy_to_user((int *)arg, &data, sizeof(int)))
   return -EFAULT;
   break;
  default:
   retval = -EINVAL;
}
return retval;
}
#ifndef VMALLOC_VMADDR
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#endif
// From: http://www.scs.ch/~frey/linux/memorymap.html
volatile void *virt_to_kseg(volatile void *address) {
pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;
unsigned long va, ret = 0UL;
va=VMALLOC_VMADDR((unsigned long)address);
/* get the page directory. Use the kernel memory map. */
pgd = pgd_offset_k(va);
/* check whether we found an entry */
if (!pgd_none(*pgd)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
  /* get the page middle directory */
  pmd = pmd_offset(pgd, va);
#else
  // I'm not sure if we need this, or the line for 2.4
  //    above will work reliably too
  // If you know, please email me
  pud_t *pud = pud_offset(pgd, va);  
  pmd = pmd_offset(pud, va);
#endif
  /* check whether we found an entry */
  if (!pmd_none(*pmd)) {
   /* get a pointer to the page table entry */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
   ptep = pte_offset(pmd, va);
#else
   ptep = pte_offset_map(pmd, va);
#endif
   pte = *ptep;
   /* check for a valid page */
   if (pte_present(pte)) {
    /* get the address the page is refering to */
    ret = (unsigned long)page_address(pte_page(pte));
    /* add the offset within the page to the page address */
    ret |= (va & (PAGE_SIZE -1));
   }
  }
}
return((volatile void *)ret);
}
static int skeleton_mmap(struct file * filp, struct vm_area_struct * vma) {
int ret;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
ret = remap_page_range(vma->vm_start,
   virt_to_phys((void*)((unsigned long)kmalloc_area)),
   vma->vm_end-vma->vm_start,
   PAGE_SHARED);
//          vma->vm_page_prot);
#else
        ret = remap_pfn_range(vma,
               vma->vm_start,
               virt_to_phys((void*)((unsigned long)kmalloc_area)) >> PAGE_SHIFT,
               vma->vm_end-vma->vm_start,
               PAGE_SHARED);
//               vma->vm_page_prot);
#endif
if(ret != 0) {
  return -EAGAIN;
}
return 0;
}
// define which file operations are supported
struct file_operations skeleton_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read  = skeleton_read,
.write = skeleton_write,
.readdir = NULL,
.poll  = NULL,
.ioctl = skeleton_ioctl,
.mmap  = skeleton_mmap,
.open  = skeleton_open,
.flush = NULL,
.release = skeleton_release,
.fsync = NULL,
.fasync = NULL,
.lock  = NULL,
//.readv = NULL,
//.writev = NULL,
};
// initialize module
static int __init skeleton_init_module (void) {
int i;
#ifndef USEASCII
int tmp, tmp2;
#endif
printk("initializing modulen/n";

i = register_chrdev (SKELETON_MAJOR, SKELETON_NAME, &skeleton_fops);
if (i != 0) return - EIO;

// reserve memory with kmalloc - Allocating Memory in the Kernel
kmalloc_ptr = kmalloc(LEN + 2 * PAGE_SIZE, GFP_KERNEL);
if (!kmalloc_ptr) {
  printk("kmalloc failedn/n";
  return 0;
}
#ifdef USEASCII
kmalloc_area = (char *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);
#else
kmalloc_area = (unsigned int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);
#endif
for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;
  virt_addr+=PAGE_SIZE) {
   // reserve all pages to make them remapable
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
   mem_map_reserve(virt_to_page(virt_addr));
#else
   SetPageReserved(virt_to_page(virt_addr));
#endif
}
printk("kmalloc_area at 0x%p (phys 0x%lx)/n", kmalloc_area,
  virt_to_phys((void *)virt_to_kseg(kmalloc_area)));
#ifdef USEASCII
// fill allocated memory with 0123456789 ascii
for( i = 48; i < 58; i++) {
  kmalloc_ptr[i-48] = (char)i;
}
i = 0;
kmalloc_ptr[58-48] = (char)i;
#else
// fill allocated memory with integers
tmp = sizeof(int);
for( i = 0; i < (10 * tmp); i = i + tmp) {
  kmalloc_ptr = (unsigned int)i;
      
  tmp2 = (unsigned int)kmalloc_ptr;
  printk("kmalloc_ptr[%d]=%d/n", i, tmp2);
}
#endif
return 0;
}
// close and cleanup module
static void __exit skeleton_cleanup_module (void) {
printk("cleaning up modulen";
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;
  virt_addr+=PAGE_SIZE) {
   // clear all pages
   ClearPageReserved(virt_to_page(virt_addr));
}
#endif
kfree(kmalloc_ptr);
unregister_chrdev (SKELETON_MAJOR, SKELETON_NAME);
}
module_init(skeleton_init_module);
module_exit(skeleton_cleanup_module);
MODULE_AUTHOR("www.captain.at";
MODULE_LICENSE("GPL";
MODULE_DESCRIPTION("Linux Device Driver Template with MMAP";


---------------Makefile----------------------
obj-m:=skeleton.o


-----------------测试程序----------------------



// Linux Device Driver Template/Skeleton with mmap
// Userspace test program
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#define CASE1 1
#define CASE2 2
#define BUFSIZE 64*1024
//extern  void hello(void);
extern  global;
//#define USEASCII
main() {
int i, fd, len, wlen, tmp, tmp2;
char string[] = "Skeleton Kernel Module Test";
char receive[128];
int data, rdata;
char * mptr;
size_t size = BUFSIZE;
#ifdef USEASCII
printf("USEASCII/n";
char buffer[BUFSIZE];
#else
printf("NO  USEASCII/n";
unsigned int buffer[BUFSIZE];
#endif
printf("global=%d/n",global);
hello();
printf("global=%d/n",global);
fd = open("/dev/skeleton", O_RDWR | O_SYNC);
if( fd == -1) {
  printf("open error.../n");
  exit(0);
}
// test device write function
wlen = strlen(string) + 1;
len = write(fd, string, wlen);
if( len == -1 ) {
  printf("write error.../n");
  exit(1);
}
printf("String '%s' written to /dev/skeleton/n", string);

// test device read function
len = read(fd, receive, 12;
if( len == -1 ) {
  printf("read error...n");
  exit(1);
}
printf("String '%s' read from /dev/skeleton/n", receive);
// test mmap
mptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
if(mptr == MAP_FAILED) {
  printf("mmap() failed/n");
  exit(1);
}
// write something into the kernel device driver memory allocated by kmalloc
// memcpy(mptr, "Hello World!", 13);
// clear our local buffer
memset(buffer, 0, size);
// read from the kmalloc area in kernel space
memcpy(buffer, mptr, size-1);
#ifdef USEASCII
printf("mmap: '%s'/n", buffer);
#else
tmp = sizeof(int);
for( i = 0; i < (10 * tmp); i = i + tmp) {
  tmp2 = (unsigned int)buffer;
  printf("buffer[%d]=%d/n", i, tmp2);
}
#endif
// test ioctl
data = 0x55555555;
ioctl(fd, CASE1, &data);
ioctl(fd, CASE2, &rdata);
printf("IOCTL test: written: '%x' - received: '%x'/n", data, rdata);
munmap(mptr, size);
close(fd);
}

论坛徽章:
0
12 [报告]
发表于 2011-11-01 17:31 |只看该作者
多谢,我的代码是完全在内核里面运行的,和上层无关的.
该问题现在已经解决:
down_write(&current->mm->mmap_sem);
        this->mux_trans_buf = (BYTE*)do_mmap_pgoff(0, 0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE, 0);
up_write(&current->mm->mmap_sem);

this->mux_trans_buf 变量就包含了current的用户空间的地址.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP