程序员的圣诞节后-零

u-boot-2014.10代码分析及移植说明

 1 ENTRY(_main)
 2
 3 /*
 4  * Set up initial C runtime environment and call board_init_f(0).
 5  */
 6
 7 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
 8     ldr    sp, =(CONFIG_SPL_STACK)
 9 #else
10     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
11 #endif
12     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
13     mov    r2, sp
14     sub    sp, sp, #GD_SIZE    /* allocate one GD above SP */
15     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
16     mov    r9, sp        /* GD is above SP */
17     mov    r1, sp
18     mov    r0, #0
1 clr_gd:
2     cmp    r1, r2            /* while not at end of GD */
3     strlo    r0, [r1]        /* clear 32-bit GD word */
4     addlo    r1, r1, #4        /* move to next */
5     blo    clr_gd

_main位于crt0.S中,该段主要是给u-boot中最根本最重要的变量gd分配空间并清零。

gd是一个结构体变量,其地址被放置于r9寄存器中(如果没记错的话,以前的版本是放入r8寄存器的),它包含了u-boot程序中最重要的全局信息,包括时钟相关变量,页表,重定位信息等,另外还包括传递给内核的板级信息。

1 #if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)
2     sub    sp, sp, #CONFIG_SYS_MALLOC_F_LEN
3     str    sp, [r9, #GD_MALLOC_BASE]
4 #endif
5     /* mov r0, #0 not needed due to above code */
6     bl    board_init_f

定义relocation之前所需的堆空间地址,之后转入board_init_f程序,从此处起,SPL即BL1阶段代码和U-BOOT即BL2阶段代码分开走向了不同的路线。

如果未定义CONFIG_SYS_GENERIC_BOARD,则为/arch/arm/lib/board.c

如果定了CONFIG_SYS_GENERIC_BOARD,则为common/board_f.c。

想了想,先以/arch/arm/lib/board.c为例讲吧,毕竟这个是针对具体architecture(真实原因是common下那个我还没看过)

 1 void board_init_f(ulong bootflag)
 2 {
 3     bd_t *bd;
 4     init_fnc_t **init_fnc_ptr;
 5     gd_t *id;
 6     ulong addr, addr_sp;
 7 #ifdef CONFIG_PRAM
 8     ulong reg;
 9 #endif
10     void *new_fdt = NULL;
11     size_t fdt_size = 0;
12
13     memset((void *)gd, 0, sizeof(gd_t));

此处又重新将gd清零了,似乎有点多余啊,难道是针对SPL的?(原因是针对common/board_f.c的,该文件中的函数没有gd初始化)

 1     gd->mon_len = (ulong)&__bss_end - (ulong)_start;
 2 #ifdef CONFIG_OF_EMBED
 3     /* Get a pointer to the FDT */
 4     gd->fdt_blob = __dtb_dt_begin;
 5 #elif defined CONFIG_OF_SEPARATE
 6     /* FDT is at end of image */
 7     gd->fdt_blob = &_end;
 8 #endif
 9     /* Allow the early environment to override the fdt address */
10     gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
11                         (uintptr_t)gd->fdt_blob);

gd->mon_len为uboot大小。

CONFIG_OF_EMBED决定着是否将dtb编入uboot,libs-$(CONFIG_OF_EMBED) += dts/

CONFIG_OF_SEPARATE也是在同时编译dtb,但是分开编译,并未编入uboot中,Makefile中可以看出,但是没找到为何是放在_end后。

1     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
2         if ((*init_fnc_ptr)() != 0) {
3             hang ();
4         }
5     }

该段则是进行一部分初始化,init_sequence为一个函数指针数组,

 1 init_fnc_t *init_sequence[] = {
 2     arch_cpu_init,        /* basic arch cpu dependent setup */
 3     mark_bootstage,
 4 #ifdef CONFIG_OF_CONTROL
 5     fdtdec_check_fdt,
 6 #endif
 7 #if defined(CONFIG_BOARD_EARLY_INIT_F)
 8     board_early_init_f,
 9 #endif
10     timer_init,        /* initialize timer */
11 #ifdef CONFIG_BOARD_POSTCLK_INIT
12     board_postclk_init,
13 #endif
14 #ifdef CONFIG_FSL_ESDHC
15     get_clocks,
16 #endif
17     env_init,        /* initialize environment */
18     init_baudrate,        /* initialze baudrate settings */
19     serial_init,        /* serial communications setup */
20     console_init_f,        /* stage 1 init of console */
21     display_banner,        /* say that we are here */
22     print_cpuinfo,        /* display cpu info (and speed) */
23 #if defined(CONFIG_DISPLAY_BOARDINFO)
24     checkboard,        /* display board info */
25 #endif
26 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
27     init_func_i2c,
28 #endif
29     dram_init,        /* configure available RAM banks */
30     NULL,
31 };

