转自:http://blog.chinaunix.net/uid-28458801-id-3486399.html
1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf;
2,am3359.pdf;
1,am335x的cpu上电后,会跳到哪个地址去执行?
答:
芯片到uboot启动流程 :ROM → MLO(SPL)→ uboot.img
AM335x 中bootloader被分成了 3 个部分:
第一级 bootloader:引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART。。。),然后跳转转到第二级 bootloader。这些代码应该是存放在 176KB 的 ROM 中。
第二级 bootloader:MLO(SPL),用以硬件初始化:关闭看门狗,关闭中断,设置 CPU 时钟频率、速度等操作。然后会跳转到第三级bootloader。MLO文件应该会被映射到 64 KB的 Internal SRAM 中。
第三级 bootloader:uboot.img,C代码的入口。
其中第一级 bootloader 是板子固化的,第二级和第三级是通过编译 uboot 所得的。
2,第二级 bootloader:MLO(SPL)做了哪些事情?
MLO(SPL)内存分布如下:
SPL内存重映射:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<
PATH : /arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
>
MEMORY
{ .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\ LENGTH
= CONFIG_SPL_MAX_SIZE }
MEMORY
{ .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \ LENGTH
= CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{ .text
:
{
__start
= .;
arch/arm/cpu/armv7/start.o
(.text)
*(.text*)
}
>.sram
.
= ALIGN(4);
.rodata
: { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
.
= ALIGN(4);
.data
: { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
.
= ALIGN(4);
__image_copy_end
= .;
_end
= .;
.bss
:
{
.
= ALIGN(4);
__bss_start
= .;
*(.bss*)
.
= ALIGN(4);
__bss_end__
= .;
}
>.sdram
} |
|
1
2
3
4
5
6
7
|
<path
:=""include=""configs=""am335x_evm.h="">
#define
CONFIG_SPL_TEXT_BASE 0x402F0400#define
CONFIG_SPL_MAX_SIZE (46 * 1024)#define
CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK#define
CONFIG_SPL_BSS_START_ADDR 0x80000000#define
CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */ <span style="font-size:16px;color:#003399;"><strong></strong></span></path> |
@[email protected] 保存启动参数 bl save_boot_params
|
1
2
3
4
5
6
7
8
9
|
<path
:=""arch=""arm=""cpu=""armv7=""start.s="">
/* *
the actual reset code
*/
reset: bl
save_boot_params
</path>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<path
:=""arch=""arm=""cpu=""armv7=""omap-common=""lowlevel_init.s="">
.global
save_boot_paramssave_boot_params: /*
*
See ifthe
rom code passed pointer is valid:
*
It is not valid ifit
is not innon-secure
SRAM
*
This may happen ifyou
are booting with the help of
*
debugger
*/
ldr
r2, =NON_SECURE_SRAM_START
cmpr2,
r0
bgt
1f
ldr
r2, =NON_SECURE_SRAM_END
cmpr2,
r0
blt
1f
/*
*
store the boot params passed from rom code or saved
*
and passed by SPL
*/
cmpr0, #0
beq
1f
ldr
r1, =boot_params
str
r0, [r1]</path>
|
|
1
2
3
4
5
6
7
8
|
/*《PATH:
/arch/arm/include/asm/arch-ti81xx/omap.h》 *
Non-secure SRAM Addresses
*
Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE
*
at 0x40304000(EMU base) so that our code works for both EMU and GP
*/
#define
NON_SECURE_SRAM_START 0x40304000#define
NON_SECURE_SRAM_END 0x4030E000#define
LOW_LEVEL_SRAM_STACK 0x4030B7FC |
问题:这些参数是保存在哪里的?大概有哪些参数?
答:
这些参数保存的内存地址为 64 KB 的 OCM RAM 中:
注:Dowloaded Image 区域:是用来保存 MLO(SPL) 文件的,其最大可达到 109 KB
@[email protected] 设置 CPU 为 SVC32 模式
|
1
2
3
4
5
6
7
8
|
<path
:=""arch=""arm=""cpu=""armv7=""start.s="">
/*
*setthe
cpu to SVC32 mode
*/
mrs
r0, cpsr
bic
r0, r0, #0x1f
orr
r0, r0, #0xd3
msr
cpsr,r0</path>
|
CPSR:程序状态寄存器(current program status register) (当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。
CPSR在用户级编程时用于存储条件码。
SPSR:程序状态保存寄存器(saved program status register),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。当特定 的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常中断 模式,所以他没有SPSR。当用户在用户模式或系统模式访问SPSR,将产生不可预知的后果。
CPSR格式如下所示。SPSR和CPSR格式相同。
31 30 29 28 27 26 7 6 5 4 3 2 1 0
N Z C V Q DNM(RAZ) I F T M4 M3 M2 M1 M0
详解:http://blog.chinaunix.net/uid-28458801-id-3487199.html
@[email protected] CPU的初始化
|
1
2
3
4
5
|
《PATH
: /arch/arm/cpu/armv7/start.S》 /*
the mask ROM code should have PLL and others stable */
#ifndef
CONFIG_SKIP_LOWLEVEL_INIT bl
cpu_init_crit
#endif |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<path
:=""arch=""arm=""cpu=""armv7=""omap-common=""lowlevel_init.s="">
.globl
lowlevel_initlowlevel_init: /*
*
Setup a temporary stack
*/
ldr
sp, =LOW_LEVEL_SRAM_STACK
/*
*
Save the old lr(passed inip)
and the current lr to stack
*/
push
{ip, lr}
/*
*
go setup pll, mux, memory
*/
bl
s_init
pop
{ip, pc}</path>
|
问题:CPU的初始化有哪些内容?
答:
@[email protected] 首先要设置堆栈区,因为将会调用 C函数来实现CPU的初始化
问题:这个堆栈在什么位置,其内存大小是多少?
答
|
1
2
|
《PATH
:/arch/arm/include/asm/arch-ti81xx/omap.h》
#define
LOW_LEVEL_SRAM_STACK 0x4030B7FC<strong></strong>
|
@[email protected] 执行 s_init() 函数,实现 CPU 的初始化
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
<path
:=""board=""ti=""am335x=""evm.c="">
/* *
early system init of muxing and clocks.
*/
voids_init(void)
{ /*
Can be removed as A8 comes up with L2 enabled */
l2_cache_enable();
/*
WDT1 is already running when the bootloader gets control
*
Disable it to avoid "random" resets
*/
__raw_writel(0xAAAA,
WDT_WSPR);
while(__raw_readl(WDT_WWPS)
!= 0x0);
__raw_writel(0x5555,
WDT_WSPR);
while(__raw_readl(WDT_WWPS)
!= 0x0);
#ifdef
CONFIG_SPL_BUILD /*
Setup the PLLs and the clocks for the peripherals */
pll_init();
/*
Enable RTC32K clock */
rtc32k_enable();
/*
UART softreset */
u32
regVal;
u32
uart_base = DEFAULT_UART_BASE;
enable_uart0_pin_mux();
/*
IA Motor Control Board has default console on UART3*/
/*
XXX: This is before we've probed / set board_id */
if(board_id
== IA_BOARD) {
uart_base
= UART3_BASE;
}
regVal
= __raw_readl(uart_base + UART_SYSCFG_OFFSET);
regVal
|= UART_RESET;
__raw_writel(regVal,
(uart_base + UART_SYSCFG_OFFSET) );
while((__raw_readl(uart_base
+ UART_SYSSTS_OFFSET) &
UART_CLK_RUNNING_MASK)
!= UART_CLK_RUNNING_MASK);
/*
Disable smart idle */
regVal
= __raw_readl((uart_base + UART_SYSCFG_OFFSET));
regVal
|= UART_SMART_IDLE_EN;
__raw_writel(regVal,
(uart_base + UART_SYSCFG_OFFSET));
/*
Initialize the Timer */
init_timer();
preloader_console_init();
printf("\nlocation
/board/ti/am335x\n"); //@@
/*@@*///
led();/*@@*/ config_am335x_ddr();
#endif}</path> |
@[email protected] 使能第二级缓冲区
|
1
2
3
4
5
6
7
8
9
10
|
/*
Can be removed as A8 comes up with L2 enabled */
l2_cache_enable();
<path
:=""arch=""arm=""cpu=""armv7=""ti81xx=""cache.s="">
l2_cache_enable: push
{r0, r1, r2, lr}
mrc
15, 0, r3, cr1, cr0, 1
orr
r3, r3, #2
mcr
15, 0, r3, cr1, cr0, 1
pop
{r1, r2, r3, pc}</path>
|
@[email protected]
关闭看门狗(WDT)
|
1
2
3
4
5
6
7
|
/*
WDT1 is already running when the bootloader gets control *
Disable it to avoid "random" resets
*/
__raw_writel(0xAAAA,
WDT_WSPR);while(__raw_readl(WDT_WWPS)
!= 0x0);
__raw_writel(0x5555,
WDT_WSPR);while(__raw_readl(WDT_WWPS)
!= 0x0);
|
|
1
2
3
4
5
6
7
8
9
10
11
|
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""cpu.h="">
#define
WDT_WSPR (WDT_BASE + 0x048)
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h="">
/*
Watchdog Timer */#ifdef
CONFIG_AM335X#define
WDT_BASE 0x44E35000
#else
#define
WDT_BASE 0x480C2000
#endif</path></path> |
@[email protected] 给外设设置好 PLL 和 时钟频率等
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/*
Setup the PLLs and the clocks for the peripherals */
pll_init();
<path
:=""board=""ti=""am335x=""pll.c="">
/* *
Configure the PLL/PRCM for necessary peripherals
*/
voidpll_init()
{ mpu_pll_config(MPUPLL_M_500);
core_pll_config();
per_pll_config();
ddr_pll_config();
/*
Enable the required interconnect clocks */
interface_clocks_enable();
/*
Enable power domain transition */
power_domain_transition_enable();
/*
Enable the required peripherals */
per_clocks_enable();
}</path> |
@[email protected] 使能 32-KHz 频率的实时时钟
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/*
Enable RTC32K clock */
rtc32k_enable();
《PATH
: /board/ti/am335x/evm.c》staticvoid rtc32k_enable(void)
{ /*
Unlock the rtc's registers */
__raw_writel(0x83e70b13,
(AM335X_RTC_BASE + RTC_KICK0_REG));
__raw_writel(0x95a4f1e0,
(AM335X_RTC_BASE + RTC_KICK1_REG));
/*
Enable the RTC 32K OSC */
__raw_writel(0x48,
(AM335X_RTC_BASE + RTC_OSC_REG));
}<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h="">
/*
RTC base address */#define
AM335X_RTC_BASE 0x44E3E000
<path
:=""board=""ti=""am335x=""evm.c="">
#define
RTC_KICK0_REG 0x6c
#define
RTC_KICK1_REG 0x70
#define
RTC_OSC_REG 0x54
</path></path> |
@[email protected] 使能UART0
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/*
UART softreset */
u32
regVal;
u32
uart_base = DEFAULT_UART_BASE;
enable_uart0_pin_mux();
/*
IA Motor Control Board has default console on UART3*/
/*
XXX: This is before we've probed / set board_id */
if(board_id
== IA_BOARD) {
uart_base
= UART3_BASE;
}
regVal
= __raw_readl(uart_base + UART_SYSCFG_OFFSET);
regVal
|= UART_RESET;
__raw_writel(regVal,
(uart_base + UART_SYSCFG_OFFSET) );
while((__raw_readl(uart_base
+ UART_SYSSTS_OFFSET) &
UART_CLK_RUNNING_MASK)
!= UART_CLK_RUNNING_MASK);
/*
Disable smart idle */
regVal
= __raw_readl((uart_base + UART_SYSCFG_OFFSET));
regVal
|= UART_SMART_IDLE_EN;
__raw_writel(regVal,
(uart_base + UART_SYSCFG_OFFSET));
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""cpu.h="">
#ifdef
CONFIG_AM335X#define
DEFAULT_UART_BASE UART0_BASE#endif<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h="">
#ifdef
CONFIG_AM335X#define
UART0_BASE 0x44E09000#else#define
UART0_BASE 0x48020000#endif</path></path> |
@[email protected] 初始化 定时器
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/*
Initialize the Timer */
init_timer();
<path
:=""board=""ti=""am335x=""evm.c="">
staticvoid init_timer(void)
{ /*
Reset the Timer */
__raw_writel(0x2,
(DM_TIMER2_BASE + TSICR_REG));
/*
Wait until the reset is done */
while(__raw_readl(DM_TIMER2_BASE
+ TIOCP_CFG_REG) & 1);
/*
Start the Timer */
__raw_writel(0x1,
(DM_TIMER2_BASE + TCLR_REG));
}<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h="">
/*
DM Timer base addresses */#define
DM_TIMER0_BASE 0x4802C000
#define
DM_TIMER1_BASE 0x4802E000
#define
DM_TIMER2_BASE 0x48040000
#define
DM_TIMER3_BASE 0x48042000
#define
DM_TIMER4_BASE 0x48044000
#define
DM_TIMER5_BASE 0x48046000
#define
DM_TIMER6_BASE 0x48048000
#define
DM_TIMER7_BASE 0x4804A000</path></path>
|
@[email protected] 初始化控制台,通过UART可以查看相关信息
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
preloader_console_init();
《PATH
: /arch/arm/cpu/armv7/omap-common/spl.c》/*
This requires UART clocks to be enabled */voidpreloader_console_init(void)
{ constchar *u_boot_rev
= U_BOOT_VERSION;
charrev_string_buffer[50];
gd
= &gdata;
gd->bd
= &bdata;
gd->flags
|= GD_FLG_RELOC;
gd->baudrate
= CONFIG_BAUDRATE;
serial_init(); /*
serial communications setup */
/*
Avoid a second "U-Boot" coming from this string */
u_boot_rev
= &u_boot_rev[7];
printf("\nU-Boot
SPL %s (%s - %s)\n", u_boot_rev,
U_BOOT_DATE,
U_BOOT_TIME);
omap_rev_string(rev_string_buffer);
printf("Texas
Instruments %s\n", rev_string_buffer);
}
<span style="font-size:14px;color:#003399;"></span>
|
@[email protected] 配置 DDR
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
config_am335x_ddr();
《PATH
:》/*
void DDR2_EMIF_Config(void); */staticvoid config_am335x_ddr(void)
{ intdata_macro_0
= 0;
intdata_macro_1
= 1;
enable_ddr_clocks();
config_vtp();
Cmd_Macro_Config();
Data_Macro_Config(data_macro_0);
Data_Macro_Config(data_macro_1);
__raw_writel(PHY_RANK0_DELAY,
DATA0_RANK0_DELAYS_0);
__raw_writel(PHY_RANK0_DELAY,
DATA1_RANK0_DELAYS_0);
__raw_writel(DDR_IOCTRL_VALUE,
DDR_CMD0_IOCTRL);
__raw_writel(DDR_IOCTRL_VALUE,
DDR_CMD1_IOCTRL);
__raw_writel(DDR_IOCTRL_VALUE,
DDR_CMD2_IOCTRL);
__raw_writel(DDR_IOCTRL_VALUE,
DDR_DATA0_IOCTRL);
__raw_writel(DDR_IOCTRL_VALUE,
DDR_DATA1_IOCTRL);
__raw_writel(__raw_readl(DDR_IO_CTRL)
& 0xefffffff, DDR_IO_CTRL);
__raw_writel(__raw_readl(DDR_CKE_CTRL)
| 0x00000001, DDR_CKE_CTRL);
config_emif_ddr2();
}《PATH
: /arm/include/asm/arch-ti81xx/cpu.h》#define
DATA0_RANK0_DELAYS_0 (DDR_PHY_BASE_ADDR + 0x134)#define
DATA1_RANK0_DELAYS_0 (DDR_PHY_BASE_ADDR + 0x1D8)/*
DDR offsets */#define
DDR_PHY_BASE_ADDR 0x44E12000#define
DDR_IO_CTRL 0x44E10E04#define
DDR_CKE_CTRL 0x44E1131C#define
CONTROL_BASE_ADDR 0x44E10000 |
@[email protected] 设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数
|
1
2
3
4
5
6
|
/*
Set stackpointer ininternal
RAM to call board_init_f */
call_board_init_f: ldr
sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic
sp, sp, #7 /* 8-byte
alignment for ABI compliance */
ldr
r0,=0x00000000
bl
board_init_f
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<path:
include=""configs=""am335x_evm.h="">
#define
CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ CONFIG_SYS_INIT_RAM_SIZE
- \
GENERATED_GBL_DATA_SIZE)
#define
CONFIG_SYS_INIT_RAM_ADDR SRAM0_START#define
CONFIG_SYS_INIT_RAM_SIZE SRAM0_SIZE<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h=""begin="">
#ifdef
CONFIG_AM335X#define
SRAM0_START 0x402F0400#else#define
SRAM0_START 0x40300000#endif<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h=""end="">
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""cpu.h=""begin="">
#if
defined(CONFIG_AM335X) || defined(CONFIG_TI814X)#define
SRAM0_SIZE (0x1B400) /* 109 KB */#define
SRAM_GPMC_STACK_SIZE (0x40)#endif<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""cpu.h=""end="">
<path
:=""am335x=""include=""generated=""generic-asm-offsets.h=""begin="">
#define
GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */<path
:=""am335x=""include=""generated=""generic-asm-offsets.h=""end=""></path></path></path></path></path></path></path:>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<path
:=""arch=""arm=""cpu=""armv7=""omap-common=""spl.c'="">
voidboard_init_f(ulong
dummy)
{ /*
*
We call relocate_code() with relocation target same as the
*
CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
*
skipped. Instead, only .bss initialization will happen. That's
*
all we need
*/
debug(">>board_init_f()\n");
relocate_code(CONFIG_SPL_STACK,
&gdata, CONFIG_SPL_TEXT_BASE);
}<path
:=""arch=""arm=""cpu=""armv7=""omap-common=""spl.c=""begin="">
#define
CONFIG_SPL_TEXT_BASE 0x402F0400#define
CONFIG_SPL_MAX_SIZE (46 * 1024)#define
CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK<path
:=""arch=""arm=""cpu=""armv7=""omap-common=""spl.c=""end="">
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""omap.h=""begin="">
#define
LOW_LEVEL_SRAM_STACK 0x4030B7FC<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""omap.h=""end=""></path></path></path></path></path>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<path
:=""arch=""arm=""cpu=""armv7=""start.s="">
/* *
void relocate_code (addr_sp, gd, addr_moni)
*
*
This "function"does
not return,
instead it continues inRAM
*
after relocating the monitor code.
*
*/
.globl
relocate_code
relocate_code: mov
r4, r0 /* save addr_sp */
mov
r5, r1 /* save addr of gd */
mov
r6, r2 /* save addr of destination 0x402F0400*/</path>
|
@[email protected] 代码重定位
代码重定向,它首先检测自己(MLO)是否已经在内存中:
如果是直接跳到下面的堆栈初始化代码 clear_bss。
如果不是就将自己从Nor Flash中拷贝到内存中。
Nor Flash 和Nand Flash 本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论
是Nor Flash 还是Nand Flash,核心思想就是将 uboot 代码搬运到内存中去运行,但是没有拷
贝bss 后面这段代码,只拷贝bss 前面的代码,bss 代码是放置全局变量的。Bss 段代码是为
了清零,拷贝过去再清零重复操作。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/*
Set up the stack */
stack_setup: mov
sp, r4
adr
r0, _start
cmpr0,
r6
moveq
r9, #0 /* no relocation.
relocation offset(r9) = 0 */
beq
clear_bss /* skip relocation */
mov
r1, r6 /* r1 <- scratch forcopy_loop
*/
ldr
r3, _image_copy_end_ofs
add
r2, r0, r3 /* r2 <- sourceend
address */
copy_loop:
/* 自拷贝 */ ldmia
r0!, {r9-r10} /* copy from sourceaddress
[r0] */
stmia
r1!, {r9-r10} /* copy to target address [r1] */
cmpr0,
r2 /* untilsource end
address [r2] */
blo
copy_loop
|
@[email protected] 清空 bss 段
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
clear_bss: ldr
r0, _bss_start_ofs
ldr
r1, _bss_end_ofs
mov
r4, r6 /* reloc addr */
add
r0, r0, r4
add
r1, r1, r4
mov
r2, #0x00000000
/* clear */
clbss_l:str
r2, [r0] /* clearloop...
*/
add
r0, r0, #4
cmpr0,
r1
bne
clbss_l
/* *
These are defined inthe
board-specific linker script.
*/
.globl
_bss_start_ofs_bss_start_ofs: .word
__bss_start - _start /* __bss_start = 0x80000000 */
|
@[email protected] 调用函数 board_init_r,用以完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/* *
We are done.
Do not return,
instead branch to second part of board
*
initialization, now running from RAM.
*/
jump_2_ram:/* *
If I-cache is enabled invalidate it
*/
#ifndef
CONFIG_SYS_ICACHE_OFF mcr
p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr
p15, 0, r0, c7, c10, 4 @ DSB
mcr
p15, 0, r0, c7, c5, 4 @ ISB
#endif ldr
r0, _board_init_r_ofs
adr
r1, _start
add
lr, r0, r1
add
lr, lr, r9
/*
setup parameters forboard_init_r
*/
mov
r0, r5 /* gd_t */
mov
r1, r6 /* dest_addr */
/*
jump to it ... */
mov
pc, lr
_board_init_r_ofs: .word
board_init_r - _start
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
《PATH
: /arch/arm/cpu/armv7/omap-common/spl.c 》voidboard_init_r(gd_t
*id, ulong dummy)
{ u32
boot_device;
debug(">>spl:board_init_r()\n");
timer_init();
i2c_init(CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE);
#ifdef
CONFIG_SPL_BOARD_INIT spl_board_init();
#endif boot_device
= omap_boot_device();
debug("boot
device - %d\n", boot_device);
switch(boot_device)
{
#ifdef
CONFIG_SPL_MMC_SUPPORT caseBOOT_DEVICE_MMC1:
caseBOOT_DEVICE_MMC2:
spl_mmc_load_image();
break;
#endif#ifdef
CONFIG_SPL_NAND_SUPPORT caseBOOT_DEVICE_NAND:
spl_nand_load_image();
break;
#endif#ifdef
CONFIG_SPL_YMODEM_SUPPORT caseBOOT_DEVICE_UART:
spl_ymodem_load_image();
break;
#endif default:
printf("SPL:
Un-supported Boot Device - %d!!!\n",
boot_device);
hang();
break;
}
switch(spl_image.os)
{
caseIH_OS_U_BOOT:
debug("Jumping
to U-Boot\n");
jump_to_image_no_args();
break;
default:
puts("Unsupported
OS image.. Jumping nevertheless..\n");
jump_to_image_no_args();
}
} |
3,第三级 bootloader:uboot.img 做了哪些事情?
uboot.img 内存分布如下:
访问 /arch/arm/lib/board.c 中 的 board_init_f() 函数:
在 uboot.img 运行过程中,有两个非常重要的结构体:gd_t 和 bd_t 。
其中 gd_t :global_data 数据结构的定义,位于:/arch/arm/include/asm/global_data.h 中。
其成员主要是一些全局的系统初始化参数。
其中 bd_t :bd_info 数据结构的定义,位于:/arch/arm/include/asm/u-boot.h 中。
其成员是开发板的相关参数。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
<path
:=""arch=""arm=""include=""asm=""global_data.h="">
/* *
The following data structure is placed in some memory which is
*
available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
*
some locked parts of the data cache) to allow for a minimum set of
*
global variables during system initialization (until we have set
*
up the memory controller so that we can use RAM).
*
*
Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedefstruct global_data
{
bd_t
*bd;
unsignedlong flags;
unsignedlong baudrate;
unsignedlong have_console; /*
serial_init() was called */
unsignedlong env_addr; /*
Address of Environment struct */
unsignedlong env_valid; /*
Checksum of Environment valid? */
unsignedlong fb_base; /*
base address of frame buffer */
#ifdef
CONFIG_FSL_ESDHC unsignedlong sdhc_clk;
#endif#ifdef
CONFIG_AT91FAMILY /*
"static data" needed by at91's clock.c */
unsignedlong cpu_clk_rate_hz;
unsignedlong main_clk_rate_hz;
unsignedlong mck_rate_hz;
unsignedlong plla_rate_hz;
unsignedlong pllb_rate_hz;
unsignedlong at91_pllb_usb_init;
#endif#ifdef
CONFIG_ARM /*
"static data" needed by most of timer.c on ARM platforms */
unsignedlong timer_rate_hz;
unsignedlong tbl;
unsignedlong tbu;
unsignedlonglong timer_reset_value;
unsignedlong lastinc;
#endif#ifdef
CONFIG_IXP425 unsignedlong timestamp;
#endif unsignedlong relocaddr; /*
Start address of U-Boot in RAM */
phys_size_t
ram_size; /* RAM size
*/
unsignedlong mon_len; /*
monitor len */
unsignedlong irq_sp; /*
irq stack pointer */
unsignedlong start_addr_sp; /*
start_addr_stackpointer */
unsignedlong reloc_off;
#if
!(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) unsignedlong tlb_addr;
#endif void **jt; /*
jump table */
char env_buf[32]; /*
buffer for getenv() before reloc. */
}
gd_t;#define
DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")<path
:=""arch=""arm=""include=""asm=""u-boot.h="">
typedefstruct bd_info
{
int bi_baudrate; /*
serial console baudrate */
unsignedlong bi_ip_addr; /*
IP Address */
ulong
bi_arch_number; /* unique
id for this board */
ulong
bi_boot_params; /* where
this board expects params */
struct /*
RAM configuration */
{
ulong
start;
ulong
size;
}
bi_dram[CONFIG_NR_DRAM_BANKS];
}
bd_t;</path></path> |
其中 DECLARE_GLOBAL_DATA_PTR 宏定义在系统初始化过程中会被频繁调用,
其的作用是,声明gd这么一个全局的指针,这个指针指向gd_t结构体类型,并且这个gd指针是保存在ARM的r8这个寄存器里面的。
uboot.img 第一个运行的文件还是 start.o,其在运行访问的 board_init_f() 函数定义在 /arch/arm/lib/board.c 中:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<path
:=""arch=""arm=""lib=""board.c="">
voidboard_init_f(ulong
bootflag)
{ bd_t
*bd;
init_fnc_t
**init_fnc_ptr;
gd_t
*id;
ulong
addr, addr_sp;
/*
Pointer is writable since we allocated a register for it */
gd
= (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/*
compiler optimization barrier needed for GCC >= 3.4 */
__asm__
__volatile__("":
: :"memory");
memset((void*)gd,
0, sizeof(gd_t));
...
}</path> |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<path
:=""include=""configs=""am335x_evm="">
#define
CONFIG_SYS_INIT_RAM_ADDR SRAM0_START#define
CONFIG_SYS_INIT_RAM_SIZE SRAM0_SIZE#define
CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ CONFIG_SYS_INIT_RAM_SIZE
- \
GENERATED_GBL_DATA_SIZE)
<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""hardware.h="">
#define
SRAM0_START 0x402F0400<path
:=""arch=""arm=""include=""asm=""arch-ti81xx=""cpu.h="">
#define
SRAM0_SIZE (0x1B400) /* 109 KB */<path
:=""am335x=""include=""generated=""generic-asm-offsets.h="">
#define
GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */</path></path></path></path> |
因此,系统初始化参数将会被保存在 (保存 MLO(SPL)文件的内存空间的)末尾 2 KB 处。
通过计算的 gb 指针指向的内存空间地址为 gb = 0x4030B000
gb_t 结构体中某些元素的值是来自于 uboot.img’s header,这个header的数据保存在内存的0x807FFFCO,大小为 64字节
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<path
:=""include=""image.h="">
/* *
Legacy format image header,
*
all data in network byte order (aka natural aka bigendian).
*/
typedefstruct image_header
{
uint32_t
ih_magic; /* Image
Header Magic Number */
uint32_t
ih_hcrc; /* Image
Header CRC Checksum */
uint32_t
ih_time; /* Image
Creation Timestamp */
uint32_t
ih_size; /* Image
Data Size */
uint32_t
ih_load; /* Data
Load Address */
uint32_t
ih_ep; /* Entry
Point Address */
uint32_t
ih_dcrc; /* Image
Data CRC Checksum */
uint8_t
ih_os; /* Operating
System */
uint8_t
ih_arch; /* CPU architecture
*/
uint8_t
ih_type; /* Image
Type */
uint8_t
ih_comp; /* Compression
Type */
uint8_t
ih_name[IH_NMLEN]; /*
Image Name */
}
image_header_t;</path> |
|
1
2
3
4
5
6
7
8
|
<path
:=""include=""configs=""am335x_evm.h="">
/* *
8MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM.
*
64 bytes before this address should be set aside for u-boot.img's
*
header. That is 0x807FFFC0--0x80800000 should not be used for any
*
other needs.
*/
#define
CONFIG_SYS_TEXT_BASE 0x80800000</path>
|