欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

u-boot分析之两阶段代码分析(三)

发布时间:2025/4/5 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 u-boot分析之两阶段代码分析(三) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

目录

  • u-boot(三)启动文件
  • 1,概述
  • 2,uboot第一阶段代码分析:
  • 汇编
  • 2,uboot第二阶段代码分析
  • C:_start_armboot
  • C:main_loop

u-boot(三)启动文件

 

1,概述

本书使用的uboot从nor flash启动,下面以开发板100ask24x0的uboot为例。

uboot属于两阶段的bootloader,第一阶段的文件为cpu/arm920t/start.S和board/100ask24x0/lowlevel_init.S,前者是平台相关的,后者是开发板相关的,主要是汇编实现,主要完成一些依赖于cpu体系结构的初始化,并调用第二阶段的代码;第二阶段的文件从lib_arm/board.c开始,主要是c语言实现,实现更复杂的功能。

2,uboot第一阶段代码分析:

(1)硬件设备初始化

将cpu设为svc模式,关闭watchdog,设置时钟,关闭MMU,CACHE,代码在cpu/arm920t/start.S中。

(2)为加载bootloader的第二阶段代码准备RAM空间

初始化RAM空间,通过在调用start.S中调用lowlevel_init函数来设置存储控制器,使得sdram可用,代码在board/100ask24x0/lowlevel_init.S中。

(3)复制bootloader的第二阶段代码到RAM空间中

将整个uboot代码(包括第一、第二阶段)都复制到SDRAM中,在cpu/arm920t/start.S中实现。(注意:100ask24x0改为用c函数实现的)。

(4)设置好栈

栈的设置灵活性很大,只要让sp指向一段没有使用的内存即可,下面分析可以看到内存的使用情况。

(5)跳转到第二阶段代码的C入口点

跳转之前清除bss段(初始值为0、无初始值的全局变量,静态变量放在bss段),c函数的运行环境准备好后,通过调用lib_arm/board.c中的start_armboot跳到c函数的入口点,这是第二阶段的入口点。

汇编:_start

cpu/arm920t/start.S