注意该处实际是个指向函数指针的数组,其好处我能想到的一点是末尾的NULL,通过指针为NULL判断作为结束标志。以下逐一分析各个初始化函数,

1.arch_cpu_init

该函数自然就是需要针对各个芯片自己实现了,通常可以在该函数中实现cache使能的控制

2.mark_bootstage

1     /* Record the board_init_f() bootstage (after arch_cpu_init()) */
2 static int mark_bootstage(void)
3 {
4     bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
5
6     return 0;
7 }

算是uboot的流程中做个标记,bootstage_mark_name函数最终可以通过和板级自己实现的一个函数挂接,实现通过打印或者led灯等各种方式来反应uboot的进程。

3.fdtdec_check_fdt

检测fdt是否存在

4.board_early_init_f

早期的一些初始化

如需要,定义宏CONFIG_BOARD_EARLY_INIT_F,并实现该函数

5.timer_init

timer初始化,题外:u-boot中timer驱动的作用是为了实现delay,因此timer驱动也是围绕udelay展开的。

6.board_postclk_init

早期时钟相关初始化

如需要,定义宏CONFIG_BOARD_POSTCLK_INIT,并实现该函数

7.get_clocks

看起来实际主要是为了获取gd->arch.sdhc_clk时钟,即为了获取sdmmc时钟,不过并不是必要。

如需要,定义宏CONFIG_FSL_ESDHC,并实现该函数

8.env_init

初始化gd中的两个成员,即环境变量表的地址,以及valid值

9.init_baudrate

初始化gd中的波特率成员变量

该处设计BAUDRATE的一个宏定义

10.serial_init

初始化串口驱动

对应串口驱动中必须添加的两个函数default_serial_console,以及serial_device结构体的start成员函数

11.console_init_f

其实没啥,只是在存在CONFIG_PRE_CONSOLE_BUFFER的情况下会有个buffer初始化的过程

12.display_banner

打印uboot版本信息等

13.print_cpuinfo

这个是各个芯片自己实现,打印一些cpu相关信息

14.checkboard

打印board相关信息

15.init_func_i2c

如果有且需要i2c的话,初始化

16.dram_init

自己实现,gd->ram_size的初始化,当然也有吧dram_bank的初始化写在这里

整个init_sequence初始化就结束了。

剩下的下期再说。

时间: 2024-11-03 05:44:17

程序员的圣诞节后-零的相关文章

年薪50W程序员必备Linux知识 — 零起点学习Linux系列

年薪50W程序员必备,零点学习Linux系列视频教程 闺蜜推荐的Linux学习资料,就需要这个视频了 楼主也是买的学习视频,支付然后加楼主微信 (171301011)索取视频 原文地址:https://www.cnblogs.com/videoer/p/11628992.html

极客时间-左耳听风-程序员攻略开篇-零基础启蒙

入门教程 Python基础: 与孩子一起学编程:以 Python 语言教你如何写程序 https://book.douban.com/subject/5338024/ 在线编程网址 Codecademy: Learn Python https://www.codecademy.com/learn People Can Program https://www.peoplecanprogram.com/ 在线练习 CodeAbbey http://www.codeabbey.com/index/ta

漫谈程序员系列:程序员零门槛?

