打印
[S3C2440]

【最新u-boot-2013.10移植】之启动代码分析

[复制链接]
8626|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qyihan|  楼主 | 2013-12-3 11:25 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
    现在arm芯片的硬件和软件资源都相对非常丰富和开放,开发好像也变得简单了,只要拿别人的核心板和软件资源进行拼凑修改就能做到基本的开发了,好多人这样说,我原来也这样认为,但是开发过程中,总感觉理解不够深入,基础还是不牢固,所以我感觉上面的方案,如果建立在熟练的基础之上可能会更加得心应手。
    “纸上得来终觉浅,绝知此事要躬行”。看到大家都喜欢(我也是)收集各种技术资料,相比手中都有很多资料,但是重要的是把这些资料,吸收转化为自己的知识体系。为了深入理解,我决定深入分析一下u-boot源代码和linux内核的源代码,大牛是没时间做这个事的,我也是一个linux的新手,下面是我这几天利用工作之余的片段时间做的分析,欢迎大家讨论和指正。

【最新u-boot-2013.10移植】uboot移植(一):u-boot启动过程
1、set the cpu to SVC32 mode2、turn off the watchdog
3、mask all IRQs by setting all bits in the INTMR
4、设置时钟比例
5、cpu_init_crit设置内存控制器
6、设置栈,调用c函数board_init_f
7、执行init_sequence里的函数
          board_early_init_f  设置时钟和GPIO端口
.................
8、重定位代码relocate_code
         拷贝代码段和数据段到addr,修改.rel.dyn段的地址
9、清除bss段,调用c函数board_init_r进入第二阶段

相关帖子

沙发
qyihan|  楼主 | 2013-12-3 11:31 | 只看该作者
本帖最后由 qyihan 于 2013-12-3 11:33 编辑

【最新u-boot-2013.10移植】uboot移植(二):启动代码分析之start.S和crt0.S
start.S

/*
* armboot - Startup Code for ARM920 CPU-core
*
* Copyright (c) 2001 Marius Gr枚ger <mag@sysgo.de>
* Copyright (c) 2002 Alex Z眉pke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/

#include <asm-offsets.h>
#include <common.h>
#include <config.h>

/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/


.globl _start
_start: b start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

_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

.balignl 16,0xdeadbeef


/*
*************************************************************************
*
* 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
*
*************************************************************************
*/

.globl _TEXT_BASE
_TEXT_BASE:
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
.word CONFIG_SPL_TEXT_BASE
#else
.word CONFIG_SYS_TEXT_BASE
#endif

/*
* These are defined in the board-specific linker script.
* Subtracting _start from them lets the linker put their
* relative position in the executable instead of leaving
* them null.
*/
.globl _bss_start_ofs
_bss_start_ofs:
.word __bss_start - _start

.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end - _start

.globl _end_ofs
_end_ofs:
.word _end - _start

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif

/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de

/*
* the actual start code
*/

start_code:
/*
  * set the cpu to SVC32 mode
  */
/*设为管理模式*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
  * relocate exception table
  */
/*atmel的芯片相关的,不需要管*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif

#ifdef CONFIG_S3C24X0
/* turn off the watchdog */

# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interrupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000    /*2410的看门狗寄存器地址,和2440一样*/
# define INTMSK 0x4A000008     /* Interrupt-Controller base addresses */
/*INTMSK
中断屏蔽寄存器的地址,一共32位,每一位都对应一个中断源,0打开,1屏蔽
*/
# define INTSUBMSK 0x4A00001C   /*INTSUBMSK 这个寄存器有11位,每一位对应一个中断源,作用和INTMSK一样*/
# define CLKDIVN 0x4C000014   /* clock divisor register */
# endif

/*关开门狗*/
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]

/*
  * mask all IRQs by setting all bits in the INTMR - default
  */
/*关中断*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

/* FCLK:HCLK:PCLK = 1:2:4 */           /*设置时钟比例*/
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C24X0 */

/*
  * we do sys-critical inits only at reboot,
  * not when booting from ram!
  */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit    /*进去之后,会关闭MMU,然后再进入路径board\samsung\smdk2410\lowlevel_init.S中的lowlevel_init,
主要做初始化SDRAM的工作*/
#endif

bl _main        /*bl  _mian实际上是跳到了arch\arm\lib\crt0.S下
的ENTRY(_main)里,下面列出crt0.S的代码*/

/*------------------------------------------------------------------------------*/

