Linux系统移植
目 录
第一部分 前言...................................................................................................................................8
1 硬件环境.....................................................................................................................................8
1.1主机硬件环境.......................................................................................................................8
1.2 目标板硬件环境...................................................................................................................8
1.3工具介绍...............................................................................................................................8
2软件环境......................................................................................................................................8
2.1主机软件环境.......................................................................................................................8
2.1.1 Windows 操作系统.......................................................................................................8
2.1.2 Linux操作系统 .......................................................................................................8
2.1.3 目标板最后运行的环境...............................................................................................9
2.2 Linux下工作用户及环境....................................................................................................9
2.2.1 交叉工具的安装...........................................................................................................9
2.2.2 uboot
移植工作目录....................................................................................................9
2.2.3 内核及应用程序移植工作...........................................................................................9
2.3 配置系统服务.....................................................................................................................10
2.3.1 tftp服务器的配置.......................................................................................................10
2.4 工具使用.............................................................................................................................12
2.4.1 minicom的使用..........................................................................................................12
3 作者介绍...................................................................................................................................13
3.1 策划, 组织, 指导, 发布者...................................................................................................13
3.2 ADS bootloader部分..........................................................................................................13
3.3 交叉工具部分.....................................................................................................................13
3.4 uboot部分...........................................................................................................................13
3.5 内核部分.............................................................................................................................13
3.6 应用程序部分.....................................................................................................................13
3.7 网卡驱动部分.....................................................................................................................13
3.8 Nand Flash 驱动部分.........................................................................................................13
第二部分 系统启动bootloader的编写(ADS).................................................................................14
1 工具介绍...................................................................................................................................14
1.1 ADS 命令行命令介绍........................................................................................................14
1.1.1 armasm........................................................................................................................14
1.1.2 armcc, armcpp.............................................................................................................14
1.1.3 armlink........................................................................................................................14
2 基本原理...................................................................................................................................15
2.1 可执行文件组成及内存映射.............................................................................................15
2.1.1 可执行文件的组成.....................................................................................................15
2.1.2 装载过程.....................................................................................................................16
2.1.3 启动过程的汇编部分.................................................................................................17
2.1.4 启动过程的C部分.....................................................................................................17
3 AXD的使用以及源代码说明...................................................................................................18
3.1 源代码说明.........................................................................................................................18
3.1.1 汇编源代码说明.........................................................................................................18
3.1.2 C语言源代码说明......................................................................................................23
3.1.3 源代码下载.................................................................................................................23
3.2 AXD的使用.......................................................................................................................23
3.2.1 配置仿真器.................................................................................................................23
3.2.2 启动AXD 配置开发板...............................................................................................23
第三部分 GNU交叉工具链.............................................................................................................25
1 设置环境变量,准备源码及相关补丁...................................................................................25
1.1 设置环境变量.....................................................................................................................25
1. 2 准备源码包............................................................................................................................25
1.2.1 binuils.........................................................................................................................25
1.2.2 gcc..............................................................................................................................25
1.2.3 glibc............................................................................................................................25
1.2.4 linux kernel..................................................................................................................26
1.3 准备补丁.............................................................................................................................26
1.3.1 ioperm.c.diff................................................................................................................26
1.3.2 flow.c.diff....................................................................................................................26
1.3.3 tlinux.
diff....................................................................................................................26
1.4 编译 GNU binutils...........................................................................................................26
1.5 准备内核头文件.................................................................................................................26
1.5.1 使用当前平台的gcc编译内核头文件......................................................................26
1.5.2 复制内核头文件.........................................................................................................27
1.6 译编glibc头文件.............................................................................................................27
1.7 编译gcc第一阶段............................................................................................................27
1.8 编译完整的glibc..............................................................................................................27
1.9 编译完整的gcc.................................................................................................................28
2 GNU交叉工具链的下载...........................................................................................................28
2.1 ARM官方网站...................................................................................................................28
2.2 本文档提供的下载.............................................................................................................28
3 GNU交叉工具链的介绍与使用...............................................................................................29
3.1 常用工具介绍.....................................................................................................................29
3.2.1 armlinuxgcc
的使用.................................................................................................29
3.2.2 armlinuxar
和 armlinuxranlib
的使用..................................................................30
3.2.3 armlinuxobjdump
的使用.........................................................................................30
3.2.4 armlinuxreadelf
的使用............................................................................................31
3.2.6 armlinuxcopydump
的使用......................................................................................32
4 ARM GNU常用汇编语言介绍.................................................................................................32
4.1 ARM GNU常用汇编伪指令介绍.....................................................................................32
4.2 ARM GNU专有符号.........................................................................................................33
4.3 操作码................................................................................................................................33
5 可执行生成说明........................................................................................................................33
5.1 lds文件说明.......................................................................................................................33
5.1.1 主要符号说明.............................................................................................................33
5.1.2 段定义说明.................................................................................................................34
第四部分 uboot
的移植...................................................................................................................35
1 uboot
的介绍及系统结构.........................................................................................................35
1.1 uboot
介绍.........................................................................................................................35
1.2 获取uboot.........................................................................................................................
35
1.3 uboot
体系结构.................................................................................................................35
1.3.1 uboot
目录结构..........................................................................................................35
2 uboot的启动过程及工作原理...................................................................................................36
2.1 启动模式介绍.....................................................................................................................36
2.2 阶段1介绍.........................................................................................................................36
2.2.1 定义入口.....................................................................................................................36
2.2.2 设置异常向量.............................................................................................................37
2.2.3 设置CPU的模式为SVC模式..................................................................................37
2.2.4 关闭看门狗.................................................................................................................37
2.2.5 禁掉所有中断.............................................................................................................37
2.2.6 设置以CPU的频率....................................................................................................37
2.2.7 设置CP15...................................................................................................................37
2.2.8 配置内存区控制寄存器.............................................................................................38
2.2.9 安装UBOOT
使的栈空间........................................................................................38
2.2.10 BSS段清0................................................................................................................38
2.2.11 搬移Nand Flash代码...............................................................................................39
2.2.12 进入C代码部分.......................................................................................................39
2.3 阶段2的C语言代码部分 .............................................................................................39
2.3.1调用一系列的初始化函数.........................................................................................39
2.3.2 初始化网络设备.........................................................................................................41
2.3.3 进入主UBOOT命令行..............................................................................................41
2.4 代码搬运.............................................................................................................................41
3 uboot的移植过程.......................................................................................................................42
3.1 环境....................................................................................................................................42
3.2 步骤....................................................................................................................................42
3.2.1 修改Makefile..............................................................................................................42
3.2.2 在board子目录中建立crane2410.............................................................................42
3.2.3 在include/configs/中建立配置头文件......................................................................42
3.2.4 指定交叉编译工具的路径.........................................................................................42
3.2.5 测试编译能否成功.....................................................................................................42
3.2.6 修改lowlevel_init.S文件...........................................................................................43
3.2.9 UBOOT的Nand Flash移植......................................................................................45
3.2.8重新编译uboot..........................................................................................................
45
3.2.9 把uboot
烧入flash....................................................................................................45
4 UBOOT
命令的使用................................................................................................................46
4.1 UBOOT
命令的介绍.........................................................................................................46
4.1.1 获得帮助信息.............................................................................................................46
4.2 常用命令使用说明.............................................................................................................47
4.2.1 askenv(F).....................................................................................................................47
4.2.2 autoscr........................................................................................................................47
4.2.3 base ...........................................................................................................................47
4.2.4 bdinfo..........................................................................................................................47
4.2.5 bootp...........................................................................................................................47
4.2.8 tftp(tftpboot)................................................................................................................48
4.2.9 bootm..........................................................................................................................48
4.2.10 go..............................................................................................................................48
4.2.11 cmp .........................................................................................................................48
4.2.12 coninfo .....................................................................................................................48
4.2.13 cp..............................................................................................................................48
4.2.14 date...........................................................................................................................49
4.2.15 erase(F)......................................................................................................................49
4.2.16 flinfo(F).....................................................................................................................49
4.2.17 iminfo........................................................................................................................49
4.2.18 loadb..........................................................................................................................49
4.2.19 md.............................................................................................................................49
4.2.20 mm ............................................................................................................................50
4.2.21 mtest .......................................................................................................................50
4.2.22 mw.............................................................................................................................50
4.2.23 nm ...........................................................................................................................50
4.2.24 printenv......................................................................................................................50
4.2.25 ping ..........................................................................................................................51
4.2.26 reset..........................................................................................................................51
4.2.27 run ...........................................................................................................................51
4.2.28 saveenv(F).................................................................................................................51
4.2.29 setenv.........................................................................................................................51
4.2.30 sleep..........................................................................................................................51
4.2.31 version.......................................................................................................................51
4.2.32 nand info....................................................................................................................51
4.2.33 nand device <n>........................................................................................................51
4.2.34 nand bad....................................................................................................................51
4.2.35 nand read...................................................................................................................52
4.2.36 nand erease................................................................................................................52
4.2.37 nand write..................................................................................................................52
4.3 命令简写说明.....................................................................................................................52
4.4 把文件写入NandFlash.......................................................................................................53
4.5 下载提供.............................................................................................................................53
5 参考资料...................................................................................................................................53
第五部分 linux 2.6内核的移植.......................................................................................................53
1 内核移植过程............................................................................................................................53
1.1 下载linux内核...................................................................................................................53
1.2 修改Makefile.....................................................................................................................53
1.3 设置flash分区...................................................................................................................54
1.3.1指明分区信息.............................................................................................................54
1.3.2 指定启动时初始化.....................................................................................................56
1.3.3 禁止Flash ECC校验 ................................................................................................56
1.4 配置内核.............................................................................................................................56
1.4.1 支持启动时挂载devfs................................................................................................56
1.4.2配置内核产生.config文件.........................................................................................57
1.4.3编译内核.....................................................................................................................58
1.4.4 下载zImage到开发板................................................................................................58
2 创建uImage...............................................................................................................................61
2.1 相关技术背景介绍.............................................................................................................61
2.2 在内核中创建uImage的方法...........................................................................................61
2.2.1 获取mkimage工具.....................................................................................................61
2.2.2 修改内核的Makefile文件.........................................................................................61
3追加实验记录.............................................................................................................................62
3.1移植linux2.6.15.7..............................................................................................................
62
3.2移植linux2.6.16.21............................................................................................................
62
3.3 移植linux2.6.17................................................................................................................
62
4 参考资料...................................................................................................................................62
第六部分 应用程序的移植..............................................................................................................63
1构造目标板的根目录及文件系统.............................................................................................63
1.1 建立一个目标板的空根目录.............................................................................................63
1.2 在my_rootfs中建立Linux目录树...................................................................................63
1.3 创建linuxrc文件................................................................................................................63
2 移植Busybox............................................................................................................................64
2.1 下载busybox......................................................................................................................64
2.3 编译并安装Busybox..........................................................................................................65
3 移植TinyLogin..........................................................................................................................66
3.1 下载....................................................................................................................................66
3.2 修改tinyLogin的Makefile................................................................................................66
3.3 编译并安装.........................................................................................................................66
4 相关配置文件的创建................................................................................................................66
4.1 创建帐号及密码文件.........................................................................................................66
4.2 创建profile文件................................................................................................................67
4.4 创建fstab文件...................................................................................................................67
4.5 创建inetd.conf配置文件...................................................................................................67
5 移植inetd...................................................................................................................................67
5.1 inetd的选择及获取............................................................................................................67
5.1.1 获取inetd....................................................................................................................67
5.2 编译inetd...........................................................................................................................67
5.2.1 修改configure文件....................................................................................................67
5.2.2 编译 ...........................................................................................................................68
5.3 配置inetd...........................................................................................................................68
5.3.1 拷贝inetd到根文件系统的usr/sbin目录中.............................................................68
6 移植thttpd Web服务器.............................................................................................................69
6.1 下载....................................................................................................................................69
6.2 编译thttpd..........................................................................................................................69
6.3 配置....................................................................................................................................69
6.3.1 拷贝thttpd二进制可执行文件到根文件系统/usr/sbin/目录中...............................69
6.3.2 修改thttpd配置文件..................................................................................................69
6.3.3 转移到根文件系统目录,创建相应的文件.............................................................69
7 建立根目录文件系统包............................................................................................................70
7.1 建立CRAMFS包...............................................................................................................70
7.1.1 下载cramfs工具........................................................................................................70
7.1.2 制作cramfs包............................................................................................................70
7.1.3 写cramfs包到Nand Flash.........................................................................................70
8 参考资料...................................................................................................................................70
第七部分 Nand flash驱动的编写与移植........................................................................................71
1 Nand flash工作原理..................................................................................................................71
1.1 Nand flash芯片工作原理..................................................................................................71
1.1.1 芯片内部存储布局及存储操作特点.........................................................................71
1.1.2 重要芯片引脚功能.....................................................................................................71
1.1.3 寻址方式.....................................................................................................................71
1.1.4 Nand flash主要内设命令详细介绍...........................................................................72
1.2 Nand Flash 控制器工作原理.............................................................................................72
1.2.1 Nand Flash控制器特性..............................................................................................72
1.2.2 Nand Flash控制器工作原理......................................................................................72
1.3 Nand flash 控制器中特殊功能寄存器详细介绍 ............................................................72
1.4 Nand Flash 控制器中的硬件ECC介绍............................................................................73
1.4.1 ECC产生方法............................................................................................................73
1.4.2 ECC生成器工作过程................................................................................................74
1.4.3 ECC的运用................................................................................................................74
2 在ADS下flash烧写程序.........................................................................................................74
2.1 ADS下flash烧写程序原理及结构...................................................................................74
2.2 第三层实现说明.................................................................................................................74
2.1.1 特殊功能寄存器定义.................................................................................................74
2.1.2 操作的函数实现.........................................................................................................74
2.3 第二层实现说明.................................................................................................................75
2.3.1 Nand Flash 初始化......................................................................................................75
2.3.3 获取Nand flash ID......................................................................................................75
2.3.4 Nand flash写入...........................................................................................................76
2.3.5 Nand flash读取...........................................................................................................77
2.3.6 Nand flash标记坏块...................................................................................................78
2.3.7 Nand Flash检查坏块..................................................................................................79
2.3.8 擦除指定块中数据.....................................................................................................79
2.4 第一层的实现....................................................................................................................80
3 在UBOOT
对Nand Flash的支持............................................................................................82
3.1 UBOOT
对从Nand Flash启动的支持.............................................................................82
3.1.1 从Nand Flash启动UBOOT
的基本原理................................................................82
3.1.2 支持Nand Flash启动代码说明.................................................................................82
3.2 UBOOT
对Nand Flash命令的支持.................................................................................84
3.2.1 主要数据结构介绍.....................................................................................................84
3.2.2 支持的命令函数说明.................................................................................................85
4 在Linux对Nand Flash的支持.................................................................................................87
4.1 Linux下Nand Flash调用关系..........................................................................................87
4.1.1 Nand Flash设备添加时数据结构包含关系..............................................................87
4.1.2 Nand Flash设备注册时数据结构包含关系..............................................................87
4.2 Linux下Nand Flash驱动主要数据结构说明..................................................................88
4.2.1 s3c2410专有数据结构...............................................................................................88
4.2.2 Linux 通用数据结构说明..........................................................................................89
4.3.1 注册driver_register....................................................................................................94
4.3.2 探测设备probe...........................................................................................................94
4.3.3 初始化Nand Flash控制器.........................................................................................94
4.3.4 移除设备.....................................................................................................................94
4.3.5 Nand Flash芯片初始化..............................................................................................94
4.3.6 读Nand Flash............................................................................................................95
4.3.7 写Nand Flash.............................................................................................................95
第八部分 Cs8900a网卡驱动的编写与移植...................................................................................95
1 Cs8900a工作原理......................................................................................................................95
2 在ADS下cs8900a的实现........................................................................................................95
2.1 在cs8900a下实现的ping 工具.........................................................................................95
3 在uboot
下cs8900a的支持......................................................................................................96
3.1 uboot
下cs8900a的驱动介绍...........................................................................................96
3.2 uboot
下cs8900a的移植说明...........................................................................................96
4 在linux下cs8900a驱动的编写与移植....................................................................................96
4.1 Linux下cs8900a的驱动说明............................................................................................96
4.2 Linux 下cs8900a的移植说明...........................................................................................96
4.2.1 为cs8900a建立编译菜单..........................................................................................96
4.2.2 修改S3C2410相关信息............................................................................................97
序
该文档的目的是总结我们在工作中的一些经验,并把它们分享给喜欢ARM和Linux的朋友, 如有错误
之处,请大家多多指点. 同样, 我们也希望更多人能把自己的工作经验和体会加入该文档,让大家共同进步.
该文档是一份交流性文档, 只供个人学习与交流,不允许公司和企业用于商业行为.
第一部分 前言
1 硬件环境
1.1主机硬件环境
开发机:Pentium-4 CPU
内存: 512MB
硬盘: 60GB
1.2 目标板硬件环境
CPU: S3C2410
SDRAM: HY57V561620
Nand flash: K9F1208U0B(64MB)
以太网芯片:CS8900A (10M/100MB)
1.3工具介绍
仿真器:Dragon-ICE
电缆:串口线,并口线
2软件环境
2.1主机软件环境
2.1.1 Windows 操作系统
ADS编译工具:ADS1.2
仿真器软件: Dragon-ICE daemon程序
2.1.2 Linux操作系统
GNU交叉编译工具:
2.95.3:
作用:编译u-boot
3.3.2, 3.4.4:
作用:编译内核和应用程序
其它工作:
tree工具:
作用:查看文件目录树
下载:从ftp://mama.indstate.edu/linux/tree/下载编译
2.1.3 目标板最后运行的环境
启动程序:
u-boot-1.1.4
内核:
linux-2.6.14.1
应用程序:
1. busybox-1.1.3
2. TinyLogin-1.4
3. Thttpd-2.25
2.2 Linux下工作用户及环境
2.2.1 交叉工具的安装
工具链的编译过程请参考第三部分.
1. 下载交叉工具
2.95.3 下载地址:ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross-
2.95.3.tar.bz2
3.3.4 下载地址:
2. 编译交叉工具
[root@localhost ~]mkdir /usr/local/arm
[root@localhost ~]cd /usr/local/arm
把cross-2.95.2.tar.bz2, cross-3.4.4.tar.gz 拷贝到/usr/local/arm目录中。解压这两个包。
[root@localhost ~]tar -xjvf cross-2.95.2.tar.bz2
[root@localhost ~]tar -xzvf cross-3.4.4.tar.gz
2.2.2 u-boot移植工作目录
1. 添加工作用户
[root@localhost ~]#useradd -G root -g root -d/home/uboot uboot
2. 建立工作目录
[uboot@localhost ~]$mkdir dev_home
[uboot@localhost ~]$cd dev_home
[uboot@localhost dev_home]$mkdir doc mybootloader uboot
.
|-- doc
|-- mybootloader
`-- uboot
3. 建立环境变量
[uboot@localhost ~]vi ~/.bashrc
export PATH=/usr/local/arm/2.95.3/bin:$PATH
2.2.3 内核及应用程序移植工作
1. 添加工作用户
[root@localhost ~]#useradd -G root -g root -d/home/arm arm
2. 建立工作目录
[arm@localhost arm]$mkdir dev_home
[arm@localhost arm]$cd dev_home
[arm@localhost arm]$mkdir bootldr btools debug doc images kernel localapps /
rootfs sysapps tmp tools
[arm@localhost arm]$tree -L 1
.
|-- bootldr
|-- btools
|-- debug
|-- doc
|-- images
|-- kernel
|-- localapps
|-- rootfs
|-- sysapps
|-- tmp
`-- tools
可以看到如上树形结构。
注:tree命令
3. 建立环境变量设置脚本
[arm@localhost arm]$vi env_sh
#!/bin/bash
PRJROOT=~/dev_home
KERNEL=$PRJROOT/kernel
ROOTFS=$PRJROOT/rootfs
LAPP=$PRJROOT/localapps
DOC=$PRJROOT/doc
TMP=$PRJROOT/tmp
export PRJROOT KERNEL LAPP ROOTFS
export PATH=/usr/local/arm/3.4.4/bin:$PATH
4. 登陆时启动环境变量
[arm@localhost arm]$vi ~/.bashrc
. ~/dev_home/env_sh
重新登陆arm用户,环境变量生效
[arm@localhost arm]$su arm
2.3 配置系统服务
2.3.1 tftp服务器的配置
如果用下面一条命令能够看到服务已经启动, 则不用安装, 否则需要按1或2点安装tftp-server服务器.
[arm@localhost arm]#netstat -a | grep tftp
udp 0 0 *:tftp *:*
1. 从RPM包安装tftp-server
从对应Linux操作系统版本的安装光盘上找到tftp-server的安装包.
下面tftp-server-0.32-4.i386.rpm包为例,把rpm包拷贝到dev_home/btools/下.
[arm@localhost arm]#cp tftp-server-0.32-4.i386.rpm /home/arm/dev_home/btools/
[arm@localhost arm]#su root
[root@localhost arm]#rpm -q tftp-server
如果没有安装tftp-server,就要用下面命令安装,否则,直接进入第2步配置服务.
[root@localhost arm]#cd /home/arm/dev_home/btools/
[root@localhost btools]#rpm -ivh tftp-server-0.32-4.i386.rpm
建立tftp的主工作目录
[root@localhost btools]#mkdir /tftpboot
2. 修改配置文件并启动服务
备份配置文件
[root@localhost btools]#if [ -f /etc/xinetd.d/tftp ]
> then
> cp /etc/xinetd.d/tftp /etc/xinetd.d/tftp.old
> fi
修改配置文件
[root@localhost btools]#vi /etc/xinetd.d/tftp
service tftp
{
disable = no
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftpboot
per_source = 11
cps = 100 2
flags = IPv4
}
检查tftp服务是否打开
[root@localhost btools]#chkconfig --list
如果tftp的服务没有打开,则用下面命令打开tftp服务开关
[root@localhost btools]#chkconfig tftp on
重启服务
#/etc/init.d/xinetd restart
#netstat -a | grep tftp
udp 0 0 *:tftp *:*
2.3.2 NFS服务器的配置
1. 安装NFS服务器
[root@localhost btools]#rpm -q nfs-utils
如果没有安装,从对应Linux操作系统版本的安装光盘上找到nfs-utils的安装包.Fedora 5中的安装包
名称为nfs-utils-1.0.8.rc2-4.FC5.2.i386.rpm。下面以该安装包为例说明:
[root@localhost btools]#rpm -ivh nfs-utils-1.0.8.rc2-4.FC5.2.i386.rpm
2. 配置NFS服务器
[root@localhost btools]#vi /etc/exports
#加入要允许被另外计算机mount的目录:
#/home/arm/dev_home/tmp 为被另外计算机mount的目录
#192.168.1.134 允许另外计算机mount的IP
#rw,sync,no_root_squash表示访问限制,更详细说明见相关手册.
/home/arm/dev_home/tmp 192.168.1.134(rw,sync,no_root_squash)
3. 启动NFS服务器
第一启动NFS服务器时用下面命令.
[root@localhost btools]#/etc/init.d/nfs start
如果你已经启动了NFS服务器时,并且重新修改了/etc/exports文件,用如下命令使新加入的目录生效:
[root@localhost btools]#/etc/init.d/nfs reload
4. 测试NFS服务器
[root@localhost btools]#netstat -a | grep nfs
5. 显示被export出的目录列表
[root@localhost btools]#exportfs
2.4 工具使用
2.4.1 minicom的使用
1.切换到root用户.
[root@localhost btools]#su -
2. 查找有效的串设备.
[root@localhost ~]#cat /proc/devices
...
4 ttyS
...
188 ttyUSB
...
如果是普通串口设备, 设备名前缀为ttyS, 第一串口为ttyS0, 第二串口为ttyS1,依次类推.
如果是USB转串口的设备, 设备名前缀为ttyUSB, 第一串口为ttyUSB0.
3. 配置ttyUSB设备
[root@localhost ~]#minicom -s ttyUSB0
会出现一个configuration窗口,
┌──[configuration]────┐
│ Filenames and paths │
│ File transfer protocols │
│ Serial port setup │
│ Modem and dialing │
│ Screen and keyboard │
│ Save setup as ttyUSB0 │
│ Save setup as.. │
│ Exit │
│ Exit from Minicom │
└───────────────┘
选择Serial port setup配置. 会出现如下窗口:
┌────────────────────────────────────────────┐
│ A - Serial Device : /dev/ttyUSB0 │
│ B - Lockfile Location : /var/lock │
│ C - Callin Program : │
│ D - Callout Program : │
│ E - Bps/Par/Bits : 115200 8N1 │
│ F - Hardware Flow Control : No │
│ G - Software Flow Control : No │
│ │
│ Change which setting? │
└───────────────────────────────────────────┘
我的设置如上所示, 设置完成后, Change which setting?项上按回车退出当前窗口, 回到第一个窗口.按 Save
setup as ttyUSB0保存设置. 再按Exit from Minicom退出Minicom.
4. 启动minicom
[root@localhost ~]#minicom
3 作者介绍
3.1 策划, 组织, 指导, 发布者
刘勇
email: littlegenius2008@163.com
如果您有新的内容,请发到这个电子邮件,我们会把您的内容加入文档,并在作者列表中加入您的名字.
3.2 ADS bootloader部分
作者:刘勇
email: littlegenius2008@163.com
3.3 交叉工具部分
作者:孙贺
email: msunhe@gmail.com
3.4 uboot部分
作者:聂强
email: wolfwind9779@yahoo.com.cn
作者:孙贺
email: msunhe@yahoo.com.cn
3.5 内核部分
作者:聂大鹏
email:dozec@mail.csdn.net
作者:牛须乐(8900a网卡移植部分)
email:clizniu@hotmail.com
3.6 应用程序部分
作者:聂大鹏
email:dozec@mail.csdn.net
3.7 Nand Flash 驱动部分
作者:孙磊,刘勇
email:sunlei3448@yahoo.com.cn
4 支持企业
4.1 尚观科技
为我们提供统许多套远峰公司的ARM开发板, 才能让我们做出统一的文档.
第部分 系统启动bootloader的编写(ADS)
1 工具介绍
1.1 ADS 命令行命令介绍
1.1.1 armasm
1. 命令:armasm [选项] -o 目标文件 源文件
2. 选项说明
-Errors 错误文件名 ;指定一个错误输出文件
-I 目录[,目录] ;指定源文件搜索目录
-PreDefine 预定义宏 ;指定预定义的宏
-NOCache ;编译源代码时禁止使用Cache进行优化
-MaxCache <n> ;编译源代码时使用Cache进行优化
-NOWarn ;关闭所有的警告信息
-G ;输出调试表
-keep ;在目标文件中保存本地符号表
-LIttleend ;生成小端(Little-endian) ARM代码
-BIgend ;生成大端(Big-endian) ARM代码
-CPU <target-cpu> ;设立目标板ARM核类型,如: arm920t.
-16 ;建立16位的thumb指令.
-32 ;建立32位的ARM指令.
3. 编译一个汇编文件
c:/adsloader>armasm -LIttleend -cpu ARM920T -32 bdinit.s
把汇编语言编译成小端, 32位, ARM920T CPU.
1.1.2 armcc, armcpp
1. 命令:armcc [选项] 源文件1 源文件2 ... 源文件n
2. 选项说明
-c ;编译但是不连接
-D ;指定一个编译时使用的预定义宏常量
-E ;仅仅对C源文件做预处理
-g ;产生调试信息表
-I ;指头文件的搜索路径
-o<file> ;指定一个输出的目标文件
-O[0/1/2] ;指定源代码的优化级别
-S ;输出汇编代码来代替目标文件
-CPU <target-cpu> ;设立目标板ARM核类型,如: arm920t.
3.编译一个C程序
c:/adsloader>armcc -c -O1 -cpu ARM920T bdisr.c
编译不连接, 二级优化, ARM920T CPU.
1.1.3 armlink
1. 命令:armlink [选项] 输入文件
2. 选项说明
-partial ;合并目标文件
-Output 文件 ;指定输出文件名
-scatter 文件 ;按照指定的文件为可执行文件建立内存映射
-ro-base 地址值 ;只读代码段的起始地址
-rw-base 地址值 ;RW/ZI段的起始地址
3. 把多个目标文件合并成一个目标文件
c:/adsloader>armlink -partial bdmain.o bdport.o bdserial.o bdmmu.o bdisr.o -o
bd.o
4. 把几个目标文件编译一个可执地文件
c:/adsloader>armlink bd.o bdinit.o -scatter bdscf.scf -o bd.axf
1.1.4 fromelf
1. 命令:fromelf [选项] 输入文件
2. 选项说明
-bin 二进制文件名 ;产生的二进制文件
-elf elf文件名 ;产生一个elf文件
-text text文件名 ;产生text文件
3. 产生一个可执行的二进制代码
c:/adsloader>fromelf bd.axf bin
o
bd.bin
2 基本原理
2.1 可执行文件组成及内存映射
2.1.1 可执行文件的组成
在ADS下,可执行文件有两种,一种是.axf文件,带有调试信息,可供AXD调试工具使用.另一种是.bin
文件,可执行的二进制代码文件。我们重点是讲描.bin文件的组成。
我们把可执行文件分为两种情况:分别为存放态和运行态。
1. 存放态
存放态是指可执行文件通过fromelf产生后,在存储介质(flash或磁盘)上的分布. 此时可执行文件一
般由两部分组成:分别是代码段和数据段。代码段又分为可执行代码段(.text)和只读数据段(.rodata),
数据段又分为初始化数据段(.data)和未初始化数据段(.bss)。可执行文件的存放态如下:
+-------------+-----------
| .bss |
+-------------+-- 数据段
| .data |
+-------------+-----------
| .rodata |
|_____________| 代码段
| .text |
+-------------+-----------
2. 运行态
可执行文件通过装载过程, 搬入到RAM中运行, 这时候可执行文件就变成运行态。在ADS下对可执行代
码各段有另一个名称:
| ... |
+-------------+-----------
| .bss | ZI 段
+-------------+-- 数据段
| .data | RW 段
+-------------+-----------
| .rodata |
|_____________| 代码段(RO 段)
| .text |
+-------------+-----------
| ... |
装载前
当可执行文件装载后, 在RAM中的分布如下:
| ... |
+-------------+-- ZI段结束地址
| ZI 段 |
+-------------+-- ZI段起始地址
| 保留区2 |
+-------------+-- RW段结束地址
| RW 段 |
+-------------+-- RW段起始地址
| 保留区1 |
+-------------+-- RO段结束地址
| RO 段 |
+-------------+-- RO段起始地址
| ... |
装载后
所以装载过程必须完成把执行文件的各个段从存储介质上搬到RAM指定的位置。而这个装载过程由谁来完
成呢?由我们的启动程序来完成.
2.1.2 装载过程
在ADS中,可以通过两种方式来指定可执行代码各段在RAM中的位置,一个是用armlink来指定,一种是
用scatter文件来指定.RAM区的起始地址:0x30000000.
1. armlink指定代码段地址
我们通常的代码,只用指定两个段开始地址, RO段的起始地址和RW段的起始地址, ZI段紧接在RW段之
后.示例见该部分的1.1.3.
2. scatter指定代码段地址
我们也可以通过scatter文件指定可执行文件各段的详细地址. Scatter文件如下:
MYLOADER 0x30000000
;MYLOADER: 为可执行文件的名称, 可自定义
;0x3000000: 起始地址
{
RO 0x30000000
;RO 只读代码段的名称
;0x30000000: 只读代码段的起始地址
{
init.o (Init, +First)
; Init代码段为可执行文件的第一部分.
* (+RO) ;所有其它的代码段和只读数据段放在该部分
}
RW +0
;RW: RW段的名称
;+0: 表示RW段紧接着RO段
{
* (+RW) ;所有RW段放在该部分
}
ZI +0
;ZI: ZI段的名称
;+0: 表示ZI段紧接着RW段
{
*(+ZI) ;所有ZI段放在该部分
}
}
3. ADS产生的各代码段宏
|Image$$RO$$Base| /* RO代码段起始地址 */
|Image$$RO$$Limit| /* RO 代码段结束地址 */
|Image$$RW$$Base| /* RW代码段起始地址 */
|Image$$RW$$Limit| /* RW 代码段结束地址 */
|Image$$ZI$$Base| /* ZI 代码段起始地址 */
|Image$$ZI$$Limit| /* ZI 代码段结束地址 */
注意:在两个$$之间的名称, 与scatter中指定的段的名称相同.
4. 装载过程说明
当从NorFlash启动时, 要把flash芯片的首地址映射到0x00000000位置, 系统启动后, 启动程序本身把自己从
flash中搬到RAM中运行. 搬移后的各段起始地址, 由以上宏来确定.
当从NandFlash启动时, S3C2410会自动把前NandFlash的前4k搬到S3C2410的内部RAM中,并把内部
RAM的首地址设为0x00000000,CPU从0x00000000开始执行. 所以, 在nandFlash的前4k程序中,必须包含从
NandFlash把BootLoader的其余部分装入RAM的程序.
2.1.3 启动过程的汇编部分
当系统启动时, ARM CPU会跳到0x00000000去执行。一般BootLoader都包括如下几个部分:
1. 建立中断向量异常表
2. 显示的切换到SVC且32指令模式
3. 关闭S3C2410的内部看门狗
4. 禁止所有的中断
5. 配置系统时钟频率和总线频率
6. 设置内存区的控制寄存器
7. 初始化中断
8. 安装中断向表量
9. 把可执行文件的各个段搬到运行态的各个位置
10. 跳到C代码部分执行
2.1.4 启动过程的C部分
1. 初始化MMU
2.初始化外部端口
3. 中断处理程序表初始化
4. 串口初始化
5. 其它部分初始化(可选)
6. 主程序循环
3 AXD的使用以及源代码说明
3.1 源代码说明
3.1.1 汇编源代码说明
;===============================================================================
; 引用头文件
;===============================================================================
get bdinit.h
;===============================================================================
; 引用标准变量
;===============================================================================
IMPORT |Image$$RO$$Base| ; Base address of RO section
IMPORT |Image$$RO$$Limit| ; End address of RO section
IMPORT |Image$$RW$$Base| ; Base address of RW section
IMPORT |Image$$RW$$Limit| ; End address of RW section
IMPORT |Image$$ZI$$Base| ; Base address of ZI section
IMPORT |Image$$ZI$$Limit| ; End addresss of ZI section
IMPORT bdmain ; The entry function of C program
;===============================================================================
; 宏定义
;===============================================================================
; macro HANDLER
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;Decrement sp (to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack
ldr r0,=$HandleLabel;Load the address of HandleXXX to r0
ldr r0,[r0] ;Load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;Store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
;===============================================================================
; 汇编语言的入口代码
;===============================================================================
AREA Init,CODE,READONLY
CODE32
ENTRY
;=====================
; 建立中断向量表
;=====================
b reset_handler ;0x00000000: Reset (SVC)
b undef_handler ;0x00000004: Undefined instruction (Undef)
b swi_handler ;0x00000008: Software Interrupt (SVC)
b iabr_handler ;0x0000000C: Instruction Abort (Abort)
b dabr_handler ;0x00000010: Data Abort (Abort)
b no_handler ;0x00000014:
b irq_handler ;0x00000018: IRQ (IRQ)
b fiq_handler ;0x0000001C: FIQ (FIQ)
LTORG
undef_handler HANDLER HandleUndef
swi_handler HANDLER HandleSWI
iabr_handler HANDLER HandlePabort
dabr_handler HANDLER HandleDabort
no_handler HANDLER HandleReserved
irq_handler HANDLER HandleIRQ
fiq_handler HANDLER HandleFIQ
;=============================
; 复位时运行的主程序
;=============================
reset_handler
;Set the cpu to SVC32 mode
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr_cxsf,r0
;Turn off watchdog
ldr r0,=WTCON
ldr r1,=0x0
str r1,[r0]
;Disable all the first level interrupts
ldr r0,=INTMSK
ldr r1,=0xffffffff
str r1,[r0]
;Disable all the second level interrupts
ldr r0,=INTSUBMSK
ldr r1,=0x7ff
str r1,[r0]
;Configure MPLL
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=12MHz,Fout=200MHz
str r1,[r0]
;Set FCLK:HCLK:PCLK = 1:2:4
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
;Set memory control registers
ldrr0,=SMRDATA
ldr r1,=BWSCON
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;Initialize stacks
bl InitStacks
;Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ
str r1,[r0]
;Copy RW/ZI section into RAM
ldr r0, =|Image$$RO$$Limit|;Get pointer to ROM data
ldr r1, =|Image$$RW$$Base| ;and RAM copy
ldr r3, =|Image$$ZI$$Base|
cmp r0, r1 ; Check that they are different
beq %F2
1
cmp r1, r3 ; Copy init data
ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
bcc %B1
2
ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
mov r2, #0
3
cmp r3, r1 ; Zero init
strcc r2, [r3], #4
bcc %B3
bl bdmain ;Jump to the main function
;Dead loop
1
nop
b %B1
;===============================================================================
; 初始中断处理程序
;===============================================================================
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;===============================================================================
; 初始化各个模式下堆栈
;===============================================================================
InitStacks
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode
ldr sp,=FIQStack
bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
mov pc,lr ;Return the call routine
LTORG
;===============================================================================
; 内存区控制寄存器值表; 你可根据需要修改bdinit.h文件, 下面代码不用做任何改动
;===============================================================================
SMRDATA DATA
DCD
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(
B7_BWSCON<<28))
DCD
((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0
DCD
((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1
DCD
((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2
DCD
((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3
DCD
((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4
DCD
((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5
DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6
DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7
DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
DCD 0x30 ;MRSR6 CL=3clk
DCD 0x30 ;MRSR7
ALIGN
;===============================================================================
; 异常及中断向量表空间; 安装异常或中断处理程序在bdisr.c中,isr_setup()来完成.
;===============================================================================
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ;表示下面数据区从_ISR_STARTADDRESS指定的位置开始
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
;=============================
; The Interrupt table
;=============================
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleRSV6 # 4
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleRSV24 # 4
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4
END
3.1.2 C语言源代码说明
void bdmain(void)
{
/* 禁止Cache 和MMU */
cache_disable();
mmu_disable();
/* 端口初始化 */
port_init();
/* 中断处理程序 */
isr_init();
/* 串口初始化 */
serial_init(0, 115200);
/* 输出信息进行主循环 */
serial_printf("is ok!/n");
while(1) {
}
}
通常基本ADS的测试程序都可以在这个架构上加入自己的代码.
3.2 AXD的使用
3.2.1 配置仿真器
1. 为仿真器安装Server
一般的仿真器都对应有一个Server程序,所以在使用在线仿真之前,必须先安装这个Server程序。我使用
是DragonICE
仿真器, 所以先要安装DragonICE
Server程序。
2. 连接仿真器
把dragonICE
仿真器的JTAG口连接上ARM板(注意:ARM板要断电连接), 另一端通过并口连接到PC上,
有的仿真器是通过USB口连接到PC上, 这与仿真器的硬件相关。连接好后, 打开ARM电源,启动ARM板。
当ARM通电启动后,启动DragonICE
Server检测ARM板,详细步骤及设置参见对应的仿真器手册。我的
dragonICE
Server启动, 按”自动检测”可以检测到ARM920T。
3.2.2 启动AXD 配置开发板
1. 启动AXD
先启动DragonICE
Server程序.
按如下步聚启动AXD:
开始>
所有程序>
ARM Developer Suite v1.2>
AXD Debugger
2. 装载仿真器库文件
从AXD菜单的Options>
Configure Target...启动”Choose Target”目标板配置窗口.
在”Choose Target”窗口中,点击”Add”按钮,选择仿真器的库文件. 我的仿真器服务器程序安装在
c:/DragonICE
下,所以选择项c:/DragonICE/
dragonice.
dll文件.
3. 为AXD在线仿真配置仿真器
在"Target Environments"中选中DragonICE
中,点击右边的"Configure"按钮.
在”FJB DragonICE
Release v1.2”窗口点击"This computer..."按钮,再点击"OK"按钮。
回到”Choose Target”窗口,点击"OK"按钮。完成配置.
回到主界面, 在右边的”Target”窗口会出现ARM920T_0.这表明AXD已经进入ARM板的在线仿真状态.
点击菜单"System Views">"
Controls Monitors".会出现"ARM920TRegister"
窗口.此时,会显示当前ARM板上所
有寄存器的状态。
4. 配置ARM板
如果ARM板通电后,没有程序运行并把内存区控制寄存器配置好的说,外部RAM是不能使用的. 所以必须
通过仿真器来设置这些寄存器. 如果ARM板已经有启动程序并且已经配置好, 这一步可以省略.
首先把2410cfg.txt拷贝到c:/下.
回到AXD主界面, 从菜单”System Views” >
“Command Line Interface”。会出现一个Command Line
Interface的调试命令行窗口,并显示如下提示符:
Debug >
输入obey c:/2410cfg.txt装载所有配置命令.
Debug >obey c:/2410cfg.txt
5. 2410cfg.txt文件说明
sreg psr, 0x00000013
;设置当前CPSR的值, 把CPU的模式切换到SVC模式和32位指令集, 关闭IRQ和FIQ。
smem 0x53000000,0,32
;设置看门狗控制寄存器WTCON
;禁止看门狗定时器
smem 0x4C000004,((0x74<<12)+(0x3<<4)+0x1),32
;设置主频率设置寄存器MPLLCON
;目前CPU的工作频率FCLK是124.00MHz
smem 0x4C000014,0x3,32
;设置时钟分频寄存器CLKDIVN
;设置FCLK/HCLK/PCLK 的频率比例1:2:4
smem 0x48000000,((2<<28)+(2<<24)+(1<<20)+(1<<16)+(1<<12)+(1<<8)+(1<<4)+0),32
;设置内存总线控制BWSCON
;SDRAM BANK 6&7 is 32位
;其它BANK is 16位
smem 0x48000004,((3<<13)+(3<<11)+(7<<8)+(3<<6)+(3<<4)+(3<<2)+3),32
;设置寄存器区0控制寄存器:BANKCON0
smem 0x4800001c,((3<<15)+(1<<2)+1),32
;设置寄存器区6控制寄存器: BANKCON6(SDRAM)
;RAS to CAS 延时3 时钟周期
;列地址是9位
smem 0x48000020,((3<<15)+(1<<2)+1),32
;设置寄存器区7控制寄存器: BANKCON7(SDRAM)
;RAS to CAS 延时 3 时钟周期
;列地址是9位
smem 0x48000024,((1<<23)+(3<<18)+(2<<16)+1113),32
;set 外部RAM刷新寄存器:REFRESH
;允许自刷新
;HCLK=FCLK/2, 60MHz,刷新计算器是1113
smem 0x48000028,0x31,32
;设置寄存器的大小
;禁止burst操作
;允许SDRAM power down模式
;SCLK在访问期间仍在活动状态
;SDRAM模式寄存器设置
smem 0x4800002c,0x30,32
smem 0x48000030,0x30,32
3.2.3 使用AXD在线仿真调试程序
1. 装载可执行的文件
AXD只支持.axf格式的可执行文件.
启动AXD, 在菜单的File中,选择Load Image..., 选择c:/adsbloadter/prj/prj_Data/DebugRel/prj.axf加载执行
image. 就可以执行并调试了. AXD提供了非常方便的调试手段, 包括在线单步, *设置断点等.
第三部分 GNU交叉工具链
1 设置环境变量,准备源码及相关补丁
1.1 设置环境变量
[arm@localhost arm]#vi ~/.bashrc
export PREFIX=/usr/local/arm/3.4.4
export TARGET=armlinux
export SYSROOT=${PREFIX}/sysroot
export ARCH=arm
export CROSS_COMPILE=${TARGET}export
PATH=${PREFIX}/bin:$PATH
export SRC=/home/arm/dev_home/btools/tchain3.4.4
1. 2 准备源码包
1.2.1 binuils
名称:binutils2.16.
tar.gz
下载地址:http://ftp.gnu.org/gnu/binutils/binutils2.16.
tar.gz
1.2.2 gcc
名称:gcc3.4.4.
tar.bz2
下载地址:http://ftp.gnu.org/gnu/gcc/gcc3.4.4/
gcc3.4.4.
tar.bz2
1.2.3 glibc
名称:glibc2.3.5.
tar.gz
glibclinuxthreads2.3.5.
tar.gz
下载地址: http://ftp.gnu.org/gnu/glibc/glibc2.3.5.
tar.gz
http://ftp.gnu.org/gnu/glibc/glibclinuxthreads2.3.5.
tar.gz
1.2.4 linux kernel
名称:linux2.6.14.1.
tar.gz
下载地址: http://ftp.kernel.org/pub/linux/kernel/v2.6/linux2.6.14.1.
tar.gz
1.3 准备补丁
1.3.1 ioperm.c.diff
作用:打修正ioperm()函数.
下载地址:http://frank.harvard.edu/~coldwell/toolchain/ioperm.c.diff
1.3.2 flow.c.diff
作用:该补丁用于产生crti.o和crtn.o文件。
下载地址:http://gcc.gnu.org/cgibin/
cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=cslarmbranch&
r1=1.563.4.2&r2=1.563.4.3
1.3.3 t-linux.diff
作用:修改gcc一处bug
下载地址:http://frank.harvard.edu/~coldwell/toolchain/tlinux.
diff
1.4 编译 GNU binutils
重新以arm用户登陆,让新设置的环境变量起作用.
[arm@localhost arm]#su arm
[arm@localhost arm]#cd ${SRC}
[arm@localhost tchain3.4.4]#tar xzvf binutils2.16.
tar.gz
[arm@localhost tchain3.4.4]#mkdir p
BUILD/binutils2.16
[arm@localhost binutils2.16]#
cd BUILD/binutils2.16
[arm@localhost binutils2.16]#
../../binutils2.16/
configure prefix=${
PREFIX} target=${
TARGET} /
withsysroot=${
SYSROOT}
[arm@localhost binutils2.16]#
make
[arm@localhost binutils2.16]#
su root
[root@localhost binutils2.16]#
make install
[root@localhost binutils2.16]#
exit
[arm@localhost binutils2.16]#
1.5 准备内核头文件
1.5.1 使用当前平台的gcc编译内核头文件
[arm@localhost tchain3.4.4]#cd ${KERNEL}
[arm@localhost kernel]#tar xvfz linux2.6.14.1.
tar.gz
[arm@localhost kernel]#cd linux2.6.14.1
[arm@localhost linux2.6.14.1]#
make ARCH=arm menuconfig
[arm@localhost linux2.6.14.1]#
make
1.5.2 复制内核头文件
[arm@localhost kernel]#su root
[root@localhost kernel]#mkdir p
${SYSROOT}/usr/include
[root@localhost kernel]#cp a
include/linux ${SYSROOT}/usr/include/linux
[root@localhost kernel]#cp a
include/asmi386
${SYSROOT}/usr/include/asm
[root@localhost kernel]#cp a
include/asmgeneric
${SYSROOT}/usr/include/asmgeneric
[root@localhost kernel]#exit
[arm@localhost kernel]#
1.6 译编glibc头文件
[arm@localhost kernel]#cd ${SRC}
[arm@localhost chain3.4.4]#tar xvfz glibc2.3.5.
tar.gz
[arm@localhost chain3.4.4]#patch d
glibc2.3.5
p1
< ioperm.c.diff
[arm@localhost glibc2.3.5]#
cd glibc2.3.5
[arm@localhost glibc2.3.5]#
tar xvfz ../glibclinuxthreads2.3.5.
tar.gz
[arm@localhost chain3.4.4]#cd ..
[arm@localhost chain3.4.4]#mkdir BUILD/glibc2.3.5headers
[arm@localhost chain3.4.4]#cd BUILD/glibc2.3.5headers
[arm@localhost glibc2.3.5headers]#../../
glibc2.3.5/
configure prefix=/
usr host=${
TARGET} /
enableaddons=
linuxthreads –withheaders=${
SYSROOT}/usr/include
[arm@localhost glibc2.3.5headers]#
su root
[root@localhost glibc2.3.5headers]#
make crosscompiling=
yes install_root=${SYSROOT} installheaders
[root@localhost glibc2.3.5headers]#
touch ${SYSROOT}/usr/include/gnu/stubs.h
[root@localhost glibc2.3.5headers]#
touch ${SYSROOT}/usr/include/bits/stdio_lim.h
[root@localhost glibc2.3.5headers]#
exit
[arm@localhost glibc2.3.5headers]#
注意: prefix=/
usr :是gcc寻找库的搜索路径。
1.7 编译gcc第一阶段
[arm@localhost glibc2.3.5headers]#
cd ${SRC}
[arm@localhost chain3.4.4]#tar xjvf gcc3.4.4.
tar.bz2
[arm@localhost chain3.4.4]#patch d
gcc3.4.4
p1
< flow.c.diff
[arm@localhost chain3.4.4]#patch d
gcc3.4.4
p1
< tlinux.
diff
[arm@localhost chain3.4.4]#mkdir p
BUILD/gcc3.4.4stage1
[arm@localhost chain3.4.4]#cd BUILD/gcc3.4.4stage1
[arm@localhost gcc3.4.4stage1]#../../
gcc3.4.4/
configure prefix=${
PREFIX} target=${
TARGET} /
enablelanguages=
c withsysroot=${
SYSROOT}
注意:不能加上"disableshared"
选项。
[arm@localhost gcc3.4.4stage1]#
make allgcc
[arm@localhost gcc3.4.4stage1]#
su root
[root@localhost gcc3.4.4stage1]#
make installgcc
[root@localhost gcc3.4.4stage1]#
exit
[arm@localhost gcc3.4.4stage1]#
1.8 编译完整的glibc
[arm@localhost gcc3.4.4stage1]
#cd ${SRC}
[arm@localhost tchain3.4.4]#mkdir BUILD/glibc2.3.5
[arm@localhost tchain3.4.4]#cd BUILD/glibc2.3.5
[arm@localhost glibc2.3.5]#
BUILD_CC=gcc CC=${CROSS_COMPILE}gcc AR=${CROSS_COMPILE}ar /
RANLIB=${CROSS_COMPILE}ranlib AS=${CROSS_COMPILE}as LD=${CROSS_COMPILE}ld /
../../glibc2.3.5/
configure prefix=/
usr build=
i386redhatlinux
host=
armunknownlinuxgnu
/
target=
armunknownlinuxgnu
without__
thread enableaddons=
linuxthreads /
withheaders=${
SYSROOT}/usr/include
说明:
prefix:
指定安装路径。
target:
指定目标平台。
host:
指定当前平台。
build:
指定编译平台。
withsysroot:
用于指定编译所需要的头文件,及链接库。
enableaddons:
加入其它的库,如线程库等。
enablelanguages:
指定gcc所支持的语言。
[arm@localhost glibc2.3.5]#
make
[arm@localhost glibc2.3.5]#
su root
[root@localhost glibc2.3.5]#
make install_root=${SYSROOT} install
[root@localhost glibc2.3.5]#
exit
[arm@localhost glibc2.3.5]#
1.9 编译完整的gcc
[arm@localhost glibc2.3.5]#
cd ${SRC}
[arm@localhost tchain3.4.4]#mkdir BUILD/gcc3.4.4
[arm@localhost tchain3.4.4]#cd BUILD/gcc3.4.4
[arm@localhost gcc3.4.4]#../../
gcc3.4.4/
configure prefix=${
PREFIX} target=${
TARGET} /
enablelanguages=
c withsysroot=${
SYSROOT}
[arm@localhost gcc3.4.4]#
make
[arm@localhost gcc3.4.4]#
su root
[root@localhost gcc3.4.4]#
make install
[root@localhost gcc3.4.4]#
exit
[arm@localhost gcc3.4.4]#
2 GNU交叉工具链的下载
2.1 ARM官方网站
工具链的官方下载地址:
http://www.arm.linux.org.uk
可以从该站点下载2.95.3, 3.0以及3.2工具链
ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross2.95.3.
tar.bz2
ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.0.
tar.bz2
ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.2.
tar.bz2
3 GNU交叉工具链的介绍与使用
3.1 常用工具介绍
名称归属作用
armlinuxas
binutils 编译ARM汇编程序
armlinuxar
binutils 把多个.o合并成一个.o或静态库(.a)
armlinuxranlib
binutils 为库文件建立索引,相当于armlinuxar
s
armlinuxld
binutils 连接器(Linker), 把多个.o或库文件连接成一个可执行文件
名称归属作用
armlinuxobjdump
binutils 查看目标文件(.o)和库(.a)的信息
armlinuxobjcopy
binutils 转换可执行文件的格式
armlinuxstrip
binutils 去掉elf可执行文件的信息. 使可执行文件变小
armlinuxreadelf
binutils 读elf可执行文件的信息
armlinuxgcc
gcc 编译.c或.S开头的C程序或汇编程序
armlinuxg++
gcc 编译c++程序
3.2 主要工具的使用
3.2.1 arm-linux-gcc的使用
1. 编译C文件,生成elf可执行文件
h1.c 源文件
#include <stdio.h>
void hellofirst(void)
{
printf("The first hello! /n");
}
h2.c 源文件
#include <stdio.h>
void hellosecond(void)
{
printf("The second hello! /n");
}
hello.c 源文件
#include <stdio.h>
void hellosecond(void);
void hellofirst(void);
int main(int argc, char *argv[])
{
hellofirst();
hellosecond();
return(0);
}
编译以上3个文件,有如下几种方法:
方法1:
[arm@localhost gcc]#armlinuxgcc
c
h1.c
[arm@localhost gcc]#armlinuxgcc
c
h2.c
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c h1.o h2.o
方法2:
[arm@localhost gcc]#armlinuxgcc
c
h1.c h2.c
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c h1.o h2.o
方法3:
[arm@localhost gcc]#armlinuxgcc
c
o
h1.o h1.c
[arm@localhost gcc]#armlinuxgcc
c
o
h1.o h1.c
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c h1.o h2.o
方法4:
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c h1.c h2.c
c:
只编译不连接。
o:
编译且连接。
2. 产生一个预处理文件
当要看一个宏在源文件中产生的结果时,比较合适。
[arm@localhost gcc]#armlinuxgcc
E
h1.i h1.c
E:
产生一个预处理文件.
3. 产生一个动态库
动态库是在运行时需要的库。
[arm@localhost gcc]#armlinuxgcc
c
fpic
h1.c h2.c
[arm@localhost gcc]#armlinuxgcc
shared
h1.o h2.o o
hello.so
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c hello.so
把hello.so拷贝到目标板的/lib目录下,把可执行文件拷贝目标板的/tmp目录下,在目标板上运行hello.
#/tmp/hello
或把hello.so和hello一起拷贝到/tmp目标下,并设置LD_LIBRARY_PATH环境变量
#export LD_LIBRARY_PATH =/tmp:$LD_LIBRARY_PATH
#/tmp/hello
3.2.2 arm-linux-ar 和 arm-linux-ranlib的使用
静态库是在编译时需要的库。
1. 建立一个静态库
[arm@localhost gcc]#armlinuxar
r
libhello.a h1.o h2.o
2. 为静态库建立索引
[arm@localhost gcc]#armlinuxar
s
libhello.a
[arm@localhost gcc]#armlinuxranlib
libhello.a
3. 由静态库产生可执行文件
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c lhello
L./
[arm@localhost gcc]#armlinuxgcc
o
hello hello.c libhello.a
hello文件可以直接拷贝到/tmp目录下运行,不需libhello.a.
3.2.3 arm-linux-objdump的使用
1. 查看静态库或.o文件的组成文件
[arm@localhost gcc]$ armlinuxobjdump
a
libhello.a
2. 查看静态库或.o文件的络组成部分的头部分
[arm@localhost gcc]$ armlinuxobjdump
h
libhello.a
3. 把目标文件代码反汇编
[arm@localhost gcc]$ armlinuxobjdump
d
libhello.a
3.2.4 arm-linux-readelf的使用
1. 读elf文件开始的文件头部
[arm@localhost gcc]$ armlinuxreadelf
h
hello
ELF Header:
Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: ARM
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x82b4
Start of program headers: 52 (bytes into file)
Start of section headers: 10240 (bytes into file)
Flags: 0x2, has entry point
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 25
2. 读elf文件中所有ELF 的头部:
[arm@localhost gcc]#armlinuxreadelf
e
hello
......
3. 显示整个文件的符号表
[arm@localhost gcc]#armlinuxreadelf
s
hello
......
4. 显示使用的动态库
[arm@localhost gcc]#armlinuxreadelf
d
hello
......
3.2.5 arm-linux-strip的使用
1. 移除所有的符号信息
[arm@localhost gcc]#cp hello hello1
[arm@localhost gcc]#armlinuxstrip
stripall
hello
stripall:
是移除所有符号信息
[arm@localhost gcc]#ll
rwxrxrx
1 arm root 2856 7月 3 15:14 hello
rwxrxrx
1 arm root 13682 7月 3 15:13 hello1
被strip后的hello程序比原来的hello1程序要小很多。
2. 移除调试符号信息
[arm@localhost gcc]#armlinuxstrip
g
hello
[arm@localhost gcc]#ll
rwxrxrx
1 arm root 4501 7月 3 15:17 hello
rwxrxrx
1 arm root 13682 7月 3 15:13 hello1
3.2.6 arm-linux-copydump的使用
生成可以执行的2进制代码
[arm@localhost gcc]#armlinuxcopydump
O
binary hello hello.bin
4 ARM GNU常用汇编语言介绍
4.1 ARM GNU常用汇编伪指令介绍
1. abort
.abort: 停止汇编
.align absexpr1,
absexpr2:
以某种对齐方式,在未使用的存储区域填充值. 第一个值表示对齐方式,4, 8,16或32. 第
二个表达式值表示填充的值.
2. if...else...endif
.if
.else
.endif: 支持条件预编译
3. include
.include "file": 包含指定的头文件, 可以把一个汇编常量定义放在头文件中.
4. comm
.comm symbol, length:在bss段申请一段命名空间,该段空间的名称叫symbol, 长度为length. Ld连接器在连接会
为它留出空间.
5. data
.data subsection: 说明接下来的定义归属于subsection数据段.
6. equ
.equ symbol, expression: 把某一个符号(symbol)定义成某一个值(expression).该指令并不分配空间.
7. global
.global symbol: 定义一个全局符号, 通常是为ld使用.
8. ascii
.ascii "string": 定义一个字符串并为之分配空间.
9. byte
.byte expressions: 定义一个字节, 并为之分配空间.
10. short
.short expressions: 定义一个短整型, 并为之分配空间.
11. int
.int expressions: 定义一个整型,并为之分配空间.
12 long
.long expressions: 定义一个长整型, 并为之分配空间.
13 word
.word expressions: 定义一个字,并为之分配空间, 4bytes.
14. macro/endm
.macro: 定义一段宏代码, .macro表示代码的开始, .endm表示代码的结束.
15. req
name .req register name: 为寄存器定义一个别名.
16. code
.code [16|32]: 指定指令代码产生的长度, 16表示Thumb指令, 32表示ARM指令.
17. ltorg
.ltorg: 表示当前往下的定义在归于当前段,并为之分配空间.
4.2 ARM GNU专有符号
1. @
表示注释从当前位置到行尾的字符.
2. #
注释掉一整行.
3. ;
新行分隔符.
4.3 操作码
1. NOP
nop
空操作, 相当于MOV r0, r0
2. LDR
ldr <register> , = <expression>
相当于PC寄存器或其它寄存器的长转移.
3.ADR
adr <register> <label>
相于PC寄存器或其它寄存器的小范围转移.
ADRL
adrl <register> <label>
相于PC寄存器或其寄存器的中范围转移.
5 可执行生成说明
5.1 lds文件说明
5.1.1 主要符号说明
1. OUTPUT_FORMAT(bfdname)
指定输出可执行文件格式.
2. OUTPUT_ARCH(bfdname)
指定输出可执行文件所运行CPU平台
3. ENTRY(symbol)
指定可执行文件的入口段
5.1.2 段定义说明
1. 段定义格式
SECTIONS { ...
段名 : {
内容
}
...
}
5.1.3 uboot.
lds 文件说明
OUTPUT_FORMAT("elf32littlearm",
"elf32littlearm",
"elf32littlearm")
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定输出可执行文件的平台为ARM
ENTRY(_start)
;指定输出可执行文件的起始代码段为_start.
SECTIONS
{
. = 0x00000000 ; 从0x0位置开始
. = ALIGN(4) ; 代码以4字节对齐
.text : ;指定代码段
{
cpu/arm920t/start.o (.text) ; 代码的第一个代码部分
*(.text) ;其它代码部分
}
. = ALIGN(4)
.rodata : { *(.rodata) } ;指定只读数据段
. = ALIGN(4);
.data : { *(.data) } ;指定读/写数据段
. = ALIGN(4);
.got : { *(.got) } ;指定got段, got段式是uboot自定义的一个段, 非标准段
__u_boot_cmd_start = . ;把__u_boot_cmd_start赋值为当前位置, 即起始位置
.u_boot_cmd : { *(.u_boot_cmd) } ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段.
__u_boot_cmd_end = .;把__u_boot_cmd_end赋值为当前位置,即结束位置
. = ALIGN(4);
__bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置
.bss : { *(.bss) }; 指定bss段
_end = .; 把_end赋值为当前位置,即bss段的结束位置
}
第四部分 u-boot的移植
1 u-boot的介绍及系统结构
1.1 u-boot介绍
Uboot
是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot
不仅仅支持嵌入式Linux
系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。UBoot
除
了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。
1.2 获取u-boot
以uboot用户登陆.
[uboot@localhost ~]#mkdir p
dev_home/uboot
[uboot@localhost ~]#cd dev_home/uboot
从下面地址下载uboot
的源代码。
http://sourceforge.net/projects/uboot
[uboot@localhost uboot]#tar xjvf
uboot1.1.4.
tar.bz2
[uboot@localhost uboot]#cd uboot1.1.4
1.3 u-boot体系结构
1.3.1 u-boot目录结构
1. 目录树
[uboot@localhost uboot1.1.4]#
tree L
1 d
.
|board
|common
|cpu
|disk
|doc
|drivers
|dtt
|examples
|fs
|include
|lib_
arm
|lib_
generic
|lib_
i386
|lib_
m68k
|lib_
microblaze
|lib_
mips
|lib_
nios
|lib_
nios2
|lib_
ppc
|net
|post
|rtc
`tools
2. board:和一些已有开发板有关的文件. 每一个开发板都以一个子目录出现在当前目录中,比如说:SMDK2410,
子目录中存放与开发板相关的配置文件.
3. common:实现uboot
命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是
cmd_bootm.c。
4. cpu:与特定CPU架构相关目录,每一款Uboot
下支持的CPU在该目录下对应一个子目录,比如有子目录
arm920t等。
5. disk:对磁盘的支持。
5. doc:文档目录。Uboot
有非常完善的文档,推荐大家参考阅读。
6. drivers:Uboot
支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。
7. fs: 支持的文件系统,Uboot
现在支持cramfs、fat、fdos、jffs2和registerfs。
8. include:Uboot
使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的
文件。该目录下configs目录有与开发板相关的配置头文件,如smdk2410.h。该目录下的asm目录有与CPU体
系结构相关的头文件,asm对应的是asmarm.
9. lib_xxxx: 与体系结构相关的库文件。如与ARM相关的库放在lib_arm中。
10. net:与网络协议栈相关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。
11. tools:生成Uboot
的工具,如:mkimage, crc等等。
2 uboot的启动过程及工作原理
2.1 启动模式介绍
大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人
员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加
载模式与下载工作模式的区别。
启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机
上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 Boot
Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。
下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手
段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Boot
Loader 保存到目标机的 RAM 中,然后再被 BootLoader 写到目标机上的FLASH 类固态存储设备中。Boot
Loader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot
Loader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令
行接口。
UBoot
这样功能强大的 Boot Loader 同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行
切换。
大多数bootloader都分为阶段1(stage1)和阶段2(stage2)两大部分,uboot
也不例外。依赖于CPU体系结构
的代码(如CPU初始化代码等)通常都放在阶段1中且通常用汇编语言实现,而阶段2则通常用C语言来实
现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
2.2 阶段1介绍
uboot
的stage1代码通常放在start.s文件中,它用汇编语言写成,其主要代码部分如下:
2.2.1 定义入口
由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0
地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
1. board/crane2410/uboot.
lds: ENTRY(_start) ==> cpu/arm920t/start.S: .globl _start
2. uboot代码区(TEXT_BASE = 0x33F80000)定义在board/crane2410/config.mk
2.2.2 设置异常向量
_start: b reset @ 0x00000000
ldr pc, _undefined_instruction @ 0x00000004
ldr pc, _software_interrupt @ 0x00000008
ldr pc, _prefetch_abort @ 0x0000000c
ldr pc, _data_abort @ 0x00000010
ldr pc, _not_used @ 0x00000014
ldr pc, _irq @ 0x00000018
ldr pc, _fiq @ 0x0000001c
当发生异常时,执行cpu/arm920t/interrupts.c中定义的中断处理函数。
2.2.3 设置CPU的模式为SVC模式
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
2.2.4 关闭看门狗
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0 @ 根据三星手册进行调置。
str r1, [r0]
2.2.5 禁掉所有中断
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
2.2.6 设置以CPU的频率
默认频率为 FCLK:HCLK:PCLK = 1:2:4,默认FCLK的值为120 MHz,该值为S3C2410手册的推荐值。
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
2.2.7 设置CP15
设置CP15, 失效指令(I)Cache和数据(D)Cache后, 禁止MMU与Cache。
cpu_init_crit:
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* 失效I/D cache, 见S3C2410手册附录的2-16 */
mcr p15, 0, r0, c8, c7, 0 /* 失效TLB, 见S3C2410手册附录的2-18 */
/*
* 禁止 MMU 和caches, 详见S3C2410手册附录2-11
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 /* 清除 bits 13, 9:8 (--V- --RS)
* Bit 8: Disable System Protection
* Bit 7: Disable ROM Protection
* Bit 13: 异常向量表基地址: 0x0000 0000
*/
bic r0, r0, #0x00000087 /* 清除 bits 7, 2:0 (B--- -CAM)
* Bit 0: MMU disabled
* Bit 1: Alignment Fault checking disabled
* Bit 2: Data cache disabled
* Bit 7: 0 = Little-endian operation
*/
orr r0, r0, #0x00000002 /* set bit 2 (A) Align, 1 = Fault checking enabled */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache, 1 = Instruction cache enabled
*/
mcr p15, 0, r0, c1, c0, 0
2.2.8 配置内存区控制寄存器
配置内存区控制寄存器,寄存器的具体值通常由开发板厂商或硬件工程师提供. 如果您对总线周期及外围
芯片非常熟悉, 也可以自己确定, 在UBOOT
中的设置文件是board/crane2410/lowlevel_init.S, 该文件包含
lowleve_init程序段. 详细寄存器设置及值的解释见3.2.2 启动AXD 配置开发板一节中的第5点.
mov ip, lr
bl lowlevel_init
mov lr, ip
2.2.9 安装U-BOOT使的栈空间
下面这段代码只对不是从Nand Flash启动的代码段有意义,对从Nand Flash启动的代码,没有意义。因为
从Nand Flash中把UBOOT执行代码搬移到RAM,由2.1.9中代码完成.
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
...
#endif
stack_setup:
ldr r0, _TEXT_BASE /* 代码段的起始地址 */
sub r0, r0, #CFG_MALLOC_LEN /* 分配的动态内存区 */
sub r0, r0, #CFG_GBL_DATA_SIZE /* UBOOT开发板全局数据存放 */
#ifdef CONFIG_USE_IRQ
/* 分配IRQ和FIQ栈空间 */
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* 留下3个字为Abort */
2.2.10 BSS段清0
clear_bss:
ldr r0, _bss_start /* BSS段的起始地址 */
ldr r1, _bss_end /* BSS段的结束地址 */
mov r2, #0x00000000 /* BSS段置0 */
clbss_l:str r2, [r0] /* 循环清除BSS段 */
add r0, r0, #4
cmp r0, r1
ble clbss_l
2.2.11 搬移Nand Flash代码
从Nand Flash中, 把数据拷贝到RAM, 是由copy_myself程序段完成, 该程序段详细解释见:第七部分的3.1节.
#ifdef CONFIG_S3C2410_NAND_BOOT
bl copy_myself
@ jump to ram
ldr r1, =on_the_ram
add pc, r1, #0
nop
nop
1: b 1b @ infinite loop
on_the_ram:
#endif
2.2.12 进入C代码部分
ldr pc, _start_armboot
_start_armboot: .word start_armboot
2.3 阶段2的C语言代码部分
lib_arm/board.c中的start armboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个
uboot(
armboot)的主函数,该函数主要完成如下操作:
2.3.1调用一系列的初始化函数
1. 指定初始函数表:
init_fnc_t *init_sequence[] = {
cpu_init, /* cpu的基本设置 */
board_init, /* 开发板的基本初始化 */
interrupt_init, /* 初始化中断 */
env_init, /* 初始化环境变量 */
init_baudrate, /* 初始化波特率 */
serial_init, /* 串口通讯初始化 */
console_init_f, /* 控制台初始化第一阶段 */
display_banner, /* 通知代码已经运行到该处 */
dram_init, /* 配制可用的内存区 */
display_dram_config,
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
checkboard,
#endif
NULL,
};
执行初始化函数的代码如下:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
2. 配置可用的Flash区
flash_init ()
3. 初始化内存分配函数
mem_malloc_init()
4. nand flash初始化
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* 初始化 NAND */
见第七部分3.2.3 节中的第3点nand_init()函数.
5. 初始化环境变量
env_relocate ();
6. 外围设备初始化
devices_init()
7. I2C总线初始化
i2c_init();
8. LCD初始化
drv_lcd_init();
9. VIDEO初始化
drv_video_init();
10. 键盘初始化
drv_keyboard_init();
11. 系统初始化
drv_system_init();
2.3.2 初始化网络设备
初始化相关网络设备,填写IP、MAC地址等。
1. 设置IP地址
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
uchar tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
}
2.3.3 进入主UBOOT命令行
进入命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
for (;;) {
main_loop (); /* 在common/main.c */
}
2.4 代码搬运
为了支持NAND flash起动,S3C2410内建了内部的4k的SRAM缓存“Steppingstone”。当起动时,NAND
flash最初的4k字节将被读入”Steppingstone”然后开始执行起动代码。通常起动代码会把NAND flash中的内容
拷到SDRAM中以便执行主代码。
使用硬件的ECC, NAND flash中的数据的有效性将会得到检测。
功能
1. NAND flash 模式:支持读/删除/编程 NAND Flash
2. 自动起动模式:在复位时起动代码将被读入”Steppingstone”中,然后开始执行起动代码。
3. 硬件ECC检测模块(硬件检测,软件纠正)
4. “Steppingstone” 4KB
内部SRAM在起动后可以另外使用。
3 uboot的移植过程
3.1 环境
详细环境设置参见:第一部分的2.2.2.
1. 工作用户
uboot
2. uboot
版本1.1.4
获取uboot1.1.4
请看1.2
3. 工具链2.95.3
3.2 步骤
我们为开发板取名叫: crane2410, 并在uboot
中建立自己的开发板类型
3.2.1 修改Makefile
[uboot@localhost uboot]#vi Makefile
#为crane2410建立编译项
crane2410_config : unconfig
@./mkconfig $(@:_config=) arm arm920t crane2410 NULL s3c24x0
各项的意思如下:
arm: CPU的架构(ARCH)
arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。
crane2410: 开发板的型号(BOARD),对应于board/crane2410目录。
NULL: 开发者/或经销商(vender)。
s3c24x0: 片上系统(SOC)。
3.2.2 在board子目录中建立crane2410
[uboot@localhost uboot]#cp rf
board/smdk2410 board/crane2410
[uboot@localhost uboot]#cd board/crane2410
[uboot@localhost crane2410]#mv smdk2410.c crane2410.c
3.2.3 在include/configs/中建立配置头文件
[uboot@localhost crane2410]#cd ../..
[uboot@localhost uboot]#cp include/configs/smdk2410.h include/configs/crane2410.h
3.2.4 指定交叉编译工具的路径
[uboot@localhost uboot]#vi ~/.bashrc
export PATH=/usr/local/arm/2.95.3/bin:$PATH
3.2.5 测试编译能否成功
[uboot@localhost uboot]#make crane2410_config
[uboot@localhost uboot]#make CROSS_COMPILE=armlinux3.2.6
修改lowlevel_init.S文件
依照开发板的内存区的配置情况, 修改board/crane2410/lowlevel_init.S文件,我的更改如下:
#include <config.h>
#include <version.h>
#define BWSCON 0x48000000
/* BWSCON */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
#define B1_BWSCON (DW16)
#define B2_BWSCON (DW16)
#define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16)
#define B5_BWSCON (DW16)
#define B6_BWSCON (DW32)
#define B7_BWSCON (DW32)
/* BANK0CON */
#define B0_Tacs 0x3 /* 0clk */
#define B0_Tcos 0x3 /* 0clk */
#define B0_Tacc 0x7 /* 14clk */
#define B0_Tcoh 0x3 /* 0clk */
#define B0_Tah 0x3 /* 0clk */
#define B0_Tacp 0x3
#define B0_PMC 0x3 /* normal */
/* BANK1CON */
#define B1_Tacs 0x3 /* 0clk */
#define B1_Tcos 0x3 /* 0clk */
#define B1_Tacc 0x7 /* 14clk */
#define B1_Tcoh 0x3 /* 0clk */
#define B1_Tah 0x3 /* 0clk */
#define B1_Tacp 0x3
#define B1_PMC 0x0
#define B2_Tacs 0x0
#define B2_Tcos 0x0
#define B2_Tacc 0x7
#define B2_Tcoh 0x0
#define B2_Tah 0x0
#define B2_Tacp 0x0
#define B2_PMC 0x0
#define B3_Tacs 0x0 /* 0clk */
#define B3_Tcos 0x3 /* 4clk */
#define B3_Tacc 0x7 /* 14clk */
#define B3_Tcoh 0x1 /* 1clk */
#define B3_Tah 0x0 /* 0clk */
#define B3_Tacp 0x3 /* 6clk */
#define B3_PMC 0x0 /* normal */
#define B4_Tacs 0x0 /* 0clk */
#define B4_Tcos 0x0 /* 0clk */
#define B4_Tacc 0x7 /* 14clk */
#define B4_Tcoh 0x0 /* 0clk */
#define B4_Tah 0x0 /* 0clk */
#define B4_Tacp 0x0
#define B4_PMC 0x0 /* normal */
#define B5_Tacs 0x0 /* 0clk */
#define B5_Tcos 0x0 /* 0clk */
#define B5_Tacc 0x7 /* 14clk */
#define B5_Tcoh 0x0 /* 0clk */
#define B5_Tah 0x0 /* 0clk */
#define B5_Tacp 0x0
#define B5_PMC 0x0 /* normal */
#define B6_MT 0x3 /* SDRAM */
#define B6_Trcd 0x1
#define B6_SCAN 0x1 /* 9bit */
#define B7_MT 0x3 /* SDRAM */
#define B7_Trcd 0x1 /* 3clk */
#define B7_SCAN 0x1 /* 9bit */
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
/* everything is fine now */
mov pc, lr
.ltorg
/* the literal pools origin */
SMRDATA:
.word
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(
B7_BWSCON<<28))
.word
((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word
((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word
((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word
((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word
((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word
((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x31
.word 0x30
.word 0x30
3.2.9 UBOOT的Nand Flash移植
UBOOT的Nand Flash支持见第七部分的第3节.
3.2.8重新编译u-boot
[uboot@localhost uboot1.1.4]make CROSS_COMPILE=armlinux3.2.9
把u-boot烧入flash
1. 通过仿真器烧入uboot
通过仿真器uboot
烧写到flash中就可以从NAND flash启动了.
2. 通过JTAG接口,由工具烧入flash
4 U-BOOT命令的使用
4.1 U-BOOT命令的介绍
UBOOT
常用命令
通常使用help(或者只使用问号?),来查看所有的UBOOT
命令。将会列出在当前配置下所有支持的命令。
但是我们要注意,尽管UBOOT
提供了很多配置选项,并不是所有选项都支持各种处理器和开发板,有些选项
可能在你的配置中并没有被选上。
4.1.1 获得帮助信息
通过help可以获得当前开发板的UBOOT
中支持的命令.
CRANE2410 # help
? - alias for 'help'
autoscr - run script from memory
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
bootelf - Boot from an ELF image in memory
bootm - boot application image from memory
bootp - boot image via network using BootP/TFTP protocol
bootvx - Boot vxWorks from an ELF image
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
date - get/set/reset date & time
dcache - enable or disable data cache
echo - echo args to console
erase - erase FLASH memory
flinfo - print FLASH memory information
go - start application at address 'addr'
help - print online help
icache - enable or disable instruction cache
iminfo - print header information for application image
imls - list all images found in flash
itest - return true/false on integer compare
loadb - load binary file over serial line (kermit mode)
loads - load S-Record file over serial line
loop - infinite loop on address range
md - memory display
mm - memory modify (auto-incrementing)
mtest - simple RAM test
mw - memory write (fill)
nand - NAND sub-system
nboot - boot from NAND device
nfs - boot image via network using NFS protocol
nm - memory modify (constant address)
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
protect - enable or disable FLASH write protection
rarpboot- boot image via network using RARP/TFTP protocol
reset - Perform RESET of the CPU
run - run commands in an environment variable
saveenv - save environment variables to persistent storage
setenv - set environment variables
sleep - delay execution for some time
tftpboot- boot image via network using TFTP protocol
version - print monitor version
4.2 常用命令使用说明
4.2.1 askenv(F)
在标准输入(stdin)获得环境变量。
4.2.2 autoscr
从内存(Memory)运行教本。(注意,从下载地址开始,例如我们的开发板是从0x30008000处开始运
行).
CRANE2410 # autoscr 0x30008000
## Executing script at 30008000
4.2.3 base
打印或者设置当前指令与下载地址的地址偏移。
4.2.4 bdinfo
打印开发板信息
CRANE2410 # bdinfo
-arch_number = 0x000000C1 (CPU体系结构号)
-env_t = 0x00000000 (环境变量)
-boot_params = 0x30000100 (启动引导参数)
-DRAM bank = 0x00000000 (内存区)
--> start = 0x30000000 (SDRAM起始地址)
--> size = 0x04000000 (SDRAM大小)
-ethaddr = 01:23:45:67:89:AB (以太网地址)
-ip_addr = 192.168.1.5 (IP地址)
-baudrate = 115200 bps (波特率)
4.2.5 bootp
通过网络使用Bootp或者TFTP协议引导境像文件。
CRANE2410 # help bootp
bootp [loadAddress] [bootfilename]
4.2.6 bootelf
默认从0x30008000引导elf格式的文件(vmlinux)
CRANE2410 # help bootelf
bootelf [address] - load address of ELF image.
4.2.7 bootd(=boot)
引导的默认命令,即运行U-BOOT中在“include/configs/smdk2410.h” 中设置的“bootcmd” 中
的命令。如下:
#define CONFIG_BOOTCOMMAND "tftp 0x30008000 uImage; bootm 0x30008000";
在命令下做如下试验:
CRANE2410 # set bootcmd printenv
CRANE2410 # boot
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:ab
CRANE2410 # bootd
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:ab
4.2.8 tftp(tftpboot)
即将内核镜像文件从PC中下载到SDRAM的指定地址,然后通过bootm来引导内核,前提是所用PC要安装设
置tftp服务。
下载信息:
CRANE2410 # tftp 0x30008000 zImage
TFTP from server 10.0.0.1; our IP address is 10.0.0.110
Filename 'zImage'.
Load address: 0x30008000
Loading: #################################################################
#################################################################
#################################################
done
Bytes transferred = 913880 (df1d8 hex)
4.2.9 bootm
内核的入口地址开始引导内核。
CRANE2410 # bootm 0x30008000
## Booting image at 30008000 ...
Starting kernel ...
Uncompressing
Linux......................................................................
done, .
4.2.10 go
直接跳转到可执行文件的入口地址,执行可执行文件。
CRANE2410 # go 0x30008000
## Starting application at 0x30008000 ...
4.2.11 cmp
对输入的两段内存地址进行比较。
CRANE2410 # cmp 0x30008000 0x30008040 64
word at 0x30008000 (0xe321f0d3) != word at 0x30008040 (0xc022020c)
Total of 0 words were the same
CRANE2410 # cmp 0x30008000 0x30008000 64
Total of 100 words were the same
4.2.12 coninfo
打印所有控制设备和信息,例如
-List of available devices:
-serial 80000003 SIO stdin stdout stderr
4.2.13 cp
内存拷贝,cp 源地址 目的地址 拷贝大小(字节)
CRANE2410 # help cp
cp [.b, .w, .l] source target count
ANE2410 # cp 0x30008000 0x3000f000 64
4.2.14 date
获得/设置/重设日期和时间
CRANE2410 # date
Date: 2006-6-6 (Tuesday) Time: 06:06:06
4.2.15 erase(F)
擦除FLASH MEMORY, 由于该ARM板没有Nor Flash, 所有不支持该命令.
CRANE2410 # help erase
erase start end
- erase FLASH from addr 'start' to addr 'end'
erase start +len
- erase FLASH from addr 'start' to the end of sect w/addr 'start'+'len'-1
erase N:SF[-SL]
- erase sectors SF-SL in FLASH bank # N
erase bank N
- erase FLASH bank # N
erase all
- erase all FLASH banks
4.2.16 flinfo(F)
打印Nor Flash信息, 由于该ARM板没有Nor Flash, 所有不支持该命令.
4.2.17 iminfo
打印和校验内核镜像头, 内核的起始地址由CFG_LOAD_ADDR指定:
#define CFG_LOAD_ADDR 0x30008000 /* default load address */
该宏在include/configs/crane2410.h中定义.
CRANE2410 # iminfo
## Checking Image at 30008000 ...
Image Name: Linux-2.6.14.1
Created: 2006-06-28 7:43:01 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1047080 Bytes = 1022.5 kB
Load Address: 30008000
Entry Point: 30008040
Verifying Checksum ... OK
4.2.18 loadb
从串口下载二进制文件
CRANE2410 # loadb
## Ready for binary (kermit) download to 0x30008000 at 115200 bps...
## Total Size = 0x00000000 = 0 Bytes
## Start Addr = 0x30008000
4.2.19 md
显示指定内存地址中的内容
CRANE2410 # md 0
00000000: ea000012 e59ff014 e59ff014 e59ff014 ................
00000010: e59ff014 e59ff014 e59ff014 e59ff014 ................
00000020: 33f80220 33f80280 33f802e0 33f80340 ..3...3...3@..3
00000030: 33f803a0 33f80400 33f80460 deadbeef ...3...3`..3....
00000040: 33f80000 33f80000 33f9c0b4 33fa019c ...3...3...3...3
00000050: e10f0000 e3c0001f e38000d3 e129f000 ..............).
00000060: e3a00453 e3a01000 e5801000 e3e01000 S...............
00000070: e59f0444 e5801000 e59f1440 e59f0440 D.......@...@...
00000080: e5801000 e59f043c e3a01003 e5801000 ....<...........
00000090: eb000051 e24f009c e51f1060 e1500001 Q.....O.`.....P.
000000a0: 0a000007 e51f2068 e51f3068 e0432002 ....h ..h0... C.
000000b0: e0802002 e8b007f8 e8a107f8 e1500002 . ............P.
000000c0: dafffffb e51f008c e2400803 e2400080 ..........@...@.
000000d0: e240d00c e51f0094 e51f1094 e3a02000 ..@.......... ..
000000e0: e5802000 e2800004 e1500001 dafffffb . ........P.....
000000f0: eb000006 e59f13d0 e281f000 e1a00000 ................
4.2.20 mm
顺序显示指定地址往后的内存中的内容,可同时修改,地址自动递增。
CRANE2410 # mm 0x30008000
30008000: e1a00000 ? fffff
30008004: e1a00000 ? eeeeee
30008008: e1a00000 ? q
CRANE2410 # md 30008000
30008000: 000fffff 00eeeeee e1a00000 e1a00000 ................
30008010: e1a00000 e1a00000 e1a00000 e1a00000 ................
30008020: ea000002 016f2818 00000000 000df1d8 .....(o.........
30008030: e1a07001 e3a08000 e10f2000 e3120003 .p....... ......
4.2.21 mtest
简单的RAM检测
CRANE2410 # mtest
Pattern FFFFFFFD Writing... Reading...
4.2.22 mw
向内存地址写内容
CRANE2410 # md 30008000
30008000: ffffdffd ffffdffc ffffdffb ffffdffa ................
CRANE2410 # mw 30008000 0 4
CRANE2410 # md 30008000
30008000: 00000000 00000000 00000000 00000000 ................
4.2.23 nm
修改内存地址, 地址不递增
CRANE2410 # nm 30008000
30008000: de4c457f ? 00000000
30008000: 00000000 ? 11111111
30008000: 11111111 ?
4.2.24 printenv
打印环境变量
CRANE2410 # printenv
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:ab
ipaddr=10.0.0.110
serverip=10.0.0.1
netmask=255.255.255.0
stdin=serial
stdout=serial
stderr=serial
Environment size: 153/65532 bytes
4.2.25 ping
ping主机
CRANE2410 # ping 10.0.0.1
host 10.0.0.1 is alive
4.2.26 reset
复位CPU
4.2.27 run
运行已经定义好的U-BOOT的命令
CRANE2410 # set myenv ping 10.0.0.1
CRANE2410 # run myenv
host 10.0.0.1 is alive
4.2.28 saveenv(F)
保存设定的环境变量
4.2.29 setenv
设置环境变量
CRANE2410 # setenv ipaddr 10.0.0.254
CRANE2410 # printenv
ipaddr=10.0.0.254
4.2.30 sleep
命令延时执行时间
CRANE2410 # sleep 1
4.2.31 version
打印U-BOOT版本信息
CRANE2410 # version
U-Boot 1.1.4 (Jul 4 2006 - 12:42:27)
4.2.32 nand info
打印nand flash信息
CRANE2410 # nand info
Device 0: Samsung K9F1208U0B at 0x4e000000 (64 MB, 16 kB sector)
4.2.33 nand device <n>
显示某个nand设备
CRANE2410 # nand device 0
Device 0: Samsung K9F1208U0B at 0x4e000000 (64 MB, 16 kB sector)
... is now current device
4.2.34 nand bad
CRANE2410 # nand bad
Device 0 bad blocks:
4.2.35 nand read
nand read InAddr FlAddr size
InAddr: 从nand flash中读到内存的起始地址。
FlAddr: nand flash 的起始地址。
size: 从nand flash中读取的数据的大小。
CRANE2410 # nand read 0x30008000 0 0x100000
NAND read: device 0 offset 0, size 1048576 ...
1048576 bytes read: OK
4.2.36 nand erease
nand erase FlAddr size
FlAddr: nand flash 的起始地址
size: 从nand flash中擦除数据块的大小
CRANE2410 # nand erase 0x100000 0x20000
NAND erase: device 0 offset 1048576, size 131072 ... OK
4.2.37 nand write
nand write InAddr FlAddr size
InAddr: 写到Nand Flash中的数据在内存的起始地址
FlAddr: Nand Flash的起始地址
size: 数据的大小
CRANE2410 # nand write 0x30f00000 0x100000 0x20000
NAND write: device 0 offset 1048576, size 131072 ...
131072 bytes written: OK
4.2.37 nboot
u-boot-1.1.4代码对于nboot命令的帮助不正确,修改如下:
正确的顺序为:
nboot InAddr dev FlAddr
InAddr: 需要装载到的内存的地址。
FlAddr: 在nand flash上uImage存放的地址
dev: 设备号
需要提前设置环境变量,否则nboot不会调用bootm
CRANE2410 #setenv autostart yes
CRANE2410 # nboot 30008000 0 100000
Loading from device 0: <NULL> at 0x4e000000 (offset 0x100000)
Image Name: Linux-2.6.14.3
Created: 2006-07-06 7:31:52 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 897428 Bytes = 876.4 kB
Load Address: 30008000
Entry Point: 30008040
Automatic boot of image at addr 0x30008000 ...
## Booting image at 30008000 ...
Starting kernel ...
4.3 命令简写说明
所以命令都可以简写,只要命令前面的一部分不会跟其它命令相同,就可以不用写全整个命令.
save命令
CRANE2410 # sa
Saving Environment to Flash...
Un-Protected 1 sectors
Erasing Flash...Erasing sector 10 ... Erased 1 sectors
4.4 把文件写入NandFlash
如果把一个传到内存中的文件写入到Nand Flash中, 如:新的uboot.bin, zImage(内核),
rootfs等, 如果做呢?我们可以用Nand Flash命令来完成. 但是Nand Flash写时,必须先要把Nand
Flash的写入区全部擦除后,才能写. 下面以把内存0x30008000起长度为0x20000的内容写到Nand
Flash中的0x100000为例.
CRANE2410 # nand erase 0x100000 20000
NAND erase: device 0 offset 1048576, size 131072 ... OK
CRANE2410 # nand write 0x30008000 0x100000 0x20000
NAND write: device 0 offset 1048576, size 131072 ...
131072 bytes written: OK
5 参考资料
1. uboot
在s3c2410开发板上移植(NAND Flash Boot)过程
http://dev.csdn.net/article/84/84538.shtm
第五部分 linux 2.6内核的移植
1 内核移植过程
1.1 下载linux内核
从http://www.kernel.org/pub/linux/kernel/v2.6/linux2.6.14.1.
tar.bz2
下载linux2.6.14.1
内核至home/arm/dev_home/kernel.
[root@localhost ~]#su arm
[arm@localhost ~]#cd $KERNEL
[arm@localhost kernel]#tar xzvf
linux2.6.14.1.
tar.gz
[arm@localhost kernel]# pwd
/home/arm/dev_home/kernel
[arm@localhost kernel]# cd linux2.6.14
进入内核解压后的目录,以后示例中,只要是相对路径全部是相对于
/home/arm/dev_home/kernel/linux2.6.14/
此目录
1.2 修改Makefile
修改内核目录树根下的的Makefile,指明交叉编译器
[arm@localhost linux2.6.14]#
vi Makefile
找到ARCH和CROSS_COMPILE,修改
ARCH ?= arm
CROSS_COMPILE ?= armlinux
然后设置你的PATH环境变量,使其可以找到你的交叉编译工具链
[arm@localhost linux2.6.14]#
echo $PATH
/usr/local/arm/3.4.4/bin:/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/ly/bin
如果/usr/local/arm/3.4.4/bin搜索路径, 加入下面语句在~/.bashrc中
[arm@localhost linux2.6.14]#
vi ~/.bashrc
export PATH=/usr/local/arm/3.4.4/bin:$PATH
再重新登陆.
[arm@localhost linux2.6.14]#
su arm
1.3 设置flash分区
此处一共要修改3个文件,分别是:
1.3.1指明分区信息
在arch/arm/machs3c2410/
devs.c文件中:
[arm@localhost linux2.6.14]$
vi arch/arm/machs3c2410/
devs.c
添加如下内容:
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <asm/arch/nand.h>
...
/* NAND Controller */
1.建立Nand Flash分区表
/* 一个Nand Flash总共64MB, 按如下大小进行分区 */
static struct mtd_partition partition_info[] ={
{ /* 1MB */
name: "bootloader",
size: 0x00100000,
offset: 0x0,
},{ /* 3MB */
name: "kernel",
size: 0x00300000,
offset: 0x00100000,
}, { /* 40MB */
name: "root",
size: 0x02800000,
offset: 0x00400000,
}, { /* 20MB */
name: "user",
size: 0x00f00000,
offset: 0x02d00000,
}
};
name: 代表分区名字
size: 代表flash分区大小(单位:字节)
offset: 代表flash分区的起始地址(相对于0x0的偏移)
目标板计划分4个区,分别存放bootloader, kernel, rootfs以及以便以后扩展使用的用户文件系统空间。
各分区在Nand flash中起始地址. 分区大小. 记录如下:
bootloader:
start: 0x00000000
len: 0x00100000
1MB
kernel:
start: 0x00100000
len: 0x00300000
3MB
rootfs:
start: 0x00400000
len: 0x02800000
40MB
User:
start: 0x02c00000
len: 0x01400000
20MB
2. 加入Nand Flash分区
struct s3c2410_nand_set nandset ={
nr_partitions: 4, /* the number of partitions */
partitions: partition_info, /* partition table */
};
nr_partitions: 指明partition_info中定义的分区数目
partitions: 分区信息表
3. 建立Nand Flash芯片支持
struct s3c2410_platform_nand superlpplatform={
tacls:0,
twrph0:30,
twrph1:0,
sets: &nandset,
nr_sets: 1,
};
tacls, twrph0, twrph1的意思见S3C2410手册的63,
这3个值最后会被设置到NFCONF中,见S3C2410手册66.
sets: 支持的分区集
nr_set:分区集的个数
4. 加入Nand Flash芯片支持到Nand Flash驱动
另外,还要修改此文件中的s3c_device_nand结构体变量,添加对dev成员的赋值
struct platform_device s3c_device_nand = {
.name = "s3c2410nand",
/* Device name */
.id = 1,
/* Device ID */
.num_resources = ARRAY_SIZE(s3c_nand_resource),
.resource = s3c_nand_resource, /* Nand Flash Controller Registers */
/* Add the Nand Flash device */
.dev = {
.platform_data = &superlpplatform
}
};
name: 设备名称
id: 有效设备编号,如果只有唯一的一个设备为1,
有多个设备从0开始计数.
num_resource: 有几个寄存器区
resource: 寄存器区数组首地址
dev: 支持的Nand Flash设备
1.3.2 指定启动时初始化
kernel启动时依据我们对分区的设置进行初始配置
修改arch/arm/machs3c2410/
machsmdk2410.
c文件
[arm@localhost linux2.6.14]$
vi arch/arm/machs3c2410/
machsmdk2410.
c
修改smdk2410_devices[].指明初始化时包括我们在前面所设置的flash分区信息
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
/* 添加如下语句即可 */
&s3c_device_nand,
};
保存,退出。
1.3.3 禁止Flash ECC校验
我们的内核都是通过UBOOT写到Nand Flash的, UBOOT通过的软件ECC算法产生ECC校验码, 这与内核
校验的ECC码不一样, 内核中的ECC码是由S3C2410中Nand Flash控制器产生的. 所以, 我们在这里选择禁止
内核ECC校验.
修改drivers/mtd/nand/s3c2410.c 文件:
[arm@localhost linux2.6.14]$
vi drivers/mtd/nand/s3c2410.c
找到s3c2410_nand_init_chip()函数,在该函数体最后加上一条语句:
chip>
eccmode = NAND_ECC_NONE;
保存,退出。
OK.我们的关于flash分区的设置全部完工.
1.4 配置内核
1.4.1 支持启动时挂载devfs
为了我们的内核支持devfs以及在启动时并在/sbin/init运行之前能自动挂载/dev为devfs文件系统,修改
fs/Kconfig文件
[arm@localhost linux2.6.14]$
vi fs/Kconfig
找到menu "Pseudo filesystems"
添加如下语句:
config DEVFS_FS
bool "/dev file system support (OBSOLETE)"
default y
config DEVFS_MOUNT
bool "Automatically mount at boot"
default y
depends on DEVFS_FS
1.4.2配置内核产生.config文件
[arm@localhost linux2.6.14]$
cp arch/arm/configs/smdk2410_defconfig .config
[arm@localhost linux2.6.14]$
make menuconfig
在smdk2410_defconfig基础上,我所增删的内核配置项如下:
Loadable module support >
[*] Enable loadable module support
[*] Automatic kernel module loading
System Type >
[*] S3C2410 DMA support
Boot options >
Default kernel command string:
noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200
#说明:mtdblock2代表我的第3个flash分区,它是我的rootfs
# console=ttySAC0,115200使kernel启动期间的信息全部输出到串口0上.
# 2.6内核对于串口的命名改为ttySAC0,但这不影响用户空间的串口编程。
# 用户空间的串口编程针对的仍是/dev/ttyS0等
Floating point emulation >
[*] NWFPE math emulation
This is necessary to run most binaries!!!
#接下来要做的是对内核MTD子系统的设置
Device Drivers >
Memory Technology Devices (MTD) >
[*] MTD partitioning support
#支持MTD分区,这样我们在前面设置的分区才有意义
[*] Command line partition table parsing
#支持从命令行设置flash分区信息,灵活
RAM/ROM/Flash chip drivers >
<*> Detect flash chips by Common Flash
Interface (CFI) probe
<*> Detect nonCFI
AMD/JEDECcompatible
flash chips
<*> Support for Intel/Sharp flash chips
<*> Support for AMD/Fujitsu flash chips
<*> Support for ROM chips in bus mapping
NAND Flash Device Drivers >
<*> NAND Device Support
<*> NAND Flash support for S3C2410/S3C2440 SoC
Character devices >
[*] Nonstandard
serial port support
[*] S3C2410 RTC Driver
#接下来做的是针对文件系统的设置,本人实验时目标板上要上的文件系统是cramfs,故做如下配置
File systems >
<> Second extended fs support #去除对ext2的支持
Pseudo filesystems >
[*] /proc file system support
[*] Virtual memory file system support (former shm fs)
[*] /dev file system support (OBSOLETE)
[*] Automatically mount at boot (NEW)
#这里会看到我们前先修改fs/Kconfig的成果,devfs已经被支持上了
Miscellaneous filesystems >
<*> Compressed ROM file system support (cramfs)
#支持cramfs
Network File Systems >
<*> NFS file system support
保存退出,产生.config文件.
.config文件能从提供的2.4.14.1的内核包中找到,文件名为config.back.
1.4.3编译内核
[arm@localhost linux2.6.14]$
make zImage
注意:若编译内核出现如下情况
LD .tmp_vmlinux1
armlinuxld:
arch/arm/kernel/vmlinux.lds:1439: parse error
make: *** [.tmp_vmlinux1] Error 1
解决方法:修改arch/arm/kernel/vmlinux.lds
[arm@localhost linux2.6.14]$
vi arch/arm/kernel/vmlinux.lds
将文件尾2条的ASSERT注释掉(1439行)
/* ASSERT((__proc_info_end __
proc_info_begin), "missing CPU support") */
/* ASSERT((__arch_info_end __
arch_info_begin), "no machine record defined") */
然后重新make zImage即可
1.4.4 下载zImage到开发板
CRANE2410 # tftp 0x30008000 zImage
TFTP from server 192.168.1.6; our IP address is 192.168.1.5
Filename 'zImage'.
Load address: 0x30008000
Loading: #################################################################
#################################################################
#################################################################
#############################
done
Bytes transferred = 1142856 (117048 hex)
CRANE2410 # bootm 0x30008000
1.4.5 目标板启动信息如下
IRQ Stack: 33fc149c
FIQ Stack: 33fc249c
1
1
DRAM Configuration:
Bank #0: 30000000 64 MB
1
NAND:64 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
zImage magic = 0x016f2818
NOW, Booting Linux......
Uncompressing Linux............................................................................ don.Linux version 2.6.14.1 (arm@dozec) (gcc
version 3.3.2) #15 Thu Jul 6 14:26:29 CST 2006
CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
Machine: SMDK2410
Warning: bad configuration page, trying to continue
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410A (id 0x32410002)
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz
S3C2410 Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
CPU0: D VIVT writeback
cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists
Kernel command line: noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200
irq: clearing subpending status 00000002
PID hash table entries: 128 (order: 7, 2048 bytes)
timer tcon=00500000, tcnt a509, tcfg 00000200,00000000, usec 00001e4c
Console: colour dummy device 80x30
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inodecache
hash table entries: 2048 (order: 1, 8192 bytes)
Memory: 16MB = 16MB total
Memory: 13712KB available (1927K code, 422K data, 104K init)
Mountcache
hash table entries: 512
CPU: Testing write buffer coherency: ok
softlockup thread 0 started up.
NET: Registered protocol family 16
S3C2410: Initialising architecture
SCSI subsystem initialized
usbcore: registered new driver usbfs
usbcore: registered new driver hub
S3C2410 DMA Driver, (c) 20032004
Simtec Electronics
DMA channel 0 at c1800000, irq 33
DMA channel 1 at c1800040, irq 34
DMA channel 2 at c1800080, irq 35
DMA channel 3 at c18000c0, irq 36
NetWinder Floating Point Emulator V0.97 (double precision)
devfs: 20040131
Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
Console: switching to colour frame buffer device 80x25
fb0: Virtual frame buffer device, using 1024K of video memory
S3C2410 RTC, (c) 2004 Simtec Electronics
s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2410
s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2410
s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2410
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
Cirrus Logic CS8900A driver for Linux (Modified for SMDK2410)
eth0: CS8900A rev E at 0xe0000300 irq=53, no eeprom , addr: 08: 0:3E:26:0A:5B
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2410nand:
mapped registers at c1980000
s3c2410nand:
timing: Tacls 10ns, Twrph0 30ns, Twrph1 10ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8bit)
NAND_ECC_NONE selected by board driver. This is not recommended !!
Scanning device for bad blocks
Creating 4 MTD partitions on "NAND 64MiB 3,3V 8bit":
0x000000000x00100000
: "bootloader"
0x001000000x00500000
: "kernel"
0x005000000x02d00000
: "root"
0x02d000000x03c00000
: "User"
usbmon: debugfs is not available
116x: driver isp116xhcd,
05 Aug 2005
s3c2410ohci
s3c2410ohci:
S3C24XX OHCI
s3c2410ohci
s3c2410ohci:
new USB bus registered, assigned bus number 1
s3c2410ohci
s3c2410ohci:
irq 42, io mem 0x49000000
usb usb1: Product: S3C24XX OHCI
usb usb1: Manufacturer: Linux 2.6.14.1 ohci_hcd
usb usb1: SerialNumber: s3c24xx
hub 10:
1.0: USB hub found
hub 10:
1.0: 2 ports detected
sl811: driver sl811hcd,
19 May 2005
usbcore: registered new driver cdc_acm
drivers/usb/class/cdcacm.
c: v0.23:USB Abstract Control Model driver for USB modems and ISDN
adaptesdrivers/usb/class/bluetty.c: USB Bluetooth support registered
usbcore: registered new driver bluetty
drivers/usb/class/bluetty.c: USB Bluetooth tty driver v0.13
usbcore: registered new driver usblp
drivers/usb/class/usblp.c: v0.13: USB Printer Device Class driver
Initializing USB Mass Storage driver...
usbcore: registered new driver usbstorage
USB Mass Storage support registered.
mice: PS/2 mouse device common for all mice
NET: Registered protocol family 2
IP route cache hash table entries: 256 (order: 2,
1024 bytes)
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
TCP reno registered
TCP bic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
Reading data from NAND FLASH without ECC is not recommended
VFS: Mounted root (cramfs filesystem) readonly.
Mounted devfs on /dev
Freeing init memory: 104K
Reading data from NAND FLASH without ECC is not recommended
mount /etc as ramfs
recreate
the /etc/mtab entries
mount
/dev/shm as tmpfs
mount
/proc as proc
mount
/sys as sysfs
init started: BusyBox v1.1.3 (2006.07.0303:
43+0000) multicall
binary
Starting pid 28, console /dev/tts/0: '/etc/init.d/rcS'
in /etc/init.d/rcS
/
sbin/ifconfig eth0 192.168.1.5
Please press Enter to activate this console.
#
1.5 Linux 下cs8900a的移植说明
1.5.1 为cs8900a建立编译菜单
1. 拷贝到文件
把cs8900a的压缩包拷贝到arm用户下的dev_home/localapps/
[arm@localhost localapps]$ tar xzvf
cs8900a.tar.gz
[arm@localhost localapps]$cd cs8900a
[arm@localhost cs8900a]$cp cs8900a.c $KERNEL/linux2.6.14.1/
drivers/net/
[arm@localhost cs8900a]$cp cs8900.h $KERNEL/linux2.6.14.1/
drivers/net/
2. 修改Kconfig文件
[arm@localhost cs8900a]$vi $KERNEL/linux2.6.14.1/
drivers/net/Kconfig
#加入如下内容
config CS8900a
tristate "CS8900a support"
depends on NET_ETHERNET && ARM && ARCH_SMDK2410
helpSupport
for CS8900A chipset based Ethernet cards. If you have a network (Ether
net) card of this type, say Y and read the EthernetHOWTO,
available from as
well as.
To compile this driver as a module, choose M here and read.
The module will be called cs8900.o.
3. 修改Makefile文件
[arm@localhost cs8900a]$vi $KERNEL/linux2.6.14.1/
drivers/net/Makefile
#加入如下内容
obj$(
CONFIG_CS8900a) += cs8900a.o
1.5.2 修改S3C2410相关信息
1. 加入CS8900A在内存中的起始位置
[arm@localhost cs8900a]$cp regcs8900.
h $KERNEL/linux2.6.14.1/
include/asmarm/
archs3c2410/
cs8900.h的内容如下:
#ifndef _INCLUDE_CS8900A_H_
#define _INCLUDE_CS8900A_H_
#include <linux/config.h>
#define pSMDK2410_ETH_IO 0x19000000 /* S3C2410_CS3 0x18000000 */
#define vSMDK2410_ETH_IO 0xE0000000
#define SMDK2410_ETH_IRQ IRQ_EINT9
#endif
2. 加入cs8900A的物理地址到虚拟地址的映射
[arm@localhost cs8900a]$vi $KERNEL/linux2.6.14.1/
arch/arm/machs3c2410/
machsmdk2410.
c
/* 加入如下内容 */
static struct map_desc smdk2410_iodesc[] __initdata = {
{vSMDK2410_ETH_IO, 0x19000000, SZ_1M, MT_DEVICE} /* Add this line */
};
2 创建uImage
2.1 相关技术背景介绍
前面已经介绍了内核编译后,生成zImage的内核镜像文件。该镜像文件可以通过UBOOT
提供的go命令,
跳转执行,引导内核。同时在uboot1.1.4
的tools目录下,提供了生成uImage的工具mkimage命令,在生成
uboot
的二进制镜像文件的同时,mkimage命令会同时编译生成,无需另外编译。通过mkimage命令,在
zImage中加入头文件(镜像头长0x40,真正的内核入口向后偏移了0x40大小),生成uImage镜像文件,该文
件就是执行bootm所需的内核镜像文件。
2.2 在内核中创建uImage的方法
2.2.1 获取mkimage工具
2.6内核树的Makefile提供了创建uImage的方法,但需要我们提供相应的mkimage命令。
所以首先拷贝uboot
中tools目录下编译后生成的mkimage到/usr/bin/下,然后便可以在内核根目录下通过
make uImage
来创建uImage文件。该文件生成在arch/arm/boot/下。
2.2.2 修改内核的Makefile文件
[arm@localhost linux2.6.14.1]$
vi arch/arm/boot/Makefile
#MKIMAGE变量记录mkimage命令的路径mkuboot.sh脚本文件可以scripts目录中找到
MKIMAGE := $(srctree)/scripts/mkuboot.sh
#zreladdry
与params_physy
可以在arch/arm/machs3c2410/
Makefile.boot当中找到
ZRELADDR := $(zreladdry)
PARAMS_PHYS := $(params_physy)
INITRD_PHYS := $(initrd_physy)
#生成uImage的mkImage命令行,其中需要关注的就是a
与 e
参数。
#参数a:
指明uImage加载的SDRAM地址,内核默认指定加载地址为0x30008000。
# uboot
引导时,bootm命令跳到与上相同位置执行,检查完镜像头后,它会跳到内核真正的入口点开
始执行。
#参数e:
指明uImage中刨去镜像头后真正的内核入口地址。
# 镜像头为0x40长,故此处指定为0x30008040。
# uboot
引导时,go命令可以直接指定此位置。go命令不检查镜像头。
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) A
arm O
linux T
kernel /
C
none a
$(ZRELADDR) e
0x30008040 /
n
'Linux$(
KERNELRELEASE)' d
$< $@
3追加实验记录
以同样方式移植其他2.6主线内核,出现问题如下:
3.1移植linux-2.6.15.7
编译通过,启动时显示:
VFS: Cannot open root device "mtdblock2" or unknownblock(
31,2)
Please append a correct "root=" boot option
Kernel panic not
syncing: VFS: Unable to mount root fs on unknownblock(
31,2)
3.2移植linux-2.6.16.21
编译通过,启动时显示:
VFS: Cannot open root device "mtdblock2" or unknownblock(
31,2)
Please append a correct "root=" boot option
Kernel panic not
syncing: VFS: Unable to mount root fs on unknownblock(
31,2)
3.3 移植linux-2.6.17
编译失败
4 参考资料
1. Porting kernel 2.6.11.7 to S3C2410
http://superlp.blogchina.com/1391393.html
非常感谢此篇文档的作者
2. devfs介绍
http://www128.
ibm.com/developerworks/cn/linux/filesystem/lfs4/
index.html#resources
3. <<BUILDING EMBEDDED LINUX SYSTEMS>>
中文名:<<构建嵌入式Linux系统>>
第六部分 应用程序的移植
1构造目标板的根目录及文件系统
1.1 建立一个目标板的空根目录
我们将在这里构建构建根文件系统,创建基础目录结构. 存放交叉编译后生成的目标应用程序
(BUSYBOX,TINYLOGIN),存放库文件等。
[arm@localhost rootfs]# mkdir my_rootfs
[arm@localhost rootfs]# pwd
/home/arm/dev_home/rootfs/my_rootfs
[arm@localhost rootfs]# cd my_rootfs
[arm@localhost my_rootfs]#
1.2 在my_rootfs中建立Linux目录树
[arm@localhost my_rootfs]#mkdir bin dev etc home lib mnt proc sbin sys tmp root usr
[arm@localhost my_rootfs]#mkdir mnt/etc
[arm@localhost my_rootfs]#mkdir usr/bin usr/lib usr/sbin
[arm@localhost my_rootfs]#touch linuxrc
[arm@localhost my_rootfs]#tree
|bin
|dev
|etc
|home
|lib
|linuxrc
/* 此文件为启动脚本,是一shell脚本文件。本文后面有专门介绍 */
|mnt
| `etc
|proc
|sbin
|sys
|tmp
|root
`usr
|bin
|lib
`sbin
权限参照你的linux工作站即可,基础目录介绍参见本文参考资料(未尾)。
需要说明的一点就是etc目录存放配置文件,这个目录通常是需要修改的,所以在linuxrc脚本当中将etc目录
挂载为ramfs文件系统,然后将mnt/etc目录中的所有配置文件拷贝到etc目录当中,这在下一节的linuxrc脚本
文件当中会有体现。
1.3 创建linuxrc文件
1. 创建linuxrc,加入如下内容:
[arm@localhost my_rootfs]#vi linuxrc
#!/bin/sh
#挂载/etc为ramfs, 并从/mnt/etc下拷贝文件到/etc目录当中
echo "mount /etc as ramfs"
/bin/mount n
t
ramfs ramfs /etc
/bin/cp a
/mnt/etc/* /etc
echo "recreate
the /etc/mtab entries"
# recreate
the /etc/mtab entries
/bin/mount f
t
cramfs o
remount,ro /dev/mtdblock/2 /
#mount some file system
echo "mount
/dev/shm as tmpfs"
/bin/mount n
t
tmpfs tmpfs /dev/shm
#挂载/proc为proc文件系统
echo "mount
/proc as proc"
/bin/mount n
t
proc none /proc
#挂载/sys为sysfs文件系统
echo "mount
/sys as sysfs"
/bin/mount n
t
sysfs none /sys
exec /sbin/init
2. 修改权限
[arm@localhost my_rootfs]#chmod 775 linuxrc
[arm@localhost my_rootfs]#ls linuxrc al
rwxrwxrx
1 root root 533 Jun 4 11:19 linuxrc
当编译内核时,指定命令行参数如下
Boot options >
Default kernel command string: 我的命令行参数如下
noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200
其中的init指明kernel执行后要加载的第一个应用程序,缺省为/sbin/init,此处指定为/linuxrc
2 移植Busybox
2.1 下载busybox
从http://www.busybox.net/downloads/busybox1.1.3.
tar.gz/下载busybox1.1.3
到/tmp目录当中,并解压.
2.2 进入解压后的目录,配置Busybox
[arm@localhost busybox1.1.3]$
make menuconfig
Busybox Settings >
General Configuration >
[*] Support for devfs
Build Options >
[*] Build BusyBox as a static binary (no shared libs)
/* 将busybox编译为静态连接,少了启动时找动态库的麻烦 */
[*] Do you want to build BusyBox with a Cross Compiler?
(/usr/local/arm/3.3.2/bin/armlinux)
Cross Compiler prefix
/* 指定交叉编译工具路径 */
Init Utilities >
[*] init
[*] Support reading an inittab file
/* 支持init读取/etc/inittab配置文件,一定要选上 */
Shells >
Choose your default shell (ash) >
/* (X) ash 选中ash,这样生成的时候才会生成bin/sh文件
* 看看我们前头的linuxrc脚本的头一句:
* #!/bin/sh 是由bin/sh来解释执行的
*/
[*] ash
Coreutils >
[*] cp
[*] cat
[*] ls
[*] mkdir
[*] echo (basic SuSv3 version taking no options)
[*] env
[*] mv
[*] pwd
[*] rm
[*] touch
Editors >
[*] vi
Linux System Utilities >
[*] mount
[*] umount
[*] Support loopback mounts
[*] Support for the old /etc/mtab file
Networking Utilities >
[*] inetd
/*
* 支持inetd超级服务器
* inetd的配置文件为/etc/inetd.conf文件,
* "在该部分的4: 相关配置文件的创建"一节会有说明
*/
2.3 编译并安装Busybox
[arm@localhost busybox1.1.3]$
make TARGET_ARCH=arm CROSS=armlinux/
PREFIX=/home/arm/dev_home/rootfs/my_rootfs/ all install
PREFIX指明安装路径:就是我们根文件系统所在路径。
*这里需要注意一点的是,只要install busybox,我们根文件系统下先前建好的linuxrc就会被覆盖为一同名二进
制文件。
所以要事先备份我们自己的linuxrc,在安装完busybox后,将linuxrc复制回去就好。
3 移植TinyLogin
3.1 下载
从http://tinylogin.busybox.net/downloads/tinylogin1.4.
tar.bz2 下载tinylogin1.4
到/tmp目录当中,并解压.
3.2 修改tinyLogin的Makefile
[arm@localhost tinylogin1.4]$
vi Makefile
修改记录如下:
指明静态编译,不连接动态库
DOSTATIC = true
指明tinyLogin使用自己的算法来处理用户密码
USE_SYSTEM_PWD_GRP = false
USE_SYSTEM_SHADOW = false
3.3 编译并安装
[root@localhost tinylogin1.4]#
make CROSS=armlinuxPREFIX=/
home/arm/dev_home/rootfs/my_rootfs all install
PREFIX指明根文件路径
4 相关配置文件的创建
进入mnt/etc中, 这里是我们存放配置文件的路径
[arm@localhost my_rootfs]$ cd mnt/etc
4.1 创建帐号及密码文件
[arm@localhost etc]$ cp /etc/passwd .
[arm@localhost etc]$ cp /etc/shadow .
[arm@localhost etc]$ cp /etc/group .
这3个文件是从你工作站当中拷贝过来的,删除其中绝大部分不需要的用户,经过删减后的上述3个文件如下。
那么现在root的登陆密码
和你工作站上的登陆口令一致了,这可能透露你工作站的信息
[arm@localhost etc]$ cat passwd
root:x:0:0:root:/root:/bin/sh /* 改为/bin/sh */
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[arm@localhost etc]$ cat shadow
root:$1$2LG20u89$UCEEUzBhElYpKMNZQPU.e1:13303:0:99999:7:::
bin:*:13283:0:99999:7:::
daemon:*:13283:0:99999:7:::
[arm@localhost etc]$ cat group
root:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
4.2 创建profile文件
[arm@localhost etc]$ vi profile
# Set search library path
# 这条语句设置动态库的搜索路径,极其重要!!!
echo "Set search library path int /etc/profile"
export LD_LIBRARY_PATH=/lib:/usr/lib
# Set user path
echo "Set user path in /etc/profile"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
4.4 创建fstab文件
[arm@localhost etc]$ vi fstab
none /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
tmpfs /dev/shm tmpfs defaults 0 0
4.5 创建inetd.conf配置文件
此处只是一个经过修改的示例配置文件,用于代理监听telnetd的23端口。
读者可以根据自己需求进行修改。该配置文件可以从busybox的examples目录中获得
[arm@localhost etc]$ vi inetd.conf
# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
#ftp stream tcp nowait root /usr/sbin/ftpd
telnet stream tcp nowait root /usr/sbin/telnetd
5 移植inetd
5.1 inetd的选择及获取
Busybox1.1.3提供了inetd支持。如果读者使用的是较低版本的不提供inetd的Busybox,那么可以考虑使
用netkit套件来提供网络服务。强烈建议使用高版本的Busybox。此节后半部分介绍如果编译布署netkit当中的
inetd。
5.1.1 获取inetd
Netkit套件可以从ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/下载。
其中netkitbase0.17
中包括inetd程序。下载netkitbase0.17
到/tmp目录并解压。
5.2 编译inetd
5.2.1 修改configure文件
开始配置netkitbase
之前需要先修改configure脚本以免它在主机上执行测试程序。
[arm@localhost netkitbase0.17]#
vi configure
将每一行出现的 ./__conftest || exit 1;
修改成:
# ./__conftest || exit 1;
5.2.2 编译
[arm@localhost netkitbase0.17]$
CC=armlinuxgcc
./configure
[arm@localhost netkitbase0.17]$
make
5.3 配置inetd
5.3.1 拷贝inetd到根文件系统的usr/sbin目录中
[arm@localhost netkitbase0.17]$
cp inetd/inetd /home/arm/dev_home/rootfs/my_rootfs/usr/sbin/
拷贝inetd的配置文件inetd.conf到根文件系统的/mnt/etc目录中
[arm@localhost netkitbase0.17]$
cp etc.sample/inetd.conf /home/arm/dev_home/rootfs/my_rootfs/mnt/etc
5.3.2 根据需要,修改inetd.conf配置文件
例如:支持telnetd的inetd.conf配置文件如下
# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
telnet stream tcp nowait root /usr/sbin/telnetd
5.3.3 拷贝配置文件
etc.sample目录下有许多网络相关配置文件,其中有一些需要拷贝到根文件系统的etc目录当中,记录如下:
[arm@localhost netkitbase0.17]$
cd etc.sample/
[arm@localhost etc.sample]$ cp host.conf /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
[arm@localhost etc.sample]$ cp hosts /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
[arm@localhost etc.sample]$ cp networks /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
[arm@localhost etc.sample]$ cp protocols /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
[arm@localhost etc.sample]$ cp resolv.conf /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
[arm@localhost etc.sample]$ cp services /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
以上重要配置文件说明如下:
host.conf:在系统中同时存在着DNS域名解析和/etc/hosts的主机表机制时,由文件/etc/host.conf来说明了解析器
的查询顺序
hosts:记录主机名到IP地址的映射
protocols:记录常用网络协议及端口别名关系,网络应用程序依赖于此文件
resolv.conf:指定DNS服务器
services:记录知名网络服务及端口,网络编程依赖于此文件
6 移植thttpd Web服务器
6.1 下载
从http://www.acme.com/software/thttpd/ 下载thttpd到/tmp目录当中,并解压.
6.2 编译thttpd
[arm@localhost thttpd2.25b]$
CC=armlinuxgcc
./configure host=
armlinux
[arm@localhost thttpd2.25b]$
vi Makefile
指定静态链接二进制文件
LDFLAGS = static
[arm@localhost thttpd2.25b]$
make LDFLAGS="static"
6.3 配置
6.3.1 拷贝thttpd二进制可执行文件到根文件系统/usr/sbin/目录中
[arm@localhost thttpd2.25b]$
cp thttpd /home/arm/dev_home/rootfs/my_rootfs/usr/sbin/
6.3.2 修改thttpd配置文件
[arm@localhost thttpd2.25b]$
vi contrib/redhatrpm/
thttpd.conf
# This section overrides defaults
dir=/etc/thttpd/html #指明WebServer存放网页的根目录路径
chroot
user=root #以root身份运行thttpd
logfile=/etc/thttpd/log/thttpd.log #日志文件路径
pidfile=/etc/thttpd/run/thttpd.pid #pid文件路径
拷贝thttpd.conf配置文件到根文件系统的mnt/etc/目录,
系统加载后,linuxrc脚本会自动将mnt/etc/下的所有文件拷贝到/etc目录中。
[arm@localhost thttpd2.25b]$
cp contrib/redhatrpm/
thttpd.conf /home/arm/dev_home/rootfs/my_rootfs/mnt/etc/
6.3.3 转移到根文件系统目录,创建相应的文件
[arm@localhost etc]$ cd /home/arm/dev_home/rootfs/my_rootfs
[arm@localhost my_rootfs]$ cd mnt/etc/
创建thttpd目录
[arm@localhost etc]$ mkdir thttpd
[arm@localhost etc]$ cd thttpd
thttpd目录下的目录结构
|html
| `index.
html Web Server网页根目录下的默认HTML文件
|log
| `thttpd.
log 创建一个空文件就可
`run
`thttpd.
pid 创建一个空文件就可
html目录下的index.html文件内容如下:
<html>
<head>
<title> Welcome to here^^ </title>
</head>
<body>
<marquee>
<font color=red>
Welcome to here^^!!!
</font>
</marquee>
</body>
</html>
7 建立根目录文件系统包
7.1 建立CRAMFS包
7.1.1 下载cramfs工具
从http://prdownloads.sourceforge.net/cramfs/cramfs1.1.
tar.gz 下载源代码包.
把下载包拷贝到dev_home/tools下.
[arm@localhost tools]$tar xzvf
cramfs1.1.
tar.gz
[arm@localhost tools]$cd cramfs1.1
[arm@localhost tools]$make
[arm@localhost tools]$su root
[root@localhost tools]$cp mkcramfs /usr/bin
[arm@localhost tools]$exit
注意:如果你的系统中已经安装了mkcramfs工具, 则在/usr/bin目录下是一个软link, 请先删除该文件之后, 再拷
贝该mkcramfs到/usr/bin下.
7.1.2 制作cramfs包
[arm@localhost tools]$mkcramfs my_rootfs my_rootfs.cramfs
7.1.3 写cramfs包到Nand Flash
[arm@localhost tools]$su root
[root@localhost tools]$cp my_rootfs.cramfs /tftpboot/
打开minicom, 进行ARM板的终端模式:
CRANE2410 #
8 参考资料
1. linux目录结构介绍
http://www.uplooking.com/content/view/1487/2/
2. <<BUILDING EMBEDDED LINUX SYSTEMS>>
中文名:<<构建嵌入式Linux系统>>
第七部分 Nand flash驱动的编写与移植
1 Nand flash工作原理
S3C2410板的Nand Flash支持由两部分组成:Nand Flash控制器(集成在S3C2410 CPU)和Nand Flash存储
芯片(K9F1208U0B)两大部分组成。当要访问Nand Flash中的数据时,必须通过Nand Flash控制器发送命
令才能完成。所以, Nand Flash相当于S3C2410的一个外设,而不位于它的内存地址区.
1.1 Nand flash芯片工作原理
Nand flash芯片型号为Samsung K9F1208U0B,数据存储容量为64MB,采用块页式存储管理。8个I/O
引脚充当数据、地址、命令的复用端口。
1.1.1 芯片内部存储布局及存储操作特点
一片Nand flash为一个设备(device), 其数据存储分层为:
1设备(Device) = 4096 块(Blocks)
1块(Block) = 32页/行(Pages/rows) ;页与行是相同的意思,叫法不一样
1块(Page) = 528字节(Bytes) = 数据块大小(512Bytes) + OOB块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于Nand Flash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过Nand Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位通过
Nand Flash内置的指针指向各自的首地址。
存储操作特点:
1. 擦除操作的最小单位是块。
2. Nand Flash芯片每一位(bit)只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前要一定将相应
块擦除(擦除即是将相应块得位全部变为1).
3. OOB部分的第六字节(即517字节)标志是否是坏块,如果不是坏块该值为FF,否则为坏块。
4. 除OOB第六字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC码(关于硬件ECC码请参看
Nandflash 控制器一节).
1.1.2 重要芯片引脚功能
I/O0I/
O7:复用引脚。可以通过它向nand flash芯片输入数据、地址、nand flash命令以及输出数据和操作
状态信息。
CLE(Command Latch Enable): 命令锁存允许
ALE(Address Lactch Enable): 地址锁存允许
CE:
芯片选择
RE:
读允许
WE:
写允许
WP:
在写或擦除期间,提供写保护
R/B:
读/忙输出
1.1.3 寻址方式
Samsung K9F1208U0B Nand Flash 片内寻址采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行
传送,并进行片内寻址。具体含义如下:
0-7位:字节在上半部、下半部及OOB内的偏移地址
8位:值为0代表对一页内前256个字节进行寻址
值为1代表对一页内后256个字节进行寻址
9-13位:对页进行寻址
14-25位:对块进行寻址
当传送地址时,从位0开始
1.1.4 Nand flash主要内设命令详细介绍
Nand Flash命令执行是通过将命令字送到Nand Flash控制器的命令寄存器来执行。
Nand Flash的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周
期将要执行的动作。
主要命令有:Read 1、Read 2、Read ID、Reset、Page Program、Block Erase、Read Status。
详细介绍如下:
1. Read 1:
功能:表示将要读取Nand flash存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。
命令代码:00h
2. Read 2:
功能:表示将要读取Nand flash存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。
命令代码:01h
3. Read ID:
功能:读取Nand flash芯片的ID号
命令代码:90h
4. Reset:
功能:重启芯片。
命令代码:FFh
5. Page Program:
功能:对页进行编程命令, 用于写操作。
命令代码:首先写入00h(A区)/01h(B区)/05h(C区), 表示写入那个区; 再写入80h开始编程模式(写入模式),接
下来写入地址和数据; 最后写入10h表示编程结束.
6. Block Erase
功能:块擦除命令。
命令代码:首先写入60h进入擦写模式,然后输入块地址; 接下来写入D0h, 表示擦写结束.
7. Read Status
功能:读取内部状态寄存器值命令。
命令代码:70h
1.2 Nand Flash 控制器工作原理
对Nand Flash存储芯片进行操作, 必须通过Nand Flash控制器的专用寄存器才能完成。所以,不能对Nand
Flash进行总线操作。而Nand Flash的写操作也必须块方式进行。对Nand Flash的读操作可以按字节读取。
1.2.1 Nand Flash控制器特性
1. 支持对Nand Flash芯片的读、检验、编程控制
2. 如果支持从Nand Flash启动, 在每次重启后自动将前Nand Flash的前4KB数据搬运到ARM的内部RAM中
3. 支持ECC校验
1.2.2 Nand Flash控制器工作原理
Nand Flash控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将Nand
Flash芯片的内设命令写到其特殊功能寄存器中,从而实现对Nand flash芯片读、检验和编程控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。
1.3 Nand flash 控制器中特殊功能寄存器详细介绍
1. 配置寄存器(NFCONF)
功能:用于对Nand Flash控制器的配置状态进行控制。
在地址空间中地址:0x4E000000,其中:
Bit15:Nand Flash控制器使能位,置0代表禁止Nand Flash控制器,置1代表激活Nand Flash控制器;
要想访问Nand Flash芯片上存储空间,必须激活Nand Flash控制器。在复位后该位自动置0,因此在初始化时
必须将该位置为1。
Bit12:初始化ECC位,置1为初始化ECC;置0为不初始化ECC。
Bit11:Nand Flash芯片存储空间使能位,置0代表可以对存储空间进行操作;置1代表禁止对存储空
间进行操作。在复位后,该位自动为1。
Bit10-8:TACLS位。根据此设定CLE&ALE的周期。TACLS的值范围在0-7之间。
Bit6-4、2-0分别为:TWRPH0、TWRPH1位。设定写操作的访问周期。其值在0-7之间。
2. 命令寄存器(NFCMD)
功能:用于存放Nand flash芯片内设的操作命令。
在地址空间中地址:0x4E000004,其中:
Bit0-7:存放具体Nand flash芯片内设的命令值。其余位保留以后用。
3. 地址寄存器(NFADDR)
功能:用于存放用于对Nand flash芯片存储单元寻址的地址值。
在地址空间中地址:0x4E000008,其中:
Bit0-7:用于存放地址值。因为本款Nand flash芯片只有I/O0-7的地址/数据复用引脚且地址是四周
期每次8位送入的,所以这里只用到8位。其余位保留待用。
4. 数据寄存器(NFDATA)
功能:Nand flash芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入Nand flash
存储空间的值也是放到该寄存器。
在地址空间中地址:0x4E00000C,其中:
Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。
5. 状态寄存器(NFSTAT)
功能:用于检测Nand flash芯片上次对其存储空间的操作是否完成。
在地址空间中地址:0x4E000010,其中:
Bit0:置0表示Nand flash芯片正忙于上次对存储空间的操作;置1表示Nand flash芯片准备好接收新
的对存储空间操作的请求。
6. ECC校验寄存器(NFECC)
功能:ECC校验寄存器
在地址空间中地址:0x4E000014,其中:
Bit0Bit7:
ECC0
Bit8Bit15:
ECC1
Bit16Bit23:
ECC2
1.4 Nand Flash 控制器中的硬件ECC介绍
1.4.1 ECC产生方法
ECC是用于对存储器之间传送数据正确进行校验的一种算法,分硬件ECC和软件ECC算法两种,在
S3C2410的Nand Flash 控制器中实现了由硬件电路(ECC 生成器)实现的硬件ECC。
1.4.2 ECC生成器工作过程
当写入数据到Nand flash存储空间时, ECC生成器会在写入数据完毕后自动生成ECC码,将其放入到
ECC0-ECC2。当读出数据时Nand Flash 同样会在读数据完毕后,自动生成ECC码将其放到ECC0-ECC2当
中。
1.4.3 ECC的运用
当写入数据时,可以在每页写完数据后将产生的ECC码放入到OOB指定的位置(Byte 6)去,这样就完成了
ECC码的存储。这样当读出该页数据时,将所需数据以及整个OOB读出,然后将指定位置的ECC码与读出数
据后在ECC0-ECC1的实际产生的ECC码进行对比,如果相等则读出正确,若不相等则读取错误需要进行重
读。
2 在ADS下flash烧写程序
2.1 ADS下flash烧写程序原理及结构
基本原理:在windows环境下借助ADS仿真器将在SDRAM中的一段存储区域中的数据写到Nand flash存
储空间中。烧写程序在纵向上分三层完成:
第一层: 主烧写函数(完成将在SDRAM中的一段存储区域中的数据写到Nand flash存储空间中);
第二层: 为第一层主烧写函数提供支持的对Nand flash进行操作的页读、写,块擦除等函数;
第三层:为第二层提供具体Nand flash控制器中对特殊功能寄存器进行操作的核心函数,该层也是真正的
将数据能够在SDRAM和Nand flash之间实现传送的函数。
下面对其三层进行分述:
2.2 第三层实现说明
2.1.1 特殊功能寄存器定义
#define rNFCONF (*(volatile unsigned int *)0x4e000000)
#define rNFCMD (*(volatile unsigned char *)0x4e000004)
#define rNFADDR (*(volatile unsigned char *)0x4e000008)
#define rNFDATA (*(volatile unsigned char *)0x4e00000c)
#define rNFSTAT (*(volatile unsigned int *)0x4e000010)
#define rNFECC (*(volatile unsigned int *)0x4e000014)
#define rNFECC0 (*(volatile unsigned char *)0x4e000014)
#define rNFECC1 (*(volatile unsigned char *)0x4e000015)
#define rNFECC2 (*(volatile unsigned char *)0x4e000016)
2.1.2 操作的函数实现
1. 发送命令
#define NF_CMD(cmd) {rNFCMD=cmd;}
2. 写入地址
#define NF_ADDR(addr) {rNFADDR=addr;}
3. Nand Flash芯片选中
#define NF_nFCE_L() {rNFCONF&=~(1<<11);}
4. Nand Flash芯片不选中
#define NF_nFCE_H() {rNFCONF|=(1<<11);}
5. 初始化ECC
#define NF_RSTECC() {rNFCONF|=(1<<12);}
6. 读数据
#define NF_RDDATA() (rNFDATA)
7. 写数据
#define NF_WRDATA(data) {rNFDATA=data;}
8. 获取Nand Flash芯片状态
#define NF_WAITRB() {while(!(rNFSTAT&(1<<0)));}
0/假: 表示Nand Flash芯片忙状态
1/真:表示Nand Flash已经准备好
2.3 第二层实现说明
2.3.1 Nand Flash 初始化
void NF_Init(void)
{
/* 设置Nand Flash配置寄存器, 每一位的取值见1.3节 */
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
/* 复位外部Nand Flash芯片 */
NF_Reset();
}
2.3.2 Nand flash复位
static void NF_Reset(void)
{
int i;
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0xFF); /* 复位命令 */
for(i=0;i<10;i++); /* 等待tWB = 100ns. */
NF_WAITRB(); /* wait 200~500us; */
NF_nFCE_H(); /* 取消Nand Flash 选中*/
}
2.3.3 获取Nand flash ID
返回值为Nand flash芯片的ID号
unsigned short NF_CheckId(void)
{
int i;
unsigned short id;
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x90); /* 发送读ID命令到Nand Flash芯片 */
NF_ADDR(0x0); /* 指定地址0x0,芯片手册要求 */
for(i=0;i<10;i++); /* 等待tWB = 100ns. */
id=NF_RDDATA()<<8; /* 厂商ID(K9S1208V:0xec) */
id|=NF_RDDATA(); /* 设备ID(K9S1208V:0x76) */
NF_nFCE_H(); /* 取消Nand Flash 选中*/
return id;
}
2.3.4 Nand flash写入
以页为单位写入.
参数说明:block 块号
page 页号
buffer 指向内存中待写入Nand flash中的数据起始位置
返回值: 0:写错误
1:写成功
static int NF_WritePage(unsigned int block, unsigned int page, unsigned char *buffer)
{
int i;
unsigned int blockPage = (block<<5)+page;
unsigned char *bufPt = buffer;
NF_RSTECC(); /* 初始化 ECC */
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x0); /* 从A区开始写 */
NF_CMD(0x80); /* 写第一条命令 */
NF_ADDR(0); /* A0~A7 位(Column Address) */
NF_ADDR(blockPage&0xff); /* A9A16,
(Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24,
(Page Address) */
NF_ADDR((blockPage>>16)&0xff); /* A25, (Page Address) */
for(i=0;i<512;i++)
{
NF_WRDATA(*bufPt++); /* 写一个页512字节到Nand Flash芯片 */
}
/*
* OOB一共16 Bytes, 每一个字节存放什么由程序员自己定义, 通常,
* 我们在Byte0Byte2
存ECC检验码. Byte6 存放坏块标志.
*/
seBuf[0]=rNFECC0; /* 读取ECC检验码0 */
seBuf[1]=rNFECC1; /* 读取ECC检验码1 */
seBuf[2]=rNFECC2; /* 读取ECC检验码2 */
seBuf[5]=0xff; /* 非坏块标志 */
for(i=0;i<16;i++)
{
NF_WRDATA(seBuf[i]); /* 写该页的OOB数据块 */
}
NF_CMD(0x10); /* 结束写命令 */
/* 等待Nand Flash处于准备状态 */
for(i=0;i<10;i++);
NF_WAITRB();
/* 发送读状态命令给Nand Flash */
NF_CMD(0x70);
for(i=0;i<3;i++);
if (NF_RDDATA()&0x1)
{ /*如果写有错, 则标示为坏块 */
NF_nFCE_H(); /* 取消Nand Flash 选中*/
NF_MarkBadBlock(block);
return 0;
} else { /* 正常退出 */
NF_nFCE_H(); /* 取消Nand Flash 选中*/
return 1;
}
}
2.3.5 Nand flash读取
参数说明:block:块号
page:页号
buffer:指向将要读取到内存中的起始位置
返回值:1:读成功
0:读失败
static int NF_ReadPage(unsigned int block, unsigned int page, unsigned char *buffer)
{
int i;
unsigned int blockPage;
unsigned char ecc0, ecc1, ecc2;
unsigned char *bufPt=buffer;
unsigned char se[16];
page=page&0x1f;
blockPage=(block<<5)+page;
NF_RSTECC(); /* 初始化 ECC */
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x00); /* 从A区开始读 */
NF_ADDR(0); /* A0~A7 位(Column Address) */
NF_ADDR(blockPage&0xff); /* A9A16,
(Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24,
(Page Address) */
NF_ADDR((blockPage>>16)&0xff); /* A25, (Page Address) */
/* 等待Nand Flash处于再准备状态 */
for(i=0;i<10;i++);
NF_WAITRB(); /*等待 tR(max 12us) */
/* 读整个页, 512字节 */
for(i=0;i<512;i++)
{
*bufPt++=NF_RDDATA();
}
/* 读取ECC码 */
ecc0=rNFECC0;
ecc1=rNFECC1;
ecc2=rNFECC2;
/* 读取该页的OOB块 */
for(i=0;i<16;i++)
{
se[i]=NF_RDDATA();
}
NF_nFCE_H(); /* 取消Nand Flash 选中*/
/* 校验ECC码, 并返回 */
if(ecc0==se[0] && ecc1==se[1] && ecc2==se[2])
return 1;
else
return 0;
}
2.3.6 Nand flash标记坏块
如果是坏块, 通过写OOB块的Byte6把该块标记为坏块。
参数说明:block块号
返回值:1:ok,成功完成标记。
0:表示写OOB块正确.
static int NF_MarkBadBlock(unsigned int block)
{
int i;
unsigned int blockPage=(block<<5);
seBuf[0]=0xff;
seBuf[1]=0xff;
seBuf[2]=0xff;
seBuf[5]=0x44; /* 设置坏块标记 */
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x50); /* 从C区开始写 */
NF_CMD(0x80); /* 发送编程命令, 让Nand Flash处理写状态 */
NF_ADDR(0x0); /* A0~A7 位(Column Address) */
NF_ADDR(blockPage&0xff); /* A9A16,
(Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24,
(Page Address) */
NF_ADDR((blockPage>>16)&0xff); /* A25, (Page Address) */
/* 写OOB数据块 */
for(i=0;i<16;i++)
{
NF_WRDATA(seBuf[i]);
}
NF_CMD(0x10); /* 结束写命令 */
/* 等待NandFlash准备好 */
for(i=0;i<10;i++); /* tWB = 100ns. */
NF_WAITRB();
/*读NandFlash的写状态 */
NF_CMD(0x70);
for(i=0;i<3;i++); /* twhr=60ns */
if (NF_RDDATA()&0x1)
{
NF_nFCE_H(); /* 取消Nand Flash 选中*/
return 0;
} else {
NF_nFCE_H(); /* 取消Nand Flash 选中*/
}
return 1;
}
2.3.7 Nand Flash检查坏块
检查指定块是否是坏块.
参数说明:block:块号
返回值:1:指定块是坏块
0:指定块不是坏块。
static int NF_IsBadBlock(U32 block)
{
int i;
unsigned int blockPage;
U8 data;
blockPage=(block<<5);
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x50); /* Read OOB数据块 */
NF_ADDR(517&0xf); /* A0~A7 位(Column Address) */
NF_ADDR(blockPage&0xff); /* A9A16,
(Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24,
(Page Address) */
NF_ADDR((blockPage>>16)&0xff); /* A25, (Page Address) */
/* 等待NandFlash准备好 */
for(i=0;i<10;i++); /* wait tWB(100ns) */
NF_WAITRB();
/* 读取读出值 */
data=NF_RDDATA();
NF_nFCE_H(); /* 取消Nand Flash 选中*/
/* 如果data不为0xff时, 表示该块是坏块 */
if(data != 0xff)
return 1;
else
return 0;
}
2.3.8 擦除指定块中数据
参数说明:block 块号
返回值:0:擦除错误。(若是坏块直接返回0;若擦除出现错误则标记为坏块然后返回0)
1:成功擦除。
static int NF_EraseBlock(unsigned int block)
{
unsigned int blockPage=(block<<5);
int i;
/* 如果该块是坏块, 则返回 */
if(NF_IsBadBlock(block))
return 0;
NF_nFCE_L(); /* 片选Nand Flash芯片*/
NF_CMD(0x60); /* 设置擦写模式 */
NF_ADDR(blockPage&0xff); /* A9A16,
(Page Address) , 是基于块擦*/
NF_ADDR((blockPage>>8)&0xff); /* A17A24,
(Page Address) */
NF_ADDR((blockPage>>16)&0xff); /* A25, (Page Address) */
NF_CMD(0xd0); /* 发送擦写命令, 开始擦写 */
/* 等待NandFlash准备好 */
for(i=0;i<10;i++); /* tWB(100ns) */
NF_WAITRB();
/* 读取操作状态 */
NF_CMD(0x70);
if (NF_RDDATA()&0x1)
{
NF_nFCE_H(); /* 取消Nand Flash 选中*/
NF_MarkBadBlock(block); /* 标记为坏块 */
return 0;
} else {
NF_nFCE_H(); /* 取消Nand Flash 选中*/
return 1;
}
}
2.4 第一层的实现
2.4.1 NandFlash烧写主函数说明
参数说明: block 块号
srcAddress SDRAM中数据起始地址
fileSize 要烧写的数据长度
返回值: 无
void K9S1208_Program(unsigned int block, unsigned int srcAddress, unsigned int fileSize)
{
int i;
int programError=0;
U32 blockIndex;
U8 *srcPt, *saveSrcPt;
srcPt=(U8 *)srcAddress; /* 文件起始地址 */
blockIndex = block; /* 块号 */
while(1)
{
saveSrcPt=srcPt;
/* 如果当前块是坏块, 跳过当前块 */
if(NF_IsBadBlock(blockIndex))
{
blockIndex++; /* 到下一个块 */
continue;
}
/* 在写之前, 必须先擦除, 如果擦除不成功, 跳过当前块 */
if(!NF_EraseBlock(blockIndex))
{
blockIndex++; /* 到下一个块 */
continue;
}
/* 写一个块, 一块有32页 */
for(i=0;i<32;i++)
{
/* 写入一个页, 如果出错, 停止写当前块 */
if(!NF_WritePage(blockIndex,i,srcPt))
{
programError=1;
break;
}
/* 如果操作正常, 文件的写位置加上1页偏移,到下一页的起始位置 */
srcPt+=512;
/* 如果写地址没有超过文件长度, 继续; 超出则终止写 */
if((U32)srcPt>=(srcAddress+fileSize))
break;
}
/* 如果写一个块时, 其中某一页写失败, 则把写地址恢复写该块之前, 并跳过当前块 */
if(programError==1)
{
blockIndex++;
srcPt=saveSrcPt;
programError=0;
continue;
}
/* 如果写地址没有超过文件长度, 继续; 超出则终止写 */
if((U32)srcPt >= (srcAddress+fileSize))
break;
/* 如果正常写成功, 继续写下一个块 */
blockIndex++;
}
}
3 在U-BOOT对Nand Flash的支持
3.1 U-BOOT对从Nand Flash启动的支持
3.1.1 从Nand Flash启动U-BOOT的基本原理
1. 前4K的问题
如果S3C2410被配置成从Nand Flash启动(配置由硬件工程师在电路板设置), S3C2410的Nand Flash控制器
有一个特殊的功能, 在S3C2410上电后, Nand Flash控制器会自动的把Nand Flash上的前4K数据搬移到4K内部
RAM中, 并把0x00000000设置内部RAM的起始地址, CPU从内部RAM的0x00000000位置开始启动。这个过
程不需要程序干涉。
程序员需要完成的工作,是把最核心的启动程序放在Nand Flash的前4K中。
2. 启动程序的安排
由于Nand Flash控制器从Nand Flash中搬移到内部RAM的代码是有限的,所以, 在启动代码的前4K里,我
们必须完成S3C2410的核心配置以及把启动代码(UBOOT)剩余部分搬到RAM中运行。以UBOOT为例, 前4K
完成的主要工作, 见第四部分的2.2节。
3.1.2 支持Nand Flash启动代码说明
首先在include/configs/crane2410.h中加入CONFIG_S3C2410_NAND_BOOT, 如下:
#define CONFIG_S3C2410_NAND_BOOT 1
支持从Nand Flash中启动.
1. 执行Nand Flash初始化
下面代码在cpu/arm920t/start.S中
#ifdef CONFIG_S3C2410_NAND_BOOT
copy_myself:
mov r10, lr
ldr sp, DW_STACK_START @安装栈的起始地址
mov fp, #0 @初始化帧指针寄存器
bl nand_reset @跳到复位C函数去执行
...
DW_STACK_START:
.word STACK_BASE+STACK_SIZE4
2. nand_reset C代码
下面代码被加在/board/crane2410/crane2410.c中
void nand_reset(void)
{
int i;
/* 设置Nand Flash控制器 */
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
/* 给Nand Flash芯片发送复位命令 */
NF_nFCE_L();
NF_CMD(0xFF);
for(i=0; i<10; i++);
NF_WAITRB();
NF_nFCE_H();
}
3. 从Nand Flash中把UBOOT拷贝到RAM
@read UBOOT
from Nand Flash to RAM
ldr r0, =UBOOT_RAM_BASE @ 设置第1个参数: UBOOT在RAM中的起始地址
mov r1, #0x0 @ 设置第2个参数:Nand Flash的起始地址
mov r2, #0x20000 @ 设置第3个参数: UBOOT的长度(128KB)
bl nand_read_whole @ 调用nand_read_whole(), 该函数在board/crane2410/crane2410.c中
tst r0, #0x0 @ 如果函数的返回值为0,表示执行成功.
beq ok_nand_read @ 执行内存比较
4. 从Nand Flash中把数据读入到RAM中
int nand_read_whole(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
/* 如果起始地址和长度不是512字节(1页)的倍数, 则返回错误代码 */
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return 1;
}
/* 激活Nand Flash */
NF_nFCE_L();
for(i=0; i<10; i++);
i = start_addr;
while(i < start_addr + size) {
/* 读A区 */
rNFCMD = 0;
/* 写入读取地址 */
rNFADDR = i & 0xff;
rNFADDR = (i >> 9) & 0xff;
rNFADDR = (i >> 17) & 0xff;
rNFADDR = (i >> 25) & 0xff;
NF_WAITRB();
/* 读出一页(512字节) */
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (rNFDATA & 0xff);
buf++;
}
}
/* 停止驱动Nand Flash */
NF_nFCE_H();
return 0;
}
5. 校查搬移后的数据
把RAM中的前4K与内部中前4K进行比较, 如果完全相同, 则表示搬移成功.
ok_nand_read:
mov r0, #0x00000000 @内部RAM的起始地址
ldr r1, =UBOOT_RAM_BASE @UBOOT在RAM中的起始地址
mov r2, #0x400 @比较1024次, 每次4字节, 4 bytes * 1024 = 4Kbytes
go_next: @ 比较1024次, 每次4个字节
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq done_nand_read
bne go_next
notmatch:
1:b 1b
done_nand_read:
mov pc, r10
3.2 U-BOOT对Nand Flash命令的支持
在UBOOT
下对Nand Flash的支持主要是在命令行下实现对nand flash的操作。对nand flash实现的命令
为:nand info、nand device、nand read、nand write、nand erease、nand bad。
用到的主要数据结构有:struct nand_flash_dev、struct nand_chip。前者包括主要的芯片型号、存储容量、
设备ID、I/O总线宽度等信息;后者是具体对nand flash进行操作时用到的信息。
3.2.1 主要数据结构介绍
1. struct nand_flash_dev数据结构
该数据结构在include/linux/mtd/nand.h中定义,在include/linux/mtd/nand_ids.h中赋初值。
struct nand_flash_dev {
char *name; /* 芯片名称 */
int manufacture_id; /* 厂商ID */
int model_id; /* 模式ID */
int chipshift; /* Nand Flash地址位数 */
char page256; /* 表明是否时256字节一页。1:是;0:否。*/
char pageadrlen; /* 完成一次地址传送需要往NFADDR中传送几次。*/
unsigned long erasesize; /* 一次块擦除可以擦除多少字节 */
int bus16; /* 地址线是否是16位,1:是;0:否 */
};
2. struct nand_chip数据结构
该数据结构在include/linux/mtd/nand.h中定义. 该结构体定义出一个Nand Flash设备数组:
struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
该数组在nand_probe()中对其进行初始化.
struct nand_chip {
int page_shift; /* Page 地址位数 */
u_char *data_buf; /* 本次读出的一页数据 */
u_char *data_cache; /* 读出的一页数据 */
int cache_page; /* 上次操作的页号 */
u_char ecc_code_buf[6]; /* ECC校验码 */
u_char reserved[2];
char ChipID; /* 芯片ID号 */
struct Nand *chips; /* Nand Flash芯片列表, 表示支持几个芯片为一个设备*/
int chipshift;
char* chips_name; /* Nand Flash芯片名称 */
unsigned long erasesize; /* 块擦写的大小 */
unsigned long mfr; /* 厂商ID */
unsigned long id; /* 模式ID */
char* name; /* 设备名称 */
int numchips; /* 有几块Nand Flash芯片 */
char page256; /* 一页是256字节, 还是512字节 */
char pageadrlen; /* 页地址的长度 */
unsigned long IO_ADDR; /* 用于对nand flash进行寻址的地址值存放处 */
unsigned long totlen; /* Nand Flash总共大小 */
uint oobblock; /* 一页的大小。本款nand flash为512 */
uint oobsize; /* spare array大小。本款nand flash为16 */
uint eccsize; /* ECC 大小 */
int bus16; /* 地址线是否是16位,1:是;0:否 */
};
3.2.2 支持的命令函数说明
1. nand info/nand device
功能:显示当前nand flash芯片信息。
函数调用关系如下(按先后顺序):
static void nand_print(struct nand_chip *nand) ;
2. nand erase
功能:擦除指定块上的数据。
函数调用关系如下(按先后顺序):
int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
3. nand bad
功能:显示坏块。
函数调用关系如下(按先后顺序):
static void nand_print_bad(struct nand_chip* nand);
int check_block (struct nand_chip *nand, unsigned long pos);
4. nand read
功能:读取nand flash信息到SDRAM。
函数调用关系如下(按先后顺序):
int nand_rw (struct nand_chip* nand, int cmd,size_t start, size_t len, size_t * retlen, u_char * buf);
static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
size_t * retlen, u_char *buf, u_char *ecc_code);
static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr);
READ_NAND(adr);
5. nand write
功能:从SDRAM写数据到nand flash中。
函数调用关系如下(按先后顺序):
int nand_rw (struct nand_chip* nand, int cmd,size_t start, size_t len, size_t * retlen, u_char * buf);
static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * ecc_code);
static int nand_write_page (struct nand_chip *nand, int page, int col, int last, u_char * ecc_code);
WRITE_NAND(d , adr);
3.2.3 U-BOOT支持Nand Flash命令移植说明
1. 设置配置选项
在CONFIG_COMMANDS中, 打开CFG_CMD_NAND选项.
#define CONFIG_COMMANDS /
(CONFIG_CMD_DFL | /
CFG_CMD_CACHE | /
CFG_CMD_NAND | /
/*CFG_CMD_EEPROM |*/ /
/*CFG_CMD_I2C |*/ /
/*CFG_CMD_USB |*/ /
CFG_CMD_PING | /
CFG_CMD_REGINFO | /
CFG_CMD_DATE | /
CFG_CMD_ELF)
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000 /* Nand Flash控制器在SFR区中起始寄存器地址 */
#define CFG_MAX_NAND_DEVICE 1 /* 支持的最在Nand Flash数据 */
#define SECTORSIZE 512 /* 1页的大小 */
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE – 1) /* 页掩码 */
#define ADDR_COLUMN 1 /* 一个字节的Column地址 */
#define ADDR_PAGE 3 /* 3字节的页块地址, A9A25*/
#define ADDR_COLUMN_PAGE 4 /* 总共4字节的页块地址 */
#define NAND_ChipID_UNKNOWN 0x00 /* 未知芯片的ID号 */
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
/* Nand Flash命令层底层接口函数 */
#define WRITE_NAND_COMMAND(d, adr) do {rNFCMD = d;} while(0)
#define WRITE_NAND_ADDRESS(d, adr) do {rNFADDR = d;} while(0)
#define WRITE_NAND(d, adr) do {rNFDATA = d;} while(0)
#define READ_NAND(adr) (rNFDATA)
#define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}
#define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}
#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}
/* 下面一组操作对Nand Flash无效 */
#define NAND_CTL_CLRALE(nandptr)
#define NAND_CTL_SETALE(nandptr)
#define NAND_CTL_CLRCLE(nandptr)
#define NAND_CTL_SETCLE(nandptr)
/* 允许Nand Flash写校验 */
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#endif /* CONFIG_COMMANDS & CFG_CMD_NAND*/
2. 加入自己的Nand Flash芯片型号
在include/linux/mtd/ nand_ids.h中的对如下结构体赋值进行修改:
static struct nand_flash_dev nand_flash_ids[] = {
......
{"Samsung K9F1208U0B", NAND_MFR_SAMSUNG, 0x76, 26, 0, 4, 0x4000, 0},
.......
}
这样对于该款Nand Flash芯片的操作才能正确执行。
3. 编写自己的Nand Flash初始化函数
在board/crane2410/crane2410.c中加入nand_init()函数.
void nand_init(void)
{
/* 初始化Nand Flash控制器, 以及Nand Flash 芯片 */
nand_reset();
/* 调用nand_probe()来检测芯片类型 */
printf ("%4lu MB/n", nand_probe(CFG_NAND_BASE) >> 20);
}
该函数在启动时被start_armboot()调用.
4 在Linux对Nand Flash的支持
4.1 Linux下Nand Flash调用关系
4.1.1 Nand Flash设备添加时数据结构包含关系
struct mtd_partition partition_info[]
--> struct s3c2410_nand_set nandset
--> struct s3c2410_platform_nand superlpplatfrom
--> struct platform_device s3c_device_nand
在该数据结构的name字段的初始化值"s3c2410-nand",必须与Nand Flash设备驱动注册时
struct device_driver结构中的name字段相同,因为platfrom bus是依靠名字来匹配的.
--> struct platform_device *smdk2410_devices[]
4.1.2 Nand Flash设备注册时数据结构包含关系
struct device_driver s3c2410_nand_driver
-->struct device *dev
该数据构由系统分配.
-->struct platform_device *pdev
-->struct s3c2410_platform_nand *plat
-->struct s3c2410_nand_set nset
-->struct mtd_partition
4.1.3 当发生系统调用时数据结构调用关系
struct mtd_info
它的*priv指向chip
-->struct nand_chip
它的*priv指向nmtd
-->struct s3c2410_nand_mtd
它是s3c2410_nand_info的一个字段
-->s3c2410_nand_info
它被设为Nand Flash设备驱动的私有数据结构,在Nand Flash设备驱动注册时分配空间.
-->struct device
4.2 Linux下Nand Flash驱动主要数据结构说明
4.2.1 s3c2410专有数据结构
1. s3c2410_nand_set
struct s3c2410_nand_set {
int nr_chips; /* 芯片的数目 */
int nr_partitions; /* 分区的数目 */
char *name; /* 集合名称 */
int nr_map; /* 可选, 底层逻辑到物理的芯片数目 */
struct mtd_partition partitions; /* 分区列表 */
};
2. s3c2410_platform_and
struct s3c2410_platform_nand {
/* timing information for controller, all times in nanoseconds */
int tacls; /* 从CLE/ALE有效到 nWE/nOE的时间 */
int twrph0; /* nWE/nOE的有效时间 */
int twrph1; /* 从释放CLE/ALE到nWE/nOE不活动的时间 */
int nr_sets; /* 集合数目 */
struct s3c2410_nand_set sets; /* 集合列表 */
/* 根据芯片编号选择有效集合 */
void (*select_chip)(struct s3c2410_nand_set , int chip);
};
3. s3c2410_nand_mtd
在drivers/mtd/nand/s3c2410.c中,
struct s3c2410_nand_mtd {
struct mtd_info mtd; /* MTD 信息 */
struct nand_chip chip; /* nand flash 芯片信息 */
struct s3c2410_nand_set set; /* nand flash 集合 */
struct s3c2410_nand_info *info; /* nand flash 信息 */
int scan_res;
};
4. s3c2410_nand_info
struct s3c2410_nand_info {
/* mtd info */
struct nand_hw_control controller; /* 硬件控制器 */
struct s3c2410_nand_mtd *mtds; /* MTD 设备表 */
struct s3c2410_platform_nand platform; /* Nand 设备的平台 */
/* device info */
struct device *device; /* 设备指针 */
struct resource *area; /* 资源指针 */
struct clk *clk; /* Nand Flash 时钟 */
void __iomem *regs; /* 寄存器基地址(map后的逻辑地址) */
int mtd_count; /* MTD的数目 */
unsigned char is_s3c2440;
};
5. struct clk
在arch/arm/machs3c2410/
clock.h中
struct clk {
struct list_head list; /* clock 列表结点 */
struct module *owner; /* 所属模块 */
struct clk *parent; /* 父结点 */
const char *name; /* 名称 */
int id; /* 编号 */
atomic_t used; /* 使用者计数 */
unsigned long rate; /* 时钟速率 */
unsigned long ctrlbit; /* 控制位 */
int (*enable)(struct clk *, int enable); /* Clock打开方法 */
};
4.2.2 Linux 通用数据结构说明
1. device_driver
include/linux/device.h
struct device_driver {
const char * name; /* 驱动名称 */
struct bus_type * bus; /* 总线类型 */
struct completion unloaded; /* 卸载事件通知机制 */
struct kobject kobj; /* sys中的对象 */
struct klist klist_devices; /* 设备列表 */
struct klist_node knode_bus; /* 总线结点列表 */
struct module * owner;/* 所有者 */
/* 设备驱动通用方法 */
int (*probe) (struct device * dev); /* 探测设备 */
int (*remove) (struct device * dev); /* 移除设备 */
void (*shutdown) (struct device * dev); /* 关闭设备 */
/* 挂起设备 */
int (*suspend) (struct device * dev, pm_message_t state, u32 level);
int (*resume) (struct device * dev, u32 level); /* 恢复 */
};
2. platform_device
include/linux/device.h
struct platform_device {
const char * name; /* 名称 */
u32 id; /* 设备编号, -1表示不支持同类多个设备 */
struct device dev; /* 设备 */
u32 num_resources; /* 资源数 */
struct resource * resource; /* 资源列表 */
};
3. resource
struct resource {
const char name; /* 资源名称 */
unsigned long start, end; /* 开始位置和结束位置 */
unsigned long flags; /* 资源类型 */
/* 资源在资源树中的父亲,兄弟和孩子 */
struct resource *parent, *sibling, *child;
};
4. device
include/linux/device.h
struct device {
struct klist klist_children; /* 在设备列表中的孩子列表 */
struct klist_node knode_parent; /* 兄弟结点 */
struct klist_node knode_driver; /* 驱动结点 */
struct klist_node knode_bus; /* 总线结点 */
struct device parent; /* 父亲 */
struct kobject kobj; /* sys结点 */
char bus_id[BUS_ID_SIZE];
struct semaphore sem; /* 同步驱动的信号量 */
struct bus_type * bus; /* 总线类型 */
struct device_driver *driver; /* 设备驱动 */
void *driver_data; /* 驱动的私有数据 */
void *platform_data; /* 平台指定的数据,为device核心驱动保留 */
void *firmware_data; /* 固件指定的数据,为device核心驱动保留 */
struct dev_pm_info power; /* 设备电源管理信息 */
u64 *dma_mask; /* DMA掩码 */
u64 coherent_dma_mask;
struct list_head dma_pools; /* DMA缓冲池 */
struct dma_coherent_mem *dma_mem; /* 连续DMA内存的起始位置 */
void (*release)(struct device * dev); /* 释放设置方法 */
};
5. nand_hw_control
include/linux/mtd/nand.h
struct nand_hw_control {
spinlock_t lock; /* 自旋锁,用于硬件控制 */
struct nand_chip *active; /* 正在处理MTD设备 */
wait_queue_head_t wq; /* 等待队列 */
};
6. nand_chip
include/linux/mtd/nand.h
struct nand_chip {
void __iomem *IO_ADDR_R; /* 读地址 */
void __iomem *IO_ADDR_W; /* 写地址 */
/* 字节操作 */
u_char (*read_byte)(struct mtd_info *mtd); /* 读一个字节 */
void (*write_byte)(struct mtd_info *mtd, u_char byte); /* 写一个字节 */
/* 双字节操作 */
u16 (*read_word)(struct mtd_info mtd); /* 读一个字 */
void (*write_word)(struct mtd_info *mtd, u16 word); /* 写一个字 */
/* buffer操作 */
void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
/* 选择一个操作芯片 */
void (*select_chip)(struct mtd_info *mtd, int chip);
/* 坏块检查操作 */
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
/* 坏块标记操作 */
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
/* 硬件控制操作 */
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
/* 设备准备操作 */
int (*dev_ready)(struct mtd_info *mtd);
/* 命令发送操作 */
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int
page_addr);
/* 等待命令完成 */
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
/* 计算ECC码操作 */
int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char
*ecc_code);
/* 数据纠错操作 */
int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
u_char *calc_ecc);
/* 开启硬件ECC */
void (*enable_hwecc)(struct mtd_info *mtd, int mode);
/* 擦除操作 */
void (*erase_cmd)(struct mtd_info *mtd, int page);
/* 检查坏块表 */
int (*scan_bbt)(struct mtd_info *mtd);
int eccmode; /* ECC模式 */
int eccsize; /* ECC 计算时使用的字节数 */
int eccbytes; /* ECC 码的字节数 */
int eccsteps; /* ECC 码计算的步骤数 */
int chip_delay; /* 芯片的延迟时间 */
spinlock_t chip_lock; /* 芯片访问的自旋锁 */
wait_queue_head_t wq; /* 芯片访问的等待队列 */
nand_state_t state; /* Nand Flash状态 */
int page_shift; /* 页右移的位数,即column地址位数 */
int phys_erase_shift; /* 块右移的位数, 即column和页一共的地址位数 */
int bbt_erase_shift; /* 坏块页表的位数 */
int chip_shift; /* 该芯片总共的地址位数 */
u_char *data_buf; /* 数据缓冲区 */
u_char *oob_buf; /* oob缓冲区 */
int oobdirty; /* oob缓冲区是否需要重新初始化 */
u_char *data_poi; /* 数据缓冲区指针 */
unsigned int options; /* 芯片专有选项 */
int badblockpos;/* 坏块标示字节在OOB中的位置 */
int numchips; /* 芯片的个数 */
unsigned long chipsize; /* 在多个芯片组中, 一个芯片的大小 */
int pagemask; /* 每个芯片页数的屏蔽字, 通过它取出每个芯片包含多少个页 */
int pagebuf; /* 在页缓冲区中的页号 */
struct nand_oobinfo *autooob; /* oob信息 */
uint8_t *bbt; /* 坏块页表 */
struct nand_bbt_descr *bbt_td; /* 坏块表描述 */
struct nand_bbt_descr *bbt_md; /* 坏块表镜像描述 */
struct nand_bbt_descr *badblock_pattern; /* 坏块检测模板 */
struct nand_hw_control *controller; /* 硬件控制 */
void *priv; /* 私有数据结构 */
/* 进行附加错误检查 */
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int
status, int page);
};
7. mtd_info
include/linux/mtd/mtd.h
struct mtd_info {
u_char type; /* 设备类型 */
u_int32_t flags; /* 设备标志位组 */
u_int32_t size; /* 总共设备的大小 */
u_int32_t erasesize; /* 擦除块的大小 */
u_int32_t oobblock; /* OOB块的大小,如:512个字节有一个OOB */
u_int32_t oobsize; /* OOB数据的大小,如:一个OOB块有16个字节 */
u_int32_t ecctype; /* ECC校验的类型 */
u_int32_t eccsize; /* ECC码的大小 */
char *name; /* 设备名称 */
int index; /* 设备编号 */
/* oobinfo信息,它可以通过 MEMSETOOBINFO ioctl命令来设置 */
struct nand_oobinfo oobinfo;
u_int32_t oobavail; /* OOB区的有效字节数,为文件系统提供 */
/* 数据擦除边界信息 */
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
u_int32_t bank_size; /* 保留 */
/* 擦除操作 */
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* 指向某个执行代码位置 */
int (*point) (struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char **mtdbuf);
/* 取消指向 */
void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
/* 读/写操作 */
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
/* 带ECC码的读/写操作 */
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
/* 带OOB码的读/写操作 */
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf);
/* 提供访问保护寄存器区的方法 */
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
/* 提供readv和writev方法 */
int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count,
loff_t from, size_t *retlen);
int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count,
loff_t from, size_t *retlen, u_char *eccbuf,
struct nand_oobinfo *oobsel);
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel);
/* 同步操作 */
void (*sync) (struct mtd_info *mtd);
/* 芯片级支持的加/解锁操作 */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
/* 电源管理操作 */
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
/* 坏块管理操作 */
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
/* 重启前的通知事件 */
struct notifier_block reboot_notifier;
void *priv; /* 私有数据结构 */
struct module *owner; /* 模块所有者 */
int usecount; /* 使用次数 */
};
4.3 Linux下Nand Flash驱动说明
4.3.1 注册driver_register
通过module_init(s3c2410_nand_init);注册Nand Flash驱动. 在 s3c2410_nand_init ()中通过driver_register()注册
s3c2410_nand_driver驱动程序,如下所示:
static struct device_driver s3c2410_nand_driver = {
.name = "s3c2410-nand",
.bus = &platform_bus_type, /* 在drivers/base/platform.c中定义 */
.probe = s3c2410_nand_probe,
.remove = s3c2410_nand_remove,
};
4.3.2 探测设备probe
在注册的Nand Flash驱动程序中, probe方法为s3c2410_nand_probe(). s3c2410_nand_probe()再调用
s3c24xx_nand_probe(). 在该函数中, 把*info作为Nand Flash驱动的私有数据结构, 并通过dev_set_drvdata(dev,
info)把*info保存在*device的*driver_data字段中.然后通过clk_get(dev, "nand")获取Nand Flash的时钟资
源, clk_use(info->clk)增加时钟资源的使用计数, clk_enable(info->clk)开启资源.填写*info的其它字段,
其中包括:
1. 通过request_mem_region()为Nand Flash寄存器区申请I/O内存地址空间区,并通过ioremap()把它映射到虚
拟地址空间.
2. 调用s3c2410_nand_inithw()初始化Nand Flash控制器.
3. 为mtd设备分配设备信息的存储空间.
4. 对当前mtd设备,调用s3c2410_nand_init_chip()进行初始化.
5. 对当前mtd设备, 调用nand_scan()检测Nand Flash芯片, nand_scan()函数在drivers/mtd/nand/nand_base.c中
定义.该函数的作用是初始化struct nand_chip中一些方法, 并从Nand Flash中读取芯片ID, 并初始化struct
mtd_info中的方法.
6. 对当前mtd设备,加入其分区信息.
7. 如果还有更多mtd设备,到4执行.
4.3.3 初始化Nand Flash控制器
s3c2410_nand_inithw()函数会初始化Nand Flash控制器, 通过设置Nand Flash控制寄存器(S3C2410_NFCONF)来
完成, 这里最重要的是根据S3C2410的PCLK计算出tacls, twrph0以及twrph1值.
4.3.4 移除设备
s3c2410_nand_remove()当设备被移除时,被device核心驱动调用.它完成的主要工作如下:
1. 把*device的*driver_data字段置空.
2. 释放mtd设备信息.
3. 释放clk资源.
4. 通过iounmap()取消映地址空间.
5. 释放申请的I/O内存资源.
6. 释放设备私有数据*info的空间.
4.3.5 Nand Flash芯片初始化
s3c2410_nand_init_chip()初始化struct nand_chip中的一些主要字段以及方法.其中主要包括的方法有:
1. s3c2410_nand_hwcontrol(); 硬件控制
2. s3c2410_nand_devready(); 设备是否准备好
3. s3c2410_nand_write_buf(); 写一个buffer到nand flash
4. s3c2410_nand_read_buf(); 读一个buffer到nand flash
5. s3c2410_nand_select_chip(); 选择操作芯片
如果支持ECC硬件校验,还设置如下方法:
1. s3c2410_nand_correct_data(); 通过ECC码校正数据
2. s3c2410_nand_enable_hwecc(); 开启硬件ECC检查
3. s3c2410_nand_calculate_ecc(); 计算ECC码
4.3.6 读Nand Flash
当对nand flash的设备文件(nand flash在/dev下对应的文件)执行系统调用read(),或在某个文件系统中对该
设备进行读操作时. 会调用struct mtd_info中的read方法,他们缺省调用函数为nand_read(),在
drivers/mtd/nand/nand_base.c中定义.nand_read()调用nand_do_read_ecc(),执行读操作. 在
nand_do_read_ecc()函数中,主要完成如下几项工作:
1. 会调用在nand flash驱动中对struct nand_chip重载的select_chip方法,即
s3c2410_nand_select_chip()选择要操作的MTD芯片.
2. 会调用在struct nand_chip中系统缺省的方法cmdfunc发送读命令到nand flash.
3. 会调用在nand flash驱动中对struct nand_chip重载的read_buf(),即s3c2410_nand_read_buf()
从Nand Flash的控制器的数据寄存器中读出数据.
4. 如果有必要的话,会调用在nand flash驱动中对struct nand_chip重载的
enable_hwecc,correct_data以及calculate_ecc方法,进行数据ECC校验。
4.3.7 写Nand Flash
当对nand flash的设备文件(nand flash在/dev下对应的文件)执行系统调用write(),或在某个文件系统中对该设备
进行读操作时, 会调用struct mtd_info中write方法,他们缺省调用函数为nand_write(),这两个函数在
drivers/mtd/nand/nand_base.c中定义. nand_write()调用nand_write_ecc(),执行写操作.在
nand_do_write_ecc()函数中,主要完成如下几项工作:
1. 会调用在nand flash驱动中对struct nand_chip重载的select_chip方法,即
s3c2410_nand_select_chip()选择要操作的MTD芯片.
2. 调用nand_write_page()写一个页.
3. 在nand_write_page()中,会调用在struct nand_chip中系统缺省的方法cmdfunc发送写命令
到nand flash.
4. 在nand_write_page()中,会调用在nand flash驱动中对struct nand_chip重载的
write_buf(),即s3c2410_nand_write_buf()从Nand Flash的控制器的数据寄存器中写入数据.
5. 在nand_write_page()中,会调用在nand flash驱动中对struct nand_chip重载waitfunc方法,
该方法调用系统缺省函数nand_wait(),该方法获取操作状态,并等待nand flash操作完成.等
待操作完成,是调用nand flash驱动中对struct nand_chip中重载的dev_ready方法,即
s3c2410_nand_devready()函数