• Linux 内存虚实内存映射


    Linux 内存虚实内存映射@TOC

    以前关于虚拟地址和物理地址的学习只是在书本上,今天在实际的开发板上实践了一下

    代码:

    #include
    #include
    #include
    #include #include

    int g=0x100;

    static int __init tarzan_init(void)
    {
    int idx;
    pr_info(“tarzan_init\n”);
    int x=0x10;
    int pint = NULL;
    printk(“PHYS_OFFSET=0x%lx\r\n” , PHYS_OFFSET);
    printk(“max_mapnr:%d\r\n” , max_mapnr);
    printk(“high memory:0x%lx\r\n” , high_memory); //0xF000_0000 0xF000_0000- 0xC000_0000=0x3000_0000=768M
    printk(“high memory(768M) -> phy addr:0x%lx\r\n” , __pa(high_memory));
    pint = kmalloc(1024
    sizeof(int),GFP_KERNEL);
    if(!pint)
    {
    return -1;
    }
    else
    {
    printk(“virtual addr is :0x%lx , phy addr:0x%x\r\n” , pint , __pa(pint));
    }
    pr_info(“g -> VA=%lx , PA=%lx\r\n” , &g , __pa(&g));
    pr_info(“x -> VA=%lx , PA=%lx\r\n” , &x , __pa(&x));
    pr_info(“PAGE_OFFSET => %lx” , PAGE_OFFSET);
    return 0;
    }
    static void __exit tarzan_exit(void)
    {
    pr_info(“tarzan_exit\n”);
    }

    module_init(tarzan_init);
    module_exit(tarzan_exit);

    MODULE_LICENSE(“GPL”);
    MODULE_AUTHOR(“ZTE-liukai”);

    Makefile:

    ifneq ($(KERNELRELEASE),)

    obj-m := tarzan.o

    else

    KDIR := /home/zte/work/hisi/hi3519/Hi3519AV100R001C02SPC020_NEW/Hi3519AV100R001C02SPC020/Hi3519AV100R001C02SPC020/01.software/board/Hi3519AV100_SDK_V2.0.2.0/osdrv/opensource/kernel/linux-4.9.y

    all:
    make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules ARCH=arm CROSS_COMPILE=arm-himix200-linux-

    clean:
    rm -f *.ko *.o *.mod.o *.mod.c .symvers modul

    endif

    1. 实验
      3.1 Hi3519AV100平台(32位,ARMv7平台)
      运行结果:
      /run/media/mmcblk0p4 #
      /run/media/mmcblk0p4 # insmod tarzan.ko
      tarzan_init
      PHYS_OFFSET=0x22000000
      max_mapnr:262144 (物理页框的个数,一个页框4KB)
      high memory:0xf0000000
      high memory(768M) -> phy addr:0x52000000
      virtual addr is :0xee89e000 , phy addr:0x5089e000
      g -> VA=bf016220 , PA=21016220
      x -> VA=ef3d1dc0 , PA=513d1dc0
      PAGE_OFFSET => c0000000
      Phy addr of 0xc0000000 is -> 0x22000000
      Phy addr of 0xc0000001 is -> 0x22000001
      Phy addr of 0xc0000002 is -> 0x22000002
      Phy addr of 0xc0000003 is -> 0x22000003
      Phy addr of 0xc0000004 is -> 0x22000004
      Phy addr of 0xc0000005 is -> 0x22000005
      Phy addr of 0xc0000006 is -> 0x22000006
      Phy addr of 0xc0000007 is -> 0x22000007
      Phy addr of 0xc0000008 is -> 0x22000008
      Phy addr of 0xc0000009 is -> 0x22000009
      Vir addr 0f 0x0 is -> 0x9e000000
      Vir addr 0f 0x1 is -> 0x9e000001
      Vir addr 0f 0x2 is -> 0x9e000002
      Vir addr 0f 0x3 is -> 0x9e000003
      Vir addr 0f 0x4 is -> 0x9e000004
      Vir addr 0f 0x5 is -> 0x9e000005
      Vir addr 0f 0x6 is -> 0x9e000006
      Vir addr 0f 0x7 is -> 0x9e000007
      Vir addr 0f 0x8 is -> 0x9e000008
      Vir addr 0f 0x9 is -> 0x9e000009
      名称 进程号 状态 优先级 父进程号
      init 1 1 120
      udevd 101 1 116
      udevd 135 1 118
      udevd 136 1 118
      lighttpd 393 1 120
      sshd 397 1 120
      dnsmasq 402 1 120
      sh 412 1 120
      insmod 425 0 120
      /-----------------------------------------------/
      /run/media/mmcblk0p4 #
      /run/media/mmcblk0p4 #
      从运行的LOG来看,内核态起始地址0xC000_0000对应的物理地址是0x2200_0000,和常见的书本上提到的"0xC000_0000映射到物理内存0x0000_0000"有出入,思考了一下,发现问题,DDR颗粒的0地址在ARM内存映射的地址不一定是0地址,系统的定义为:PHYS_OFFSET,该参数的定义为:DDR的地址偏移,后来从海思的手册里找到这个参数的定义:
      在这里插入图片描述

    从这张图里可以看出DDR给到Linux OS的地址是从0x2200_0000偏移开始的。

    3.2 Hi3516DV300平台 (ARMv7 32)

    insmod tarzan.ko

    tarzan_init
    PHYS_OFFSET=0x80000000
    max_mapnr:131072
    high memory:0xe0000000
    high memory(768M) -> phy addr:0xa0000000
    virtual addr is :0xde7de000 , phy addr:0x9e7de000g -> VA=bf55221c , PA=7f55221c
    x -> VA=de711dc0 , PA=9e711dc0
    PAGE_OFFSET => c0000000
    Phy addr of 0xc0000000 is -> 0x80000000
    Phy addr of 0xc0000001 is -> 0x80000001
    Phy addr of 0xc0000002 is -> 0x80000002
    Phy addr of 0xc0000003 is -> 0x80000003
    Phy addr of 0xc0000004 is -> 0x80000004
    Phy addr of 0xc0000005 is -> 0x80000005
    Phy addr of 0xc0000006 is -> 0x80000006
    Phy addr of 0xc0000007 is -> 0x80000007
    Phy addr of 0xc0000008 is -> 0x80000008
    Phy addr of 0xc0000009 is -> 0x80000009

    Vir addr 0f 0x0 is -> 0x40000000
    Vir addr 0f 0x1 is -> 0x40000001
    Vir addr 0f 0x2 is -> 0x40000002
    Vir addr 0f 0x3 is -> 0x40000003
    Vir addr 0f 0x4 is -> 0x40000004
    Vir addr 0f 0x5 is -> 0x40000005
    Vir addr 0f 0x6 is -> 0x40000006
    Vir addr 0f 0x7 is -> 0x40000007
    Vir addr 0f 0x8 is -> 0x40000008
    Vir addr 0f 0x9 is -> 0x40000009
    /-----------------------------------------------/
    ~ #
    ~ #
    在这里插入图片描述

    可见,Hi3516DV300的 DDR起始地址为0x8000_0000
    3.3 飞思卡尔i.max6平台
    /mnt # insmod tarzan.ko
    tarzan_init
    PHYS_OFFSET=0x80000000
    max_mapnr:131072
    high memory:0xa0000000
    high memory(768M) -> phy addr:0xa0000000
    virtual addr is :0x88429000 , phy addr:0x88429000
    g -> VA=7f00021c , PA=7f00021c
    x -> VA=887fbdf0 , PA=887fbdf0
    PAGE_OFFSET => 80000000
    Phy addr of 0xc0000000 is -> 0xc0000000
    Phy addr of 0xc0000001 is -> 0xc0000001
    Phy addr of 0xc0000002 is -> 0xc0000002
    Phy addr of 0xc0000003 is -> 0xc0000003
    Phy addr of 0xc0000004 is -> 0xc0000004
    Phy addr of 0xc0000005 is -> 0xc0000005
    Phy addr of 0xc0000006 is -> 0xc0000006
    Phy addr of 0xc0000007 is -> 0xc0000007
    Phy addr of 0xc0000008 is -> 0xc0000008
    Phy addr of 0xc0000009 is -> 0xc0000009
    Vir addr 0f 0x0 is -> 0x0
    Vir addr 0f 0x1 is -> 0x1
    Vir addr 0f 0x2 is -> 0x2
    Vir addr 0f 0x3 is -> 0x3
    Vir addr 0f 0x4 is -> 0x4
    Vir addr 0f 0x5 is -> 0x5
    Vir addr 0f 0x6 is -> 0x6
    Vir addr 0f 0x7 is -> 0x7
    Vir addr 0f 0x8 is -> 0x8
    Vir addr 0f 0x9 is -> 0x9

    在这里插入图片描述

    飞思卡尔的该芯片使用的是1:1 (user:kernel)模型,即用户态和内核态地址范围均为2GB。
    在这里插入图片描述

    该平台为1:1的使用模型,PAGE_OFFSET=80000000(2GB), PHYS_OFFSET=0x80000000,最后的结果为物理地址=虚拟地址
    4. 结论

    i.max地址映射范围可知,DDR的起始地址为0x8000_0000 , 故PHYS_OFFSET=0x80000000
    这个参数Kernel是怎么知道的?答案是通过单板的DTS传给内核的,起始地址为0x8000_0000,大小为512MB
    在这里插入图片描述

                          i.max6 dts 内存配置
    
    • 1

    在这里插入图片描述

                        hi3519 dts 内存配置
    
    • 1

    在这里插入图片描述

                     hi3516 dts内存配置
    
    • 1

    在低端内存的虚实地址换算的方法如下,为线性映射,两者之间差一个固定偏移,这个偏移不一定是0xC000_0000,还和DDR内存地址在系统中的起始地址有关系,具体计算方法如下:
    虚拟地址=物理地址 - PHYS_OFFSET + PAGE_OFFSET
    物理地址=虚拟地址 - PAGE_OFFSET + PHYS_OFFSET

  • 相关阅读:
    笔试强训day01
    No qualifying bean of type ‘...‘ available错误解决
    Flutter的基础知识、核心概念以及一些实际开发技巧
    几种取时间的方法(附代码)
    【Docker】Docker File
    Windows 安装 Nginx, 本地访问vue打包项目
    大一学生作品《前端框架开发技术》 期末网页制作 HTML+CSS+JavaScript 个人主页网页设计实例
    Java:Stream流
    MySQL视图
    Unity修改编辑器
  • 原文地址:https://blog.csdn.net/weixin_34392906/article/details/128126888