一.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爲真)