这篇接着上一篇,来分析上一篇程序里面的MLO和app文件启动过程,基本涵盖到整个am335x的大部分操作,包括:时钟初始化、代码搬移、中断向量的重定位、中断的处理等。要分析程序,首先分析makefile和连接脚本lds文件,然后顺藤摸瓜,当同名函数太多时,可以考虑反汇编elf文件,进行对比判断。
0.添加Source Insight工程
创建新工程,添加所有文件,注意Source Insight添加对asm和makefile文件支持,更有利于分析
1.bootloader分析
查看build/armv7a/gcc/am335x/sbc8600/bootloader目录makefile和lds文件可知(*bl_init.o),第一个文件为bootloader/src/armv7a/gcc/bl_init.S
#bootloader/src/armv7a/gcc/bl_init.S
Entry:
bl_start
#bootloader/src/bl_main.c
/* 各种初始化 */
DeviceConfig()
#bootloader/src/bl_am335x.c
// 关看门狗
HWREG(SOC_WDT_1_REGS + WDT_WSPR) = 0xAAAAu;
while(HWREG(SOC_WDT_1_REGS + WDT_WWPS) != 0x00);
HWREG(SOC_WDT_1_REGS + WDT_WSPR) = 0x5555u;
while(HWREG(SOC_WDT_1_REGS + WDT_WWPS) != 0x00);
// 初始化时钟
PLLInit();
// 使能控制模块
HWREG(SOC_CM_WKUP_REGS + CM_WKUP_CONTROL_CLKCTRL) =
CM_WKUP_CONTROL_CLKCTRL_MODULEMODE_ENABLE;
// 初始化内存
EMIFInit();
DDR3Init();
// 初始化串口
UARTSetup();
/* 打印启动信息 */
UARTPuts("StarterWare ", -1);
/* 将app从mmc复制到ram */
ImageCopy();
#bootloader/src/bl_copy.c
MMCSDBootCopy();
#bootloader/src/bl_hsmmcsd.c
// 初始化控制器
HSMMCSDInit();
// 复制mmc内容到ram
HSMMCSDImageCopy();
// 设置app入口地址
entryPoint = imageHdr.load_addr;
/* 跳转到app执行 */
appEntry = (void (*)(void)) entryPoint;
UARTPuts("Jumping to StarterWare Application...
", -1);
(*appEntry)( );
2.app分析
查看build/armv7a/gcc/am335x/sbc8600/bootloader目录makefile和lds文件可知(*init.o),第一个文件为system_config/armv7a/gcc/init.S
#system_config/armv7a/gcc/init.S
Entry:
start_boot
#system_config/armv7a/am335x/startup.c
/* 中断向量重定位 */
CopyVectorTable();
CP15VectorBaseAddrSet(AM335X_VECTOR_BASE);
#system_config/armv7a/gcc/cp15.S
CP15VectorBaseAddrSet:
dest[count] = src[count];
static unsigned int const vecTbl[14]=
(unsigned int)IRQHandler,
#system_config/armv7a/am335x/gcc/exceptionhandler.S
IRQHandler:
/* 保存现场 */
...
/* 处理中断 */
LDR r0, =fnRAMVectors
/* 恢复现场 */
...
/* 调用main函数 */
main();
#examples/sbc8600/uart/uartEcho.c
/* 打开时钟 */
UART0ModuleClkConfig();
/* 串口初始化 */
UartFIFOConfigure();
......
/* 配置中断 */
UartInterruptEnable();
UART0AINTCConfigure();
IntRegister(SYS_INT_UART0INT, UARTIsr);
#system_config/armv7a/am335x/interrupt.c
void IntRegister(unsigned int intrNum, void (*fnHandler)(void))
fnRAMVectors[intrNum] = fnHandler;
void (*fnRAMVectors[NUM_INTERRUPTS])(void);
/* 死循环 */
while(1);
整个uart裸机程序分为两部分:MLO、app,其中MLO用于完成基本初始化,然后跳转到app入口,app负责完成中断向量(interrupt vector)重定位,并负责实现中断的处理,当uart发生收发中断时,会暂时停止当前工作,跳转到异常入口中断,进行对数据的处理,当处理完中断后,返回前面位置继续运行。
最后总结一下,分析要点:
makefile、lds、反汇编