ARM SCP framework初始化

        在现有的 ARMv9提供的 fvp代码包含多个部件的代码,主要包括 scp、atf、uefi、grub、kernel、busybox几个部分。模拟器的源码对于初学者可以不用理会,ARM V9主要用于服务器 SOC,其中 SCP则是包含了更多裸系统的外设控制。

        SCP代码相对其它部件而言,代码框架并不复杂,毕竟是对外设的操作,用于执行 ATF和 BMC传递过来的指令。了解框架,我们可以先从链接脚本开始分析

目录

1.   找到入口函数

2. 入口函数分析

2. 1  fwk_arch_init里面做了啥

2.2  fwk的 IO初始化

2.3 中断 gic初始化

2.3.1 回调函数 arm_gic_init分析

2.3.2 gic提供的相关接口 

3. 框架相关的初始化

3.1  fwk模块初始化

        首先这里定义了一个本地全局的实例

3.2  fwk模块核心启动  

3.2.1 初始化所有 fwk_module

3.2.2 主线程的初始化和运行


1.   找到入口函数

         链接脚本: // scp\arch\arm\armv8-a\src\arch.ld.S

ENTRY(_entrypoint) 

SECTIONS {
    .text : {
        *(.vectors)
        *(.entrypoint)  //入口函数
        *(.text*)
        *(.rodata*)
        *(.note.gnu.build-id)
    } > mem0

    __text__ = .;

    __sram_copy_start__ = .;
    .system_ram : {
        __system_ram_start__ = .;
        *(.system_ram*)
        *iic_dvfs.o(.rodata)
        __system_ram_end__ = .;
    } > sram AT> mem0

    . = __text__ + SIZEOF(.system_ram);

    /*
     * Define a linker symbol to mark start of the RW memory area for this
     * image.
     */
    __RW_START__ = . ;

    .data : {
        . = ALIGN(4);
        *(.data*)
        . = ALIGN(4);
#if FMW_MEM_MODE == ARCH_MEM_MODE_SINGLE_REGION
    } > mem0 /* .data follows .text in mem0 */
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_NO_RELOCATION
    } > mem1 /* .data is the first section in mem1 */
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_RELOCATION
    } > mem1 AT>mem0  /* Run-time image is at mem1, but loaded from mem0 */
#else
    ASSERT(0, "Unrecognized FMW_MEM_MODE")
#endif

    .bss : {
        . = ALIGN(4);
        *(.bss*)
        . = ALIGN(4);
#if FMW_MEM_MODE == ARCH_MEM_MODE_SINGLE_REGION
    } > mem0  /* Run-time image is at mem1, but loaded from mem0 */
#else
    } > mem1 /* .bss follows .data in mem1 */
#endif

    .stack (NOLOAD) : {
        . = . + STACK_SIZE;
    } > stack
    __RW_END__ = .;

    /*
     * Define a linker symbol to mark end of the RW memory area for this
     * image.
     */

    __TEXT_START__ = LOADADDR(.text);
    __TEXT_SIZE__ = SIZEOF(.text);
    __TEXT_END__ = __TEXT_START__ + __TEXT_SIZE__;

    __STACK_START__ = LOADADDR(.stack);
    __STACK_SIZE__ = SIZEOF(.stack);
    __STACK_END__ = __STACK_START__ + __STACK_SIZE__;
    __STACK_TOP__ = __STACK_END__;
    __STACK_SP3_SIZE__ = 0x400;
    __STACK_SP0_TOP__ = __STACK_END__ - __STACK_SP3_SIZE__;

    __DATA_LMA_START__ = LOADADDR(.data);
    __DATA_START__ = ADDR(.data);
    __DATA_SIZE__ = SIZEOF(.data);

    __BSS_START__ = ADDR(.bss);
    __BSS_SIZE__ = SIZEOF(.bss);
    __BSS_END__ = __BSS_START__ + __BSS_SIZE__;

    __HEAP_START__ = __BSS_START__ + __BSS_SIZE__;
    __HEAP_END__ = __STACK_START__;
    __HEAP_SIZE__ = __HEAP_END__ - __HEAP_START__;
}

        从链接脚本看来,首先是初始化中断向量表,里面针对 arm64和 arm32做了区分,包括 freertos。这里只看入口函数:  _entrypoint

        // scp\arch\arm\armv8-a\src\arch_crt0.S

