/***Purpose: the document is used to learn detailed information aboutimx51 cpu start.S, *referring to some documents on websites.*file address: U-boot-2009.08/Cpu/Arm_cortexa8/start.S** writer: xfhai 2011.7.22**Instruction:*1.@xxxx : indicates annotation*2./*************/ : stand for code in my files*3.instructions refers to code not included in my file**/Section 1: uboot overview大多数bootloader都分为stage1和stage2两部分,u-boot也不例外。
依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
1、Stage1 start.S代码结构u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下:==> (1)定义入口。
由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
==>(2)设置异常向量(Exception Vector)。
==>(3)设置CPU的速度、时钟频率及终端控制寄存器。
==>(4)初始化内存控制器。
==>(5)将ROM中的程序复制到RAM中。
==>(6)初始化堆栈。
==>(7)转到RAM中执行,该工作可使用指令ldr pc来完成。
2、Stage2 C语言代码部分lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作:==>(1)调用一系列的初始化函数。
==>(2)初始化Flash设备。
==>(3)初始化系统内存分配函数。
==>(4)如果目标系统拥有NAND设备,则初始化NAND设备。
==>(5)如果目标系统有显示设备,则初始化该类设备。
==>(6)初始化相关网络设备,填写IP、MAC地址等。
==>(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
Section 2: demos3、U-Boot的启动顺序(示例,其他u-boot版本类似)cpu/arm920t/start.S(my file is U-boot-2009.08/Cpu/Arm_cortexa8/start.S )@文件包含处理#include <config.h>@由顶层的mkconfig生成,其中只包含了一个文件:configs/<顶层makefile中6个参数的第1个参数>.h#include <version.h>#include <status_led.h>/**************************************************************************** Jump vector table as in table 3.1 in [1]***************************************************************************/注:ARM微处理器支持字节(8位)、半字(16位)、字(32位)3种数据类型向量跳转表,每条占四个字节(一个字),地址范围为0x0000 0000~@0x0000 0020,ARM体系结构规定在上电复位后的起始位置,必须有8条连续的跳转指令,通过硬件实现。
他们就是异常向量表。
ARM在上电复位后,是从0x00000000开始启动的,其实如果bootloader存在,在执行下面第一条指令后,就无条件跳转到start_code,下面一部分并没执行。
设置异常向量表的作用是识别bootloader。
以后系统每当有异常出现,则CPU会根据异常号,从内存的0x00000000处开始查表做相应的处理/******************************************************;当一个异常出现以后,ARM会自动执行以下几个步骤:;1.把下一条指令的地址放到连接寄存器LR(通常是R14).---保存位置;2.将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中---保存CPSR;3.根据异常类型,强制设置CPSR的运行模式位;4.强制PC(程序计数器)从相关异常向量地址取出下一条指令执行,从而跳转到相应的异常处理程序中*********************************************************/.globl _start /*系统复位位置,整个程序入口*/@_start是GNU汇编器的默认入口标签,.globl将_start声明为外部程序可访问的标签,.globl是GNU汇编的保留关键字,前面加点是GNU汇编的语法_start: b start_code @0x00//diff here: _start: b reset@ARM上电后执行的第一条指令,也即复位向量,跳转到start_code@reset用b,就是因为reset在MMU建立前后都有可能发生@其他的异常只有在MMU建立之后才会发生ldr pc, _undefined_instruction /*未定义指令异常,0x04*/ldr pc, _software_interrupt /*软中断异常,0x08*/ldr pc, _prefetch_abort /*内存操作异常,0x0c*/ldr pc, _data_abort /*数据异常,0x10*/ldr pc, _not_used /*未适用,0x14*/ldr pc, _irq /*慢速中断异常,0x18*/ldr pc, _fiq /*快速中断异常,0x1c*/@对于ARM数据从内存到CPU之间的移动只能通过L/S(load && storage)指令,如:ldr r0,0x12345678为把0x12345678内存中的数据写到r0中,还有一个就是ldr伪指令,如:ldr r0,=0x12345678为把0x12345678地址写到r0中,mov只能完成寄存器间数据的移动,而且立即数长度限制在8位_undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq//three more lines here://.pad: .word 0x12345678 /*now 16*4=64*///.global _end_vector//_end_vect://don’t make sense@.word为GNU ARM汇编特有的伪操作,为分配一段字内存单元(分配的单元为字对齐的),可以使用.word把标志符作为常量使用。
如_fiq:.word fiq即把fiq存入内存变量_fiq中,也即是把fiq放到地址_fiq中。
.balignl 16,0xdeadbeef.balign是意思是:以当前地址为开始开始,找到第一次出现的以第一个参数为整数倍的地址,并将其作为结束地址,在这个结束地址前面存储一个字节长度的数据,存储内容正是第二个参数。
如果当前地址正好是第一个参数的倍数,则没有数据被写入到内存。
.balign 8, 0xde这条指令的含义可以用下图表示:图解:以当前地址为开始开始,找到第一次出现的以8为整数倍的地址,并将其作为结束地址,在这个结束地址前面存储一个字节长度的数据0xde。
如果当前地址正好是8的倍数,则没有数据被写入到内存。
以此类推,.balignw则表示第二个参数存入的内容长度为2字节:.balignw 4, 0x368d因为现在填入的内容为2个字节,那就存在以下几种情况:当前地址没有偏移就满足了以4为倍数的地址当前地址偏移了1个字节就满足了以4为倍数的地址当前地址偏移了2个字节就满足了以4为倍数的地址当前地址编移了3个字节就满足了以4为倍数的地址分析一下这四种情况:当没有偏移的时候,地址中间肯定没有办法填上信息当偏移1个字节的时候,地址中间空隙不够,所以填入的数值,是末定义,也就是说,填入什么值,不清楚当偏移2个字节的时候,地址中间的空隙正好填入0x368d两个字节的内容当偏移3个字节的时候,地址中间的空隙大于所要填的内容。
此时填入的数值,是末定义,填入什么值,不清楚以此类推,.balignl,这个指令用来填与一个字,即4个字节的长度仔细分析一下就知道,对于.balignl 16, 0xdeadbeef,如果想要0xdeadbeef一定填到当前地址后面某个部分,当前地址偏移量就必须为4字节,这样才能保证在任何情况下,偏移的地址所留的空隙刚好填入所要填的内容。
//伪操作指机器码里没有对应的汇编指令,由编译器实现其功能/**************************************************************************** Startup Code (called from the ARM reset exception vector)** do important init only if we don't start from memory!* relocate armboot to ram* setup stack* jump to second stage**************************************************************************@保存变量的数据区,保存一些全局变量,用于BOOT程序从FLASH拷贝@到RAM,或者其它的使用。