搜索
bottom↓
回复: 3

i.mx28 Boot-stream分析(转载)

[复制链接]

出0入0汤圆

发表于 2013-4-7 21:22:08 | 显示全部楼层 |阅读模式
本帖最后由 liupeng08305 于 2013-4-7 21:23 编辑

一: 摘要
基于freescale的i.MX28处理器,ARM926EJ-S内核,最高主频400MHZ,内存DDR2 128MB,NAND FLASH 128MB,i.MX28有极高的集成度,可以降低系统总体成本,低功耗平台,能满足电池供电环境。内嵌L2 Switch,支持双网口;双CAN总线;多达6个UART,便于工控产品系统集成。平台软件丰富稳定,为降低客户设计要求,在linux操作系统之上封装了丰富的协议、基础库、应用程序框架和应用程序支撑层。无需熟悉底层繁琐的基础性,linux API,只需要会C++即可设计出完美的客户应用程序。工业级和汽车级环境,宽温度范围,高稳定性,非常适合于工业控制、汽车电子、医疗器械、仪器仪表。




imx28 启动模式提供了2种引导linux kernel 的方法






1:Boot-stream:

直接启动linux,使用imx-boolets 生成_linux.sb包含了硬件初始化和kernel引导代码。Linux_prep阶段将内核启动参数传递给kernel,然后跳到kernel (zImage) 处运行。



2:U-boot
对于i.MX28,U-Boot是用于在网络上的Linux内核映像加载到SDRAM,因为i.MX28内置ROM固件中没有实现的TCP / IP网络协议栈。i.MX28 U-Boot实现了FEC以太网控制器内置的驱动程序,可以使用TCP / IP网络下载kernel. (NFS,TFTP)
   本文的主角是Boot-stream,所以U-boot就此飘过.......




二:启动流程
   Boot stream 启动经历四个阶段; 这里直接引用IMX28 USER'S GUIDE 文档的说明:




  •  power_prep — This bootlet configures the power supply.
  •  boot_prep — This bootlet configures the clocks and SDRAM.
  •  linux_prep — This bootlet prepares to boot Linux



               








三:代码分析

  (1)power_prep
国际惯例,先来查看linker script ,
     在./imx-bootlets-src/power_prep目录下:link.lds文件:

点击(此处)折叠或打开
1.  OUTPUT_ARCH(arm)
2.  ENTRY(_start)
3.  SECTIONS
4.  {
5.   . = 0x00000000;
6.   . = ALIGN(4);
7.   .text : { *(.text) }
8.   .data : { *(.data) }
9.   .bss : { *(.bss) }
10.  }
OUTPUT_ARCH(arm):;指定输出可执行文件的平台为ARM  

=号前的"."为地址计数器(location counter ), 该符号只能用于SECTIONS命令内部,初始值为‘0’,可以对该符号进行赋值,也可以使用该符号进行计算或赋值给其他符号。它会自动根据SECTIONS命令内部所描述的输出段的大小来计算当前的地址。  
可以看出,代码的执行地址和存储地址就是0x00000000,以4字节对齐方式存储,依次存放text,data,bbs段。
ENTRY(_start)指定代码执行的入为_start。




    进入imx-bootlets-src/power_prep/power_prep.c   



_start:对寄存器的设置




PowerPrep_CPUClock2XTAL();
//设置时钟为外部时钟源。
PowerPrep_ClearAutoRestart();
//clear RTC ALARM wakeup or AUTORESTART bits here
hw_power_SetPowerClkGate( false );
//空函数,采用默认的设置
HW_POWER_VDDDCTRL.B.LINREG_OFFSET=  HW_POWER_LINREG_OFFSET_STEP_BELOW;

HW_POWER_VDDACTRL.B.LINREG_OFFSET =
HW_POWER_LINREG_OFFSET_STEP_BELOW;

HW_POWER_VDDIOCTRL.B.LINREG_OFFSET =
HW_POWER_LINREG_OFFSET_STEP_BELOW;
//如果没在这个范围,将产生一个FIQ,可以参照 i.MX28 Datasheet 在不同频率时设置这个掉电

//电压。即设置电源的波动范围
/*关于VDDD VDDA VDDIO,这里引用数据手册的解释:
• VDDD—provides power to the digital components of the i.MX28 processor. The system clocks
use the VDDD power rail.
• VDDA—provides power specifically to the audio systems, headphone amp. The VDDA power rail
also provides power to regulate the VDDMEM rail.
• VDDIO—provides power to the I/O peripherals and also to the NAND Flash and external Secure
Digital/MultiMedia Cards (SD/MMC).
*/

