Bootloader
Bootloader 以其本身的含義來講就是下載和啟動系統,它類似于 PC 中的 BIOS,大部
分芯片廠商所提供的嵌入式系統都提供有這樣的程式,而且都比較成熟,大可不必自行撰寫,
為研究其作業原理,清掃上個章節裸機程式中的知識盲點,本章節將通過vivi單獨介紹Bootloader的技術細節,vivi由三星提供,韓國 mizi 公司原創,開放源代碼,必須使用 arm-linux-gcc 進行編譯,主要適用于三星 S3C24xx 系列 ARM 芯片,用以啟動 Linux 系統,支持串口下載和網路檔案系統啟動等常用簡易功能,
vivi編譯原始碼
vivi需要在linux環境下編譯,本文給出的viv原始碼交叉編譯器版本為arm-linux-gcc-2.95.3,從官網下載gcc,解壓到/usr/local/arm/2.95.3目錄,下載vivi-20090630.tar.gz,解壓到合適目錄,cd進入vivi目錄,輸入make命令進行編譯,編譯完成后生成vivi二進制檔案,使用jlink或者其他BootLoader將其燒錄到nand flash中,
vivi原始碼決議
vivi原始碼目錄層次結構如下:

|
arch目錄包含了芯片啟動初始化相關代碼,drivers目錄為外設相關的驅動代碼,包括FLASH、以太網、串口,init目錄包含了main主程式和版本資訊相關代碼,其他目錄包含的工具相關的輔助代碼 |
首先決議‘vivi/arch/s3c2440/head.S’這個匯編檔案,該檔案是芯片上電后最開始執行的代碼,地址為0x00000000,從下一章節“Nand Flash驅動”章節可知,上電后,硬體會自動將nand flash中前4K代碼復制到RAM中運行,映射的RAM起始地址為0x00000000,此處的head.S即對應前4K代碼,
1 #include "config.h"
2 #include "linkage.h"
3 #include "machine.h"
4 #define CONFIG_DEBUG_LL
5 #define CONFIG_SERIAL_UART0 1
6 ENTRY(_start)
7 ENTRY(ResetEntryPoint)
8 @ 0x00: Reset
9 b Reset
10
11 UndefEntryPoint:
12 b HandleUndef
13
14 SWIEntryPoint:
15 b HandleSWI
16
17 PrefetchAbortEnteryPoint:
18 b HandlePrefetchAbort
19
20 DataAbortEntryPoint:
21 b HandleDataAbort
22
23 NotUsedEntryPoint:
24 b HandleNotUsed
25
26 IRQEntryPoint:
27 b HandleIRQ
28
29 FIQEntryPoint:
30 b HandleFIQ
31
32 @ 0x20: magic number so we can verify that we only put
33 .long 0
34 @ 0x24:
35 .long 0
36 @ 0x28: where this vivi was linked, so we can put it in memory in the right place
37 .long _start
38 @ 0x2C: this contains the platform, cpu and machine id
39 .long ARCHITECTURE_MAGIC
40 @ 0x30: vivi capabilities
41 .long 0
42 #ifdef CONFIG_PM
43 @ 0x34:
44 b SleepRamProc
45 #endif
46 #ifdef CONFIG_TEST
47 @ 0x38:
48 @ b hmi
49 #endif
50 Reset:
51 @ disable watch dog timer
52 mov r1, #0x53000000
53 mov r2, #0x0
54 str r2, [r1]
55 @ disable all interrupts
56 mov r1, #INT_CTL_BASE
57 mov r2, #0xffffffff
58 str r2, [r1, #oINTMSK]
59 ldr r2, =0x7ff
60 str r2, [r1, #oINTSUBMSK]
61 @ initialise system clocks
62 mov r1, #CLK_CTL_BASE
63 mvn r2, #0xff000000
64 str r2, [r1, #oLOCKTIME]
65
66 mov r1, #CLK_CTL_BASE
67 ldr r2, clkdivn_value
68 str r2, [r1, #oCLKDIVN]
69
70 mrc p15, 0, r1, c1, c0, 0 @ read ctrl register
71 orr r1, r1, #0xc0000000 @ Asynchronous
72 mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
73
74 mov r1, #CLK_CTL_BASE
75 @ldr r2, mpll_value @ clock default
76 ldr r2, =0x5C011 @mpll_value_USER @ clock user set @0x7f021
77 str r2, [r1, #oMPLLCON]
78 mov r2, #0x05
79 str r2, [r1, #oCLKDIVN]
80 bl memsetup
81
82 #ifdef CONFIG_PM
83 @ Check if this is a wake-up from sleep
84 ldr r1, PMST_ADDR
85 ldr r0, [r1]
86 tst r0, #(PMST_SMR)
87 bne WakeupStart
88 #endif
89
90 @ All LED on
91 mov r1, #GPIO_CTL_BASE
92 add r1, r1, #oGPIO_B
93 ldr r2,=0x155555
94 str r2, [r1, #oGPIO_CON]
95 mov r2, #0xff
96 str r2, [r1, #oGPIO_UP]
97 mov r2, #0xAA
98 str r2, [r1, #oGPIO_DAT]
99
100 mov r0, #0x1
101 bl ShowLedVal
102 mov r0, #120
103 bl Delay_ms
104 mov r0, #0x2
105 bl ShowLedVal
106 mov r0, #120
107 bl Delay_ms
108 mov r0, #0x4
109 bl ShowLedVal
110 mov r0, #120
111 bl Delay_ms
112 mov r0, #0x8
113 bl ShowLedVal
114 mov r0, #120
115 bl Delay_ms
116 mov r0, #0x0
117 bl ShowLedVal
118
119 #ifdef CONFIG_S3C2440_SMDK
120 mov r1, #GPIO_CTL_BASE
121 add r1, r1, #oGPIO_H
122 ldr r2, =0x00faaa
123 str r2, [r1, #oGPIO_CON]
124 ldr r2, =0x7ff
125 str r2, [r1, #oGPIO_UP]
126 #endif
127 bl InitUART
128
129 mov r1, #UART0_CTL_BASE @old is SerBase
130 mov r0, #'\r'
131 bl PrintChar
132 mov r0, #'\n'
133 bl PrintChar
134 mov r0, #'1'
135 bl PrintChar
136 mov r0, #'@'
137 bl PrintChar
138 mov r0, pc
139 bl PrintHexWord
140
141 mov r0, #'B'
142 bl PrintChar
143 mov r0, #':'
144 bl PrintChar
145 ldr r0, =on_the_ram
146 bl PrintHexWord
147
148 mov r0, #'@'
149 bl PrintChar
150 bl copy_myself
151
152 mov r1, #GPIO_CTL_BASE
153 add r1, r1, #oGPIO_F
154 mov r2, #0x00
155 str r2, [r1, #oGPIO_DAT]
156
157 @ jump to ram
158 ldr r1, =on_the_ram
159 add pc, r1, #0
160 nop
161 nop
167 1: b 1b @ infinite loop
168
169 on_the_ram:
170 @ Print current Program Counter
171 mov r1, #UART0_CTL_BASE
172 mov r0, #'\r'
173 bl PrintChar
174 mov r0, #'\n'
175 bl PrintChar
176 mov r0, #'2'
177 bl PrintChar
178 mov r0, #'@'
179 bl PrintChar
180 mov r0, pc
181 bl PrintHexWord
182
183 mov r1, #UART0_CTL_BASE
184 ldr r0, STR_STACK
182 bl PrintWord
183 ldr r0, DW_STACK_START
184 bl PrintHexWord
185
186 ldr sp, DW_STACK_START @ setup stack pointer
187 mov fp, #0 @ no previous frame, so fp=0
188 mov a2, #0 @ set argv to NULL
189
190 bl main @ call main
191
192 mov pc, #FLASH_BASE @ otherwise, reboot
193
194 copy_myself:
195 mov r10, lr
196 @ get read to call C functions (for nand_read())
197 ldr sp, DW_STACK_START @ setup stack pointer
198 mov fp, #0 @ no previous frame, so fp=0
199
200 mov r1, #GPIO_CTL_BASE
201 add r1, r1, #oGPIO_F
202 mov r2, #0xe0
203 str r2, [r1, #oGPIO_DAT]
204
205 @ copy vivi to RAM
206 ldr r0, =VIVI_RAM_BASE
207 mov r1, #0x0
208 mov r2, #0x20000
209
210 bl nand_read_ll
211
212 ldr r1, =VIVI_RAM_BASE
213 ldr r0, [r1, #0x0]
214 bl PrintHexWord
215 ldr r0, [r1, #0x4]
216 bl PrintHexWord
217 ldr r0, [r1, #0x8]
218 bl PrintHexWord
219 ldr r0, [r1, #0xC]
220 bl PrintHexWord
221
222 mov r1, #GPIO_CTL_BASE
223 add r1, r1, #oGPIO_F
224 mov r2, #0xb0
225 str r2, [r1, #oGPIO_DAT]
226 bl PrintHexWord
227 tst r0, #0x0
228 beq ok_nand_read
229 bad_nand_read:
230 ldr r0, STR_FAIL
231 ldr r1, SerBase
232 bl PrintWord
233 1: b 1b @ infinite loop
234
235 ok_nand_read:
236 ldr r0, STR_OK
237 ldr r1, SerBase
238 bl PrintWord
239 mov r0, #'_'
240 bl PrintChar
241 mov r0, #'c'
242 bl PrintChar
243 mov r0, #'p'
244 bl PrintChar
245 mov r0, #'\r'
246 bl PrintChar
247 mov r0, #'\n'
248 bl PrintChar
249
250 @ verify
251 mov r0, #0
252 ldr r1, =0x33f00000
253 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
254 go_next:
255 ldr r3, [r0], #4
256 ldr r4, [r1], #4
257 teq r3, r4
258 bne notmatch
259 subs r2, r2, #4
260 beq done_nand_read
261 bne go_next
262 notmatch:
263 sub r0, r0, #4
264 ldr r1, SerBase
265 bl PrintHexWord
266 ldr r0, STR_FAIL
267 ldr r1, SerBase
268 bl PrintWord
269 mov r0, r3
270 bl PrintHexWord
271 mov r0, r4
272 bl PrintHexWord
273 ldr r1, =0x33f00004
274 ldr r4, [r1], #4
275 mov r0, r4
276 bl PrintHexWord
277
278 1: b 1b
279 done_nand_read:
280 ldr r0, STR_OK
281 ldr r1, SerBase
282 bl PrintWord
283
284 mov r1, #GPIO_CTL_BASE
285 add r1, r1, #oGPIO_F
286 mov r2, #0x70
287 str r2, [r1, #oGPIO_DAT]
288
289 mov pc, r10
Line9 b Reset即對應0x00000000,此處是一個跳轉指令,跳轉到Reset標識處,
Line52~54禁用看門狗,Line56~60禁用所有中斷,
Line62~79用于設定時鐘,
Line80 初始化記憶體,具體設定的值此處忽略,
Line82~88判斷是否從睡眠模式中喚醒
Line91~98點亮LED燈
Line100~117依次點亮每個LED燈,ShowLedVal和Delay_ms可在串口啟用前除錯代碼,將需要Debug的值,輸入到ShowLedVal中,配合Delay_ms觀測LED點燈情況,
Line120~127設定串口,后續可使用串口列印log方式除錯bootloader程式,
Line129~139通過串口列印出了PC暫存器的值,通過觀察可知,值為0x00000140,
Line145~146列印出了on_the_ram標識處的地址,即0x33F00188,該地址也可以通過map檔案找到,
Line150 跳轉到Line194
Line195保存回傳地址
Line197~198準備C語言呼叫的環境
Line200~203設定GPIOF埠
Line206~210向C語言函式nand_read_ll傳入3個引數0x33F00000(0x30000000+0x04000000-0x00100000),0,0x20000,用于從flash讀取資料到RAM中,詳細流程,參看下一章“Nand Flash驅動”
Line212~220串口輸出copy進RAM前16個位元組的資料,即“EA00000B,EA000111,EA000116,EA00011B”
Line227~228用于檢測nand_read_ll的回傳值是否為0,是則串口輸出“OK”“_cp”字樣,
Line251~261比較RAM中0~4K-1和剛copy的資料是否一致,是則輸出“OK”字樣,
Line289代碼段copy_myself回傳,跳轉到Line152,
Line158~159 跳轉到on_the_ram,此處跳轉為直接地址跳轉,跳轉到地址0x33F00188,
Line171~181串口依次輸出’\r\n2@’以及PC暫存器地址,此處為0x33F001B4,從這里看到,程式已經跳轉到了我們copy的ram地址區域中了,
Line183~184(代碼處數字有誤,此處指第一個183到第二個184處),串口輸出“STKP”字樣,以及堆疊指標,0x33DEFFFC
Line186~190初始化C語言堆疊指標、fp指標、main函式引數,最后跳轉到main函式,
至此程式已進入main主函式,
串口輸出資訊如下:
1@00000140
B:33F00188
@EA00000B
EA000111
EA000116
EA00011B
00000250
OK
_cp
OK
2@33F001B4
STKP
33DEFFFC
VIVI version 0.1.4 (root@summertree-desktop) (gcc version 2.95.3 20010315 (release)) #0.1.4 Thu Sep 23 21:18:06 CST 2021
MMU table base address = 0x33DFC000
Succeed memory mapping.
NAND device: Maf Id:236, dev Id:218
NAND device: Manufacture ID: 0xec, Chip ID: 0xda (Samsung K9F2G08U0B)
Found default vivi parameters
Press Return to start the LINUX now, any other key for vivi
type "help" for help.
FriendlyARM>
FriendlyARM> help
Usage:
flash [{cmds}] -- Manage Flash memory
cpu [{cmds}] -- Manage cpu clocks
bon [{cmds}] -- Manage the bon file system
reset -- Reset the system
param [eval|show|save [-n]|reset] -- set/get parameter
part [add|del|show|reset] -- Manage MTD partitions
mem [{cmds}] -- Manage Memory
load [{cmds}] -- Load a file to RAM/Flash
go <addr> <a0> <a1> <a2> <a3> -- jump to <addr>
dump <addr> <length> -- Display (hex dump) a range of memory.
call <addr> <a0> <a1> <a2> <a3> -- jump_with_return to <addr>
boot [{cmds}] -- Booting linux kernel
help [{cmds}] -- Help about help?
FriendlyARM>
FriendlyARM>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302867.html
標籤:其他
上一篇:ESP32-IDF開發實體-基于TWAI的實時串行通信
下一篇:基于STM32的超聲波測距