.globl c_runtime_cpu_setup
c_runtime_cpu_setup:

mov pc, lr

/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
  * flush v4 I/D caches
  */
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

/*
  * disable MMU stuff and caches
  */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0

/*
  * before relocating, we have to setup RAM timing
  * because memory timing is board-dependend, you will
  * find a lowlevel_init.S in your board directory.
  */
mov ip, lr

bl lowlevel_init

mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*
………………………………


crt0.S


/*
* crt0 - C-runtime startup Code for ARM U-Boot
*
* Copyright (c) 2012 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/

#include <config.h>
#include <asm-offsets.h>
#include <linux/linkage.h>

/*
* entry point of crt0 sequence
*/

ENTRY(_main)

/*
* Set up initial C runtime environment and call board_init_f(0).
*/

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)    /*通过反汇编代码知道sp = 30000f60*/
#endif
/*通过反汇编代码知道sp又减去了0x98,在sp上面,存放了一个gd结构体*/
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
mov r9, sp /* GD is above SP */
mov r0, #0         /*给board_init_f传递参数,给c函数传递的参数放在r0,r1,r2寄存器里*/


bl  board_init_f    /*调用c函数,arch/arm/lib/board.c下的board_init_f函数*/
/*在board.c的开始处,有这样一个宏DECLARE_GLOBAL_DATA_PTR; 它是定义arch/arm/include/asm/global_data.h中:
#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
定义一个寄存器变量,如果去读gd,实际上就是去读r8
即 gd 的地址是存在 r8寄存器的. 此时gd空间已经准备好, 可以交给 board_init_f 去初始化了.
*/

#if ! defined(CONFIG_SPL_BUILD)

/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
/*
* 重新设置sp,指向addr_sp
* 设置返回地址
*/

ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */

adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
/*调用重定位代码arch\arm\lib\relocate_code.S,详细分析见uboot移植三*/
b relocate_code
here:

/* Set up final (full) environment */
/*下面的代码是清除bss段*/

bl  c_runtime_cpu_setup /* we still call old routine here */

ldr r0, =__bss_start /* this is auto-relocated! */
ldr r1, =__bss_end /* this is auto-relocated! */

mov r2, #0x00000000 /* prepare zero to clear BSS */

clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
/*
* 从代码中找不到coloured_LED_init和red_led_on的定义,
* 从反汇编看这两条语句是同一条指令:e1a0f00e mov pc, lr
* 也就是说这两条指令什么也没做,又返回了
* 所以这两个函数,我们可以自己来定义,用来做调试用
*/

bl coloured_LED_init
bl red_led_on

/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
/*调用c函数,进入第二阶段*/
ldr pc, =board_init_r /* this is auto-relocated! */

/* we should not return here. */

#endif

ENDPROC(_main)





使用特权

评论回复
板凳
qyihan|  楼主 | 2013-12-3 11:36 | 只看该作者
本帖最后由 qyihan 于 2013-12-3 11:39 编辑

【最新u-boot-2013.10移植】uboot移植(三):启动代码分析之重定位和内存分布图

接着uboot移植(二)
执行void board_init_f(ulong bootflag)函数


memset((void *)gd, 0, sizeof(gd_t));       /*把从gd开始,sizeof(gd_t)大小的空间清零,跳转前有这样一句话
                                                                    mov r9, sp /* GD is above SP */那么gd就在sp的上面*/
/*源码在这里还有一系列参数设置,具体查看源码*/


/*然后是依次执行init_sequence里的一系列初始化函数*/
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   hang ();
  }
}
...........
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux *//*机器码*/
和u-boot-2012.04.01相比区别是没有在这个函数里调用重定位代码的函数


如何确定mon_len是u-boot代码长度的分析:
board.c
gd->mon_len = _bss_end_ofs;
addr -= gd->mon_len;
addr &= ~(4096 - 1);
start.s
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end - _start
连接脚本u-boot.lds
从连接脚本可以看出__bss_end - _start为u-boot的代码,数据和bbs的总长度
ENTRY(_start)
........
KEEP(*(.__bss_end));
从反汇编知道_bss_end_ofs=000be064,所以addr = 33ff0000 - 000be064 = 33F31F9C,
addr &= ~(4096 - 1) = 33f31000