PowerPrep_Setup5vDetect();
PowerPrep_SetupBattDetect();
//设置电源探测的初始化。

PowerPrep_ConfigurePowerSource();
//探测可用的电源:
//内部电池或者外部充电电源。
//如果探测到可用的电池,就将电池作为供电电源,否则用外部电池。
//但是电池需要开发板的支持,IMX28 EVK没自带电池。
//探测过程的PMU寄存器的设置繁琐的"令人发指"。但只要依据数据手册的设置就没问
//题了。

PowerPrep_EnableOutputRailProtection();
//开启了三路电源vddio vdda vddd的browout的中断,但是如果在插入SD卡时候,导//致板子重

//启,那是因为插入SD卡,VDDIO负载变大,导致出现电压变化 。可以在

//PowerPrep_EnableOutputRailProtection()中禁止掉VDDIO的browout中断。

ddi_power_SetVddio(3300, 3150);  
ddi_power_SetVddd(1350, 1200);
//设置VDDIO和VDDD的值和brownout level 。
HW_POWER_CTRL_CLR(
BM_POWER_CTRL_VDDD_BO_IRQ |
BM_POWER_CTRL_VDDA_BO_IRQ |
BM_POWER_CTRL_VDDIO_BO_IRQ |
BM_POWER_CTRL_VDD5V_DROOP_IRQ |
BM_POWER_CTRL_VBUSVALID_IRQ |
BM_POWER_CTRL_BATT_BO_IRQ |
BM_POWER_CTRL_DCDC4P2_BO_IRQ
);
//清除不必要中断。

if (!bBatteryReady)
    HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_PWDN_5VBRNOUT);
//如果电池没输入,就自动关闭电池电压。注意只是关闭电池。如果外部电源有输入,
//系统启动没影响。
return iRtn;




  


(2) boot_prep

    依旧查看imx-bootlets-src/boot_prep 目录下的link.lds



点击(此处)折叠或打开
1.  OUTPUT_ARCH(arm)
2.  ENTRY(_start)
3.  SECTIONS
4.  {
5.   . = 0x00000000;
6.   . = ALIGN(4);
7.   .text : { *(.text) }
8.   .data : { *(.data) }
9.   .bss : { *(.bss) }
10.  }
link.lds和powe_prep下的link.lds一样,毫无压力,你们懂得。

代码到此将进入boot_prep的_start()
过程很简单,结果很完美。





    1:设置RAM为DDR2模式
    2:设置CPU CLK
    3:设置DDR2 的频率为166MHZ
    4:测试RAM





设置完全就是寄存器的配置。这里就不一一分析了,参照数据手册很好就明白了。
这里测试RAM的方法很简单,
volatile int *pTest = 0x40000000;
向0x40000000写入1000个数,在读出来,没有错误就说明RAM正常。






(3) linux_prep




   向kernel传递正确的参数,引导linux kernel。设置好标记列表后就要调用内核了。但调用内核前,CPU寄存器的设置必须满足下面的条件:
  Ø r0=0
  Ø r1=机器码
  Ø r2=内核参数标记列表在RAM中的起始地址


imx-bootlets-src/linux_prep/core/entry.S 承载着这一使命。




_start:
stmdb sp!, {r4-r12, lr}
/* Check entry counter */
ldr r4, entry_count
cmp r4, #0
bne start_kernel
//如果从休眠启动内核,entry_count > 0跳到try_to_resume;
//否则entry_count = 0;直接start_kernel
bl try_to_resume
/* Update counter to show we were here */
add r4, r4, #1
str r4, entry_count
//增加entry_count,用以标示内核从什么状态启动。
/* Return to ROM */
ldmia sp!, {r4-r12, lr}
bx lr

//在来看看start_kernel 做了哪些工作呢?
start_kernel:
bl clear_bss
//首选清除BBS段,如果不清除,以后程序会出现执行错误
/* Initialize HW modules relevant for linux_prep */
bl hw_init
/* Setup tags for Linux kernel and save tags pointer in r2 */
bl setup_tags
mov r2, r0
//R2里面保持了内核启动参数的地址, r0里面存储的是setup_tags()的返回值。
//即内核启动参数的地址
//setup_tags()函数式用C语言编写,设置启动内核的参数
/* Store machine id in r1 */
ldr r1, =MACHINE_ID
//R1保持了MX28_EVK的ID
//其实就是个数字 #define   MACHINE_ID 2531
/* Zero r0 register */
mov r0, #0
//当然要清除R0了,这个启动内核前的需求。
/* Jump to Linux kernel */
ldr lr, =KERNEL_BASE_ADDRESS
mov pc, lr
//跳到内核代码处,将执行内核代码的自解压程序
//如果从休眠状态启动内核,就跳到 try_to_resume .







   设置启动内核的参数




