在继续分析之前,先回顾一下当前相关寄存器的值、内存空间的使用情况和相关变量的值的情况。
r0 = 0x42BF_FF60 @ &gd
r1 = 0x42C0_0000
r2 = 0x42BF_FF10 @ &sp
r9 = 0x42BF_FF60 @ &gd
r13 = &( bl mmu_turn_on ) @ /uboot-root/arch/arm/cpu/slsiap/s5p4418/start.S
sp = 0x42BF_FF10
lr = &( bl gdt_reset ) @ /uboot-root/arch/arm/cpu/slsiap/s5p4418/start.S
RAM:
0xC000_0000
-
0x5000_0000(RAM_TOP)
-
0x4FFE_F800
UBOOT(Reserve 478K)
0x4FF7_8000
-
0x4FFF_4000
TLB table
0x4FFF_0000
-
0x4DF9_8000
malloc(Reserve 32768K)
0x4DF7_8000
Board Info(Reserve 80B) = gd->bd
0x4DF7_7FB0
New GD
0x4DF7_7F10
IRQ
0x4DF7_7F00(IRQ_SP)
-
0x4DF7_7EF0
-
0x4500_0000
Heap
0x4300_0000
-
0x42C8_C000
Page
0x42C8_0000
-
0x42C7_7988
UBOOT
0x42C0_0000
GD
0x42BF_FEB8
BD Info
0x42BF_FE68(START_ADDR_SP)
UBoot-Stack
0x4000_0000
gd内容:
bd_t *bd = 0x42BF_FF10
{
unsigned long bi_memstart = 0
phys_size_t bi_memsize = 0
unsigned long bi_flashstart = 0
unsigned long bi_flashsize = 0
unsigned long bi_flashoffset = 0
unsigned long bi_sramstart = 0
unsigned long bi_sramsize = 0
unsigned long bi_bootflags = 0
unsigned long bi_ip_addr = 0
unsigned char bi_enetaddr[6] = 0
unsigned short bi_ethspeed = 0
unsigned long bi_intfreq = 0
unsigned long bi_busfreq = 0
ulong bi_arch_number = 4330
ulong bi_boot_params = 0x4000_0100
struct bi_dram[1]
{
ulong start = 0x4000_0000
ulong size = 0x4000_0000
}
}
unsigned long flags = 0
unsigned int baudrate = 115200
unsigned long cpu_clk = 0
unsigned long bus_clk = 0
unsigned long pci_clk = 0
unsigned long mem_clk = 0
unsigned long have_console = 1
unsigned long env_addr = &default_environment[0]
unsigned long env_valid = 1
unsigned long ram_top = 0x5000_0000
unsigned long relocaddr = 0x4500_0000
phys_size_t ram_size = 0x1000_0000
unsigned long mon_len = 0x0007_7988
unsigned long irq_sp = 0x4DF7_7F00
unsigned long start_addr_sp = 0x42BF_FF10
unsigned long reloc_off = 0
struct global_data *new_gd = 0x4df7_7f10
const void *fdt_blob = 0
void *new_fdt = 0
unsigned long fdt_size = 0
void **jt = 0
char env_buf[32] = 0
unsigned long timebase_h = 0
unsigned long timebase_l = 0
struct arch_global_data arch
{
unsigned long timer_rate_hz = 0
unsigned long tbu = 0
unsigned long tbl = 0
unsigned long lastinc = 0
unsigned long long timer_reset_value = 0
unsigned long tlb_addr = 0x4fff_0000
unsigned long tlb_size = 0x0000_4000
}
现在继续分析,目前已经执行到 /uboot-root/arch/arm/cpu/slsiap/s5p4418/start.S 的第153行,代码如下所示:
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, =(CONFIG_SYS_MALLOC_END) /* dest_addr for malloc heap end */
/* call board_init_r */
ldr pc, =board_init_r /* this is auto-relocated! */
这里是为调用 board_init_r() 作参数准备。在调用到最后一句指令时,相关寄存器的值如下:
r0 = 0x42BF_FEB8 @ &gd
r1 = 0x4500_0000
r2 = 0x42BF_FF10 @ &sp
r9 = 0x42BF_FEB8 @ &gd
r13 = &( bl mmu_turn_on ) @ /uboot-root/arch/arm/cpu/slsiap/s5p4418/start.S
lr = &( bl gdt_reset ) @ /uboot-root/arch/arm/cpu/slsiap/s5p4418/start.S
由于最后一句指令是使用 ldr 进行跳转,因此 lr 寄存器不受影响。board_init_r()位于 /uboot-root/common/board_r.c 中。其代码如下:
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
gd = new_gd;
if (initcall_run_list(init_sequence_r))
hang();
/* NOTREACHED - run_main_loop() does not return */
hang();
}
这里的重点还是在于 initcall_run_list()。与之前的 board_init_f()一样,这里也有一个函数指针数组 init_sequence_r[]。以下是它的内容:
init_fnc_t init_sequence_r[] = {
initr_trace,
initr_reloc,
initr_caches,
board_init, /* Setup chipselects */
initr_reloc_global_data,
initr_serial,
initr_announce,
initr_barrier,
initr_malloc,
bootstage_relocate,
power_init_board,
initr_mmc,
initr_env,
initr_secondary_cpu,
stdio_init,
initr_jumptable,
console_init_r, /* fully init console as a device */
arch_misc_init, /* miscellaneous arch-dependent init */
interrupt_init,
board_late_init,
run_main_loop,
};
首先调用的是 initr_trace(),该函数什么东西都没做,忽略。
接下来调用的是 initr_reloc(),该函数更新了gd->flags和标识了一下UBoot所在的阶段。
接下来调用的是 initr_caches(),该函数什么都没做,忽略。
接下来调用的是位于 /uboot-root/board/s5p4418/nanopi2/board.c 中的 board_init(),这里主要是设置LCD的,不再详细展开。
接下来调用的是 initr_reloc_global_data(),该函数也是什么都没做,忽略。
接下来调用的是 initr_serial(),里面调用了位于/uboot-root/drivers/serial/serial.c中的serial_initialize()。在这个函数中,有很多个板子初始化串口的函数,但经过宏定义的过滤,真正有效的是里面的pl01x_serial_initialize(),以及最后一行的serial_assign()。代码如下所示:
void serial_initialize(void)
{
pl01x_serial_initialize();
serial_assign(default_serial_console()->name);
}
先看pl01x_serial_initialize(),代码如下所示:
void pl01x_serial_initialize(void)
{
serial_register(&pl01x_serial_drv);
}
这里的serial_register()是一个注册过程,说白了就是维护一条链表。代码如下所示:
void serial_register(struct serial_device *dev)
{
dev->next = serial_devices;
serial_devices = dev;
}
serial_devices定义如下:
static struct serial_device *serial_devices;
由于这个指针到现在才出现,并未使用过,而且它属于在bss段里的,所以初始值为0,即为NULL。另外,分析注册过程可以得出serial_devices始终指向链表头。所以上面注册完后,该链表如下所示:
serial_devices = pl01x_serial_drv -> NULL
执行完注册过程后,又返回调用的serial_assign()。调用时以pl01x_serial_drv->name为参数,其代码如下:
int serial_assign(const char *name)
{
struct serial_device *s;
for (s = serial_devices; s; s = s->next) {
if (strcmp(s->name, name))
continue;
serial_current = s;
return 0;
}
return -EINVAL;
}
从代码可以看出,这里为变量serial_current赋值。该变量用于指示当前使用的输出串口设备,也有用于指定默认串口设备。
接下来调用的是 initr_announce(),这里只是输出一些调试信息。
接下来调用的是 initr_barrier(),该函数什么都没做,忽略。
接下来调用的是 initr_malloc()。这里主要是初始化位于0x4300_0000至0x4500_0000的堆空间为0。
接下来调用的是位于 /uboot-root/common/bootstage.c 中的bootstage_relocate()。这里只是初始化启动记录标志而已,与整体流程并没有大的影响,因此不详细展开。
接下来调用的是 power_init_board()。该函数什么都没做,忽略。
接下来调用的是 initr_mmc()。由于这里是初始化mmc设备的,具体与CPU设置有关,这里就不详细展开了。
接下来调用的是 initr_env()。这里是通过读取MMC将环境变量读取出来,并更新当前的环境变量。更新后的环境变量如下:
baudrate=115200
bloader=ext4load mmc 0:1
bootcmd=$bloader 0x48000000 $kernel;$bloader 0x49000000 root.img.gz;bootm 0x48000000
bootdelay=0
bootfile=uImage
ethaddr=00:e2:1c:ba:e8:60
firstboot=0
gatewayip=192.168.1.254
ipaddr=192.168.1.165
kernel=uImage
netmask=255.255.255.0
serverip=192.168.1.164
stderr=serial
stdin=serial
stdout=serial
接下来调用的是 initr_secondary_cpu()。该函数什么都没做,忽略。
由于篇幅原因,本节暂告一段落。