跳转到主要内容

【干货分享】 MPSoC的芯片启动流程

judy 提交于

作者:付汉杰,<a href="mailto:hankf@xilinx.com">hankf@xilinx.com</a&gt;,文章转载自:<a id="link_3" href="https://forums.xilinx.com/t5/%E5%B5%8C%E5%85%A5%E5%BC%8F-%E5%B7%A5%E5%8…;

MPSoC A53执行的第一条代码定义在BSP工程的目录\psu_cortexa53_0\libsrc\standalone_v7_0\src\asm_vectors.S里。

去掉Xen相关代码后,简化如下:
<pre>
.org 0

.section .vectors, "a"

_vector_table:
.set VBAR, _vector_table
.org VBAR

b _boot
.org (VBAR + 0x200)
b SynchronousInterruptHandler

.org (VBAR + 0x280)
b IRQInterruptHandler

.org (VBAR + 0x300)
b FIQInterruptHandler

.org (VBAR + 0x380)
b SErrorInterruptHandler
</pre>

上述代码的地址,由《ARM® Architecture Reference Manual,ARMv8, for ARMv8-A architecture profile》(ARM DDI 0487C)定义,可以参考Table D1-7 Vector offsets from vector table base address。

EL0的Synchronous offset是0x0。其他EL级别,Synchronous offset是0x200,IRQ or vIRQ offset是0x280, FIQ or vFIQ offset是0x300, SError or vSError offset是0x380,
MPSoC A53启动后,在EL0,执行的第一条代码是“b _boot”。

符号_boot的定义在BSP工程的目录\psu_cortexa53_0\libsrc\standalone_v7_0\src\boot.S里。简化后的代码如下。
<pre>
/* this initializes the various processor modes */
_prestart:
_boot:
mov x0, #0
... ...
mov x30, #0
#if 0 //dont put other a53 cpus in wfi
//Which core am I
// ----------------
mrs x0, MPIDR_EL1
and x0, x0, #0xFF //Mask off to leave Aff0
cbz x0, OKToRun //If core 0, run the primary init code
EndlessLoop0:
wfi
b EndlessLoop0
#endif
OKToRun:

mrs x0, currentEL
cmp x0, #0xC
beq InitEL3

cmp x0, #0x4
beq InitEL1

b error // go to error if current exception level is neither EL3 nor EL1
</pre>

InitEL3/InitEL1会设置reset vector address,Invalidate cache,设置stack pointer。
执行上述代码后,会执行“bl _startup”。

符号_startup的定义在BSP工程的目录\psu_cortexa53_0\libsrc\standalone_v7_0\src\xil-crt0.S里。符号_startup先清除SBSS和BSS段,然后运行global constructors,再跳到C语言的定义在文件xfsbl_main.c里的入口函数main。

FSBL的main()里的调用关系是XFsbl_Initialize()->XFsbl_SystemInit()->XFsbl_HookPsuInit()->psu_init().。

psu_init由Vivado导出,含有芯片的管脚、pll、DDR初始化,主要代码如下。
<pre>
psu_init(void)
{
status &= psu_mio_init_data();
status &= psu_pll_init_data();
status &= psu_clock_init_data();
status &= psu_ddr_init_data();
status &= psu_ddr_phybringup_data();
status &= psu_peripherals_init_data();
status &= init_serdes();
init_peripheral();

status &= psu_peripherals_powerdwn_data();
status &= psu_afi_config();
}
</pre>

上述流程,可以在SDK里双击应用程序的ELF文件,查看应用程序的反汇编文件确认。