Memory Layout介绍
1. 概述¶
本文档介绍了SStar平台上特有的memory layout方式,以及与mma heap相关的一些基本概念。
2. MMAP¶
2.1. MMAP介绍¶
MMAP(全称memorymap),是整个SOC系统内存Layout,如下图所示,MMAP内配置的内存分成两个部分。
-
Hardware IP私有的内存。
-
LX_MEM,Linux Kernel能使用的内存。
图2-1
每块内存的使用者必须保证自己不得越界,例如Linux kernel使用的内存由Linux内部机制保证,HW IP
使用的内存由硬件保证。
LX_MEM有可能有好几块,例如某些SOC上会有双通道DDR,每个DDR上面会各自分配一块LX_MEM。还有某些特别的情况,一颗DDR上面可能会分配多个LX_MEM。多个LX_MEM的命名规则为LX_MEM1、LX_MEM2,以此类推。
在LX_MEM中由拉出来一块给MMA Heap使用,类似于Linux的cma,这部分内存是给MI SYS通过软件的方式动态分配给HW IP使用的内存池,而与MMAP中给Hardware IP私有的内存不同的,后者是静态分配的,它在系统初始化的时候就已经分配好,只有此IP独占。
需要注意的是,MMA Heap以及HW IP Layout分配出来的内存在物理上是连续的,LX_MEM中Linux Kernel使用的部分有可能会经过LINUX MMU转成虚拟地址,在物理上不连续。
每一颗DDR上都有对应的内存控制器(MIU),所有的HW IP,不论是静态分配或者动态分配的内存,都会通过MIU才能访问到DDR。
由于SOC的版本众多,因而MMAP的版本也有很多,目前是以Chip Name来分类。
MMAP存放的路径在: ALKAID/project/board/$(CHIP)/
中,例如某些chip有64MB,128MB,256MB之分,通过文件名就可判断。在Build config中会通过设置脚本变量MMAP = xxx配置其使用哪一个MMAP。
MMAP的文件虽然以.h为后缀,但是目前它不会编译进代码中,程序编译和运行时会以动态加载的方式导入内存,并通过私有的mmap parser函数进行解析,这部分会在后面的章节进行介绍。
2.2. MMAP在系统打包阶段的处理¶
上一节介绍,Linux内核中的内存配置是看MMAP中的LX_MEM的位置和大小,原生的Linux kernel是在DTS中配置内存,SStar的平台比较特殊,为了一包kernel image兼容多个内存配置,它通过bootargs把内存大小和地址传递给kernel,如此就不用改动image的内存。
ALKAID的project中兼容了多个平台的打包流程,管理了非常多的build config,因此MMAP也有很多,如果靠人工维护build config中的LX_MEM,配置会非常繁琐且易出错,因此开发出了一个在build server上运行的应用程序,通过打包的shell执行,解析MMAP,获取一些字符串作为参数传递给bootargs中的LX_MEM。
代码路径在:
ALKAID/project/image/makefiletools/src/mmappaser/
直接进入到此路径下执行gcc ./*.c -o mmappaser
,会在当前目录下生成一个二进制可执行文件mmappaser。
目前mmappaser已经编译好放置在ALKAID/project/image/makefiletools/bin/,系统在打包的时候Makefile会自动找到此路径,并执行默认的mmappaser而不自动编译,如果有mmappaser的改动需求,请一并release编译好的可执行文件到bin文件夹下。
“mmappaser” 实现解析MMAP的代码与在板子起来后在板子上解析MMAP的代码是一样的,实现原理这里不再讨论,其目的只是为了配合编译系统,输出指定字段在MMAP中的值。
“mmappaser” 命令执行格式:
./mmappaser [MMAP Path] [CHIP] [cmd para0] [cmd para1]
“mmappaser” 执行后会以打印(printf)的形式输出结果,其结果可以被shell脚本获取作为参数值进行传递。打包阶段执行mmappaser的过程就是通过配置MMAP的路径和CHIP,自动化解析对应的字符串并作为系统参数值传递给bootargs的一个过程。
在板子上解析MMAP的文件存放路径在 /config/mmap.ini,此文件就是ALKAID/project/board/$(CHIP)/
中的以.h为后缀的文件重命名得来。
“mmappaser” 获取某块内存的地址和size,地址分为物理地址以及MIU地址:
./mmappaser [MMAP Path] [CHIP] [MEMORY NAME] phyaddr ./mmappaser [MMAP Path] [CHIP] [MEMORY NAME] miuaddr ./mmappaser [MMAP Path] [CHIP] [MEMORY NAME] size
Makefile/Shell脚本示例:
文件: ALKAID/project/setup_config.sh
图2-2
编译执行setup_config.sh
会在config/current.configs
中自动添加类似字段:
KERNEL_MEMADR = $(shell /home/malloc.peng/ALKAID/project/image/makefiletools/bin/mmapparser /home/malloc.peng/ALKAID/project/board/$(CHIP)/mmap/$(MMAP) $(CHIP) E_LX_MEM phyaddr) KERNEL_MEMLEN = $(shell /home/malloc.peng/ALKAID/project/image/makefiletools/bin/mmapparser /home/malloc.peng/ALKAID/project/board/$(CHIP)/mmap/$(MMAP) $(CHIP) E_LX_MEM size)
2.3. Bootarg内存配置¶
上一节提到,在系统打包的过程中会自动解析MMAP中的LX_MEM字段获取地址和大小,并把它作为bootargs传递给linux kernel。
打包完成后在系统的set_config中如下显示:
图2-3
LX_MEM是miu0上的内存大小,默认从头地址开始,不得修改,如果配置LX_MEM2,则需要添加物理地址起始值。例如有多个LX_MEM的配置:
图2-4
Bootargs中还有mma heap的配置,其设置并不能自动生成,它会根据build config中通过手动修改,后面章节会再介绍。
2.4. MMAP在系统初始化阶段的处理¶
MMAP在初始化阶段处理分为两部分:
-
在Linux kernel初始化阶段读取bootargs的处理:
Code 路径:
kernel/driver/sstar/cpu/memory.c
通过kernel标准的流程解析bootargs中相关字段。
图2-5
图2-6
函数: void __init prom_meminit(void),会在系统初始化的时候执行,其中主要的逻辑会先把dts中配置的内存移除,再把bootargs中的内存添加进系统。
图2-7
-
Linux Kernel加载完毕后在MI_SYS阶段的处理:
kernel初始化阶段只会使用MMAP中LX_MEM的部分,在MI_SYS中会读取MMAP中所有的配置,并存
在私有的结构体中。
使用命令/config/dump_mmap可以dump出SYS读取的mmap配置:
图2-8
2.5. SCA工具修改MMAP¶
MMAP中的地址偏移量和size的修改比较繁琐,不建议手工修改MMAP文件,推荐使用SCA工具修改。
-
打开
图2-9
-
添加
图2-10
-
修改
内存修改包括buf的大小改动,位置改动,以及调整整个DDR的大小,任何内存大小改动后,都应当把内存填满,不得有内存溢出或者遗漏,否则在保存的时候会报错。
图2-11
-
删除
图2-12
-
保存
按
Save
按钮进行保存。
2.6. Linux可用内存计算¶
通过命令cat /proc/meminfo可以得出当前kernel中可以使用的内存大小,此内存大小由以下公式得出。
Meminfo 内存大小 = ( Bootargs中配置所有LX_MEM大小之和) - (所有MMA的size + Kernel reserve 5M)
2.7. 一些特殊layout举例¶
-
128MB + 128MB 带DLA MMAP
图2-13
从上图可知,有两个DDR,所以LX_MEM会分配两块,在MIU1上有layout一块DLA的内存,DLA的输入内存是从DIVP的output端口出来的,而DLA对内存的地址要求必须在它自己FW地址的后面,因此可以看到在E_MMAP_ID_DLA之后有layout了一块LX_MEM2。
DIVP使用的输出内存必须配置到E_LX_MEM2上DLA才能读到,所以mma heap配置上会单独配置一块mma_heap_name1给divp使用,使其输出的内存地址在miu1的E_LX_MEM2中,参考bootargs配置:
LX_MEM=0x7f00000 LX_MEM2=0xa6000000,0x2000000
mma_heap=mma_heap_name0,miu=0,sz=0x5000000
mma_heap=mma_heap_name1,miu=1,sz=0x500000
mma_heap=mma_heap_name2,miu=1,sz=0x1800000
3. MMA HEAP¶
3.1. 配置以及Dump¶
通过修改bootargs中的mma_heap字段可以动态地修改mmap heap的大小。在每个project的build config中都会针对应用场景配置一个默认的mma heap size,这个大小只是预估值,FAE可以在现场针对客户的应用场景精确计算大小。
Mmap_heap配置的几个flag:
-
mma_memblock_remove=1
此flag代表是否把kernel reserve出来给mma的内存从kernel内存部分移除。
-
max_start_off=$(MMA_START_OFFSET)
Mma从kernel reserve出来的内存尾地址不得超过$(MMA_START_OFFSET),否则申请失败。
Dump mma:
cat /proc/mi_modules/mi_sys_mma/mma_heap_name0
cat /proc/mi_modules/mi_sys_mma/mma_heap_name1
3.2. 物理地址以及MIU地址¶
物理地址是HW design上,"CPU"存取DRAM的physical地址
譬如双通道ddr的CPU存取MIU0的起始物理地址为0x20000000,MIU1的起始物理地址为0xA0000000。
MIU地址是HW IP通过MIU访问DRAM的地址,MIU0的地址从0x0开始,MIU1从0x80000000开始。