本文主要是介绍OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 SPL 镜像运行部分 boot 详细解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
url : git@github.com:lisider/u-boot.git
branch : ok6410a
commit id : e63a4077ad3aea53107495b0b68b95e720fe6033
config : ok6410a_mini_defconfig
// 涉及的 .S .s .c 文件 有 67个
- 从入口出口来看
// 运行在 0x0c00 0000
// 入口 为 arch/arm/lib/vectors.S 中的 _start 标号处的 b resetreset arch/arm/cpu/arm1176/start.S 39 lowlevel_init(108) board/samsung/ok6410a/lowlevel_init.S 72_main(110) arch/arm/lib/crt0.S 91board_init_f(117) board/samsung/ok6410a/ok6410a.c 266debug_uart_init(271) include/debug_uart.h 193_debug_uart_init(196) drivers/serial/s3c64xx_serial.c 315 board_init_r(177) common/spl/spl.c 589spl_board_init(641) board/samsung/ok6410a/ok6410a.c 255spl_boot_mmc(258) board/samsung/ok6410a/bl2_mmc_copy.c 18mmc_bl2_copy(23) board/samsung/ok6410a/bl2_mmc_copy.c 7CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, bl2_base, MOVI_INIT_REQUIRED)(13) arch/arm/mach-s3c64xx/include/mach/movi.h 25bl2base(24) // 跳转到 u-boot 的u-boot镜像
- 详细解析
// common/init/board_init.c
// register volatile gd_t *gd asm ("r9");
// arch/arm/include/asm/global_data.h:112:#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")resetsave_boot_params// nullmrs r0, cpsrbic r0, r0, #0x3f// 清 bit[4:0] 为0 // 设置 mode 为 system // 清 bit[5] 为 0 // 设置 T 为0 , 指令集 为 ARMorr r0, r0, #0xd3// 与 0b11010011// 设置mode 为 Supervisor// 设置 I 为 1,disable IRQ// 设置 F 为 1,disable FIQ msr cpsr, r0// 设置 cpsr lowlevel_initspl_config_uart_baudrateulong val = spl_uart_getclk(is_mpll) / 115200;_UBRDIV = val / 16 - 1;_UDIVSLOT = udivslot[val % 16];mem_ctrl_asm_init_mainboard_init_f_alloc_reserve// 申请 struct global_data 个字节 用来存储 gd_t *gd 指向的 gd_t 结构体// include/asm-generic/global_data.h 中 有 gd_t 的 定义board_init_f_init_reserve// 初始化 gd_t *gd 指向的 gd_t 结构体 空间 为 0// 初始化 gd_t *gd 指向的 gd_t 结构体 的 成员 malloc_base// 问题: spl 阶段初始化好的 gd结构体空间 , u-boot 阶段继承了吗?// u-boot 阶段没阶段,清空了.// 但是 u-boot 阶段不清空的话,就可以继承 spl 初始化好的数据// 在spl加载u-boot过程中,r9没变化,且r9指向的空间也没被破坏/*下面的这几行有两个目标// 此时开始布局ddr中的内存,而不是0x0c00 0000在的iram// i-ram 只用作 u-boot-spl.bin(最多8KB) 的存储,所以如果在这8KB使用堆栈,则有可能破坏 i-ram 中的 u-boot-spl.bin1. 设置sp2. 存储gd指针变量并clear gd指针变量指向的空间,并设置 gd->malloc_base = 0x5f9f ff20;ldr r0, =((0x5FB00000 - 0x0C)) => r0 : 5FAF FFF4bic r0, r0, #7 => r0 : 5FAF FFF0mov sp, r0 => sp : 5FAF FFF0bl board_init_f_alloc_reserve => r0 : 5f9f ff20 (5FAF FFF0 - 0x10 0000 - 0xD0)mov sp, r0 => sp : 5f9f ff20 ***** 设置了 栈指针mov r9, r0 => r9 : 5f9f ff20 ***** 存储了 gd指针变量的值bl board_init_f_init_reserve => 初始化 (5f9fff20 - 5f9fff20+0xD0) 的空间*//*// .code .rodata .data .bss .stack .heap此时i-ram的内存分布0C00 2000---------------------0C00 20008KB(0x2000)大小,用于存储8KB的u-boot-spl.bin// 不管u-boot-spl.bin有没有8KB,都会从mmc上拷贝8KB过来内存中的u-boot.bin 中存在 .bss段 内存中的u-boot.bin 也存在 .code .rodata .data0C00 0000---------------------0C00 0000此时ddr的内存分布5FFF FFFF---------------------5FFF FFFF5120KB(0x500000)大小,空洞5FB0 0000---------------------16B(0x10)大小,空洞5FAF FFF0---------------------1024KB(0x100000)大小,用于sys_malloc5F9F FFF0---------------------208B(0xD0)大小,用于gd5F9F FF20---------------------255999KB(约250MB)大小,用于栈5000 0000---------------------5000 0000*/ board_init_fdebug_uart_init // 被调用时第一次使用栈(sp指针)board_debug_uart_init// null_debug_uart_initstruct s3c64xx_uart *uart = (struct s3c64xx_uart *)0x7F005000;s3c64xx_serial_init(uart);uart->UFCON = 0;uart->UMCON = 0;uart->ULCON = 3;uart->UCON =0xa45;s3c64xx_serial_baud(uart, get_uart_clk(0), 115200);val = (uclk / baudrate) % 16;uart->UBRDIV = uclk / baudrate / 16 - 1;uart->UDIVSLOT = udivslot[val];for (val = 0; val < 100; val++)__asm__ __volatile__("": : :"memory");CLEAR_BSSldr r0, =__bss_startldr r3, =__bss_endmov r1, #0x00000000subs r2, r3, r0bl memset // lib/string.cspl_relocate_stack_gd// nullboard_init_rspl_set_bd// common/spl/spl.c static struct bd_info bdata __attribute__ ((section(".data")));// gd->bd = &bdata;// 填充bd , 为填充板子数据做准备spl_init// spl_common_init(1)// gd->malloc_limit = 0x100000;// gd->malloc_ptr = 0;// gd->flags |= GD_FLG_SPL_INIT; // include/asm-generic/global_data.h// 为 malloc 做准备timer_init// 设置 s3c6410的timer // 0x7F006000// 设置 gd->arch.timer_rate_hz// 设置 gd->arch.lastinc// 设置 gd->arch.timer_reset_value// 为 delay 做准备spl_board_initspl_boot_mmculong bl2base=0x5FB00000;mmc_bl2_copywritel(readl(HM_CONTROL4) | (0x3 << 16), HM_CONTROL4);// ({ u32 __v = ({ u32 __v = (*(volatile unsigned int *)((0x8c))); asm volatile ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0)); __v; }) | (0x3 << 16); asm volatile ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0)); (*(volatile unsigned int *)((0x8c)) = (__v)); __v; });ret = CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, bl2_base, MOVI_INIT_REQUIRED);// ret = (((int(*)(int, uint, ushort, uint *, int))(*((uint *)(0x0C004000 + 0x8))))(0,((*((volatile unsigned int*)(0x0C004000 - 0x4)) - ((1 * 1024) / 512)) - ((8 * 1024) / 512) - ((512 * 1024) / 512) - (0x4000 / 512)),((512 * 1024) / 512),bl2_base,0));bl2base
可以看出来 spl 的流程1. 上电2. 设置 cpsr3. 调用 lowlevel_init 初始化clock和uart和ddr和中断和gpio4. 调用_main4.1 整理ddr的内存布局.code .bss .data .rodata 在iram.heap .stack 在 ddr4.2 重新初始化uart4.3 清BSS (与4.1为一体)4.4 填充gd为填充板子数据做准备为malloc做准备初始化timer,为delay做准备4.5 直接 调用 i-tcm 的函数拷贝 u-boot 到 ddr , 并跳转到 u-bootA. 初始化但是没有用到的东西uart 与 timer 与 中断 与 gpio.heapgd与已经初始化的gd成员
- 详细解析 lowlevel_init
mov r12, lr// GPKCON0ldr r0, =0x7f008000ldr r1, =0x55555555str r1, [r0, #0x800]// GPKCON1ldr r1, =0x55555555str r1, [r0, #0x804]// GPLCON0ldr r1, =0x22222666str r1, [r0, #0x810]mov r0, #0bl lcd_backlight_switch// GPMCONldr r0, =0x7f008000ldr r1, =0x00111111str r1, [r0, #0x820]// GPMPUDldr r1, =0x00000555str r1, [r0, #0x828]// GPMDATldr r1, =0x002astr r1, [r0, #0x824]// MEM1DRVCONldr r1, =0str r1, [r0, #0x1D4]// Watchdogldr r0, =0x7e000000 @0x7e004000orr r0, r0, #0x4000mov r1, #0str r1, [r0]// EINTPENDldr r0, =(0x7f008000 +0x924)ldr r1, [r0]str r1, [r0]// VIC0ldr r0, =(0x71200000) @0x71200000// VIC1ldr r1, =(0x71300000) @0x71300000// Disable all interruptsmvn r3, #0x0str r3, [r0, #(0x14)]str r3, [r1, #(0x14)]// Set all interrupts as IRQmov r3, #0x0str r3, [r0, #(0x0C)]str r3, [r1, #(0x0C)]// Pending Interrupt Clearmov r3, #0x0str r3, [r0, #(0xF00)]str r3, [r1, #(0xF00)]
# 141 "../board/samsung/ok6410a/lowlevel_init.S"// ELFIN_CLOCK_POWER_BASEldr r0, =0x7e00f000ldr r1, [r0, #0x1C]orr r1, r1, #0x2000str r1, [r0, #0x1C]mov r0, # 1bl spl_config_uart_baudratebl uart_asm_initmov r0, #0x4F @'O'bl asm_putcmov r0, #0x4B @'K'bl asm_putc
# 184 "../board/samsung/ok6410a/lowlevel_init.S"mov r0, #0x2B @'+'bl asm_putc// Memory subsystemldr r0, =0x7e00f120mov r1, #0x0Dstr r1, [r0]mov r0, #0x2B @'+'bl asm_putc// ddrbl mem_ctrl_asm_initmov r0, #0x2D @'-'bl asm_putcmov r0, #0x2D @'-'bl asm_putc// Wakeup supportldr r0, =(0x7e00f000 + 0x904)ldr r1, [r0]bic r1, r1, #0xfffffff7cmp r1, #0x8beq wakeup_reset1:mov lr, r12mov pc, lr
- 详细解析mem_ctrl_asm_init
.globl mem_ctrl_asm_init
mem_ctrl_asm_init:ldr r0, =0x7e001000ldr r1, =0x4str r1, [r0, #(0x04)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 7800) - 1) / 1000000)str r1, [r0, #(0x10)]ldr r1, =(3<<1)str r1, [r0, #(0x14)]ldr r1, =1str r1, [r0, #(0x18)]ldr r1, =2str r1, [r0, #(0x1C)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 45) - 1) / 1000000 + 1)str r1, [r0, #(0x20)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 68) - 1) / 1000000 + 1)str r1, [r0, #(0x24)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1)ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1) - 3) << 3)orr r1, r1, r2str r1, [r0, #(0x28)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 80) - 1) / 1000000 + 1)ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 80) - 1) / 1000000 + 1) - 3) << 5)orr r1, r1, r2str r1, [r0, #(0x2C)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1)ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1) - 3) << 3)orr r1, r1, r2str r1, [r0, #(0x30)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 15) - 1) / 1000000 + 1)str r1, [r0, #(0x34)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 15) - 1) / 1000000 + 1)str r1, [r0, #(0x38)]ldr r1, =2str r1, [r0, #(0x3C)]ldr r1, =2str r1, [r0, #(0x40)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 120) - 1) / 1000000 + 1)str r1, [r0, #(0x44)]ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 120) - 1) / 1000000 + 1)str r1, [r0, #(0x48)]ldr r1, =0x0001001astr r1, [r0, #(0x0C)]ldr r1, =0xB45str r1, [r0, #(0x4C)]ldr r1, =0x150F0str r1, [r0, #(0x200)]ldr r1, =0x0str r1, [r0, #(0x304)]ldr r1, =0x0c0000str r1, [r0, #(0x08)]ldr r1, =0x000000str r1, [r0, #(0x08)]ldr r1, =0x040000str r1, [r0, #(0x08)]str r1, [r0, #(0x08)]ldr r1, =0x0a0000str r1, [r0, #(0x08)]ldr r1, =0x080032str r1, [r0, #(0x08)]mov r1, #0x0str r1, [r0, #(0x04)]check_dmc1_ready:ldr r1, [r0, #(0x00)]mov r2, #0x3and r1, r1, r2cmp r1, #0x1bne check_dmc1_readynopmov pc, lr
- 详细解析之 gd_t
gd_t // include/asm-generic/global_data.harch // arch/arm/include/asm/global_data.hlastinctimer_reset_valuetimer_rate_hzstruct bd_info *bd;unsigned long flags;unsigned int baudrate;unsigned long cpu_clk;unsigned long bus_clk;unsigned long pci_clk;unsigned long mem_clk;unsigned long fb_base;unsigned long malloc_limit;unsigned long malloc_ptr;
- 详细解析之 timer
// 硬件部分// base : 0x7F006000// 相对地址
typedef struct { S3C64XX_REG32 TCFG0; S3C64XX_REG32 TCFG1; S3C64XX_REG32 TCON; S3C64XX_TIMER ch[4]; S3C64XX_REG32 TCNTB4; S3C64XX_REG32 TCNTO4;
} S3C64XX_TIMERS;
lib/time.c 中 有 __weak 声明的 函数(get_ticks get_timer timer_init)
arm/mach-s3c64xx/timer.c 实现(get_ticks get_timer timer_init 和 get_tbclk)提供给lib/time.c 如下函数 : get_tbclk get_ticks 提供给common/spl/spl.c 如下函数 : timer_init目的是在 spl/lib/time.c 中 提供 delay/udelay 函数使用者命令中的 resetdrivers/serial/serial.c 中的 U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); // 当前版本中 在 spl 中 无 实际作用用于 assert fail 和 panic
这篇关于OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 SPL 镜像运行部分 boot 详细解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!