Chinaunix首页 | 论坛 | 博客
  • 博客访问: 780240
  • 博文数量: 37
  • 博客积分: 575
  • 博客等级: 中士
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-12 10:43
个人简介

活到老,学到老!

文章分类

全部博文(37)

文章存档

2019年(4)

2018年(4)

2015年(1)

2014年(14)

2011年(1)

2010年(13)

我的朋友

分类: 嵌入式

2014-08-20 22:52:44

barebox-2014.08.0

flash to SD card
sudo dd if=./barebox.s5p of=/dev/sdb bs=512 seek=1

启动流程分析:

一般的bootloader都会以一个汇编文件作为起始,但是barebox没有

这个c函数作为了整个image的入口,关键是__section(.text_entry)lds文件起了作用。

lds文件是arch/arm/lib/barebox.lds.S,它会被编译成barebox.lds并最终参与链接。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(start)

SECTIONS

{

#ifdef CONFIG_RELOCATABLE

         . = 0x0;

#else

         . = TEXT_BASE;

#endif

 

         . = ALIGN(4);

         .text      :

         {

                  _stext = .;

                  _text = .;

                  *(.text_entry*)

                  __bare_init_start = .;

                  *(.text_bare_init*)

                  __bare_init_end = .;

                  __exceptions_start = .;

                  KEEP(*(.text_exceptions*))

                  __exceptions_stop = .;

                  *(.text*)

         }

         BAREBOX_BARE_INIT_SIZE

 

*(.text_entry*)就相当于把start函数关联进了lds文件,然后ENTRY(start)又指定整个image的入口,于是start函数就成了整个image的入口。

TEXT_BASE则是dram中的地址,后面barebox会把自己拷贝到这个地址并跳转过去。

arch/arm/cpu/start.c 

//第一条语句调用内联函数barebox_arm_head ()

1.      arch/arm/include/asm/barebox-arm-head.h

static inline void __barebox_arm_head(void)

{

__asm__ __volatile__ (

#ifdef CONFIG_THUMB2_BAREBOX

          ".arm\n"

          "adr r9, 1f + 1\n"

          "bx r9\n"

          ".thumb\n"

          "1:\n"

          "bl 2f\n"

          ".rept 10\n"

          "1: b 1b\n"

          ".endr\n"

#else

          "b 2f\n"

          "1: b 1b\n"

          "1: b 1b\n"

          "1: b 1b\n"

          "1: b 1b\n"

          "1: b 1b\n"

          "1: b 1b\n"

          "1: b 1b\n"

#endif

          ".asciz \"barebox\"\n"

          ".word _text\n"                                 /* text base. If copied there,

                                                       * barebox can skip relocation

                                                       */

          ".word _barebox_image_size\n"           /* image size to copy */

          ".rept 8\n"

          ".word 0x55555555\n"

          ".endr\n"

          "2:\n"

);

}

static inline void barebox_arm_head(void)

{

__barebox_arm_head();

__asm__ __volatile__ (

          "b barebox_arm_reset_vector\n"

);

}

这两个函数都是inline函数,所以代码都会被内嵌到start函数中去。

于是c函数start其实就变成了一个汇编函数。

我们可以看到,在汇编代码的最前端,连续的8个跳转,其实是模仿arm8个异常向量。

这里其实并没有什么作用,只是简单的做了下跳转到2。

用UltraEdit打开barebox.bin,即看到先是一个8个字节大小的字符串barebox,然后是两个4字节变量,一个保存的是barebox的链接地址0x23e00000(TEXT_BASE),还有个是barebox的大小,最后则是连续8个0x55555555。

lowlevel.c

接下来,程序就会调用arch/arm/boards/friendlyarm-tiny210/lowlevel.c中的barebox_arm_reset_vector函数。

void __bare_init barebox_arm_reset_vector(void)

{

arm_cpu_lowlevel_init();

#ifdef CONFIG_S3C_PLL_INIT

s5p_init_pll();           //初始化PLL

#endif

debug_led(0, 1);      //点亮LED1

if (get_pc() < IRAM_CODE_BASE) /* Are we running from iRAM? */          

          /* No, we don't. */                  //SD卡启动时,PC= IRAM_CODE_BASE

          goto boot;

s5p_init_dram_bank_ddr2(S5P_DMC0_BASE, 0x20E00323, 0, 0);      //初始化DDR

debug_led(1, 1);                       //点亮LED2

//SD卡中的barebox装载到TEXT_BASE位置,+/-16是因为加了16字节的校验头。

/*此处用到s5pv210的一个特殊功能,它的rom code提供了从sd卡读取数据的函数,所以只要直接调用这个地址就可以实现barebox的加载了*/

if (! load_stage2((void*)(ld_var(_text) - 16),                 

                            ld_var(_barebox_image_size) + 16)) {

          debug_led(3, 1);

          while (1) { } /* hang */

}

debug_led(2, 1);             //点亮LED3

jump_sdram(IRAM_CODE_BASE - ld_var(_text));                  //跳转offsetTEXT_BASE执行

debug_led(1, 0);

boot:

barebox_arm_entry(S3C_SDRAM_BASE, SZ_256M, 0);

}

arm_cpu_lowlevel_init只是预留了一个接口,暂时并没有实现什么功能。

所以第一步做的事情是配置pll。然后判断当前代码的运行位置。

假设程序是通过rom code加载到sram运行的话,其pc值必定是从0xD0020000起,外加16个字节的校验,所以就是0xD0020010了。

如果已经是在dram中的话,那就没有必要再初始化dram以及把barebox加载到dram了。

当然,在我们这种正常启动情况下,代码会顺序往下走,进行dram的初始化配置。

dram配置完毕后,就把整个bareboxsd卡读取到dram中去。

最后一步就是通过jump_sdram跳转到dram中去,这之后运行的barebox_arm_entry函数,就是运行在dram中的了。

这里还有一点需要注意,我们可以发现,在跳转到dram之前运行的函数都是有__bare_init的

#define __bare_init __section(.text_bare_init.text)

在lds文件中是紧随*(.text_entry*)之后的。

估计是因为barebox的链接地址是dram中的地址,所以刚开始在sram中运行时被调用的函数都需要靠近以保证跳转时使用的是相对偏移而不是绝对地址。

DRAM(barebox_arm_entry)

arm_setup_stack() 设置栈SP指针,指向0x20000000+0x10000000-16

S3C_SDRAM_BASE+SZ_256M -16

接着跳转到__start,还在arch/arm/cpu/start.c

最后,执行start_barebox()

Common/startup.c

调用经典的initcall(),所有的设备、驱动、文件系统都在这里完成,类似linux。

读取环境变量

最后执行死循环run_shell()

initcall()

打开bareboxDEBUG选项

Make menuconfig->Debugging,都改为7即可

配合barebox.map分析打印信息

pure_initcall(globalvar_init);          // register_device

pure_initcall(platform_init);           // bus_register  -> register_device

pure_initcall(spi_bus_init);            // bus_register  -> register_device

pure_initcall(fs_bus_init);               // bus_register  -> register_device

core_initcall(s3c_clk_src_init);      //Timer4(需要理解)

postcore_initcall(hist_init);             //

postcore_initcall(init_fs);                //

console_platform_driver(s3c_serial_driver);                 //

console_initcall(tiny210_console_init);                          //s3c_serial作为控制台,并分配缓冲区

                                                                                                0xe2900000:0xe29003ff

//这中间有个cs0  没有弄明白

mem_initcall(tiny210_mem_init);                           //注册mem0,空间为0x20000000:0x3fffffff

coredevice_initcall(mem_malloc_resource);                //划分空间如下

bss                             0x23e16910:0x23e19d87

barebox data           0x23e1591a:0x23e1690f

                  barebox                    0x23e00000:0x23e15919

                  malloc space           0x23a00000:0x23dfffff

coredevice_initcall(bootsource_init);                     //boot,引导启动相关

coredevice_initcall(reset_source_init);                           //复位源初始化

coredevice_initcall(ramfs_init);                               //ramfs

coredevice_initcall(devfs_init);                                //devfs

coredevice_initcall(arm_request_stack);               //分配stack0x2fff8000:0x2fffffff

fs_initcall(mount_root);                                                     //挂载ramfs-> /   devfs->/dev

fs_initcall(binfmt_sh_init);                                        //shell脚本解释器

fs_initcall(binfmt_uimage_init);                               //通过shell调用bootm语法解释

device_initcall(loglevel_init);                                    //调试信息等级

device_initcall(null_init);                                                    //创建一个null的字符设备,null_write

device_initcall(full_init);                                                     //创建一个full的字符设备,full_read

device_initcall(zero_init);                                          //创建一个zero的字符设备,zero_read

device_initcall(mem_init);                                         // Memory Functions

device_initcall(tiny210_devices_init);                     //板文件,平台初始化(GPIO。。。)

device_initcall(s3c_detect_reset_source);            //检测复位源

late_initcall(console_global_init);                           //控制台相关(允许交互)

late_initcall(bootm_init);                                          //初始化bootm需要传递的参数(imageinitrd

late_initcall(init_command_list);                             //初始化命令列表

late_initcall(display_meminfo);                               //打印内存信息

barebox code: 0x23e00000 -> 0x23e15919

bss segment:  0x23e16910 -> 0x23e19d87

malloc space: 0x23a00000 -> 0x23dfffff (size 4 MiB)

late_initcall(trigger_init);                                          //trigger led

late_initcall(s5pcxx_dump_clocks);                        //时钟

late_initcall(armlinux_register_image_handler); // register_image_handler,根据不同的image类型,bootm指令调用不同的函数

Done

读取环境变量 environment

首先,程序去读取/dev/env0到/env,正常情况下/dev/env0存放的是saveenv保存的压缩文件。
envfs_load(default_environment_path, "/env", 0);
初始化时找不到此文件,所有会读取/dev/defaultenv到/env
defaultenv_load("/env", 0);
然后执行/env/bin/init

 


阅读(4234) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~