歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> linux內存管理概述(三)

linux內存管理概述(三)

日期:2017/2/25 10:38:11   编辑:Linux教程
 有兩種方法建立頁表:

  1使用remap_pfn_range函數一次全部建立,2或者通過nopage VMA方法每次建立一個頁表。

  int remap_pfn_range(struct vm_area_struct *vma,

  unsigned long virt_addr, /*重新映射時,起始用戶虛擬地址*/

  unsigned long pfn, /*頁幀號,phys_addr>>PAGE_SHIFT,更多用vma->vm_pgoff的值*/

  unsigned long size, /*以字節為單位*/

  pgprot_t prot); /*保護屬性,用vma->vm_page_prot的值*/

  int io_remap_page_range(struct vm_area_struct *vma,

  unsigned long virt_addr,

  unsigned long phys_addr, /*指向IO內存*/

  unsigned long size,

  pgprot_t prot);

  簡單的示例:

  static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)

  {

  if (remap_pfn_range(vma, vma->vm_start, vm->vm_pgoff,

  vma->vm_end - vma->vm_start,

  vma->vm_page_prot))

  return -EAGAIN;

  vma->vm_ops = &simple_remap_vm_ops;

  simple_vma_open(vma);

  return 0;

  }

  然後便是為VMA添加新操作:

  void simple_vma_open(struct vm_area_struct *vma)

  {

  printk(KERN_NOTICE "Simple VMA open, virt %lx, phys %lx\n",

  vma->vm_start, vma->vm_pgoff << PAGE_SHIFT);

  }

  void simple_vma_close(struct vm_area_struct *vma)

  {

  printk(KERN_NOTICE "Simple VMA close.\n");

  }

  static struct vm_operations_struct simple_remap_vm_ops = {

  .open = simple_vma_open,

  .close = simple_vma_close,

  };

  最後是在mmap中將默認的vm_ops指針替換為自己的操作:

  vma->vm_ops = &simple_remap_vm_ops;

  如果要支持mremap系統調用,就必須實現nopage函數。

  struct page *(*nopage)(struct vm_area_struct *vma,

  unsigned long address, /*包含引起錯誤的虛擬地址*/

  int *type);

  當用戶需要訪問VMA,而該頁又不在內存中時,將調用相關的nopage函數。

  remap_pfn_range函數的一個限制是:它只能訪問保留頁和超出物理內存的物理地址。(Linux中,在內存映射時,物理地址頁被標記為reserved,表示內存管理對其不起作用。如在PC中,640KB-1MB之間的內存被標記為保留的,因為這個范圍位於內核自身代碼的內部。)所以remap_pfn_range不允許重新映射常規地址。包括調用get_free_page函數所獲得的地址。相反,他能映射零內存頁。

  nopage函數可用於重新映射RAM。

  直接執行I/O訪問

  直接I/O開銷巨大,又沒有使用緩存I/O的優勢。無論如何在字符設備中執行直接I/O是不可行的。

  只有確定設置緩沖I/O的開銷特別巨大,才使用直接I/O。2.6內核的一個例子是SCSI磁帶機驅動程序,因為磁帶機傳輸通常是面向記錄的。

  通過下面的函數實現直接I/O:

  int get_user_pages(struct task_struct *tsk,

  struct mm_struct *mm,

  unsigned long start,

  int len,

  int write,

  int force,

  struct page **pages,

  struct vm_area_struct **vmas);

  如果調用成功,調用這就會擁有一個指向用戶空間緩沖區的頁數組,它將被鎖在內存中。為了能夠直接操作緩沖區,內核空間代碼必須用kmap函數將每個page結構指針轉換成內核虛擬地址。

  一旦直接I/O操作完成,就必須釋放用戶內存頁。

  直接內存訪問(DMA)

  the software asks for data (via a function such as read), the steps involved can be summarized as follows:

  When a process calls read, the driver method allocates a DMA buffer and instructs the hardware to transfer its data into that buffer. The process is put to sleep.

  The hardware writes data to the DMA buffer and raises an interrupt when it's done.

  The interrupt handler gets the input data, acknowledges the interrupt, and awakens the process, which is now able to read data.

  hardware asynchronously pushes data to the system,The steps are slightly different:

  The hardware raises an interrupt to announce that new data has arrived.

  The interrupt handler allocates a buffer and tells the hardware where to transfer its data.

  The peripheral device writes the data to the buffer and raises another interrupt when it's done.

  The handler dispatches the new data, wakes any relevant process, and takes care of housekeeping.

  高效的DMA處理依賴於中斷報告!

  分配的DMA緩沖區須使用線性物理內存區,用kmalloc及get_free_page函數,使用GFP_DMA標志。

Copyright © Linux教程網 All Rights Reserved