• LINUX内核内存管理kmalloc,vmalloc


    一.kmalloc与vmallco

        在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,释放内存用的是kfree,vfree,kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要. 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA。vmalloc函数的工作方式类似于kmalloc,只不过前者分配的内存虚拟地址是连续的,而物理地址则无需连 续。通过vmalloc获得的页必须一个一个地进行映射,效率不高, 因此,只在不得已(一般是为了获得大块内存)时使用。vmalloc函数返回一个指针,指向逻辑上连续的一块内存区,其大小至少为size。在发生错误 时,函数返回NULL。vmalloc可能睡眠,因此,不能从中断上下文中进行调用,也不能从其它不允许阻塞的情况下调用。要释放通过vmalloc所获 得的内存,应使用vfree函数

        vmalloc和kmalloc的分配内存的特点大概如下:

            

      区别大概可总结为:

          1,vmalloc分配的一般为高端内存,只有当内存不够的时候才分配低端内存;kmallco从低端内存分配。

          2,vmalloc分配的物理地址一般不连续,而kmalloc分配的地址连续,两者分配的虚拟地址都是连续的;

          3,vmalloc分配的一般为大块内存,而kmaooc一般分配的为小块内存,(一般不超过128k);

       

    二.DMA工作

        为了减少CPU对快速设备入出的操作,可以通过把这 批数据的传输过程交由一块专用的接口卡(DMA接口)来控制,让DMA卡代替CPU控制在快速设备与主存储器之间直接传输数据,其大概工作的机制是在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了 CPU资源占有率。

        工作示意图大概如下:

                

        以下是测试的代码:

              

      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
    ");
     41 
     42     printk("KERNEL SPACE: read from d0003000: %s
    ", 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
    ", 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
    ", 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
    ", 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
    ");
     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为真)

  • 相关阅读:
    JS笔记009
    JS笔记008
    JS笔记007
    JS笔记006
    JS笔记005
    JS笔记004
    JS笔记003
    JS笔记001
    CSS3笔记012
    expdp SYNONYM of publick and schema owner
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4533960.html
Copyright © 2020-2023  润新知