嵌入式linux应用

2019-07-12 17:52发布

#############review embedded linux application############
嵌入式linux应用:
一、嵌入式综述,基本概念:
1.GPL:连接了它的库就要一样GPL;
LGPL:修改了,才要LGPL;
总的来说,GPL在保护自由软件上更加严格些。
2.ARM LINUX:特指在ARM平台上运行的LINUX移植版本,带MMU的;
uCLinux:一个全新的linux,而不是linux的移植版本,不带MMU,对内存空间不进行保护,多个进程共享一个运行空间;
RT-Linux/RTAL:支持硬实时的linux发行版本,它的基本思想是将kernel当作一个优先级最低的实时任务。
3.补丁文件:
命名规则:patch-x.y.z-rmkn.gz--x.y.z是linux kernel版本号,n是补丁版本号;
pre-patch-x.y.z-rmkn.gz -- 是alpha or beta的,通常不稳定;
diff-2.4.18-rmk7-pxa3.gz -- 一看名字diff就知道了,是对打完补丁的kernel再打补丁,注意,一定要先打patch 再打 diff.
4.操作系统分层模型:
/********************************************/
    User program and application libraries
   ^
   |
 C libary
   ^
   |
 kernel
/********************************************/
5  GNU = GNU'S NOT UNIX ,它要实现一个新的操作系统。
二、嵌入式LINUX开发工具:
1.GCC -- GNU Compiler Collective.的编译参数:
-c:生成.o文件;
-D:后面加宏名;
-E:只运行C的预编译器cpp.
-I:后面接包含的头文件所在路径。
-L:接函数库搜索路径。
-l:连接时需要连接的库文件名称。
-O(n):优化级别;
-MM:输出源文件的依赖关系;
-fPIC:产生位置无关代码,一般在生成共享库时用。
-shared:生成支持动态共享库的执行文件;
-static:不支持动态共享库,把函数库内容静态连接到执行文件中,(可执行文件将很大)。
2.binutils -- 一组二进制工具集合,辅助GCC。
ar:建立归档文件。e.g:做静态库时用。
as:GNU汇编器。 主要用来编译GCC -S生成的汇编代码,然后生成一个二进制代码,存放到object文件中。 ld:连接器,编译的最后一步了。主要是将目标文件和归档文件连接到一起,然后重定位数据,并连接符合引用,最终形成一个可执行文件。 nm:列出目标文件的符号。 objcopy:将目标文件的内容复制到另一个目标文件,并可以改变文件类型;
e.g: objcopy a.out -O binary a.bin
file a.out -- elf,not stripped. 在PC上跑,要有操作系统的支持。
file a.bin -- data. 可以直接在板子上裸奔。
objdump -- 汇编人的最爱:display one or complex object file,并可以用选项来控制其显示信息。e.g: objdump -S a.out > a.txt 看ELF文件的汇编代码;但是a.out已经是一个ld过的文件了,所以汇编code 可能很多,所以我一般这样做:
gcc -c a.c
objdump -S a.o > a.txt

readelf:显示可执行文件的一些信息,例如HEAD信息。 strip:瘦身命令; 3.交叉编译器 --Cross-Compiler
arm-linux-gcc:编译出可以在ARM上的LINUX系统下跑的ELF文件;
arm-elf-gcc: 编译出在没有MMU上的uClinux上跑的FLAT的ELF文件;

tar xzvf arm-linux-gcc-2.95.3.tar.gz -C Dir rpm -ivh ....rpm
卸载:rpm -e arm-linux-gcc
安装目录一般都在/usr/local/bin or /usr/local/arm-linux/bin下
查看安装情况:which arm-linux-gcc e.g:
 arm-elf-gcc -elf2flt main.c -o helloworld /*生成flat的elf可执行文件*/
 armm-linux-gcc main.c -o helloworld
