Skip to content

Latest commit

 

History

History
313 lines (240 loc) · 6.91 KB

嵌入式系统设计实验报告四.md

File metadata and controls

313 lines (240 loc) · 6.91 KB
嵌入式系统设计实验报告
(四)




























作者:康赣鹏

学号:14130140377

Email:[email protected]

教师:朱光明


##内存分配与内存映射 ###一、实验目的

掌握字符设备驱动程序中利用nopage进行内存映射的方法。

掌握利用get_free_pages进行连续物理地址空间申请的方法。

###二、实验要求

按实验内容编写驱动程序及测试程序

编译驱动程序及测试程序

在嵌入式设备上加载驱动程序并进行测试

###三、实验内容

写一个简单的驱动程序,要求:

  • 在加载驱动程序时利用get_free_pages函数申请一片64KB的连续物理地址空间;
  • 利用nopage机制实现对申请到的64KB地址空间进行内存映射;
  • 编写应用程序利用mmap进行内存映射,读写映射内存区域,通过打印输出观察具体每个页面实际进行内存映射的时机;
  • 在卸载驱动程序时利用free_pages释放申请到的64KB空间

###四、实验步骤

参考《嵌入式系统设计》课程第09讲内容,根据实验内容要求设计编写驱动程序及应用程序

编译和加载驱动程序

运行应用程序进行驱动程序测试

卸载驱动程序

在docker上make成功

将文件通过网线和路由器将文件发送到树莓派中

动态加载模块 并查看当前模块

测试模块

Makefile: obj-m:=page.o ledmod-y:=page.o

KERNELBUILD:=../../linux-rpi-4.4.y/
ccflags-y := -std=gnu99


module: page.c
	$(MAKE) ARCH=arm -C $(KERNELBUILD)    M=$(shell pwd) modules ARCH=arm CROSS_COMPILE=armv7-rpi2-linux-gnueabihf-

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

测试程序:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fs.h>

int main() {

  char *buffer = NULL;

	int fd = open("/dev/page",O_RDWR);

  buffer = (char*)mmap(0,524288,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

	char buf[16] = "123456";
	bzero(buf,16);
  int i = 0;
  for(i=0;i<1;i++)
  {
    memcpy(buf,buffer+(unsigned int)(i*4096),15);
    printf("%s",buf);
  }
	close(fd);
}

代码清单:

#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/mm.h>

#define PAGE_COUNT (4)
#define PAGE_T_SIZE ((1 << PAGE_COUNT) * PAGE_SIZE)

struct led_dev {
  struct cdev cdev;
};


//// Datas
static unsigned int count=0;
static dev_t dev_id;
static unsigned int led_major = 0;
static struct led_dev* led_devs;

static char * pages;

static int rwbuf_open(struct inode *inode, struct file *filep) {
  if(count == 0 || pages == NULL) {
    pages = __get_free_pages(GFP_KERNEL,PAGE_COUNT);
    if(pages == NULL){
      printk("can not alloc\n");
      return -1;
    }
    printk("alloc\n");
  }
  int i = 0;
  for (i=0;i<16;i++)
  {
    *(pages+i)=i+40;
  }
  try_module_get(THIS_MODULE);
  ++ count;
  return 0;
}

// the close
static int rwbuf_close(struct inode *inode, struct file *filep)
{
  --count;
  printk("close %u",count);
  if(count == 0) {
    if(pages) {
      free_pages(pages,PAGE_COUNT);
      printk("free\n");
      pages = NULL;
    }
  }
  module_put(THIS_MODULE);
  return 0;
}


static ssize_t rwbuf_write(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = -ENOMEM;
  if(pages) {
    if (*f_pos < PAGE_T_SIZE) {
        len = count + *f_pos > PAGE_T_SIZE ? PAGE_T_SIZE - *f_pos : count;
        copy_from_user(pages + *f_pos,buf,len);
    }
    else {
        len = count > PAGE_T_SIZE ? PAGE_T_SIZE : count;
        copy_from_user(pages + *f_pos,buf,len);
    }
    *f_pos += len;
  }
  return len;
}

static ssize_t rwbuf_read(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = 0;
  if(pages) {
    if (*f_pos < PAGE_T_SIZE) {
        len = count + *f_pos > PAGE_T_SIZE ? PAGE_T_SIZE - *f_pos : count;
        copy_to_user(buf,pages + *f_pos,len);
    }
    *f_pos += len;
  }
  return len;
}

// vma
static void rwbuf_vma_open(struct vm_area_struct *vma) {
  printk("open, virt %lx, phys %lx\n",vma->vm_start, vma->vm_pgoff << PAGE_SHIFT);
}

static void rwbuf_vma_close(struct vm_area_struct *vma) {
  printk("close\n");
}

static struct page* rwbuf_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) {
  struct page *page;
  if (vmf->pgoff >= (1 << PAGE_COUNT))
    return VM_FAULT_SIGBUS;
  unsigned long viraddr = pages + (unsigned long)(vmf->virtual_address) - vma->vm_start  + (vma->vm_pgoff << PAGE_SHIFT);
  page = virt_to_page(viraddr);
  get_page(page);
  if (vma->vm_file)
    page->mapping = vma->vm_file->f_mapping;
  else
    printk(KERN_ERR "no mapping available\n");
  vmf->page = page;
  return 0;
}

static struct vm_operations_struct rwbuf_remap_vm_ops = {
 open  : rwbuf_vma_open,
 close : rwbuf_vma_close,
 fault : rwbuf_vma_fault,
};

static int rwbuf_fault_mmap(struct file *filp, struct vm_area_struct *vma) {
  unsigned long offset = vma -> vm_pgoff << PAGE_SHIFT;
  if(offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
    vma->vm_flags |= VM_IO;
  vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);

  vma->vm_ops = &rwbuf_remap_vm_ops;
  rwbuf_vma_open(vma);
  return 0;
}



// file operations
static struct file_operations rwbuf_fops = {
 open:    rwbuf_open,
 release: rwbuf_close,
 read:    rwbuf_read,
 write:   rwbuf_write,
 mmap:    rwbuf_fault_mmap,
};

//// MODULE INIT
static int init_ledc(void) {
  pages = NULL;
  count = 0;
  printk("start!\n");
  if(alloc_chrdev_region(&dev_id,0,1,"page")<0) {
	printk("fail alloc devices\n");
	return -1;
  }
  led_major = MAJOR(dev_id);
  led_devs = (struct led_dev*)kzalloc(sizeof(struct led_dev),GFP_KERNEL);
  if (led_devs == NULL) {
    printk("fail to create devs");
    return -1;
  }
  dev_t devno = MKDEV(led_major,0);
  cdev_init(&led_devs->cdev,&rwbuf_fops);
  led_devs->cdev.owner = THIS_MODULE;
  if(cdev_add(&led_devs->cdev,devno,1)) {
    printk("fail to add to devno");
    return -31;
  }
  return 0;
}

//// MODULE CLEANUP
static void exit_ledc(void) {
  printk("exit!\n");
  cdev_del(&led_devs->cdev);
  unregister_chrdev_region(dev_id,1);
  kfree(led_devs);
  if(pages) {
    free_pages(pages,PAGE_COUNT);
    printk("free");
  }
}

module_init(init_ledc);
module_exit(exit_ledc);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kangkang");