func _entrypoint
    ldr w0, _boot_flag
    ldr w1, =R_WARMBOOT
    cmp w1, w0
    beq _restore_system

    ldr x0,  =__STACK_TOP__
    mov sp, x0 /* SP_EL3 */

    adr x0, _vector_table
    msr vbar_el3, x0
    isb

    msr spsel, #0
    ldr x0, =__STACK_SP0_TOP__
    mov sp, x0 /* SP_EL0 */
    stp x29, x30, [sp, #-32]!

    adr x0, __RW_START__
    adr x1, __RW_END__
    sub x1, x1, x0
    bl  inv_dcache_range

    ldr x0, =__BSS_START__
    ldr x1, =__BSS_SIZE__
    bl  zeromem

#if USE_COHERENT_MEM
    ldr x0, =__COHERENT_RAM_START__
    ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__
    bl  zeromem
#endif

    mrs   x0, scr_el3
    /* RW[10]=1, HCE[8]=0, SMD[7]=0, EA[3]=1, FIQ[2]=1, IRQ[1]=1, NS[0]=0 */
    mov   x0, #(1<<10 | 0<<8 | 0<<7 | 1<<3 | 1<<2 | 1<<1 | 0<<0)
    msr   scr_el3, x0

    /* --------------------------------------------------
     * Initialize platform and jump to our c-entry point
     * for this type of reset.
     * --------------------------------------------------
     */
#ifdef BUILD_HAS_NOTIFICATION
    bl  __fwk_notification_reset
#endif
    bl  arm_main

    mov x0, 1
    ldp x29, x30, [sp], #32

    ret

endfunc _entrypoint

        从上面的汇编文件可以看出,构建了堆栈后直接跳到 C代码 arm_main

2. 入口函数分析

    

static struct fwk_arch_init_driver arch_init_driver = {
    .interrupt = arm_gic_init,
};

arm_main(void)   // scp\arch\arm\armv8-a\src\arch_main.c

        fwk_arch_init(&arch_init_driver); //这里传入的是架构 gic

2. 1  fwk_arch_init里面做了啥

        架构 fwk主要是 module初始化, io初始化, 中断 gic初始化

int fwk_arch_init(const struct fwk_arch_init_driver *driver) // scp\framework\src\fwk_arch.c

        fwk_module_init();

        fwk_io_init();

        fwk_arch_interrupt_init(driver->interrupt); //调用架构 gic相关代码

        fwk_module_start();

        上面的 module其实对应是 arm里面的硬件模块,我们可以在目录看到  scp\module

/scp/module

drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 apcontext/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 apremap/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 armv7m_mpu/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 bootloader/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 clock/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 cmn600/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 cmn650/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 cmn700/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 cmn_booker/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 css_clock/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 ddr_phy500/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 debug/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 debugger_cli/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 dmc500/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 dmc620/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 dvfs/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 dw_apb_i2c/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 dwt_pmi/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 fip/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 gtimer/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 i2c/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 isys_rom/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mhu/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mhu2/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mock_clock/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mock_psu/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mock_sensor/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 mock_voltage_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 msys_rom/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 pcid/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 pcie_integ_ctrl/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 pik_clock/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 pl011/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 pmi/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 power_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 ppu_v0/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 ppu_v1/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 psu/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 reg_sensor/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 reset_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 resource_perms/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_apcore/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_clock/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_perf/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_power_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_reset_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_sensor/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_system_power/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 scmi_voltage_domain/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 sds/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 sensor/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 sid/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 smt/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 ssc/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 statistics/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 stdio/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 system_info/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 system_pll/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 system_power/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 timer/
drwxr-xr-x 1 Administrator 197121     0 Dec 15 09:34 voltage_domain/

2.2  fwk的 IO初始化

struct fwk_io_stream *fwk_io_stdin = &fwk_io_null;
struct fwk_io_stream *fwk_io_stdout = &fwk_io_null;

int fwk_io_init(void)

{

          fwk_io_open(&stdin_stream, FMW_IO_STDIN_ID, FWK_IO_MODE_READ);
          fwk_io_stdin = &stdin_stream;

          fwk_io_open(&stdout_stream, FMW_IO_STDOUT_ID, FWK_IO_MODE_WRITE);
          fwk_io_stdout = &stdout_stream;

}

这里构建了一个全局的  fwk_io_stdin、 fwk_io_stdout, 在后面的终端输出有用

2.3 中断 gic初始化

        gic 初始化相关代码: // scp\framework\src\fwk_arch.c

int fwk_arch_init(const struct fwk_arch_init_driver *driver)        

         fwk_arch_interrupt_init(driver->interrupt);  //这个是main函数入口传入

                interrupt_init_handler(&driver);  //执行回调函数

                fwk_interrupt_init(driver); // scp\framework\src\fwk_interrupt.c

                        fwk_interrupt_driver = driver; //这里构建以模块句柄

2.3.1 回调函数 arm_gic_init分析

static struct fwk_arch_init_driver arch_init_driver = {
    .interrupt = arm_gic_init,
};

// scp\arch\arm\armv8-a\src\arch_gic.c

arm_gic_init(const struct fwk_arch_interrupt_driver **driver) 

        gic_init();  // 这个以后再分析,主要还是初始化 gic相关寄存器

         *driver = &arm_gic_driver;   // 这里传入的是二级指针

2.3.2 gic提供的相关接口 

        从上上面的代码分析,可以看出经过 fwk_arch_interrupt_init函数初始化后,构建了一个全局句柄  fwk_interrupt_driver , 其提供的接口如下

// scp\arch\arm\armv8-a\src\arch_gic.c

static const struct fwk_arch_interrupt_driver arm_gic_driver = {
    .global_enable = global_enable,
    .global_disable = global_disable,
    .is_enabled = is_enabled,
    .enable = enable,
    .disable = disable,
    .is_pending = is_pending,
    .set_pending = set_pending,
    .clear_pending = clear_pending,
    .set_isr_irq = set_isr_irq,
    .set_isr_irq_param = set_isr_irq_param,
    .set_isr_nmi = set_isr_dummy,
    .set_isr_nmi_param = set_isr_dummy_param,
    .set_isr_fault = set_isr_dummy,
    .get_current = get_current,
};

        对外接口如下: // scp\framework\include\fwk_interrupt.h

int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver);
inline static void fwk_interrupt_global_enable(void)
inline static void fwk_interrupt_global_disable(void)
int fwk_interrupt_is_enabled(unsigned int interrupt, bool *enabled);
int fwk_interrupt_enable(unsigned int interrupt);
int fwk_interrupt_disable(unsigned int interrupt);
int fwk_interrupt_is_pending(unsigned int interrupt, bool *pending);
int fwk_interrupt_set_pending(unsigned int interrupt);
int fwk_interrupt_clear_pending(unsigned int interrupt);
int fwk_interrupt_set_isr(unsigned int interrupt, void (*isr)(void));
int fwk_interrupt_set_isr_param(unsigned int interrupt, void (*isr)(uintptr_t param),uintptr_t param);
int fwk_interrupt_get_current(unsigned int *interrupt);

        这样以后,所有对中断操作,只需要使用上面的 API即可, 具体的都是对相关寄存器操作, 嵌入汇编代码实现。框架是比较简单,寄存器相关操作在后续章节分析。

