S3C2440驱动开发(七)
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代码加载到内部的SRAM缓冲区中运行,映射的起始地址为0x00000000。此处的head.S即对应前4K代码。因Flash内部的SRAM缓冲区只有4K,无法存放bootloader全部功能的代码,故该缓存区代码主要功能是将Nand Flash中存储的vivi代码全部复制到SDRAM中,让其具备足够的内存空间运行。
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。根据字面含义,程序已经跳转到了SDRAM空间运行。
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>
S3C2440驱动开发(七)相关推荐
- S3C2440驱动开发(四)
裸机程序开发之蜂鸣器程序 程序实现了控制蜂鸣器输入pwm频率和开关功能.输入数字1开启蜂鸣器,输入数字0关闭蜂鸣器,输入字符+增加蜂鸣器输入pwm频率,输入字符-减少蜂鸣器输入pwm频率.代码如下: ...
- S3C2440驱动开发(二)
裸机程序开发之LED程序 以下代码段实现了一个简单的LED显示程序,程序比较简单,共53行. 1 #include "def.h" 2 #include & ...
- windows xp 驱动开发(七)WDK源码 UsbSamp例子的编译及使用
转载请标明是引用于 http://blog.csdn.net/chenyujing1234 参考文章: http://msdn.microsoft.com/zh-cn/library/windows/ ...
- Windows驱动开发学习笔记(七)—— 多核同步内核重载
Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...
- Linux USB 驱动开发实例(七)—— 基于USB 总线的无线网卡浅析
回顾一下USB的相关知识 USB(Universal Serial Bus)总线又叫通用串行外部总线, 它是20世纪90年代发展起来的.USB接口现在得到了广泛的应用和普及,现在的PC机中都带有大量的 ...
- linux 内核驱动开发
一.为什么要学习内核? 有些人要学习内核,而有些人则可以不学习它.你如果以后要从事系统研发或驱动开发的话,就要学习内核. 刚刚接触内核,主要学习内核的接口函数.不要深入的去读内核,因为你读也读不懂,内 ...
- MF Porting之USB驱动开发
花费了近三个礼拜的时间,终于完成了TI开发板的USB驱动开发,现在回头想一想,其实也没有什么,具体硬件方面的通信由DM355实现了,软件层面的数据交互由MF Porting实现了,所做的也就是熟悉了解 ...
- Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析
关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸机开发 -- IIC总线 ,下面回顾下 IIC 基础概念 一.IIC 基础概念 IIC(Inter-Integrated Ci ...
- Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言
Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...
最新文章
- java 环境配置 mac_Java:配置环境(Mac)——JDK
- Angular 如何自定义 pipe 管道以及参数传递问题
- java学习(43):值参数传递
- python包里面的dll是什么_使用R的程序包提示我们无法使用怎么回事?因为计算机丢失jvm.dll...
- 推荐几个好评率超高的公众号,有远见的程序员都关注了!
- Java:集合系列目录(Category)
- 792. 高精度减法
- vscode中vue-cli项目es-lint的配置
- openstack 报错
- 对2016年android就业的一些看法
- Python多进程实现原理
- 计算机专业英语词汇缩写,计算机专业英语词汇中英文对照其他缩写,外语网
- 使用深度森林(Deep Forest)进行分类-Python
- 利用mongodb实现分布式WEB图片存储
- 成都VS上海,先锋设计机构与未来建筑的“双城battle”
- 网站实现记住我(自动登录)的方法总结
- String类练习:我国的居民身份证号码,由由十七位数字本体码和一位数字校验码组成。
- Web3对于我们普通人意味着什么?
- Python作业题整理
- GILT市场方兴未艾