• 107查看
  • 0回复

[底层软件] S32K324 数据初始化Rom到Ram Copy的方式

[复制链接]

该用户从未签到

发表于 19-4-2024 22:25:18 | 显示全部楼层 |阅读模式

汽车零部件采购、销售通信录       填写你的培训需求,我们帮你找      招募汽车专业培训老师




    前言

    基础知识


      ld文件中的段定义

      ld文件中的符号定义

    ld定义copy地址范围

    启动文件中的定义

    Copy的使用

    总结

前言

之前一直不理解在ld文件中加__xxx_ram_start,__xxx_rom_start,__xxx_rom_end这些的作用,也不清楚原理。前几天遇到一个内存copy的问题,对这些有了更进一步的理解,记录一下过程。
基础知识

ld文件中的段定义

具体可以参考The Gnu Linker-3.8.3Output Section Attributes章节,下面的定义不是完整的解释,仅供参考
section [address][type] : [ALIGN(section_align)] [(flags)] [AT(address)]

其中:
section:是要定位的输入或输出段的名称,如 .text、.data 或用户自定义的段名。
[address]:可选参数,用于直接指定该段在内存或文件中的起始地址。如果不指定,通常由链接器根据其他规则(如链接脚本中的其他命令或默认布局)确定。
[type]:可选参数,用来指定段的类型,如 PROGBITS、NOLOAD 等。若不指定,链接器会根据段的内容自动推断其类型。
ALIGN:字节对齐使用。
[(flags)]:可选参数,包含一组以逗号分隔的标志,用于指定段的属性,如 ALLOC(分配空间)、READONLY(只读)、WRITE(可写)等。
AT(address):关键部分,用于指定该段在加载或运行时应被放置到的绝对地址。这里的 address 是一个具体的内存地址值。

ld文件中的符号定义

ld文件中以“__”开头定义的符号,一般会关联到指定的地址。例如:
        __SysCore_INIT_RAM_START = .;

在链接脚本上下文中,.表示当前位置(即当前正在处理的段的起始地址)。通过该符号,即可记录对应段的起始地址及结束地址。该符号后面可以被源文件使用。(c文件中使用时需要加extern,s文件中可以直接使用)
ld定义copy地址范围

了解之前符号的定义,我们可以获取需要copy的ram起始地址,ram结束地址,rom起始地址,rom结束地址。最终实际传递到.c或.s的只需要3个地址即可(ram起始地址,rom起始地址,rom结束地址)
/* -------------------------------------------------------------------------- */
/* Sections of INIT                                                          */
/* -------------------------------------------------------------------------- */
SECTIONS
{

    .SysCore_init ALIGN(4): AT(__POSTBUILD_CONST_END)
    {
        __SysCore_INIT_RAM_START = .;
        ...
        __SysCore_INIT_RAM_END = .;

    } > int_sram_sys
   
__SysCore_INIT_ROM_START = __POSTBUILD_CONST_END;
__SysCore_INIT_ROM_END = __SysCore_INIT_ROM_START + (__SysCore_INIT_RAM_END - __SysCore_INIT_RAM_START);
}

__POSTBUILD_CONST_END是之前记录的一块flash区的结束地址,此处表示在其之后,作为ram数据的存放地址。
使用AT指令,指定该Ram区的数据放到对应flash中。
此处我们得到了__SysCore_INIT_RAM_START,__SysCore_INIT_ROM_START,__SysCore_INIT_ROM_END
在后面会使用
启动文件中的定义

.section ".init_table", "a"
  .long 6
  .long __RAM_CACHEABLE_START
  .long __ROM_CACHEABLE_START
  .long __ROM_CACHEABLE_END
  .long __RAM_NO_CACHEABLE_START
  .long __ROM_NO_CACHEABLE_START
  .long __ROM_NO_CACHEABLE_END
  .long __RAM_SHAREABLE_START
  .long __ROM_SHAREABLE_START
  .long __ROM_SHAREABLE_END
  .long __RAM_INTERRUPT_START
  .long __ROM_INTERRUPT_START
  .long __ROM_INTERRUPT_END
  .long __shared_INIT_RAM_START
  .long __shared_INIT_ROM_START
  .long __shared_INIT_ROM_END
  .long __SysCore_INIT_RAM_START
  .long __SysCore_INIT_ROM_START
  .long __SysCore_INIT_ROM_END

.section ".init_table", "a" 定义一个可分配的段init_table
这个段其实在ld文件中定义了,放在pflash中
此处相当于往里面写数据,实际可以理解为指针或者数组的应用,在后面使用的时候其实也是按数组来用的
.long 6 -定义4个字节,值为6,实际是表示的需要copy的rom-ram的对数,此处有6对
后面的定义3个为1组,分别为ram起始地址,rom起始地址,rom结束地址,都是在ld文件中定义的
此处定义好的数据在pflash中如下

S32K324 数据初始化Rom到Ram Copy的方式w1.jpg
从0x41BB14到0x41BB5F.存放了6组数据,包括其对应的ram起始地址,rom起始地址,rom结束地址
ld文件中通过    __INIT_TABLE获取首地址
__INIT_TABLE                  = ADDR(.init_table);
Copy的使用