3. 框架相关的初始化

        先回到入口函数: // scp\framework\src\fwk_arch.c

  int fwk_arch_init(const struct fwk_arch_init_driver *driver)

        fwk_module_init(); // scp\framework\src\fwk_module.c
        fwk_module_start();

3.1  fwk模块初始化

        首先这里定义了一个本地全局的实例

static struct {   // scp\framework\src\fwk_module.c
    bool initialized;
    struct fwk_module_ctx module_ctx_table[FWK_MODULE_IDX_COUNT];
    enum fwk_module_stage stage;
    fwk_id_t bind_id;
} fwk_module_ctx;

        这个本地全局实体在本模块初始化

void fwk_module_init(void) // scp\framework\src\fwk_module.c

    for (uint32_t i = 0U; i < (uint32_t)FWK_MODULE_IDX_COUNT; i++) {

        struct fwk_module_ctx *ctx = &fwk_module_ctx.module_ctx_table[i];

        fwk_id_t id = FWK_ID_MODULE(i);

        const struct fwk_module *desc = module_table[i];
        const struct fwk_module_config *config = module_config_table[i];

        *ctx = (struct fwk_module_ctx){
            .id = id,

            .desc = desc,
            .config = config,
        };

        // 上面通过匿名结构体赋值,
         fwk_list_init(&ctx->delayed_response_list); //挂接到模块链表里

     }

