|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 阳阳天 于 2019-10-24 09:31 编辑 % z8 Z/ b y6 L" ?
, w, @5 l2 R* l/ ?
在第一章中,介绍了Exynos4412的iROM、启动方式、源码组成等;在第二章中,介绍. R9 i2 q% ^) V6 L& L, t
uboot 编译等。通过前面对编译的详细分析,了解到 uboot 源码中有以下几个文件是非常重
& B/ z/ N, d: k0 n( k3 p" n1 X要的:
2 o3 t n/ |5 U$ ]8 H“cpu/ARM_cortexa9/start.S”
5 Q6 t7 ]9 g* \: W3 t! w6 j“board/samsung/smdkc210/lowlevel_init_SCP.S 或者 lowlevel_init_POP.S”
# L; B8 x- l# G6 x& I“include/configs/itop_4412_android.h 或者 itop_4412_ubuntu.h”0 O1 A9 v, `/ x9 A. p
其中“cpu/arm_cortexa9/start.S”是 uboot 代码入口文件,分析 uboot 一般是从 M6 s3 s, z, c% u& P6 \
“start.S”文件开始,“lowlevel_init_SCP.S”文件是内存初始化、时钟初始化和串口初始化
- h' L# c+ S, K等的文件,start.S 文件在运行过程中会跳到这个文件中。1 Q0 |# O( x4 _! }; X, d0 U* t1 q
“itop_4412_android.h 或者 itop_4412_ubuntu.h”文件是重要的配置头文件,里面的- z* g7 }6 _, Z- A3 ?3 h" W
宏配置,会影响以上文件如何编译和运行,包括在下一章节中 uboot 源码的 C 语言部分,很
6 J4 }: b, d$ F% Q' y; v, m, O多代码编译和运行都会受到这个头文件的影响。- q2 B6 ?9 [6 [4 T
本章主要内容是,从“start.S”文件开始分析所有汇编代码,截止于 uboot 开始执行 C
- u0 a* ?7 q0 g* {/ V代码。其中涉及到很多不常用概念,需要我们去了解和掌握;涉及到汇编语法,需要我们去了
* B2 y v/ t8 C* \* p' y解。) J) v8 \. A. Z$ e
3.1 分析 uboot 汇编源码必要的知识和学习方法汇总
. {* {6 H9 w) b" x本小节,结合 datasheet 介绍 4412 的物理地址概念,这部分和单片机中类似;介绍汇编
0 p9 r1 W- `6 T% N* e7 N1 U语法如何学习以及要掌握到什么程度;汇编部分调试方法。
( U" Q1 `& ~. f5 y9 G3.1.1 4412 的物理地址和虚拟地址介绍
6 @# w0 h6 S" M) f- w0 B0 y" g如果用户学习过迅为的 linux 驱动教程,其中有一期,专门介绍物理地址和虚拟地址的概
5 n. d' O6 ?* X1 `2 M念。几乎在所有现代操作系统中,物理地址都是通过 MMU(内存管理单元)映射为虚拟地
" m# @3 Z5 J6 y; `* o( X$ _址。但是在 uboot 汇编部分,还是直接操作物理地址的。" ~3 t+ _3 C: Y# P4 @' @: Z
物理地址的概念。) n' [& k& r3 \9 B
MPU 地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给
4 b0 _, B, S# T5 w! L内存条中的内存的。物理地址空间,一部分给内存用,一部分给总线用,这是由硬件设计来决$ U" p! s0 Z2 Z: }/ m/ x
定的,因此在 32 bits 地址线的处理器中,物理地址空间是 2 的 32 次方,即 4GB,但物理1 X' v6 l1 ]1 N
RAM 一般不能上到 4GB,因为还有一部分要给总线用(总线上还挂着别的许多设备)。
- N7 n) |% V1 R! l& j1 W对于有单片机基础的用户来说,物理地址还是比较好理解,例如在 51 单片机中,P0.0 表
6 {/ E8 t% z1 G! F0 g示小灯的输出寄存器,给这个寄存器写 1 小灯灭,写 0 小灯亮,寄存器 P0.0 的地址就是物理% k! D/ A3 M4 v9 u N! f9 V; n
地址。
$ ^4 z4 B+ l. ?- s( e- <p>P0 = 0xfe;//小灯亮</p><p>P0 = 0xff;//小灯灭</p>
复制代码 P0 在 51 寄存器头文件中,有一个宏定义它的实际地址,也就是物理地址。9 n4 C# n9 c& p2 B# x
在 4412 中,物理地址太多了,根本没有办法全部介绍,2000 多页的 datasheet 中大部9 z# A! q, g! z, [
分都是介绍寄存器,一个一个介绍是无法实现的。但是我们有必要掌握和理解其中的寄存器框
) B/ @# z, P* q& H架和典型寄存器。* S9 t# w/ B( S7 q' C& Q$ _1 m
在 4412datasheet 第三章“Memory Map”中,如下图所示,这是 4412 全部基地址的描述。
( r7 j: _, Q, @4 U$ ~/ D0 @! d0 O
- M1 B @$ u- l3 M' v4 n5 w注意上表中,0x4000_0000~0xA000_0000,0xA000_0000~0x0000_0000 这两个地址) r$ h2 J5 I7 }5 T" y; X4 ?
区间,这两个区间是 DMC 内存控制器的寻址地址,也就是内存的物理地址。实际上 4412 最, O8 s1 N: V+ _! p9 g W6 C6 _! Y
大支持的内存可以达到 3G,32 位处理器理论上可以支持 2 的 32 次方(最大 4G),如上表
+ i& P2 s/ a+ B所示,其中 1G 的地址给了 iROM、iRAM 等等这些 MPU 内部寄存器使用,所以 32 位 MPU
, G* e9 l: V8 q- T* z" ]是不可能达到 4G 内存的。
8 @5 W2 A& {9 H现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要% {# N) x5 Q; B% U( d/ ]0 K% m6 ^+ n
MMU(Memory Management Unit)的支持。MMU 通常是 CPU 的一部分,如果处理器: [5 Q4 |+ @0 D) G
没有 MMU,或者有 MMU 但没有启用,CPU 执行单元发出的内存地址将直接传到芯片引脚
; `% u' J& n e8 u上,被内存芯片(物理内存)接收,这称为物理地址(Physical Address),如果处理器启用
) k. r; P% \0 R# P了 MMU,CPU 执行单元发出的内存地址将被 MMU 截获,从 CPU 到 MMU 的地址称为虚拟5 b8 l6 c4 `8 ^
地址(Virtual Address),而 MMU 将这个地址翻译成另一个地址发到 CPU 芯片的外部地址
: d3 i3 v& r; _引脚上,也就是将虚拟地址映射成物理地址。通过内存管理单元,可以实现 4G 的虚拟内存。
* v/ c) E' e8 D: I, j6 Q在 uboot 代码中,需要多次用到以上地址的概念,其中内存管理单元被开启或者关闭, c+ ]+ u# L9 V5 B
所以有必要先介绍一下这几个地址的概念。; Q3 x$ n* \ O
3.1.2 关于汇编语法1 c) C1 b7 D) V! O7 T
如果学习过单片机课程,会发现大部分都是使用 C 语言去编码,汇编使用的非常少了。3 r, c0 M3 n. a4 H1 @7 B8 N/ u
那么还有必要去学习汇编么?其实是没有必要的,因为在 uboot 中汇编代码量非常少,以
* D& C) u* F \4412 的 uboot 源码为例,其中有效的汇编代码不足 200 行,我们根本不需要为了读懂 200
* P K; l& Y4 B2 s, N7 d行代码专门去学习一门编程语言。! E% c. s7 [4 p( l! G. @/ v! I" |
作者这里建议,首先我们的目标是一定要把这些代码读明白,如果不明白会影响后面 C
* z( L9 ]" H; o: m; k2 M5 ]8 Q& ]6 d0 A代码的阅读,以及 uboot 的移植;其次,我们要弄清楚每一行有效汇编代码的语法。8 H$ I0 P$ i' o* V
现在我们已经知道汇编是从“cpu/arm_cortexa9/start.S”这个文件开始执行,那么我们* s' y6 N) Y/ P' ^& n
就从第一行代码的语法开始学习,代码执行到或者跳到哪一行,我们就学习这一行代码的语
5 g3 ?$ d* m3 @8 V; l法。
- H$ z) B- U" F, H4 j! }在手册的附录部分,我们会依次介绍汇编代码中出现的语法,大家也可以通过互联网学习5 M; j# F* C# V% k* S; W# ~
每一行执行的汇编语法。$ T+ |8 h& M5 X$ O( ?7 }& J- Y8 V3 b
3.1.3 uboot 汇编代码初始化串口之前的简易调试方法
$ z2 Q W. p* R# U+ n, S6 j+ T在前面教程中我们介绍过,从 A9 开始,开发板一般都不配 jtag,jtag 价格昂贵,在 A96 @3 {/ _) s4 _9 ]( R( o* R
之前,由于引导程序 uboot 必须通过 jtag 来烧写,但是在 A9 处理器上,大部分都是支持 tf
2 c; w) l. E+ H$ N. ^8 p卡引导,这样可以免去 jtag 的费用,烧写变的简单高效。2 ~6 L6 Z8 T, j+ }: `
那么没有 jtag,对于 uboot 的调试,我们没法单步调试,如果有一行代码我们不是很确' q+ ]4 V) g$ x% i( G7 s
定到底执行了没,或者跳到哪一行。如果代码已经执行到串口初始化阶段,当然是可以通过串+ K8 _# K0 x/ a) T$ s6 b% N. W, a
口打印字符来实现,在串口初始化之前,其实可以通过控制 LED 灯来跟踪代码。
) Q5 y9 }( @( r# O: h. T以下是开发板上两个小灯控制的代码,可以将小灯点亮。
" q+ R) b: b) a7 n2 e& c! v点亮 LED2 灯:ldr r0, =0x11000104 /* GPL2(0) */
; c0 A1 x0 x# Gldr r1, =0x00000001 /* GPL2(0 output high) */
/ m' A4 T: _% h* T [: Qstr r1, [r0]5 ]! a3 C: z7 V+ W, B. y$ i* I
ldr r0, =0x11000100 /* GPL2(0) */
( E5 G& g$ w: Y- l5 Q3 ^3 A/ kldr r1, =0x00000001 /* GPL2(0 output high) */
# I3 @8 l( _+ A" I: `str r1, [r0]7 s% v. ]# ^ l; m6 h- Z
点亮 LED3:
+ r N# d4 h: k9 J9 P9 [0 Cldr r0, =0x11000060
! K4 f$ ~! m% Uldr r1, =0x00000010
, |6 r% I* P- k) F3 \str r1, [r0]
% A4 H5 S7 g' p$ wldr r0, =0x11000064+ S9 M! z% ^5 Y$ t* f( {
ldr r1, =0x000000028 o ?& W; E3 Y2 s m
str r1, [r0]# C4 P! n/ n- r
这里简单介绍下这几行汇编代码的含义。( c2 ]0 A! u/ x, E9 Q8 v' A1 @- x
ldr r0, =0x110001041 ^+ q' t2 O- f/ f; v1 M/ P# B! c; Y
ldr 是将 0x11000104 值赋给 r0 寄存器。这个值地址为 GPL2DAT。3 A7 }% B5 S. I$ L- c, H# z
ldr r1, =0x000000011 [+ m! j$ @+ @3 g4 w r
ldr 是取 0x11000104 地址的值赋给 r1 寄存器。
3 X2 r3 ~0 l$ l$ D# mstr r1, [r0]2 F6 [- Y6 t8 G: _1 \- ^ p
str 是将 r1 的值写入到 r0 数值对应物理地址寄存器中。将 0x00000001 写入到$ q z0 U8 ]6 {, X
0x11000104 地址寄存器中,0x11000104 地址是 GPL2DAT 寄存器。
2 q. t# o7 g- W4 q2 s' B, mldr r0, =0x11000100 /* GPL2(0) */
; ^* J+ a) d! @, C2 ildr r1, =0x00000001 /* GPL2(0 output high) */
; p/ I4 V' i! ^- e# n" |str r1, [r0]
' F, G) E; w, c* L将 0x00000001 写入到 0x11000100 地址寄存器中,0x11000100 地址是 GPL2CON 寄
7 m7 M$ ~/ J5 m& C2 T存器。执行这两步就可以将 LED2 点亮。
]0 A: `1 \5 G. L$ L点亮 LED3 和点亮 LED2 类似。# E2 u7 l% ~1 t, g k
在串口初始化之前可以通过点灯来实现调试,串口初始化之后可以通过打印字符来跟踪调
6 x" d- w* e% w' B' F: `) r; q试代码。; ^% l9 _4 S T: i' i k7 q4 n2 Y. O
3 S. G$ }0 s$ y# f4 M4 z2 r% w4 M* D# A, x
( u9 o+ u4 K: j' L% V5 | |
|