OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 SPL 镜像运行部分 boot 详细解析

2024-05-27 15:58

本文主要是介绍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 详细解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007935

相关文章

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

Goland debug失效详细解决步骤(合集)

《Golanddebug失效详细解决步骤(合集)》今天用Goland开发时,打断点,以debug方式运行,发现程序并没有断住,程序跳过了断点,直接运行结束,网上搜寻了大量文章,最后得以解决,特此在这... 目录Bug:Goland debug失效详细解决步骤【合集】情况一:Go或Goland架构不对情况二:

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

docker如何删除悬空镜像

《docker如何删除悬空镜像》文章介绍了如何使用Docker命令删除悬空镜像,以提高服务器空间利用率,通过使用dockerimage命令结合filter和awk工具,可以过滤出没有Tag的镜像,并将... 目录docChina编程ker删除悬空镜像前言悬空镜像docker官方提供的方式自定义方式总结docker

Spring Boot整合log4j2日志配置的详细教程

《SpringBoot整合log4j2日志配置的详细教程》:本文主要介绍SpringBoot项目中整合Log4j2日志框架的步骤和配置,包括常用日志框架的比较、配置参数介绍、Log4j2配置详解... 目录前言一、常用日志框架二、配置参数介绍1. 日志级别2. 输出形式3. 日志格式3.1 PatternL

Springboot 中使用Sentinel的详细步骤

《Springboot中使用Sentinel的详细步骤》文章介绍了如何在SpringBoot中使用Sentinel进行限流和熔断降级,首先添加依赖,配置Sentinel控制台地址,定义受保护的资源,... 目录步骤 1: 添加 Sentinel 依赖步骤 2: 配置 Sentinel步骤 3: 定义受保护的