linux内核编程之内存寻址

note

内存寻址:虚拟地址映射到物理地址
x86虚拟地址到物理地址机制:分段+分页
linux为了增加通用性,没有分段机制,64位系统采用四级分页机制,也就是有四级页表
寻址过程:虚拟地址->第一级页目录->第二级页目录->第三级页目录->第四级页目录->页表项->物理地址

测试

v2p.c

/* 申请一个页面,然后按照虚拟地址到物理地址的寻页步骤,找到物理地址 */
/* 代码模拟mmu寻页过程 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/export.h>

static unsigned long cr0,cr3;
static unsigned long vaddr = 0; /*虚拟地址*/

static void get_pgtalbe_macro(void) {
    cr0 = read_cr0();
    cr3 = read_cr3_pa();
    printk("cr0:0x%lx,cr3:0x%lx\n", cr0, cr3);
    printk("PGDIR_SHIFT:%d\n", PGDIR_SHIFT);
    printk("P4D_SHIFT:%d\n", P4D_SHIFT);    /*四级页偏移*/
    printk("PUD_SHIFT:%d\n", PUD_SHIFT);    /*三级页偏移*/
    printk("PMD_SHIFT:%d\n", PMD_SHIFT);    /*二级页偏移*/
    printk("PAGE_SHIFT:%d\n", PAGE_SHIFT);  /*一级页映射对数*/
    printk("PTRS_PER_PGD:%d\n", PTRS_PER_PGD);
    printk("PTRS_PER_P4D:%d\n", PTRS_PER_P4D);
    printk("PTRS_PER_PUD:%d\n", PTRS_PER_PUD);
    printk("PTRS_PER_PMD:%d\n", PTRS_PER_PMD);
    printk("PTRS_PER_PTE:%d\n", PTRS_PER_PTE);
    printk("PAGE_MASK:0x%lx\n", PAGE_MASK);
}
/*虚拟地址->物理地址*/
static unsigned long vaddr2paddr(unsigned long vaddr) {
    pgd_t* pgd;
    p4d_t* p4d;
    pud_t* pud;
    pmd_t* pmd;
    pte_t* pte;
    unsigned long paddr = 0;
    unsigned long page_addr = 0;
    unsigned long page_offset = 0;
    pgd = pgd_offset(current->mm, vaddr);   /*所有内核进程共享页表,所以用当前进程current的页表*/
    printk("pgd_val:0x%lx, pgd_index:%lu\n", pgd_val(*pgd), pgd_index(vaddr));
    if (pgd_none(*pgd)) {
        printk("not mapping in pgd\n");
        return(-1);
    }
    p4d = p4d_offset(pgd, vaddr);
    printk("p4d_val:0x%lx, p4d_index:%lu\n", p4d_val(*p4d), p4d_index(vaddr));
    if (p4d_none(*p4d)) {
        printk("not mapping in p4d\n");
        return(-1);
    }
    pud = pud_offset(p4d, vaddr);
    printk("pud_val:0x%lx, pud_index:%lu\n", pud_val(*pud), pud_index(vaddr));
    if (pud_none(*pud)) {
        printk("not mapping in pud\n");
        return(-1);
    }
    pmd = pmd_offset(pud, vaddr);
    printk("pmd_val:0x%lx, pmd_index:%lu\n", pmd_val(*pmd), pmd_index(vaddr));
    if (pmd_none(*pmd)) {
        printk("not mapping in pmd\n");
        return(-1);
    }
    pte = pte_offset_kernel(pmd, vaddr);
    printk("pte_val:0x%lx, pte_index:%lu\n", pte_val(*pte), pte_index(vaddr));
    if (pte_none(*pte)) {
        printk("not mapping in pte\n");
        return(-1);
    }
    page_addr = pte_val(*pte) & PAGE_MASK;
    page_offset = vaddr & ~PAGE_MASK;
    paddr = page_addr | page_offset;
    printk("page_addr:%lx,page_offset:%lx\n", page_addr, page_offset);
    printk("vaddr:%lx,paddr:%lx\n", vaddr, paddr);
    return(paddr);
}
static int __init v2p_init(void) {
    unsigned long vaddr = 0;
    printk("v2p_init\n");
    get_pgtalbe_macro();
    vaddr = __get_free_page(GFP_KERNEL);    /* 获取空闲内存页 */
    if (vaddr == 0) {
        printk("__get_free_page error\n");
        return(0);
    }
    printk("__get_free_page return:%lx\n", vaddr);
    sprintf((char*)vaddr, "this is v2p_module"); // 往虚拟地址写入内容,将在物理地址读取到
    vaddr2paddr(vaddr);
    return(0);
}
static void __exit v2p_exit(void) {
    printk("v2p_exit\n");
    free_page(vaddr);
}

module_init(v2p_init);
module_exit(v2p_exit);
MODULE_LICENSE("GPL");

效果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值