kmalloc物理内存地址和虚拟地址连续实例验证

先上代码,主要用到virt_to_phys,虚拟物理地址的转换方法。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>


static char *ptr;
int alloc_size = 1024;

struct stu
{
       int a;
       char *name;
       unsigned int size;
       unsigned int bb;
};

module_param(alloc_size, int, 0);

static int test_hello_init(void)
{
    struct stu *aa;
    ptr = kmalloc(alloc_size,GFP_ATOMIC);
    aa = kmalloc(alloc_size,GFP_ATOMIC);
    aa->a = 4;
    aa->name="zhang";
    aa->size=7;
    aa->bb=10;
    pr_err("memory_debug2 sself=%p, s=%p, %p, namepo%p %s, ssize:%u,%p, bbpointer:%p\n", &aa, aa, aa->name,&(aa->name), aa->name, aa->size, &(aa->size), &(aa->bb));
    pr_err("memory_debug3 s,name,size,bb:%llx,%llx,%llx,%llx\n", (unsigned long long)aa, (unsigned long long)(&(aa->name)), (unsigned long long)(&(aa->size)), (unsigned long long)(&(aa->bb)));
    if(!ptr) {
        /* handle error */
        pr_err("memory allocation failed\n");
        return -ENOMEM;
    } else {
        pr_info("Memory allocated successfully:%p\t%p\n", ptr, ptr+100);
        pr_info("Physical address:%llx\t %llx\n", virt_to_phys(ptr), virt_to_phys(ptr+100));
    }
    kfree(aa);
    return 0;
}

static void test_hello_exit(void)
{
    kfree(ptr);
    pr_info("Memory freed\n");

}
module_init(test_hello_init);
module_exit(test_hello_exit);
MODULE_LICENSE("GPL");

[   90.569094] <1>.(1)[7809:insmod]calling  test_hello_init+0x0/0x184 [mem] @ 7809
[   90.570143] <1>.(1)[7809:insmod]memory_debug2 sself=00000000d65661d1, s=0000000067d823c8, 000000008eb19172, namepo00000000b1b57255 zhang, ssize:7,000000001263649f, bbpointer:000000008acc5477
[   90.572310] <1>.(1)[7809:insmod]memory_debug3 s,name,size,bb:ffffffc028e99280,ffffffc028e99288,ffffffc028e99290,ffffffc028e99294
[   90.573794] <1>.(1)[7809:insmod]Memory allocated successfully:00000000b34a50e2       00000000058c7568
[   90.575044] <1>.(1)[7809:insmod]Physical address:68e98c80     68e98ce4
[   90.575875] <1>.(1)[7809:insmod]initcall test_hello_init+0x0/0x184 [mem] returned 0 after 5611 usecs

可以看到物理地址0x68e98ce4-0x68e98c80 =0x64,即kmalloc物理地址上是连续的;

可以看到虚拟地址0xffffffc028e99294-0xffffffc028e99290=0x4, 及kmalloc虚拟地址是连续的;

同时要注意:

在使用%p打印内核内存地址时,内核会尝试保护自己,不打印真实地址。相反,它会为该地址打印一个不同的散列唯一标识符。所以确实需要打印响应地址,你可以使用%px。

其他一些物理虚拟地址转换接口:

struct page * alloc_pages(gfp_mask, order) // 分配 1<<order 个连续的物理页

struct page * alloc_page(gfp_mask) // 分配一个物理页

返回page对应的逻辑地址的:

__get_free_pages(gfp_mask, order) // 和alloc_pages一样,只不过返回的是第一个页的内核逻辑地址

__get_free_page(gfp_mask) // 返回一个页的逻辑地址

page_address(pages); //page_address( )宏的功能是获得物理页的逻辑地址

page_to_phys

phys_to_page

//把内核态虚拟地址转成物理地址
#define __virt_to_phys(x)   (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
//把物理内存地址转成内核态虚拟地址
#define __phys_to_virt(x)   ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))


//把内核虚拟地址转成其内存单元对应page
#define virt_to_page(addr)  pfn_to_page(virt_to_pfn(addr))
//把内存单元对应page转成内核虚拟地址
#define page_to_virt(page)  pfn_to_virt(page_to_pfn(page))


//把内核态虚拟地址转成物理地址
#define __pa(x)         __virt_to_phys((unsigned long)(x))
//把物理地址转成内核态虚拟地址
#define __va(x)         ((void *)__phys_to_virt((phys_addr_t)(x)))
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

a2591748032-随心所记

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值