三、启动代码 -- bootloader
1.硬件启动后第一个执行的软件程序,固化在ROM中,加电自启动。
2.What is bootloader do?
1) 初始化 SDRAM ,建立堆栈环境,为跳转到 C 语言代码的入口做好准备。
2) 初始化 UART ,建立目标板和调试主机之间的通信。
3) 实现一个基于串口输入的命令解释器,提供一些基本的用户命令。
    其实 bootloader 初始化的任务还有很多,但我觉得这三个任务是比较重大的。
这里结合 lumit4510 的代码,我给出了一个经过简化的 bootloader ( l-boot ) ,
只包含了 startup.s 和 main.c 两个程序,一个是汇编代码,一个是 C 语言入口。
可以很直观的看出,系统运行到 C 语言之前,需要经过哪些必要的初始化步骤。
ResetEntry
    |
    ++++ SYS_RST_HANDLER
                | 
                ++++ InitSystem
                         |
                         ++++ InitMemory
                                   |
                ++++++++++++++++++++ 
                |        
                ++++ Copy ROM to RAM
                |
                ++++ Set up SVC stack
                |
                ++++ Remap Memory
                |
                ++++ Goto main ( in main.c )
/*初始化硬件。
加载、执行、调试程序和操作系统内核。*/

3.二个阶段和主要功能:
第一个阶段:用汇编写的,依赖于CPU体系结构的代码。
初始化硬件;
设置RAM空间,建立堆栈环境;
拷贝stage2到RAM空间;
跳转到stage2的C入口;
第二阶段:用C写的,这样可以实现一些复杂的功能,而且代码会有更好的可读性和可移植性。
1)初始化本阶段常用的硬件设备。
2)内存映射 -- mmap;
3)将kernel image文件和根文件系统image从flash读到RAM空间;
4)为内核设置启动参数;
5)调用内核;
bootloader工作结束,退出历史舞台,以后就是kerner的天下了。
4.为什么都要用Main函数当入口,因为在调用MAIN前会做这么多事儿:
1)Copies RO and RW execution regions from their Load Addresses to their Execution Addresses.
2)Zeroes BSS regions.
3)Set up stack and heap.
4)Initialize referenced library functions.
5)Set up argc and agrv for main().
6)Calls main()

四、内核配置、编译、剪切、移植
1.directory是kernel源文件所在目录
patch -p1 -d directory < ....patch
or
cat ../..patch | patch -p1 -d directory
2.配置kerner:
make menuconfig
config.in -- 添加menu中的选项; .config -- 对menu配置完后,将配置结果保存在这里; autoconf.h -- 最后,唯一真正去编译的就是它。 3.uClinux 的内核编译和linux内核编译的区别,比linux多做哪几个事:
1)make lib_only
2)make user_only
3)make romfs.img
4.ELF文件:
1)一种为linux系统所采用的通用文件格式,支持动态连接。
文件开始为头信息,描述了各section的相关信息。包括连接地址和执行地址。
有三种类型:
 .o目标文件;
 .so共享文件;
 .elf可执行文件。
2)一个ELF文件的可执行程序segment一般包括3个section:
.text -- 只读代码区;
.data -- 可读写的数据区;
.bss -- 在内存空间里于.data section相邻,为可读写的未初始化的数据区;
FLAT格式:
 对ELF的头信息做了简化,一般在uCLinux上用。
 arm-linux-gcc  -elf2flt hello.c
BIN格式:
 二进制文件,不包含地址定位信息;
