Memory Layout介绍


1. 概述

本文档介绍了SStar平台上特有的memory layout方式,以及与mma heap相关的一些基本概念。


2. MMAP


2.1. MMAP介绍

MMAP是memory map的简写,它是整个SOC系统内存Layout,如图2-1所示,MMAP内配置的内存分成两个部分。

  1. Hardware IP私有的内存。

  2. 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在初始化阶段处理分为两部分:

  1. 在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

  2. 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工具修改。

  1. 打开

    图2-9

  2. 添加

    图2-10

  3. 修改

    内存修改包括buf的大小改动,位置改动,以及调整整个DDR的大小,任何内存大小改动后,都应当把内存填满,不得有内存溢出或者遗漏,否则在保存的时候会报错。

    图2-11

  4. 删除

    图2-12

  5. 保存

    按’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

图2-14

从上图可知,有两个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:

  1. mma_memblock_remove=1

    此flag代表是否把kernel reserve出来给mma的内存从kernel内存部分移除。

  2. 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开始。