3.2  fwk模块核心启动  

        先看代码几个主要步骤

fwk_module_start(void)  // scp\framework\src\fwk_module.c

        __fwk_thread_init(FWK_MODULE_EVENT_COUNT);

        fwk_module_init_modules();

         start_modules();

        __fwk_thread_run();

3.2.1 初始化所有 fwk_module

fwk_module_init_modules();  // scp\framework\src\fwk_module.c

           for (unsigned int i = 0U; i < (unsigned int)FWK_MODULE_IDX_COUNT; i++) {
                        fwk_module_init_module(&fwk_module_ctx.module_ctx_table[i]);

                               const struct fwk_module *desc = ctx->desc;
                               const struct fwk_module_config *config = ctx->config;

                               desc->init(ctx->id, ctx->element_count, config->data);   //调用模块初始化                               

                                fwk_module_init_elements(ctx); //后续分析      
            }

start_modules();

       for (module_idx = 0; module_idx < FWK_MODULE_IDX_COUNT; module_idx++) {
                module_ctx = &fwk_module_ctx.module_ctx_table[module_idx];
                fwk_module_start_module(module_ctx);

                        module->start(module_ctx->id); //调用每个模块的 start函数
       }

3.2.2 主线程的初始化和运行

int fwk_module_start(void) // scp\framework\src\fwk_thread.c

        __fwk_thread_init(FWK_MODULE_EVENT_COUNT);

             event_table = fwk_mm_calloc(event_count, sizeof(struct fwk_event));
             fwk_list_init(&ctx.free_event_queue);
             fwk_list_init(&ctx.event_queue);
             fwk_list_init(&ctx.isr_event_queue);

             for (event = event_table; event < (event_table + event_count); event++) {
                  fwk_list_push_tail(&ctx.free_event_queue, &event->slist_node);
             }

         __fwk_thread_run();
   
             for (;;) {
                while (!fwk_list_is_empty(&ctx.event_queue)) {
                    process_next_event();
                }

                if (process_isr()) {
                    continue;
                }

                 (void)fwk_log_unbuffer();
            }

        主线程跑起来之后运行状态,从上面的代码可以看出,主要做两件事情

        1.         处理队列里所有的事件

        2.         处理所有的中断请求 

        具体事件和中断在后续进一步分析

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
SCP(Secure Copy Protocol)是一种用于在不同计算机系统之间安全地传输文件的协议。它是SSH(Secure Shell)协议的一部分,提供了加密和身份验证的功能。以下是对ARM SCP代码的详细解释: ARM SCP代码是一种特定于ARM架构的实现SCP协议的代码。SCP的实现可以分为两个角色:发送主机(即本地主机)和接收主机(即远程主机)。发送主机使用SCP命令将文件从本地主机复制到远程主机,而接收主机接收并存储来自发送主机的文件。 发送主机的SCP代码首先通过SSH协议与接收主机建立一个加密通道。加密通道的建立包括身份验证和密钥交换。接着,发送主机会通过加密通道发送SCP命令和文件信息给接收主机,并等待接收主机的响应。 接收主机的SCP代码在收到SCP命令后,会解析命令并执行相应的操作。例如,如果是通过SCP命令发送文件,接收主机的SCP代码会创建一个目标文件,并在加密通道中等待发送主机发送文件内容。接收主机会解密接收到的文件内容并写入目标文件。 在整个过程中,SCP代码使用SSH协议提供的加密机制来确保传输的安全性。它使用加密算法对数据进行加密和解密,以防止数据被窃听和篡改。另外,SCP代码还使用身份验证机制,比如密码或密钥,来确保发送和接收的实体是合法的。 总结:ARM SCP代码是一种用于在ARM架构下实现SCP协议的代码。它通过SSH协议建立加密通道,并使用加密和身份验证机制来安全地传输文件。发送主机通过SCP命令将文件发送到接收主机,接收主机在建立连接后接收并存储文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tcutee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值