zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.83k stars 6.6k forks source link

qustion: Can link a function into SRAM, not FLASH? #10253

Closed qianfan-Zhao closed 5 years ago

qianfan-Zhao commented 6 years ago

I am using a custom Atmel SAM E70 board and want read this chip's unique id from flash.

Here is a example from atmel's asf:

__no_inline
RAMFUNC
uint32_t efc_perform_read_sequence(Efc *p_efc,
        uint32_t ul_cmd_st, uint32_t ul_cmd_sp,
        uint32_t *p_ul_buf, uint32_t ul_size)
{
    volatile uint32_t ul_status;
    uint32_t ul_cnt;

#if (SAM3U4 || SAM3XA || SAM4SD16 || SAM4SD32 || SAM4C32 || SAM4CMS32|| SAM4CMP32)
    uint32_t *p_ul_data =
            (uint32_t *) ((p_efc == EFC0) ?
            READ_BUFF_ADDR0 : READ_BUFF_ADDR1);
#elif (SAM3S || SAM4S || SAM3N || SAM3U || SAM4E || SAM4N || SAM4C || SAMG || \
       SAM4CP || SAM4CM || SAMV71 || SAMV70 || SAMS70 || SAME70)
    uint32_t *p_ul_data = (uint32_t *) READ_BUFF_ADDR;
#else
    return EFC_RC_NOT_SUPPORT;
#endif

    if (p_ul_buf == NULL) {
        return EFC_RC_INVALID;
    }

    p_efc->EEFC_FMR |= (0x1u << 16);

    /* Send the Start Read command */
#if (SAM4S || SAM4E || SAM4N || SAM4C || SAMG || SAM4CP || SAM4CM || \
     SAMV71 || SAMV70 || SAMS70 || SAME70)
    p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0)
            | EEFC_FCR_FCMD(ul_cmd_st);
#else
    p_efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0)
            | EEFC_FCR_FCMD(ul_cmd_st);
#endif
    /* Wait for the FRDY bit in the Flash Programming Status Register
     * (EEFC_FSR) falls.
     */
    do {
        ul_status = p_efc->EEFC_FSR;
    } while ((ul_status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);

    /* The data is located in the first address of the Flash
     * memory mapping.
     */
    for (ul_cnt = 0; ul_cnt < ul_size; ul_cnt++) {
        p_ul_buf[ul_cnt] = p_ul_data[ul_cnt];
    }

    /* To stop the read mode */
    p_efc->EEFC_FCR =
#if (SAM4S || SAM4E || SAM4N || SAM4C || SAMG || SAM4CP || SAM4CM || \
     SAMV71 || SAMV70 || SAMS70 || SAME70)
            EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
            EEFC_FCR_FCMD(ul_cmd_sp);
#else
            EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0) |
            EEFC_FCR_FCMD(ul_cmd_sp);
#endif
    /* Wait for the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
     * rises.
     */
    do {
        ul_status = p_efc->EEFC_FSR;
    } while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);

    p_efc->EEFC_FMR &= ~(0x1u << 16);

    return EFC_RC_OK;
}

And I want portting this function to Zephyr, but the problem is this function MUST link into SRAM region, can't link to FLASH, otherwise the system will be hang at 'p_efc->EEFC_FMR &= ~(0x1u << 16);'

So I want a way to link a function into SRAM and don't know if current link scripts support this feature.

Thanks!

qianfan-Zhao commented 6 years ago

I try add this feature, but failed now. And create a PR in: WIP: DNM: arm: Add ramfunc section to link scripts #10255

hongshui3000 commented 6 years ago

my LD fix:

 SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,)
    {
    __data_ram_start = .;
    KERNEL_INPUT_SECTION(.data)
    KERNEL_INPUT_SECTION(".data.*")
    *(".kernel.*")

#ifdef CONFIG_CUSTOM_RWDATA_LD
/* Located in project source directory */
#include <custom-rwdata.ld>
#endif
    KEEP(*(MY_RAM_CODE))/* my code */
    } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
qianfan-Zhao commented 6 years ago

