【Linux驱动】内存管理

关于linux内存管理的概念请参考笔者前面的博文:
linux内存管理(一)基础篇
linux内存管理(二)伙伴算法
linux内存管理(三)slab分配器

下面的驱动程序中的函数的区别,以及对应的函数介绍请参考第一个链接(linux内存管理基础篇)

#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/mm.h>

MODULE_LICENSE("Dual BSD/GPL");

#define DEBUG_SWITCH 1
#if DEBUG_SWITCH
    #define P_DEBUG(fmt, args...)  printk("<1>" "<kernel>[%s]"fmt,__FUNCTION__, ##args)
#else
    #define P_DEBUG(fmt, args...)  printk("<7>" "<kernel>[%s]"fmt,__FUNCTION__, ##args)
#endif

#define DEV_SIZE 20//方便测试写进程阻塞
#define WQ_MAJOR 230

struct page *p;
char *s, *kp;


static int __init wq_init(void)
{
    unsigned long virt, phys;

    kp = (char *)kmalloc(10, GFP_KERNEL);//分配10大小,实际上会分配16字节大小的内存,满足2^n
    if(NULL == kp)
    {
        P_DEBUG("kmalloc error\n");
        return -ENOMEM;
    }
    memcpy(kp, "hello world", 16);//将数据拷贝到分配的内存,这里故意大于10,为了测试

    printk("kello kernel, %s\n", kp);

#define SWITCH 0
#if SWITCH
    p = alloc_pages(GFP_KERNEL, 1);//2^1 = 2,分配两个页面大小,返回的是物理地址,不能直接用p访问

    if(NULL == p)
    {
        P_DEBUG("alloc_pages error\n");
        return -ENOMEM;
    }
    s = page_address(p);//将其转换为对应的虚拟地址,这样可以访问
#else
    s = (char *)__get_free_pages(GFP_KERNEL, 1);//分配2^1个页面,返回逻辑地址
    if(NULL == s)
    {
        P_DEBUG("__get_free_pages error\n");
        return -ENOMEM;
    }
#endif

    phys = __pa((unsigned long)s);//通过虚拟地址获得对应的物理地址
    virt = (unsigned long)__va(phys);//通过物理地址获得对应的虚拟地址

    printk("virtual address: %p\n", s);//打印分配后的虚拟地址
    printk("phys address: %p\n", (void *)phys);//打印转换后的物理地址
    printk("virt address: %p\n", (void *)virt);//打印再转换后的虚拟地址

    memcpy(s, "hello world", 16);//拷贝数据
    printk("hello kernel, %s\n", s);

    return 0;
}

static void  __exit wq_exit(void)
{
    vfree(kp);//释放
#if SWITCH
    __free_pages(p, 1);//释放函数必须与分配函数一一对应
#else
    free_pages((unsigned long)s, 1);
#endif

    printk("good bye kernel\n");
}

module_init(wq_init);
module_exit(wq_exit);

测试:直接加载模块,然后dmesg就可以看到结果。

你可能感兴趣的:(内存管理,linux驱动)