下面分析重定位函数relocate_code
ENTRY(relocate_code)
/*
* 从链接地址和反汇编知道__image_copy_start为0地址,就是代码的开始
* __image_copy_end为.text和.data段结束的地址
*/
ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
/*
* r0=gd->addr,就是u-boot在SDRAM中的地址,
* r4=r0-r1 = 33f31000 - 0 = 33f31000,就是重定位的偏移量
*/

subs r4, r0, r1 /* r4 <- relocation offset */
beq relocate_done /* skip relocation */
ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */

copy_loop:
/*
* 拷贝.text段和.data到addr处
*/
ldmia r1!, {r10-r11} /* copy from source address [r1] */
stmia r0!, {r10-r11} /* copy to target address [r0] */
cmp r1, r2 /* until source end address [r2] */
blo copy_loop

/*
  * fix .rel.dyn relocations
  */
/*
* 在反汇编里根本找不到__rel_dyn_start和__rel_dyn_end,只找到了下面的
* 0006fe5c <__rel_dyn_end-0x9478>:
* 推测__rel_dyn_end-0x9478就是__rel_dyn_start,按这个思路把数带进去看一下
*/
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
//r2 = 0006fe5c
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
//r3 = 0006fe5c + 0x9478 = 000792d4(.rel.dyn段的结束地址也确实是 000792d4,那就证明了上面的假设是正确的)
fixloop:
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
/*
* r0 = [0006fe5c] = 00000020
* r1 = [0006fe5c + 4] = 00000017
* r2 = r2 +8
*/
and r1, r1, #0xff
//r1 = 0x17   这里的0x17是标志位
cmp r1, #23 /* relative fixup? */
//r1 == #23
bne fixnext

/* relative fix: increase location by offset */
add r0, r0, r4
//r0 = 00000020 + 33f31000 = 33f31020,重定位之后的.rel.dyn段的地址
ldr r1, [r0]
//r1 = [33f31020],也就是[20]处的值,查看反汇编知道是<_undefined_instruction>,值为000000e0
add r1, r1, r4
//r1 = 000000e0 + 33f31000 = 33f310e0
str r1, [r0]
//r1 = [33f310e0],把修改过的地址,存放到重定位之后的.rel.dyn段
fixnext:
cmp r2, r3
//比较r2和r3看是否修改完
blo fixloop

relocate_done:

#ifdef __XSCALE__
/*
  * On xscale, icache must be invalidated and write buffers drained,
  * even with cache disabled - 4.2.7 of xscale core developer's manual
  */
mcr p15, 0, r0, c7, c7, 0 /* invalidate icache */
mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
#endif

/* ARMv4- don't know bx lr but the assembler fails to see that */

#ifdef __ARM_ARCH_4__
mov pc, lr
#else
bx lr
#endif

ENDPROC(relocate_code)




0006fe5c <__rel_dyn_end-0x9478>:
   6fe5c: 00000020 andeq r0, r0, r0, lsr #32
   6fe60: 00000017 andeq r0, r0, r7, lsl r0
   6fe64: 00000024 andeq r0, r0, r4, lsr #32
   6fe68: 00000017 andeq r0, r0, r7, lsl r0
   6fe6c: 00000028 andeq r0, r0, r8, lsr #32
   6fe70: 00000017 andeq r0, r0, r7, lsl r0
   6fe74: 0000002c andeq r0, r0, ip, lsr #32
   6fe78: 00000017 andeq r0, r0, r7, lsl r0
   6fe7c: 00000030 andeq r0, r0, r0, lsr r0
   6fe80: 00000017 andeq r0, r0, r7, lsl r0
   6fe84: 00000034 andeq r0, r0, r4, lsr r0
   ……   ……
上面是.rel.dyn段的部分汇编代码,其中的 00000017是标志位, 上面的代码所做的就是把 00000020里存放的地址加上33f31000,因为原来的代码是基于0地址进行编译的,重定位到SDRAM就要修改原来的地址了。

使用特权

评论回复
地板
黄小俊| | 2013-12-3 14:28 | 只看该作者

使用特权

评论回复
5
zdhlixiang2006| | 2013-12-4 22:08 | 只看该作者
佩服的体无完肤

使用特权

评论回复
6
天黑| | 2013-12-10 10:47 | 只看该作者
你好,我使用这个版本是直接解压后执行
make mini2440_config
make
后出现下面的错误这是为什么呢?

用的交叉编译器版本是arm-linux-gcc-3.4.5-glibc-2.3.6

使用特权

评论回复
7
qyihan|  楼主 | 2013-12-10 16:26 | 只看该作者
天黑 发表于 2013-12-10 10:47
你好,我使用这个版本是直接解压后执行
make mini2440_config
make

