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
|
#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 */
|
@1@ 保存启动参数 bl save_boot_params
1
2
3
4
5
6
7
|
/*
* the actual reset code
*/
reset:
bl save_boot_params
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
.global save_boot_params
save_boot_params:
/*
* See
if
the rom code passed pointer is valid:
* It is not valid
if
it is not
in
non-secure SRAM
* This may happen
if
you are booting with the help of
* debugger
*/
ldr r2, =NON_SECURE_SRAM_START
cmp
r2, r0
bgt 1f
ldr r2, =NON_SECURE_SRAM_END
cmp
r2, r0
blt 1f
/*
* store the boot params passed from rom code or saved
* and passed by SPL
*/
cmp
r0,
#0
beq 1f
ldr r1, =boot_params
str r0, [r1]
|
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
@a2@ 设置 CPU 为 SVC32 模式
1
2
3
4
5
6
7
8
|
/*
*
set
the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0,
#0x1f
orr r0, r0,
#0xd3
msr cpsr,r0
|
CPSR:程序状态寄存器(current program status register)(当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。
CPSR在用户级编程时用于存储条件码。
SPSR:程序状态保存寄存器(saved program statusregister),每一种处理器模式下都有一个状态寄存器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
@a3@ 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
|
.globl lowlevel_init
lowlevel_init:
/*
* Setup a temporary stack
*/
ldr sp, =LOW_LEVEL_SRAM_STACK
/*
* Save the old lr(passed
in
ip) and the current lr to stack
*/
push {ip, lr}
/*
* go setup pll, mux, memory
*/
bl s_init
pop {ip, pc}
|
问题:CPU的初始化有哪些内容?
答:
@b1@ 首先要设置堆栈区,因为将会调用 C函数来实现CPU的初始化
问题:这个堆栈在什么位置,其内存大小是多少?
答
1
2
|
《PATH :/arch/arm/
include
/asm/arch-ti81xx/omap.h》
#define LOW_LEVEL_SRAM_STACK
0x4030B7FC
|
@b2@ 执行 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
|
/*
* early system init of muxing and clocks.
*/
void
s_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
}
|
@c1@ 使能第二级缓冲区
1
2
3
4
5
6
7
8
9
10
|
/* Can be removed as A8 comes up with L2 enabled */
l2_cache_enable();
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}
|
@c2@ 关闭看门狗(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
|
#define WDT_WSPR (WDT_BASE +
0x048
)
/* Watchdog Timer */
#ifdef CONFIG_AM335X
#define WDT_BASE
0x44E35000
#
else
#define WDT_BASE
0x480C2000
#endif
|
@c3@ 给外设设置好 PLL 和 时钟频率等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/* Setup the PLLs and the clocks for the peripherals */
pll_init();
/*
* Configure the PLL/PRCM for necessary peripherals
*/
void
pll_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();
}
|
@c4@ 使能 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
|
/* Enable RTC32K clock */
rtc32k_enable();
《PATH : /board/ti/am335x/evm.c》
static
void
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));
}
/* RTC base address */
#define AM335X_RTC_BASE
0x44E3E000
#define RTC_KICK0_REG
0x6c
#define RTC_KICK1_REG
0x70
#define RTC_OSC_REG
0x54
|
@c5@ 使能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));
#ifdef CONFIG_AM335X
#define DEFAULT_UART_BASE UART0_BASE
#endif
#ifdef CONFIG_AM335X
#define UART0_BASE 0x44E09000
#else
#define UART0_BASE 0x48020000
#endif
|
@c6@ 初始化 定时器
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();
static
void
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));
}
/* 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
|
@c7@ 初始化控制台,通过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 */
void
preloader_console_init(
void
)
{
const
char
*u_boot_rev = U_BOOT_VERSION;
char
rev_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);
}
|
@c8@ 配置 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); */
static
void
config_am335x_ddr(
void
)
{
int
data_macro_0 = 0;
int
data_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
|
@c DONE@
@b DONE@
@a4@ 设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数
1
2
3
4
5
6
|
/* Set stackpointer
in
internal 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
|
#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
#ifdef CONFIG_AM335X
#define SRAM0_START 0x402F0400
#else
#define SRAM0_START 0x40300000
#endif
#if defined(CONFIG_AM335X) || defined(CONFIG_TI814X)
#define SRAM0_SIZE (0x1B400) /* 109 KB */
#define SRAM_GPMC_STACK_SIZE (0x40)
#endif
#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
void
board_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);
}
#define CONFIG_SPL_TEXT_BASE 0x402F0400
#define CONFIG_SPL_MAX_SIZE (46 * 1024)
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK
#define LOW_LEVEL_SRAM_STACK 0x4030B7FC
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This
"function"
does not
return
, instead it continues
in
RAM
* 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*/
|
@a5@ 代码重定位
代码重定向,它首先检测自己(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
cmp
r0, r6
moveq r9,
#0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch
for
copy_loop */
ldr r3, _image_copy_end_ofs
add r2, r0, r3 /* r2 <-
source
end address */
copy_loop: /* 自拷贝 */
ldmia r0!, {r9-r10} /* copy from
source
address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp
r0, r2 /*
until
source
end address [r2] */
blo copy_loop
|
@a6@ 清空 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] /*
clear
loop... */
add r0, r0,
#4
cmp
r0, r1
bne clbss_l
/*
* These are defined
in
the board-specific linker script.
*/
.globl _bss_start_ofs
_bss_start_ofs:
.word __bss_start - _start /* __bss_start = 0x80000000 */
|
@a7@ 调用函数 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
for
board_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 》
void
board_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
case
BOOT_DEVICE_MMC1:
case
BOOT_DEVICE_MMC2:
spl_mmc_load_image();
break
;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
case
BOOT_DEVICE_NAND:
spl_nand_load_image();
break
;
#endif
#ifdef CONFIG_SPL_YMODEM_SUPPORT
case
BOOT_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) {
case
IH_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();
}
}
|
@a DONE@
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
|
/*
* 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)
*/
typedef
struct
global_data {
bd_t *bd;
unsigned
long
flags;
unsigned
long
baudrate;
unsigned
long
have_console;
/* serial_init() was called */
unsigned
long
env_addr;
/* Address of Environment struct */
unsigned
long
env_valid;
/* Checksum of Environment valid? */
unsigned
long
fb_base;
/* base address of frame buffer */
#ifdef CONFIG_FSL_ESDHC
unsigned
long
sdhc_clk;
#endif
#ifdef CONFIG_AT91FAMILY
/* "static data" needed by at91's clock.c */
unsigned
long
cpu_clk_rate_hz;
unsigned
long
main_clk_rate_hz;
unsigned
long
mck_rate_hz;
unsigned
long
plla_rate_hz;
unsigned
long
pllb_rate_hz;
unsigned
long
at91_pllb_usb_init;
#endif
#ifdef CONFIG_ARM
/* "static data" needed by most of timer.c on ARM platforms */
unsigned
long
timer_rate_hz;
unsigned
long
tbl;
unsigned
long
tbu;
unsigned
long
long
timer_reset_value;
unsigned
long
lastinc;
#endif
#ifdef CONFIG_IXP425
unsigned
long
timestamp;
#endif
unsigned
long
relocaddr;
/* Start address of U-Boot in RAM */
phys_size_t ram_size;
/* RAM size */
unsigned
long
mon_len;
/* monitor len */
unsigned
long
irq_sp;
/* irq stack pointer */
unsigned
long
start_addr_sp;
/* start_addr_stackpointer */
unsigned
long
reloc_off;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
unsigned
long
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")
typedef
struct
bd_info {
int
bi_baudrate;
/* serial console baudrate */
unsigned
long
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;
|
其的作用是,声明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
|
void
board_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));
...
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#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)
#define SRAM0_START 0x402F0400
#define SRAM0_SIZE (0x1B400) /* 109 KB */
#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
|
因此,系统初始化参数将会被保存在 (保存 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
|
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
typedef
struct
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;
|
1
2
3
4
5
6
7
8
|
/*
* 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
|