六个小故事,一一来看. 博主从技术支持转做开发 2005年3月份我决定辞去技术支持工作,转行做软件开发.大学时我曾经学习过PASCAL这种编程语言,但和程控交换机打了几年交道之后,PASCAL早已灰飞烟灭,渣都找不到了,而且我孤陋寡闻,也没听说哪个软件公司用PASCAL做开发.于是呢,我决定学习C语言,花了一个星期,走马观花式学习了由Brian W. Kernighan和Dennis M. Ritchie合著的<The C Programming Language>(译作<C程序设计语言

黑马程序员:从零基础到精通的前端学习路线

随着互联网的深入发展,前端开发工程师一跃成为市场上非常抢手的人才.很多同学,包括以前做UI的.Java的.或者对于IT完全零基础的同学都想学习前端.下图是网上流传甚广的一张前端学习思维导图,很多初学者表示看到这些密密麻麻的知识点就已经晕了.确实,前端是一门涵盖面很广的学科.但是想学前端的你也不用慌张,内容虽多但有迹可循,只要循序渐进就不怕学不好前端! 那么前端开发到底需要学什么?应该怎么学?接下来黑马程序员前端学院教你如何从零基础学习前端. 一.前端开发入门 在入门阶段,你首先要学会最基本的技能

Java程序员从笨鸟到菜鸟之(一百零三)java操作office和pdf文件(一)java读取word,excel和pd

在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下java对word.excel.pdf文件的读取.本篇博客只是讲解简单应用.如果想深入了解原理.请读者自行研究一些相关源码. 首先我们来认识一下读取相关文档的jar包: 1. 引用POI包读取word文档内容 poi.jar 下载地址 http://apache.freelamp.com/poi/release/bin/poi-bin-3.6-20091214.ziph

编程零基础做程序员,该怎么学习?首先要学习什么?

编程零基础做程序员,该怎么学习?首先要学习什么?众所周知程序员是21世纪比较吃香的工作.程序员工资高还不需要和复杂的社会打交道.那么作为一个零基础,什么都不懂的人该怎么成为一名程序员?当程序员需要学什么?下面就来分析下.零基础的我该如何学习?如果想做一个程序员,在没有基础的情况下,买书自学是一个办法,但是大多数人会因为没有相关的基础知识,导致看书看得一知半解,因为有不同的语言,不同的开发环境,在你不了解的时候,买的书不一定合适.笔者是一个Java出身的程序员,学习编程有什么学习问题或者关于Jav

程序员必备英语.net版(.net菜鸟的成长之路-零基础到精通)

通过一段时间的.NET学习,我发现英文不好是我的软肋~我觉得好好补习一下英文单词水平.可是要背哪些单词呢? 经过一段时间的整理,终于整理出来了一套比较完整的.NET程序员必备单词文档.单词加详细说明.现在分享给大家~希望能给大家帮助~~~!下面是word截图.为了方便阅读我已经给制作成了PDF. 下载地址:http://yunpan.cn/cd6JQeLZfxS7A  访问密码 52cb

Java程序员从笨鸟到菜鸟之(一百零一)sql注入攻击详解(二)sql注入过程详解

在上篇博客中我们分析了sql注入的原理,今天我们就来看一下sql注入的整体过程,也就是说如何进行sql注入,由于本人数据库和网络方面知识有限,此文章是对网上大量同类文章的分析与总结,其中有不少直接引用,参考文章太多,没有注意出处,请原作者见谅) SQL注入攻击的总体思路是: 1.发现SQL注入位置: 2.判断后台数据库类型: 3.确定XP_CMDSHELL可执行情况 4.发现WEB虚拟目录 5. 上传ASP木马: 6.得到管理员权限: 一.SQL注入漏洞的判断 一般来说,SQL注入一般存在于形如

一个“纯屌丝”如何零基础转行做程序员

高考落榜后,生活像被蒙上了一层灰色的雾霾,看不清未来.在接下来的一两年中,磕磕绊绊地走了一些弯路.庆幸的是,我一直勇敢前行,欣慰的是,如今拨云见日,天朗气清. 放弃复读 一路波折 或许是因为年轻,心性不够成熟,我对高考的失败一直耿耿于怀,只顾嗟叹,连复读的勇气都没有.每每看到考上大学的同学在QQ空间发表状态.晒照片,总会有一种羡慕的感觉郁结心头. 在家闲的无聊,总觉得该找点事做,我在广告宣传的引导下来到传说中的新*电脑学校,学习网络技术,当时,不谙世事的我以为学完之后就能成功跨进IT行业,成为一