总结:ELF,FLAT都是elf的,都要在操作系统上跑,FLAT可以用在uCLinux上,是因为uCLinux没有MMU. 5.uCLinux:
1)内核加载方式:
可以在flash上执行,也可以在RAM中解压内核后执行,支持位置无关代码;
2)ROMFS作为其根文件系统:
代码体积减小。
不支持动态块擦除。如果系统需要动态保存的数据,那就要采用RAM-Disk + EXT2作文件系统了。
3)使用了FLAT格式的ELF文件,更节省空间。
4)对glibc,应用程序库都作了精简。 对用户程序采用静态连接形式,代码可固化。
6.对uCLinux源码目录下的images/下的文件说明:
1)romfs.img -- 是通过tools/romfs-inst.sh生成的romfs目录和其下的文件,然后用genromfs打包成一个文件romfs.img.
可以放在flash中,也可以放在sdram中,但是编译内核时要在driver/block/blkmem.c里指定地址,以便内核找到它。
2)linux.txt:编译后内核的.text段,一般放在flash中,只读。
linux.data:编译后内核中的.data段,一般在sdram空间,读写。
3)image.bin: 由上面三个文件顺序连接而生成 =linux.txt + linux.data + romfs.img. 7.uCLinux的image.rom是一个压缩过的内核,这个文件可以直接烧到flash。= linux生成的zImage.
image.ram -- 解压image.rom到sdram中运行的elf格式的linux内核。
可以形象的说:image.rom = gunzip program + gzipped(image.ram) 8.arm linux 编译后生成的二种内核镜像。
vmlinux;没有压缩的原始linux kernel 镜像;elf format;pc;
zImage;压缩后的linux kernel image; bin format; 裸奔;
五、根文件系统 -- RootFS 1.ROMFS文件系统:
1)相对于EXT2文件系统更节省空间:
kernel支持romfs需要的代码少;
romfs建立文件系统超级块需要更少的空间。
2)romfs是只读的文件系统,所以系统同时需要虚拟盘(ramdisk)来支持临时文件和数据文件的存储。 RAM肯定要采用EXT2文件系统。 2.JFFS2文件系统、YAFFS文件系统:
1)JFFS2:
主要是针对NorFlash设计的。
--(Jounaling Flash Filesystem 2)日志文件系统。
2)YAFFS (Yet Another Flash Filesystem)
主要针对NANDFlash设计。
适用于大容量的存储。
它们都是为嵌入式存储设备设计的文件系统:
 支持损耗平衡,修改少量的数据时,只是附加,而不是重写整个扇区。
 提供了更好的崩溃/掉电安全保护。

3.NFS文件系统:
 /etc/init.d/nfs start | restart
 modprobe nfs //?????????
 mount -t nfs 192.168.0.33:/usr/src/ /mnt
4.Initrd -- 对romfs剪裁后的放在RAM中的最小的文件系统。
制作:
1)dd if=/dev/zero of=initrd.img bs=1024 count=500 /*dd 用指定大小的块拷贝一个文件*/
2)mke2fs -m0 -F initrd.img /*用EXT2格式化*/
3)mkdir rom ram
4)mount initrd.img ram/ -o loop
5)mount romfs.img rom/ -o loop
6)mkdir ram/bin ram/sbin ram/dev ram/etc ram/var ram/lib ram/probe ram/usr ram/tmp
7)cp -a rom/etc/* ram/etc/
8)cp -a rom/bin/* ram/bin/
9)cp -a rom/bin/init ram/bin/init
10)mknod ram/dev/ttyS0 c 4 64 /*串口设备*/
11)mknod ram/dev/console c 5 1 
12)umount ram
   umount rom
BUSYBOX -- 瑞士军刀; ram disk制作完成,可以用ftp方式将initrd.img下载到开发板上。有了kernel,在加上现在做得文件系统,我们就完成了一个自己的uCLinux操作系统了,哈哈。
5.内核启动参数:
作用:不用重新编译内核,在启动时改变内核行为。
具体参数可参见:Documentation/kernel-parametes.txt 常用举例:
1) root=/dev/ram0 rw /*root=根文件系统所在设备,rw-读写方式加载根文件系统*/
 init=/linuxrc  /*内核初始化末尾将运行的脚步,缺省值是/sbin/init*/
 console=ttyS0,115200n8 console=tty0 /*启动信息的控制台*/
 ramdisk_size=8192
 cachepolicy=writethrough
2)  root=/dev/nfs ip=bootp console=ttyS0,115200n8
六、应用程序开发 -- Applications
1.arm-elf-gcc main.c -elf2flt
arm-linux-gcc main.c
2.make -c subdir /*将make command传递到分别的subdir下执行其有的Makefile*/