程序员的圣诞节

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

鉴于没有妹纸可以陪,那就找件事打发时间吧,写到哪算哪。

2014.10与2013.07的版本相比,代码上并没有跨越式的改变,但是编译方式上,却有了极大的改变,一种更为优越的编译体系Kbuild&Kconfig System终于被引入了u-boot中。

Kbuild全称是the Linux Kernel Build System,它是从linux 2.6开始引入内核的,而Kconfig即Kernel config其实算是该体系的一部分。无论在该体系引入前还是引入后,内核编译根本上所使用的一直都是GNU make那一套,即使用Makefile及其对应规则来进行编译链接。然而,linux是一个多平台的系统,其支持多种架构以及各种设备驱动,这也就意味着,它的源码是它所有支持的架构以及驱动的一个集合,我们必须针对我们自己的系统进行裁剪,即有选择性的编译。如果没有kbuild体系,我们就需要面对浩如烟海的Makefile文件,针对每一个需要或者不需要编译的文件进行对应的修改,尤其对于一些牵一发而动全身的配置,更显得麻烦。而Kbuild体系则很好的解决了这一问题,它不仅事实上简化了makefile文件,同时也简化了维护的工作。Kbuild相当于是构建在Makefile上的一个抽象层。我们只需要在代码新添加时对Kconfig及Makefile进行一次修改,之后我们的维护工作就只是通过make *config来进选择而已。另外,还需要提及的一点是,对于编译过程,Kbuild能够展示出一个很清晰的依赖关系,更方便我们的维护。

基于以上这些优点,u-boot在2002年即有人建议将其引入主线,而直到2013.10,才开始引入Kbuild,而一直到2014.10,该体系才算完整的引入主线,如今,u-boot也可以如内核一般通过make *config来方便的进行配置。

以上是编译方面的新变化,接下来以armv7架构为例逐步分析代码,该代码是直接从官网新鲜下载的,所以,也许又tm有变化。

依照往常的规矩,我们可以打开arch/arm/cpu/armv7/start.S,该文件中包含着整个程序的入口

 1 /*
 2  * armboot - Startup Code for OMAP3530/ARM Cortex CPU-core
 3  *
 4  * Copyright (c) 2004    Texas Instruments <[email protected]>
 5  *
 6  * Copyright (c) 2001    Marius Gr枚ger <[email protected]>
 7  * Copyright (c) 2002    Alex Z眉pke <[email protected]>
 8  * Copyright (c) 2002    Gary Jennejohn <[email protected]>
 9  * Copyright (c) 2003    Richard Woodruff <[email protected]>
10  * Copyright (c) 2003    Kshitij <[email protected]>
11  * Copyright (c) 2006-2008 Syed Mohammed Khasim <[email protected]>
12  *
13  * SPDX-License-Identifier:    GPL-2.0+
14  */
15
16 #include <asm-offsets.h>
17 #include <config.h>
18 #include <version.h>
19 #include <asm/system.h>
20 #include <linux/linkage.h>
21
22 /*************************************************************************
23  *
24  * Startup Code (reset vector)
25  *
26  * do important init only if we don‘t start from memory!
27  * setup Memory and board specific bits prior to relocation.
28  * relocate armboot to ram
29  * setup stack
30  *
31  *************************************************************************/
32
33     .globl    reset
34
35 reset:
36     bl    save_boot_params

我们顺利找到了复位入口--reset,但是前面直接就是文件头和注释是怎么回事?-----特么的异常向量表呢?!