交叉编译器版本太低    可以用4.3.2或者以上的

使用特权

评论回复
8
qyihan|  楼主 | 2013-12-10 16:26 | 只看该作者
天黑 发表于 2013-12-10 10:47
你好,我使用这个版本是直接解压后执行
make mini2440_config
make

交叉编译器版本太低    可以用4.3.2或者以上的

使用特权

评论回复
9
qyihan|  楼主 | 2013-12-10 16:26 | 只看该作者
天黑 发表于 2013-12-10 10:47
你好,我使用这个版本是直接解压后执行
make mini2440_config
make

交叉编译器版本太低    可以用4.3.2或者以上的

使用特权

评论回复
10
天黑| | 2013-12-10 16:31 | 只看该作者
qyihan 发表于 2013-12-10 16:26
交叉编译器版本太低    可以用4.3.2或者以上的

嗯,好的,我试试去,谢谢:)

使用特权

评论回复
11
qyihan|  楼主 | 2013-12-10 16:32 | 只看该作者
sorry,网络卡了,连着点了几下,就发重复了

使用特权

评论回复
12
qyihan|  楼主 | 2013-12-10 16:55 | 只看该作者
13
天黑| | 2013-12-10 17:35 | 只看该作者
qyihan 发表于 2013-12-10 16:26
交叉编译器版本太低    可以用4.3.2或者以上的

你好,按照你的方法网上找了个交叉编译器,然后把原来交叉编译器的环境变量去掉了,

然后make又出现这样的错误,

搞不懂了,这是为什么了

使用特权

评论回复
14
qyihan|  楼主 | 2013-12-10 17:38 | 只看该作者
天黑 发表于 2013-12-10 17:35
你好,按照你的方法网上找了个交叉编译器,然后把原来交叉编译器的环境变量去掉了,

然后make又出现这样 ...

你先make distclean下,然后配置smdk2410的make smdk2410_config,make
试试smdk2410的行不,我这边是可以的

使用特权

评论回复
15
qyihan|  楼主 | 2013-12-10 17:43 | 只看该作者
天黑 发表于 2013-12-10 17:35
你好,按照你的方法网上找了个交叉编译器,然后把原来交叉编译器的环境变量去掉了,

然后make又出现这样 ...

我按你的方法也做了一遍,我这边可以编译通过

使用特权

评论回复
16
天黑| | 2013-12-10 17:45 | 只看该作者
qyihan 发表于 2013-12-10 17:38
你先make distclean下,然后配置smdk2410的make smdk2410_config,make
试试smdk2410的行不,我这边是可 ...

你好,可以的,这个可以编译通过,生成的u-boot.bin 这就不明白了,难道是这个版本的一个bug

使用特权

评论回复
17
天黑| | 2013-12-10 17:46 | 只看该作者
qyihan 发表于 2013-12-10 17:43
我按你的方法也做了一遍,我这边可以编译通过

然后我是不是应该自己建立个自己的板子的配置项来编译了

使用特权

评论回复
18
天黑| | 2013-12-10 17:48 | 只看该作者
qyihan 发表于 2013-12-10 17:43
我按你的方法也做了一遍,我这边可以编译通过

嗯,我的也可以了,原来要先执行make distclean 才行,我没有这样做,谢谢了

使用特权

评论回复
19
qyihan|  楼主 | 2013-12-10 18:03 | 只看该作者
天黑 发表于 2013-12-10 17:48
嗯,我的也可以了,原来要先执行make distclean 才行,我没有这样做,谢谢了 ...

刚才看你用的是mini2440配置的,然后我特意试了一下,编译出来一个135K的u-boot.bin,烧到板子上(我用的TQ2440的板子):


看来u-boot-2013.10对mini2440的板子是有简单的支持的,如果在这个基础上移植可能要快一点
你用的是mini2440的板子吗

使用特权

评论回复
20
天黑| | 2013-12-10 18:59 | 只看该作者
qyihan 发表于 2013-12-10 18:03
刚才看你用的是mini2440配置的,然后我特意试了一下,编译出来一个135K的u-boot.bin,烧到板子上(我用的 ...

嗯,我用的是mini2440,现在回到宿舍了,板子不在边上,明天继续弄了,你写的教程很好,我刚入门,谢谢你

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:嵌入式软件成长。。。<*_*>

13

主题

284

帖子

0

粉丝