• 内核分配大块连续内存的方法【转】


    参数传递:

        uboot向内核传递参数的方式分为两类。

        (1)第一类是通过boot cmd 例如在uboot终端提示行使用pri命令现实出的boot arg等。

        (2)第二类是通过DeviceTree。在/arch/arm/boot/dts/文件中和定义了和开发板相关的板级描述信息。

    注(1)Device Tree的分析在其它文章中分析

    以soc devkit (友晶)为参考在dts目录下文件socfpga_cyclone5.dtsi或者socfpga.dts文件中有以下描述:

    memory {

    name = "memory";

    device_type = "memory";

    reg = <0x0 0x40000000>; /* 1 GB */

    };

    描述了开发办的物理内存使用情况为1G。设备类型为deivce_type。

        在函数:setup_arch()中调用setup_machine_fdt()。这个函数参数是__atags_pointer。这个地址是由uboot传递。Uboot把控制权交给kernel之前会在R2寄存中存放device tree的线性地址。物理还是虚拟地址?虚拟地址。此地址和物理地址相差一个pgd。即段映射的高12位做基地址。Kernel还没有真正使用mmu的三级映射方案,还是停留在段映射的空间内。

    函数调用顺序:

    setup_arch()

    i early_init_dt_scan_memory()

    early_init_dt_add_memory_arch()

    arm_add_memory()

    中作相关处理。主要是把reg字段解析。最后把base和size等参数存放入相关结构体。这些结构体在下一章中解释。

    uboot cmd 传递参数:

    static int __init early_mem(char *p) 

    以上两种参数传递都是通过R2寄存器中的__atags_pointer传递。在setup_arch函数中解析。这个函数还是用了cmdline作为参数分析uboot传递的参数。

    以上两种方式方法主要初始化以下全局变量:(memory的使用SOC采用的是Device Tree)

    /*

     * Memory map description

     */

    struct membank {

    phys_addr_t start;

    phys_addr_t size;

    unsigned int highmem;

    };

    struct meminfo {

    int nr_banks;

    struct membank bank[NR_BANKS];

    };

    内存描述:

    由membank到meminfo的过渡

    membank描述了硬件的相关信息,这些信息最后落实到linux的管理范围之内。并且依据处理后的相关信息分配布置内存空间。这个过程使用到了memblock_type和memblock的数据结构。

    struct memblock_type {

    unsigned long cnt; /* number of regions */

    unsigned long max; /* size of the allocated array */

    phys_addr_t total_size; /* size of all regions */

    struct memblock_region *regions;

    };

    struct memblock {

    phys_addr_t current_limit;

    struct memblock_type memory;

    struct memblock_type reserved;

    };

    Reserved 和memory代表的是保留和物理内存描述。可以结合一下打印信息进行分析。

    MEMBLOCK configuration:

     memory size = 0x40000000 reserved size = 0x54f553

     memory.cnt  = 0x1

     memory[0x0]    [0x00000000000000-0x0000003fffffff], 0x40000000 bytes

     reserved.cnt  = 0x3

     reserved[0x0]  [0x00000000004000-0x00000000007fff], 0x4000 bytes

     reserved[0x1]  [0x000000000081c0-0x0000000054e763], 0x5465a4 bytes

     reserved[0x2]  [0x00000003ffb000-0x00000003ffffae], 0x4faf bytes

       所有保留的数据大小综合为0x54f553。Memory的区域没有记录。只是调用create_mapping把这些物理地址建立相应的页表和叶目录项。那么那些记录为reserve的内存大小又是什么呢?其实这就是内核本身以及device tree 还有一些其它的数据指令段。这些段都是已经存在于内存中。并且系统本身以及系统将会用到的数据和指令等,这些信息非常重要,一定要保留。既然保留,那么一定是将来的其它管理方案接手并且采用自己的方案管理。但是不会对前一任管理方案所保留的内容进行破坏。

        内核内存管理方案在初始化和运行时是不同的。初始化偏重于“区分”,而运行时偏重于“效率”。初始化一定要把不同的区域区分明白,告诉后者如何有效管理。至于后者的管理是否和前者冲突,当然有这些reserve的区域来解决。(实际使用更复杂)

  • 相关阅读:
    Beans
    Redis记录-Redis命令
    Redis记录-Redis介绍
    RESTful记录-RESTful服务
    RESTful记录-RESTful内容
    RESTful记录-RESTful介绍
    HTTP记录-HTTP介绍
    Solr记录-solr检索和查询数据
    Solr记录-solr文档xml
    Solr记录-solr内核与索引
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5567487.html
Copyright © 2020-2023  润新知