02.uboot分析之源码第一阶段

网友投稿 645 2022-05-29

之前写的硬件相关的裸机源码的流程和uboot差不多。之前的实验主要完成以下操作:

(1)初始化:关看门狗,初始化时钟,初始化sdram。

(2)程序很大时,把程序从nandflash拷贝到sdaram。

(3)调用C函数必须设置栈sp

.globl _start /*跳转到reset*/ _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq .balignl 16,0xdeadbeef reset: /* * set the cpu to SVC32 mode 管理模式 */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 /* turn off the watchdog 关看门狗*/ #if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #elif defined(CONFIG_S3C2410) # define pWTCON 0x53000000 # define INTMOD 0X4A000004 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ #endif #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default 关中断 */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif /* * we do sys-critical inits only at reboot, * not when booting from ram! * CPU初始化 */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT /*读地址指令 如果是上电后运行,代码是从nandflash自动拷贝到sdram,则r0为0.如果是通过下载器下载到sdram,则r0为他的链接地址0x33f8000*/ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ /*不相等则证明sdram还没有被初始化。*/ cmp r0, r1 /* don't reloc during debug */ blne cpu_init_crit #endif #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: /* * flush v4 I/D caches 关flash */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches 清mmu */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15, 0, r0, c1, c0, 0 /* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */ mov ip, lr /*初始化存储控制器,初始化之后内存才可以使用*/ bl lowlevel_init mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */ /* Set up the stack 设置栈 */ /*栈会一直减下去,指向不同的位置*/ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot r0=0x33f80000 */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area r0 =r0-CFG_MALLOC_LEN */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo r0 =r0-CFG_GBL_DATA_SIZE */ #ifdef CONFIG_USE_IRQ /*r0=r0-(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)*/ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* leave 3 words for abort-stack r0=r0-12 */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT /*调用初始化时钟的C函数*/ bl clock_init #endif /*把代码从flash读到sdram链接地址*/ relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq clear_bss ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ /*清楚BSS段,初始化为0的静态变量或者全局变量*/ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ ldr pc, _start_armboot /*调用c函数start_armboot*/ _start_armboot: .word start_armboot

1

2

3

4

5

6

7

02.uboot分析之源码第一阶段

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

小结:设置管理模式,关看门狗,屏蔽中断,sdram的初始化,设置栈,设置时钟,代码重定位,清除bss段(之前的都称为uboot的第一阶段),调用C函数start_armboot(第二阶段开始)。

BSS段清零的原因是因为这个段是BSS

要说为什么要有BSS的话,历史就比较久远了。 BSS段我所知道的起源是Unix最初的时候(当然,不排除可能有更早的情况)。变量分两种:局部变量、全局变量。

根据C语法的规定,局部变量不设置初始值的时候,其初始值是不确定的,局部变量(不含静态局部变量)的存储位置位于栈上,具体位置不固定。

全局变量(和静态局部变量)有专门数据段存储,初始值是0,具体位置是固定的。

其实说到底,就两种,一种是位置固定(数据段里),一种是位置不固定的(栈上)。

要知道,早期的计算机存储设备是很贵的,而很多时候,数据段里的全局变量都是0(或者没有初始值),那么存储这么多的0到目标文件里其实是没有必要的。所以为了节约空间,在生成目标文件的时候,就把没有初始值(实际就是0)的数据段里的变量都放到BSS段里,这样目标文件就不需要那么大的体积里(节约磁盘空间)。只有当目标文件被载入的时候,加载器负责把BSS段清零(一个循环就可以搞定)。 之后,这个规则慢慢的成为一个标准配置,大多数编译器也就都支持了BSS段。

然后解释几个问题: Q:为什么局部变量初始值不是0? A:局部变量初始值也可以是零(在某些语言中就是),但这实际上需要消耗硬件指令去完成,有些时候这种清零的动作意义不大,对于编译器来说也是一种负担,每次调用函数都要消耗指令去清零,负担太大。要知道全局变量在内存中只有一份,局部变量(非静态)可以是多份的,前者一次清零就可以了,后者多次清零,负担太大。

Q:如果BSS不清零可不可以? A:可以,如果编译器规定BSS段不清零,也是可以的,但这样的话C语言语法就要改了:未初始化的全局变量和静态局部变量,其值是未知的。甚至其它语言也要跟着改语法。

所以,BSS段清零的原因是因为这个段是BSS 现在存储介质这么便宜了,是不是BSS已经没有必要了?当然不是了,介质便宜仅限于PC和数码产品这一块,嵌入式行业永远都不存在存储介质没有限制的情况。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:PHPstorm相关设置以及快捷键
下一篇:Linux开发_Linux下进程编程
相关文章