linux内核空间申请超过2MB连续空间的实现函数。

 /*
kmalloc can apply 128KB memory only. This func support any continous memory allocate more than 2MB.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>


#define KMEM_PAGES        //apply more than one page
#define KMEM_DEBUG        //debug message switch

/*
// Pure 2^n version of get_order
static __inline__ __attribute_const__ int get_order(unsigned long size)
{
    int order;

    size = (size - 1) >> (PAGE_SHIFT - 1);
    order = -1;
    do {
        size >>= 1;
        order++;
    } while (size);
    return order;
}
*/

/*
alloc memory for DMA using in kernel space.
*/
void *kmem_alloc(size_t size, dma_addr_t *dma_handle, unsigned long flags)
{
    struct page *page;        //start page address
    void *cpu_addr = NULL;        //cpu io address
    struct page *end;        //end of pages
    unsigned int  PageOrder=0;
    
    size = PAGE_ALIGN(size);    //must be times of 4KB
    PageOrder=get_order(size);
#ifdef CONFIG_ISOLATE_HIGHMEM        //allocate in high memory
    page = alloc_pages(GFP_HIGHUSER, PageOrder);
#else                                //allocate from low memory
    page = alloc_pages(GFP_KERNEL, PageOrder);        //get_order(size) means how many 4KB page do you want to apply. 2^n
#endif
    if(!page) {
    err("alloc_pages fail! (requested %#x)", size);
    goto no_page;
    }
#ifdef KMEM_DEBUG
    printk("kmem_alloc 0x%x size 0x%x,order=%d/n",page_to_phys(page),size,PageOrder);
#endif

    *dma_handle =  page_to_phys(page);    //transform to physical address
 
    cpu_addr = __ioremap(*dma_handle, size, flags, 1);        //map to kernal io space
    
    if(cpu_addr) {
#ifdef KMEM_PAGES
        end = page + (1 << PageOrder);        //count to get the last page
        do {
            set_page_count(page, 1);            //only one user
            SetPageReserved(page);            //set page used flag
            page++;
        } while (size -= PAGE_SIZE);

        /*
         * Free the unused pages. get_order(size) means 2^n to apply, so there must be more pages to alloc than we want.
         */
        while (page < end) {
            set_page_count(page, 1);
            if (!PageReserved(page) && put_page_testzero(page))
                free_cold_page(page);        //only we can use this func to free page
            page++;
        }
#else        //just apply one page
        set_page_count(page, 1);
        SetPageReserved(page);
#endif
    }
    else {
    __free_pages(page, PageOrder);        //free more than one pages
    err("__ioremap fail! (phy %#x)", *dma_handle);
    }
 no_page:
    return cpu_addr;
}
EXPORT_SYMBOL(kmem_alloc);

void kmem_free(size_t size, void *cpu_addr, dma_addr_t handle)
{
    struct page *page = pfn_to_page(handle >> PAGE_SHIFT);        //equal to phys_to_pages()
    struct page *pg;
    unsigned int sz;
    
    pg=page;
    sz=PAGE_ALIGN(size);
#ifdef KMEM_DEBUG
    printk("kmem_free 0x%x size 0x%x/n",page_to_phys(pg),sz);
#endif

    __iounmap(cpu_addr);        //un map from kernel io space

#ifdef KMEM_PAGES
    do {
        ClearPageReserved(page);
        if (!PageReserved(page) && put_page_testzero(page))
            free_cold_page(page);
        page++;
    } while (sz -= PAGE_SIZE);

#else
    ClearPageReserved(page);
    if (!PageReserved(page) && set_page_count(page, 0))
        __free_pages_ok(page,get_order(size));
#endif


}

EXPORT_SYMBOL(kmem_free);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草根大哥

进军大神程序员路上,谢谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值