@hongshui3000 You menas push a function into data section? And I had write another section named ramfun in pr #10255, could you please also check it ?

hongshui3000 commented 6 years ago

是 放到数据段,在看来code和数据没有差别(我很懒)

我利用下面的代码帮我拷贝,我不想动zephyr的代码

#ifdef CONFIG_XIP
/**
 *
 * @brief Copy the data section from ROM to RAM
 *
 * This routine copies the data section from ROM to RAM.
 *
 * @return N/A
 */
void _data_copy(void)
{
    memcpy(&__data_ram_start, &__data_rom_start,
         ((u32_t) &__data_ram_end - (u32_t) &__data_ram_start));
#ifdef CONFIG_CCM_BASE_ADDRESS
    memcpy(&__ccm_data_start, &__ccm_data_rom_start,
         ((u32_t) &__ccm_data_end - (u32_t) &__ccm_data_start));
#endif
#ifdef CONFIG_APPLICATION_MEMORY
    memcpy(&__app_data_ram_start, &__app_data_rom_start,
         ((u32_t) &__app_data_ram_end - (u32_t) &__app_data_ram_start));
#endif
}
#endif
qianfan-Zhao commented 6 years ago

@hongshui3000 根据PR #10255 的代码,改为添加ramfunc到datas中:

--- a/include/arch/arm/cortex_m/scripts/linker.ld
+++ b/include/arch/arm/cortex_m/scripts/linker.ld
@@ -336,6 +336,8 @@ SECTIONS
        __data_ram_start = .;
        KERNEL_INPUT_SECTION(.data)
        KERNEL_INPUT_SECTION(".data.*")
+       KERNEL_INPUT_SECTION(.ramfunc)
+       KERNEL_INPUT_SECTION(".ramfunc.*")
        *(".kernel.*")

利用data段的数据拷贝将ramfunc中的函数拷贝一下。在hello world中添加测试代码:

diff --git a/samples/hello_world/src/main.c b/samples/hello_world/src/main.c
index 2d4a7f0..398a85e 100644
--- a/samples/hello_world/src/main.c
+++ b/samples/hello_world/src/main.c
@@ -7,7 +7,13 @@
 #include <zephyr.h>
 #include <misc/printk.h>

+static void __ramfunc ramfunc_test(void)
+{
+       printk("RUN IN RAM: %p\n", ramfunc_test);
+}
+
 void main(void)
 {
        printk("Hello World! %s\n", CONFIG_BOARD);
+       ramfunc_test();
 }

在没有MPU的平台上能运行,但是有MPU的情况下会MPU FAULT(不管是直接插入data段中,还是新建另一个段,都会出现MPU FAULT)

***** MPU FAULT *****
  Instruction Access Violation
***** Hardware exception *****
Current thread ID = 0x20400078
Faulting instruction address = 0x20400ea4
Fatal fault in essential thread! Spinning...

目前还没找到在什么地方设置的MPU。可能要为ramfunc单独设置一段,并设置下该段的MPU。

hongshui3000 commented 6 years ago

我没有使用过MPU。

walter-xie commented 6 years ago

I don't think it is good idea to run function in sram. Usually, the boot ROM would provide API to program the flash. Did you check that?

hongshui3000 commented 6 years ago

在sram 中运行程序可能是要解决现实工程中的问题: 1.boot rom 中的code 有bug 不得不在sram中patch 2.在boot 中根本没有你要的功能,而这种功能又不能在flash中做 3.sram 执行比flash 拥有更高的效率

qianfan-Zhao commented 6 years ago

@walter-xie 像Ateml SAME70芯片,芯片唯一ID存在FLASH中,按照提供的ASF实例代码,读芯片UID的程序有操作FLASH,这部分代码只能 放到 SRAM中运行。

@walter-xie @hongshui3000 目前而言,单独设置函数链接到SRAM中并运行倒是没什么大的问题,在PR 中已经实现了。问题是在有MPU保护的SOC中 ,默认SRAM没有运行 权限,会导致MPU FALUT。如何更改MPU这部分才是大问题。

nashif commented 6 years ago

folks, please try to use english here so others can join the conversation. thanks.