TQ210——下载总结
学习方法:(分阶段学习)-----内核学习是一个长期的过程
1.学习使用内核提供的接口函数 (涉及到很多操作系统知识,编程规范)
2.找到一个函数如do_fork来学习进程管理模块
3.通过kmalloc函数来学习进程管理,通过do_irq学习中断管理
1.U-BOOT配置与烧写常用命令 (生成u-boot.bin)(u-boot下载地址:)
(1) u-boot配置及烧写
tar xzvf*.zip
tar xjvf*.bz2
配置:make TQ210_config 运行:make ARCH=armCROSS_COMPILE=arm-linux-
大约 2分钟后编译完成,生成u-boot.bin,然后烧写到开发板中
烧写准备:网线连接,下载线连接,电源线连接 (ping通就可以),将u-boot.bin复制到tftp服务器目录下 (固化到开发板起始处)
tftp30000000 u-boot.bin /*下载到内存中*/
nand erase0 100000 /*擦除1M空间*/
nand write30000000 0 100000 /*将30000000处内容写1M到硬盘开始处*/
(2) u-boot命令详解
help:察看当前单板所支持的命令
printenv:打印环境变量
setenv:添加、修改、删除环境变量
saveenv:保存环境变量
tftp:通过网络下载文件
bootmaddr:执行程序,addr是执行地址
nand erase起始地址start 长度len --- 擦除start处开始的,长度为len的区域
nand write内存起始地址 flash起始地址 长度len --- 将内存起始地址处,长度为len的数据,写入flash起始地址处
nand read 内存起始地址 flash起始地址 长度len---将flash起始地址处,长度为len的数据,读到内存起始地址处
附:
<1> 配置 U-Boot
TQ210: makeTQ210_config
Smart210: make smart210_config
OK210: make forlinx_linux_config
OK6410: make forlinx_nand_ram256_config
Tiny6410: make tiny6410_config
TQ2440: make TQ2440_config
Mini2440: make mini2440_config
<2> 下载与运行
TQ210: tftp 0xc0008000 uImage
Smart210: tftp 0x20000000 uImage
OK210: tftp 0xc0008000 uImage
OK6410: tftp 0xc0008000 uImage
Tiny6410: tftp 0xc0008000 uImage
TQ2440: tftp 0x31000000
Mini2440: tftp 0x31000000 uImage
2.内核配置与编译
(1) 为什么要配置内核
硬件需求 软件需求 ----选出需要的,去掉不要的
(2) 内核配置方法
makeconfig:基于文本模式的交互式配置
makemenuconfig:基于文本模式的菜单型配置 (更好一些)
<*> 编译时比选的
<M> 编译时可选的
<> 不选的
(3) 内核配置结果:放在.config中
(4) 内核编译:make uImage j 2
编译好的内核位于arch/<cpu>/boot/目录下uImage
(5) 清理内核:make clean make distclean
mkimage工具讲解:(编译内核时将mkimage移动到/bin目录下)
uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件.
mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么
./mkimage -n 'U-boot' -A arm -O linux -T firmware -Cnone -d u-boot.bin u-boot.img
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
参数说明:
-A 指定CPU的体系结构:
取值 表示的体系结构
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000
-O 指定操作系统类型,可以取以下值:
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos
-T 指定映象类型,可以取以下值:
standalone、kernel、ramdisk、multi、firmware、script、filesystem
-C 指定映象压缩方式,可以取以下值:
none 不压缩
gzip 用gzip的压缩方式
bzip2 用bzip2的压缩方式
-a 指定映象在内存中的加载地址,映象下载到内存中时,要按照用mkimage制作映象时,这个参数所指定的地址值来下载
-e 指定映象运行的入口点地址,这个地址就是-a参数指定的值加上0x40(因为前面有个mkimage添加的0x40个字节的头)
-n 指定映象名
-d 指定制作映象的源文件
/mkimage -A arm-O linux -C gzip -a 0x20008000 -e 0x20008000 -d linux.bin.gz uImage
-a参数后是内核的运行地址,-e参数后是入口地址
<1> 如果我们没用mkimage对内核进行处理的话,那直接把内核下载到0x30008000再运行就行,内核会自解压运行(不过内核运行需要一个tag来传递参数,而这个tag建议是由bootloader提供的,在u-boot下默认是由bootm命令建立的)。
<2>如果使用mkimage生成内核镜像文件的话,会在内核的前头加上了64byte的信息,供建立tag之用。bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址相同。
(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之
(2)如果相同的话那就让其原封不同的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部
3.内核模块
(1) 特点:<1> 模块本身并不被编译进内核文件(zImage或者bzImage)
<2> 可以根据需求,在内核运行期间动态的安装或卸载
(2) 范例
// hello.c
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void)
{
printf(KERN_WARNING"Hello,world!\n");
return 0;
}
static void hello_exit(void)
{
printf("KERN_INFO"Goodbye,world!\n");
}
module_init(hello_init);//加载内核模块
module_exit(hello_exit);//卸载内核模块
Makefile:
obj -m := hello.o
KDIR := /lib/modules/2.6.../build # 内核代码路径
all:
make -C$(KDIR) M=$(PWD) modules
(3) 安装与卸载
安装:insmod (insmod hello.ko)
卸载:rmmod (rmmod hello)
查看:lsmod
(4) 模块声明
MODULE_LICENSE("遵循的协议") --- 申明该模块遵守的许可证协议,如:“GPL“、”GPL v2“等
MODULE_AUTHOR("作者") --- 申明模块的作者
MODULE_DESCRIPTION("模块的功能描述") --- 申明模块的功能
MODULE_VERSION("V1.0")--- 申明模块的版本
(5) 模块参数
应用程序中:int main(int argc,char**argv) argc表示命令行输入的参数个数,argv中保存输入的参数
内核模块中:通过宏module_param指定保存模块参数的变量,模块参数用于在加载模块时传递参数给模块
module_param(name,type,perm)
name:变量的名称
type:变量类型,bool:布尔型 int:整型 charp:字符串型
perm是访问权限,S_IRUGO:读权限 S_IWUSR:写权限
例如:
inta = 3;
char*st;
module_param(a,int,S_IRUGO);
module_param(st,charp,S_IRUGO);
(6) 符号导出
内核符号的导出使用宏:EXPORT_SYMBOL(符号名)
(7) 总结
对比应用程序,内核模块具有以下不同:
<1>.应用程序是从头(main)到尾执行任务,执行结束后从内存中消失。
<2>.内核模块的初始化函数结束时,模块仍然存在于核中,直到卸载函数被调用,模块才从内核中消失。
4.Linux内核制作 (生成uImage)(www.kernel.com)
解压: tar xzvf *.zip
tarxjvf *.bz2
步骤:
(1) 清理 make distclean
(2) 配置 make menuconfig ARCH=arm
(3) 编译 make uImage ARCH=arm CROSS_COMPILE=arm-linux-
提示:mkimage not found ---mkimage帮助加文件头
在u-boot的tools目录中,移动mkimage到/bin下,再重复(3)操作
(4) 在/arch/arm/boot中生成了uImage
烧写到开发板:(固化到开发板5M处) 具体值参考/drivers/mtd/nand/s3c_nand.c文件
tftp30000000 uImage
nand erase500000 5000000
nand write30000000 500000 500000
环境变量设置
setenvbootcmd read 30000000 500000 500000\;bootm 300000
5.根文件系统的制作 (套件下载:)
(1) 建立跟文件系统目录
---建议使用shell脚本
<1> 创建目录
mkdirbin devetc lib proc sbin sys usr mnt tmp var
mkdirusr/bin usr/lib usr/sbin lib/modules
<2> 创建设备文件
cdrootfs/dev
mknod-m 666 console c51
mknod-m 666 null c13
<3> 加入配置文件
taretc.tar.gz ()
mvetc/*...*/root/etc/ -rf
<4> 编译安装busybox
/**************************************************************
下载 BusyBox 的源码包
下载地址:www.busybox.net/downloads,最新版本为busybox-1.20.2
tar jxvfbusybox-1.20.2.tar.bz2
cdbusybox-1.20.2
修改 Makefile 中的体系结构 ARCH 和交叉编译器前缀 CROSS_COMPILE
vimMakefile
把 164 行修改为:
CROSS_COMPILE= /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- (路径不要复制,根据自己的情况填写)
把 190 行修改为:
ARCH = arm
**************************************************************/
makemenuconfig
BusyboxSettings àbuild Options->
选中 “Build busybox as astaticbinary”, 静态链接
CrossCompiler prefix (arm-linux-)
InstallationOptions->
选中 “Don‘t use /usr”, 选中该项可以避免busybox 被安装到宿主系统的
/usr目录下,破坏宿主系统
BusyboxInstallation Prefix(/xxx/rootfs)
该选项表明编译后的busybox的安装位置
make(编译)
makeinstall (安装)
最后生成一个_install子目录
mv_install mini_rootfs
cdmini_rootfs
编写一个脚本文件(略)--用于创建目录和文件的
(2) 挂载跟文件系统
<1> 拷贝交叉编译器里的动态链接库到 lib 目录:cp/usr/local/arm/arm-none-linux-gnueabi/lib/ *.so* lib -rdf
<2> 对 lib 目录下的动态链接库进行裁减:arm-none-linux-gnueabi-striplib/.so
<3> 获得mkyaffs2image 工具的源码包:http://fatplus.googlecode.com/files/yaffs2-source.tar
编译mkyaffs2image 工具: ar xvf yaffs2-source.tar
cdyaffs2/utils
make
cpmkyaffs2image /usr/local/bin/
<4> 制作根文件系统镜像:mkyaffs2image mini_rootfsrootfs.img
<5> 烧写到开发板 (rootfs.img) --- 固化到10M出(/drivers/mtd/nand/s3c_nand.c文件)
tftp30000000 rootfs.img
nanderase a00000 1400000
nandwrite.yaffs 30000000 a00000 实际img大小
环境变量设置:
nfs:setenvbootargs console=ttySAC0 root=/dev/nfs rwnfsroot=192.168.1.8:/home/libang/nfs/roof/ip=192.168.1.6:192.168.0.1::255.255.255.0::eth0:off init=/linuxrc
yaffs2:setenvbootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=yaffs2 rw init=/linuxrc
6.下载到开发板总结
u-boot.bin uImage rootfs.img
固化u_boot:tftp 30000000u-boot.bin
nand erase 0 100000
nand write 30000000 0 100000
固化Kernel:tftp 30000000 uImage
nand erase 500000 500000
nand write 30000000 500000 500000
固化fs:tftp 30000000rootfs.img
nand erase a00000 1400000
nand write.yaffs 30000000 a00000 1400000
引导内核:setenv read 30000000500000 500000\;bootm 30000000
引导文件系统: 开发使用--(nfs) setenv bootargsconsole=ttySAC0 root=/dev/nfs rw nfsroot=192.168.1.8:/home/libang/nfs/roof/ip=192.168.1.6:192.168.0.1::255.255.255.0::eth0:off init=/linuxrc (启动nfs:/etc/init.d/nfsrestart)
产品使用--- (yaffs2)setenvbootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=yaffs2 rw init=/linuxrc
7.内核架构
(1) 系统调用接口SCI (System Call Interface):SCI层为用户空间提供了一套标准的系统调用函数来访问Linux内核,搭起了用户空间到内核空间的桥梁.
(2) 进程管理PM (Process Management):进程管理的重点是创建进程(fork、exec),停止进程(kill、exit),并控制它们之间的通信(signal 或者 POSIX 机制).进程管理还包括控制活动进程如何共享CPU,即进程调度.
(3) 虚拟文件系统VFS (Virtual File System):VFS(虚拟文件系统)隐藏各种文件系统的具体细节,为文件操作提供统一的接口
(4) 内存管理MM (Memory Management):内存管理的主要作用是控制多个进程安全地共享内存区域
(5) 网络协议栈 (Network Stack):内核协议栈为Linux提供了丰富的网络协议实现
(6) Arch:CPU
(7) 设备驱动DD (Device Drivers):Linux内核中有大量代码都在设备驱动程序中,它们控制特定的硬件设备
8.内核源代码 (不允许在windows下解压,windows下不区分大小写)
(1) 下载内核源代码
www.kernel.com--- linux
(2) 内核目录结构 (树状)
Linux内核源代码采用树形结构进行组织,非常合理地把功能相关的文件都放在同一个子目录下,使得程序更具可读性
<1>Arch:特定体系结构相关代码,内核所支持的每种架构的 CPU 的相关目录集合,在 arch 目录下,有支持 arm 的目录、支持 x86的目录和支持 mips 的目录等,如:arch/arm、arch/x86 和arch/mips 等
<2>block:块设备通用函数
<3>Document:内核源码说明文档目录
<4>drives:设备驱动程序目录集合, drivers 里的某一子目录对应着内核中的某一种驱动程序,如:drivers/char 为字符设备驱动程序、drivers/block 为块设备驱动程序,drivers/net 为网络设备驱动程序、drivers/usb为usb总线设备驱动程序、drivers/i2c为i2c总线设备驱动程序等
<5>fs:Linux支持的文件系统的代码(包括虚拟文件系统 VFS),每个子目录对应一种文件系统,比如 fs/jffs2/、fs/cramfs、fs/ext2/
||--devpts/* /dev/pts虚拟文件系统*/
||--ext2/*第二扩展文件系统*/
||--fat/*MS的fat32文件系统*/
||--isofs/*ISO9660光盘cd-rom上的文件系统*/
<6>include:内核的头文件目录,如:基本的头文件(存放在include/linux目录下)、各种驱动或功能部件的头文件(比如 include/media、include/video/、include/net)
<7>init:内核的初始化代码(不是内核的引导代码),其中 main.c 文件中的start_kernel 函数是内核引导后运行的第一个函数
<8>kernel:内核管理的核心代码,与处理器相关的代码位于 arch/../kernel目录下
<9>net目录
网络协议的实现代码
||--802 /*802无线通讯协议核心支持代码*/
||--appletalk /*与苹果系统连网的协议*/
||--ax25 /*AX25无线INTERNET协议*/
||--bridge /*桥接设备*/
||--ipv4 /*IP协议族V4版32位寻址模式*/
||--ipv6 /*IP协议族V6版*/