此时,只能从链接脚本中寻找答案了,打开arch/arm/cpu/u-boot.lds ,

 1 #include <config.h>
 2 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 3 OUTPUT_ARCH(arm)
 4 ENTRY(_start)
 5 SECTIONS
 6 {
 7     . = 0x00000000;
 8     . = ALIGN(4);
 9     .text :
10     {
11         *(.__image_copy_start)
12         *(.vectors)
13         CPUDIR/start.o (.text*)
14         *(.text*)
15     }

在start.o之前有个.vectors段,于是顺藤摸瓜,找到arch/arm/vector.S

 1 /*
 2  *  vectors - Generic ARM exception table code
 3  *
 4  *  Copyright (c) 1998    Dan Malek <[email protected]>
 5  *  Copyright (c) 1999    Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
 6  *  Copyright (c) 2000    Wolfgang Denk <[email protected]>
 7  *  Copyright (c) 2001    Alex Z眉pke <[email protected]>
 8  *  Copyright (c) 2001    Marius Gr枚ger <[email protected]>
 9  *  Copyright (c) 2002    Alex Z眉pke <[email protected]>
10  *  Copyright (c) 2002    Gary Jennejohn <[email protected]>
11  *  Copyright (c) 2002    Kyle Harris <[email protected]>
12  *
13  * SPDX-License-Identifier:    GPL-2.0+
14  */
15
16 #include <config.h>
17
18 /*
19  *************************************************************************
20  *
21  * Symbol _start is referenced elsewhere, so make it global
22  *
23  *************************************************************************
24  */
25
26 .globl _start
27
28 /*
29  *************************************************************************
30  *
31  * Vectors have their own section so linker script can map them easily
32  *
33  *************************************************************************
34  */
35
36     .section ".vectors", "x"
37
38 /*
39  *************************************************************************
40  *
41  * Exception vectors as described in ARM reference manuals
42  *
43  * Uses indirect branch to allow reaching handlers anywhere in memory.
44  *
45  *************************************************************************
46  */
47
48 _start:
49
50 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
51     .word    CONFIG_SYS_DV_NOR_BOOT_CFG
52 #endif
53
54     b    reset
55     ldr    pc, _undefined_instruction
56     ldr    pc, _software_interrupt
57     ldr    pc, _prefetch_abort
58     ldr    pc, _data_abort
59     ldr    pc, _not_used
60     ldr    pc, _irq
61     ldr    pc, _fiq

通过文件头的 .section ".vectors" 可以确定,这就是我们所需要的异常向量表,而其中全局变量_start便是整个程序的真正起点。至于这样做的原因,大概是在于,所有ARM架构的芯片,异常向量表的位置及结构是万年不易的,是可以复用的代码,因此从start.S中提出来了。
回到start.s,

 1     /*
 2      * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
 3      * except if in HYP mode already
 4      */
 5     mrs    r0, cpsr
 6     and    r1, r0, #0x1f        @ mask mode bits
 7     teq    r1, #0x1a        @ test for HYP mode
 8     bicne    r0, r0, #0x1f        @ clear all mode bits
 9     orrne    r0, r0, #0x13        @ set SVC mode
10     orr    r0, r0, #0xc0        @ disable FIQ and IRQ
11     msr    cpsr,r0

注释已经很完善,关闭中断(FIQ和IRQ,说起来FIQ现在几乎无用了啊!),进入强大(伪)的特权模式--SVC模式

 1 /*
 2  * Setup vector:
 3  * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
 4  * Continue to use ROM code vector only in OMAP4 spl)
 5  */
 6 #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
 7     /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
 8     mrc    p15, 0, r0, c1, c0, 0    @ Read CP15 SCTRL Register
 9     bic    r0, #CR_V        @ V = 0
10     mcr    p15, 0, r0, c1, c0, 0    @ Write CP15 SCTRL Register
11
12     /* Set vector address in CP15 VBAR register */
13     ldr    r0, =_start
14     mcr    p15, 0, r0, c12, c0, 0    @Set VBAR
15 #endif

配置异常向量表基址,及将_start的地址值写入VBAR寄存器

1     /* the mask ROM code should have PLL and others stable */
2 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
3     bl    cpu_init_cp15
4     bl    cpu_init_crit
5 #endif

所谓lowlevel init,涉及的是CPU的初始化以及芯片内PLL/CRPM/DDR等的初始化
至于cpu_init_cp15,这是针对cache以及mmu的一系列无效及关闭操作,属于无需更改的代码 。
而cpu_init_crit才是主要的lowlevel init。

 1 /*************************************************************************
 2  *
 3  * CPU_init_critical registers
 4  *
 5  * setup important registers
 6  * setup memory timing
 7  *
 8  *************************************************************************/
 9 ENTRY(cpu_init_crit)
10     /*
11      * Jump to board specific initialization...
12      * The Mask ROM will have already initialized
13      * basic memory. Go here to bump up clock rate and handle
14      * wake up conditions.
15      */
16     b    lowlevel_init        @ go setup pll,mux,memory
17 ENDPROC(cpu_init_crit)

该函数,调用了lowlevel_init,
依照惯例,我们打开arch/arm/cpu/armv7/lowlevel_init.S

 1 #include <asm-offsets.h>
 2 #include <config.h>
 3 #include <linux/linkage.h>
 4
 5 ENTRY(lowlevel_init)
 6     /*
 7      * Setup a temporary stack
 8      */
 9     ldr    sp, =CONFIG_SYS_INIT_SP_ADDR
10     bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
11 #ifdef CONFIG_SPL_BUILD
12     ldr    r9, =gdata
13 #else
14     sub    sp, sp, #GD_SIZE
15     bic    sp, sp, #7
16     mov    r9, sp
17 #endif
18     /*
19      * Save the old lr(passed in ip) and the current lr to stack
20      */
21     push    {ip, lr}
22
23     /*
24      * go setup pll, mux, memory
25      */
26     bl    s_init
27     pop    {ip, pc}
28 ENDPROC(lowlevel_init)

这其中无非就是指定了一个临时的栈地址,用于接下来真正的初始化中使用,即s_init,s_init是需要是针对具体芯片或者单板的初始化,因此是需要自己实现的,通常以C代码来实现,其中最重要的是初始化pll、crpm以及ddr。
该函数当然也可以自己实现,但是实际上个人觉得殊无必要,因为本来也就没几行代码。
接下来就是start.S的最后一句了

1     bl    _main

看看十一点多了,总算把平安夜打发了,就此打住了

时间: 2024-10-22 04:19:28

程序员的圣诞节的相关文章

《程序员修炼之道》---- 修的是什么

学习最好的方式,是有个好师傅.他根据你的不同阶段,教导你不同的技能,循序渐进:师傅不单教你练功,还会教你做人,使你内修于心,外化于形.教你的一些道理,你可能当时不太懂,但等你苦练多日,历经曲折,终有一日茅塞顿开,再去学艺做事,事半功倍,大有精进: 有一个位好导师自然是得之我幸的事情,但实际工作中很难得,也许有前辈们偶尔的点拨,有朋友的激励,但最平实可靠的方法还是来自于阅读 本书原名 "The Pragmatic Programmer",也就是"注重实效的程序员".本

【头条网给你一个机会做代言人】征文大赛三等奖:程序员联盟

[头条网给你一个机会做代言人]征文大赛三等奖-参赛文章 最近喜获头条网举办的[头条网给你一个机会做代言人]征文大赛三等奖,虽然不算什么. 不过有网友要求我发参赛文章,不才在此献丑了: 大家好! 我叫谢恩铭,网名frogoscar,浙江嘉兴桐乡人.我是一个热爱编程的程序员(专业是"嵌入式软件与移动信息"). 2014年圣诞节期间在头条网建立了自媒体<程序员联盟>,至今发表了近60篇文章,全部都是本人一个字一个字打出来的原创作品.有些资料参考了百度百科和维基百科,引用的文字我基

OSChina 周六乱弹 —— 程序员专用经典语录

1 IT人表示屁股上还得纹一个</body>, 要不中间来个hello world! 2 真正的程序员喜欢兼卖爆米花,他们利用CPU散发出的热量做爆米花,可以根据米花爆裂的速度听出正在运行什么程序. 3 十年生死两茫茫,写程序,到天亮. 千行代码,Bug何处藏. 纵使上线又怎样,朝令改,夕断肠. 领导每天新想法,天天改,日日忙. 相顾无言,惟有泪千行. 每晚灯火阑珊处,夜难寐,又加班. 4 老婆给当程序员的老公打电话:"下班顺路买三个包子带回来,如果看到卖西瓜的,买一个."

迈向更好的程序员的行列

学习最好的方式,是有个好师傅.他根据你的不同阶段,教导你不同的技能,循序渐进:师傅不单教你练功,还会教你做人,使你内修于心,外化于形.教你的一些道理,你可能当时不太懂,但等你苦练多日,历经曲折,终有一日茅塞顿开,再去学艺做事,事半功倍,大有精进: 有一个位好导师自然是得之我幸的事情,但实际工作中很难得,也许有前辈们偶尔的点拨,有朋友的激励,但最平实可靠的方法还是来自于阅读. 面对这份职业,你应如何开始? 和程序员读的绝大多数应用书籍不同的是,开篇给你讲的就是态度.对待错误.不整洁的代码.团队协作

有哪些好笑的关于程序员的笑话

0. 某女:你能让这个论坛的人都吵起来,我今晚就跟你走. 某软件工程师:PHP 是最好的语言! 某论坛炸锅了,各种吵架... 某女:服了你了,我们走吧你想干啥都行. 某软件工程师:今天不行,我一定要说服他们,PHP 必须是最好的语言某女:....... 1. 你们饭店需要客户端吗? 不忙的时候都是小二端,只有忙的时候才需要客户端. 2. “你们用盗版的时候有想过做出这款软件的程序员吗?!他们该如何养家糊口?” “哈哈哈,别逗了,程序员哪有家要养啊!” 3. 某程序员被一个妹子请去修宽带,那个破电

程序员成功秘密:从6个互联网大佬参悟人生!

我刚毕业,如何入行计算机网络这一行业? 干了几年网络了,感觉进入瓶颈期,不知道下一步该怎么走了? 大家做生意的做生意,转管理的也不在少数,我还需要坚持做技术么? 问题虽然五花八门,但是总结下来就是一个:程序员的职业道路该如何走? 我想,这个问题最好的答案,还是需要那些历经沧桑的过来人,才最有资格和大家谈论这个话题. 特别凑巧,前几天在网上闲逛时,发现某个北美网络运维协会NANOG视频访谈类节目上,6个普通人分享了他们如何成为一名成功的网络工程师,甚至公司高管和公司创始人的历程. 第一位:一名设计

写代码有这些想法,同事才不会认为你是复制粘贴程序员

前言 最近做完12月份版本需求,有一些思考不够深入的代码,因此写一下总结,希望大家日常写代码多点思考,多点总结,加油!同时哪里有不对的,也望指出. 一.复杂的逻辑条件,是否可以调整顺序,让程序更高效呢. 假设业务需求是这样:会员,第一次登陆时,需要发一条感谢短信.如果没有经过思考,代码直接这样写了 if(isUserVip && isFirstLogin){ sendMsg(); } 假设总共有5个请求,isUserVip通过的有3个请求,isFirstLogin通过的有1个请求. 那么以

[稀土掘金日报] 优秀Android程序员的孤岛战役

先给大家报告一个好消息,前几天圣诞节的掘金翻译计划里的35篇技术文章在短短的24小时内就被大家认领完毕了,今天已经有20多个 PR,看来大家是相当热情.想知道我们掘金翻译计划收录了哪些优质的技术文章?快来我们 Github 页面围观吧,戳→https://github.com/xitu/gold-miner 优秀程序员都有一些共同的特质,今天稀土君为大家列出10个例子提供给大家参考. 成为优秀程序员的10个Tips 优秀程序员都有一些共同的特质,业内大牛从自身丰富的从业经验中提炼出成为优秀程序员

程序员们,你们再这样下去会没朋友的。

引言 写这篇文章,其实源于之前有个群里的同学,问了LZ一个问题. 当时他给LZ发了一张图片,然后问LZ,"这个@Test注解引用不了是咋回事?" 看到这个问题,LZ当时恰好没事,就顺手给他回复了一下,说这个错误引起的原因是,注解的特性只在JDK1.5或者更高的版本才能用. 话虽这么说,但其实LZ当时心里多少是有些无语的. 提示写的这么清楚了,看不懂吗?就算英文阅读水平差点,百度翻译一下会不会呢? 最让LZ郁闷的是,当LZ回答完以后,这个新人同学只回了一个字,"哦!"