u-boot也是一个牛逼的单片机程序,所以也就需要:

  • 硬件相关初始化
  • 看门狗
  • 时钟
  • sdram
  • nand copy程序
  • 设置sp
  • 接下去就是读取内核,启动内核等
  • 程序实际的步骤是:

    1.set the cpu to SVC32 mode 2.turn off the watchdog 3.mask all IRQs 4.clock_init board\100ask24x0\boot_init.c 5.cpu_init_crit do sys-critical inits only at reboot,not when booting from ram!判断 是不是从内部ram启动还是仿真直接烧写到链接地址,如果不在正确的加载地址的话,执行cpu_init_critcpu_init_crit执行SDRAM初始化flush v4 I/D caches,disable MMU stuff and caches,lowlevel_init 这个会去初始化sdram,这个函数在lowlevel_init.S in your board directory也就是board\100ask24x0\lowlevel_init.S 6.Set up the stack 7.relocate CopyCode2Ram中自动识别当前是nor还是nand启动,nand启动时自动cp到内部ram中运行,所以可写,CopyCode2Ram位于board\100ask24x0\boot_init.c 8.bss段清零 9.调用C函数 _start_armboot

    堆栈设置如下

    0x33F80000uboot程序
    ·=-CFG_MALLOC_LENmalloc area
    .=-CFG_GBL_DATA_SIZEbdinfo
    .=-CONFIG_STACKSIZE_IRQIRQ 的栈
    .=-CONFIG_STACKSIZE_FIQFRQ的栈
    .=-12leave 3 words for abort-stack
    sp的初始位置 

    内存图:

    2,uboot第二阶段代码分析

    (1)初始化本阶段要使用到的硬件设备

    (2)检测系统内存映射(memory map) 

    (3)uboot命令的格式

    (4)为内核设置启动参数

    第二阶段从lib_arm/board.c中的start_armboot函数开始,程序流程如下:

    C:_start_armboot

    文件路径:lib_arm\board.c,这里就是u-boot执行C代码的地方了.

    • 分配了一个gd的结构体内存
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));//在这里,_armboot_start=_start,根据链接脚本,这也就是代码段的起始=0x33F80000 //也就是指向了内存图128的地方了
    • 执行init_sequence数组里预先定义的一些初始化函数

    board_init中设置了gd->bd->bi_arch_number = MACH_TYPE_S3C2440;,设置了一个参数gd->bd->bi_boot_params =            0x30000100;这个就是启动内核参数的地址

    • flash_init、nand_init:flash/nand 初始化
    • 堆栈初始化
    • env_relocate:环境变量的设置存储(环境变量来源有两种:一种是代码写死(也就是默认),一种在FLASH上保存,uboot启动后会检查flash上是否有可用的环境变量,有就用flash上的,否则使用默认)
    • main_loop:进入主循环

    代码摘要

    void start_armboot (void) { //-----/* Pointer is writable since we allocated a register for it */gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //----- //函数指针,初始化设备for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}} //---- flash初始化,识别 #ifndef CFG_NO_FLASH/* configure available FLASH banks */size = flash_init ();display_flash_config (size); #endif /* CFG_NO_FLASH */ ---- nand初始化 #if (CONFIG_COMMANDS & CFG_CMD_NAND)puts ("NAND: ");nand_init(); /* go init the NAND */ #endif //------//分配堆/* armboot_start is defined in the board-specific linker script */mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //-----//uboot的环境变量/* initialize environment */env_relocate (); //-----//经过一系列的初始化/* main_loop() can return to retry autoboot, if so just run it again. */for (;;) {main_loop ();}init_fnc_t *init_sequence[] = {cpu_init, /* basic cpu dependent setup */board_init, /* basic board dependent setup */interrupt_init, /* set up exceptions */env_init, /* initialize environment */init_baudrate, /* initialze baudrate settings */serial_init, /* serial communications setup */console_init_f, /* stage 1 init of console */display_banner, /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo, /* display cpu info (and speed) */ #endif #if defined(CONFIG_DISPLAY_BOARDINFO)checkboard, /* display board info */ #endifdram_init, /* configure available RAM banks */display_dram_config,NULL, };int board_init (void) {---/* support both of S3C2410 and S3C2440, by www.100ask.net */if (isS3C2410){/* arch number of SMDK2410-Board */gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;}else{/* arch number of SMDK2440-Board */gd->bd->bi_arch_number = MACH_TYPE_S3C2440;}/* adress of boot parameters */gd->bd->bi_boot_params = 0x30000100;}

    C:main_loop

    common/main.c

    main_loop两种选择:

    ①在bootdelay减到零之前敲下任意键将进入uboot控制界面(命令行模式),不过这里100ask24x0自定义一个menu命令,所以此时进入的是自己实现的菜单模式,可输入‘q’退出此模式转而进入命令行模式,readline (CFG_PROMPT)不断接收串口传过来的命令,run_command (lastcommand, flag)执行这些命令 。

    ②若倒计时结束前没有敲下任意键,将根据参数bootcmd来启动内核,getenv ("bootcmd")获得参数bootcmd值,可知bootcmd = read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,其中read.jffs2和bootm均为uboot命令,所以uboot核心是命令,要继续分析uboot是如何将内核从flash上搬到sdram并启动内核,必须深入分析这些命令才能清楚。

    内核启动

    这里实现了u-boot的倒计时,有打印命令,获取环境变量等,最关键的代码是

    s = getenv ("bootcmd"); if(倒计时结束) {printf("Booting Linux ...\n"); run_command (s, 0);}

    实际的环境变量是bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,读取内核,启动内核

    菜单处理(自定义实现)

    如果倒计时结束前输入了空格,进入命令模式run_command("menu", 0);

    命令处理

  • 死循环
  • 读取串口输入len = readline (CFG_PROMPT);
  • 执行命令rc = run_command (lastcommand, flag);
  • 转载:https://www.cnblogs.com/zongzi10010/p/10023676.html

    总结

    以上是生活随笔为你收集整理的u-boot分析之两阶段代码分析(三)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。