LINUX內核內存管理kmalloc,vmalloc

一.kmalloc與vmallcolinux

    在設備驅動程序或者內核模塊中動態開闢內存,不是用malloc,而是kmalloc ,vmalloc,釋放內存用的是kfree,vfree,kmalloc函數返回的是虛擬地址(線性地址). kmalloc特殊之處在於它分配的內存是物理上連續的,這對於要進行DMA的設備十分重要. 而用vmalloc分配的內存只是線性地址連續,物理地址不必定連續,不能直接用於DMA。vmalloc函數的工做方式相似於kmalloc,只不過前者分配的內存虛擬地址是連續的,而物理地址則無需連 續。經過vmalloc得到的頁必須一個一個地進行映射,效率不高, 所以,只在不得已(通常是爲了得到大塊內存)時使用。vmalloc函數返回一個指針,指向邏輯上連續的一塊內存區,其大小至少爲size。在發生錯誤 時,函數返回NULL。vmalloc可能睡眠,所以,不能從中斷上下文中進行調用,也不能從其它不容許阻塞的狀況下調用。要釋放經過vmalloc所獲 得的內存,應使用vfree函數編程

    vmalloc和kmalloc的分配內存的特色大概以下:app

        

  區別大概可總結爲:函數

      1,vmalloc分配的通常爲高端內存,只有當內存不夠的時候才分配低端內存;kmallco從低端內存分配。測試

      2,vmalloc分配的物理地址通常不連續,而kmalloc分配的地址連續,二者分配的虛擬地址都是連續的;spa

      3,vmalloc分配的通常爲大塊內存,而kmaooc通常分配的爲小塊內存,(通常不超過128k);指針

   

二.DMA工做code

    爲了減小CPU對快速設備入出的操做,能夠經過把這 批數據的傳輸過程交由一塊專用的接口卡(DMA接口)來控制,讓DMA卡代替CPU控制在快速設備與主存儲器之間直接傳輸數據,其大概工做的機制是在DMA模式下,CPU只須向DMA控制器下達指令,讓DMA控制器來處理數據的傳送,數據傳送完畢再把信息反饋給CPU,這樣就很大程度上減輕了 CPU資源佔有率。orm

    工做示意圖大概以下:blog

            

 

    如下是測試的代碼:

          

  1 #include <linux/init.h>
  2 #include <linux/thread_info.h>
  3 #include <linux/module.h>
  4 #include <linux/sched.h>
  5 #include <linux/errno.h>
  6 #include <linux/kernel.h>
  7 #include <linux/module.h>
  8 #include <linux/slab.h>
  9 #include <linux/input.h>
 10 #include <linux/init.h>
 11 #include <linux/serio.h>
 12 #include <linux/delay.h>
 13 #include <linux/clk.h>
 14 #include <linux/miscdevice.h>
 15 #include <linux/io.h>
 16 #include <linux/ioport.h>
 17 #include <linux/vmalloc.h>
 18 #include <linux/dma-mapping.h>
 19 #include <linux/export.h>
 20 #include <linux/gfp.h>
 21 
 22 #include <asm/dma-mapping.h>
 23 #include <asm/uaccess.h>
 24 
 25 #include <linux/gpio.h>
 26 #include <mach/gpio.h>
 27 #include <plat/gpio-cfg.h>
 28 
 29 MODULE_LICENSE("GPL");
 30 MODULE_AUTHOR("bunfly");
 31 
 32 
 33 unsigned long vmalloc_to_pfn(const void *vmalloc_addr);
 34 int test_init()
 35 {
 36     int ret = 0;
 37     unsigned char *vmalloc_virt, *normal_virt, *phys;
 38     unsigned long pfn;
 39 
 40     printk("KERNEL SPACE: init\n");
 41 
 42     printk("KERNEL SPACE: read from d0003000: %s\n", 0xd0003000);
 43     //讀出d0003000虛擬地址裏面的數據
 44 
 45     normal_virt = kmalloc(40, GFP_KERNEL);
 46     //kmalloc分配一段虛擬地址,大小,睡眠不可中斷
 47 
 48     phys = virt_to_phys(normal_virt);
 49     printk("KMAKLLOC: kmalloc virt: %p <==> phys: %p\n", normal_virt, phys);
 50 
 51     kfree(normal_virt);
 52 
 53     //分配頁
 54     //--------------------------------------
 55     vmalloc_virt = vmalloc(500);
 56     //vmalloc分配內存
 57 
 58     pfn = vmalloc_to_pfn(vmalloc_virt);
 59     //頁分配
 60     phys = (pfn << 12) | ((unsigned long)vmalloc_virt & 0xfff);
 61     //將頁地址轉換成物理地址
 62     normal_virt = phys_to_virt(phys);
 63     //再將物理地址轉換成虛擬地址
 64     printk("VMALLOC: vmalloc_virt = %p, normal_virt = %p\n", vmalloc_virt, normal_virt);
 65 
 66     //dma分配
 67     normal_virt = dma_alloc_coherent(NULL, 1024, &phys, GFP_KERNEL);
 68     printk("DMA: vmalloc_virt = %p, normal_virt = %p\n", vmalloc_virt,phys);
 69     dma_free_coherent(NULL, 1024, normal_virt, phys);
 70 
 71     vfree(vmalloc_virt);
 72     return 0;
 73 }
 74 
 75 void test_exit()
 76 {
 77     printk("KERNEL SPACE: exit\n");
 78 }
 79 
 80 module_init(test_init);
 81 module_exit(test_exit);
 82 
~                                                                                                                                                                                                                                                                                                                                                                                                                                  
~                                                                                                                                                                                                                                                                                                                                                                                                                                  
~  

      首先,在50003000地址放入數據,而後在d0003000的物理地址中讀出數據:

      

      查看50003000地址中的數據:

      

 

      啓動板子,插入模塊,運行結果:

       

      能夠看到kmalloc的物理地址是低端內存的,(從40000000開始),而vmalloc分配的物理地址是高端內存,而經過    DMA內存的也是低端一點的。

  補充說明:kmalloc函數原型:

   static __always_inline void *kmalloc(size_t size, gfp_t flags)
        其中falgs有

      

      主要的要分配兩種:通常都是

            GFP_KERNLE;內核使用內存--------能夠睡眠

            GFP_USER;   用戶空間內存;

            GFP_ATOMIC;  原子分配  ---------不能夠睡眠

    內核編程的法則:

        中斷上下文不能夠睡眠(能夠用is_inetrruput()函數查看是不是中斷處理調用函數,返回1爲真)

相關文章
相關標籤/搜索