u32 setup_tags (void)
{
    enum magic_key magic_key;
    magic_key = get_magic_key();
    find_command_lines();
    setup_start_tag();
    setup_mem_tag();
    setup_initrd_tag();
    setup_cmdline_tag(cmdlines[magic_key]);
    setup_end_tag();
    return (u32)ATAGS_BASE_ADDRESS;
}






(1)setup_start_tag函数
static void setup_start_tag (bd_t *bd)
{
params = (struct tag*)ATAGS_BASE_ADDRESS; /* 内核的参数的开始地址 */
         params->hdr.tag = ATAG_CORE;
         params->hdr.size = tag_size(tag_core);
         params->u.core.flags = 0;
         params->u.core.pagesize = 0;
         params->u.core.rootdev = 0;
         params = tag_next(params);
}
标记列表必须以ATAG_CORE开始,setup_start_tag函数在内核的参数的开始地址设置了一个ATAG_CORE标记。
(2)setup_memory_tags函数
static void setup_memory_tags (bd_t *bd)
{
        params->hdr.tag = ATAG_MEM;
        params->hdr.size = tag_size(tag_mem32);       
        params->u.mem.start = SDRAM_BASE;
        params->u.mem.size = get_sdram_size();
        params = tag_next(params);
}
setup_memory_tags函数设置了一个ATAG_MEM标记,该标记包含内存起始地址,内存大小这两个参数。

(3)setup_initrd_tag函数
static void setup_initrd_tag(void)
{
        params->hdr.tag = ATAG_INITRD2 ;
        params->hdr.size = tag_size(tag_initrd);
        params->u.initrd.start = 0x40400000;
        params->u.initrd.size =  0x00400000;
        params = tag_next(params);
}
设置了 ramdisk image 的起始物理地址和大小。
(4)setup_end_tag函数
static void setup_end_tag (bd_t *bd)
{
        params->hdr.tag = ATAG_NONE;
        params->hdr.size = 0;
}
标记列表必须以标记ATAG_NONE结束,setup_end_tag函数设置了一个ATAG_NONE标记,表示标记列表的结束。

ldr lr, =KERNEL_BASE_ADDRESS
mov pc, lr
接下来,将KERNEL_BASE_ADDRESS 传递给PC指针,将代码控制权交给linux kernel。Boot-stream 精彩的生命到此结束了,留下了OS的各种膜拜和感激,让OS去走它自己的路吧。相信它会走的更好。


四:IMX28-EVK编译bootlets.
直接启动linux 这种方法需要将生产的zImage镜像制成imx28_linux.sb镜像imx28_linux.sb镜像是对zImage镜像做了些加工,为zImage的运行准备环境。
在编译boot-stream前假定已经安装好了整个开发环境(ltib).如果没有安装,请参照宁一篇文章 《Freescale Imx28 开发环境的搭建 》
   
    #mkdir boot-stream
    #cd boot-stream
    #sudo tar xvfz /opt/freescale/pkgs/imx-bootlets-src
    # cp  ~/linux/arch/arm/boot/zImage  ./imx-bootlets-src/
    #make CROSS_COMPILE=
   /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-      linux-gnueabi-
   BOARD=iMX28_EVK
   注意,这里可能会出现如下错误
    elftosb2 -z -c ./linux_prebuilt.db -o imx28_linux.sb
    make: elftosb2: Command not found
    可能是环境设置不对,在这里为了图方便,直接cp /opt/freescale/ltib/usr/bin/elftosb2
    到 imx-bootlets-src下。当然你也可以用export 导出环境变量。
    编译完成后将生成imx28-linux.sb。这个就是将要烧写的linux。
    然后插入SD卡,利用ltib提供的mk_hdr.sh 烧写进SDCARD就行.
    #cp  imx28-linnux.sb  ~/ltib/rootfs/boot
    #cd  ~/ltib
    #./mk_hdr.sh  /dev/sdx       //sdx插入的SDCARD,sdb. 在烧写前,需要先umount SD卡。

烧写完成将SDCARD插入到IMX28-EVK的socket 0 。按下power,启动linux。Enjoy it!!!

到这里boot-stream 的讲解也ALT+F4了,不过探索linux的路才刚刚起步。










阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2013-4-12 07:30:32 | 显示全部楼层
谢谢!收藏了!

出0入0汤圆

发表于 2013-4-22 17:05:50 | 显示全部楼层
顶一个!!!

出0入0汤圆

发表于 2013-5-23 13:22:14 | 显示全部楼层
谢谢!!学习了!!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 03:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表