在startup.c中对__INIT_TABLE声明,并使用
typedef struct
{
    uint8 * ram_start; /*!< Start address of section in RAM */
    uint8 * rom_start; /*!< Start address of section in ROM */
    uint8 * rom_end;   /*!< End address of section in ROM */
} Sys_CopyLayoutType;
typedef struct
{
    uint8 * ram_start; /*!< Start address of section in RAM */
    uint8 * ram_end;   /*!< End address of section in RAM */
} Sys_ZeroLayoutType;

extern uint32 __INIT_TABLE[];
extern uint32 __ZERO_TABLE[];
#if (defined(__ARMCC_VERSION))
    extern uint32 __VECTOR_RAM;
#else
    extern uint32 __VECTOR_RAM[];
#endif
/*******************************************************************************
* Code
******************************************************************************/
/*FUNCTION**********************************************************************
*
* Function Name : init_data_bss
* Description   : Make necessary initializations for RAM.
* - Copy the vector table from ROM to RAM.
* - Copy initialized data from ROM to RAM.
* - Copy code that should reside in RAM from ROM
* - Clear the zero-initialized data section.
*
* Tool Chains:
*   __GNUC__           : GNU Compiler Collection
*   __ghs__            : Green Hills ARM Compiler
*   __ICCARM__         : IAR ARM Compiler
*   __DCC__            : Wind River Diab Compiler
*   __ARMCC_VERSION    : ARMC Compiler
*
* Implements    : init_data_bss_Activity
*END**************************************************************************/
#define PLATFORM_START_SEC_CODE
#include "Platform_MemMap.h"

void init_data_bss(void);

void init_data_bss(void)
{
    const Sys_CopyLayoutType * copy_layout;
    const Sys_ZeroLayoutType * zero_layout;
    const uint8 * rom;
    uint8 * ram;
    uint32 len = 0U;
    uint32 size = 0U;
    uint32 i = 0U;
    uint32 j = 0U;

    const uint32 * initTable_Ptr = (uint32 *)__INIT_TABLE;
    const uint32 * zeroTable_Ptr = (uint32*)__ZERO_TABLE;

    /* Copy initialized table */
    len = *initTable_Ptr;
    initTable_Ptr++;
    copy_layout = (const Sys_CopyLayoutType *)initTable_Ptr;
    for(i = 0; i < len; i++)
    {
        rom = copy_layout.rom_start;
        ram = copy_layout.ram_start;
        size = (uint32)copy_layout.rom_end - (uint32)copy_layout.rom_start;

        for(j = 0UL; j < size; j++)
        {
            ram[j] = rom[j];
        }
    }
   
    /* Clear zero table */
    len = *zeroTable_Ptr;
    zeroTable_Ptr++;
    zero_layout = (const Sys_ZeroLayoutType *)zeroTable_Ptr;
    for(i = 0; i < len; i++)
    {
        ram = zero_layout.ram_start;
        size = (uint32)zero_layout.ram_end - (uint32)zero_layout.ram_start;

        for(j = 0UL; j < size; j++)
        {
            ram[j] = 0U;
        }
    }
}
#define PLATFORM_STOP_SEC_CODE
#include "Platform_MemMap.h"

通过上面的代码,实现了rom到ram的拷贝,实际只需要在.s中配置对应的参数即可
那这个函数是什么时候被调用的呢?
在启动文件中被调用,如下所示
_DATA_INIT:
#ifndef RAM_DATA_INIT_ON_ALL_CORES
    /* If this is the primary core, initialize data and bss */
    ldr  r0, =0x40260004
    ldr  r1,[r0]

    ldr  r0, =MAIN_CORE
    cmp  r1,r0
    beq  _INIT_DATA_BSS
    b    __SYSTEM_INIT
#endif

_INIT_DATA_BSS:
  bl init_data_bss

上述启动代码解释如下:
1.条件判断:检查是否需要在所有核心上进行 RAM 数据初始化。若仅需在主核心上进行初始化(即未定义 RAM_DATA_INIT_ON_ALL_CORES),则执行后续操作;否则,直接执行_INIT_DATA_BSS(调用init_data_bss函数)。
2.核心识别:通过读取特定内存地址处的值,判断当前运行的核心是否为主核心。
3.主核心处理:若当前核心为主核心,跳转至 _INIT_DATA_BSS 标签处,执行数据和 BSS 初始化。
4.data与 BSS 初始化:在 _INIT_DATA_BSS 标签处,调用 init_data_bss 函数,完成数据段和 BSS 段的初始化工作。
5.非主核心处理或系统初始化:若当前核心非主核心(或不需要在所有核心上进行数据初始化),直接跳转至 __SYSTEM_INIT 标签处,继续进行其他系统初始化任务(调用SystemInit函数)。
总结

虽然没学过汇编语言,但遇到问题还是得上~慢慢学习吧!学无止境!

快速发帖

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|Archiver|汽车工程师之家 ( 渝ICP备18012993号-1 )

GMT+8, 3-5-2024 09:23 , Processed in 0.266712 second(s), 30 queries .

Powered by Discuz! X3.5

© 2001-2013 Comsenz Inc.