(Ref: http://maozheng11.blog.hexun.com/22338272_d.html)
一、构建自己的交叉编译环境
二、u-boot移植
三、编译内核
四、构建文件系统
二、u-boot移植
三、编译内核
四、构建文件系统
过程:
一、构建自己的交叉编译环境
嵌 入式设备由于不具备一定的处理器能力和存储空间,程序开发一般用PC来完成,然后将可执行文件下载到嵌入式系统中运行。这是目前嵌入式程序开发的不二选择 ——Host/target模式。但这引发了一个问题:由于Host和Target的处理器体系结构不同,我们不能直接用PC上既有的程序开发工具,必须 使用跨平台开发工具,即在Host上生成能在Target上运行格式的目标文件。以下我会简单的说一下怎么构建交叉编译环境,当然如果不想麻烦也可以到网 上去下载。
先下载binutils、gcc、glibc、linux-kernel等包和几个插件,可到 http://weintroub.com/~coldwell/toolchain/处下载,先解压glibc-2.3.5,打开INSTALL文件, 看其中对gcc、awk、sed等软件的要求,此处为:
GNU `make' 3.79 or newer
GCC 3.2 or newer
GNU `binutils' 2.13 or later
GNU `texinfo' 3.12f
GNU `awk' 3.0, or some other POSIX awk
Perl 5
GNU `sed' 3.02 or newer
GNU `autoconf' 2.53 or higher
GNU `gettext' 0.10.36 or later
1、设置环境变量
TARGET=arm-linux
PREFIX=/usr/arm
SYSROOT=${PREFIX}/sysroot
export ARCH=arm
export CROSS_COMPILE=${TARGET}-
export PATH=$PATH:${PREFIX}/bin
2、建立二进制工具
mkdir -p ${PREFIX}/src
cd ${PREFIX}/src
tar zxvf binutils-2.16.tar.gz
mkdir -p BUILD/binutils-2.16
cd BUILD/binutils-2.16
../../binutils-2.16/configure --prefix=${PREFIX} --target=${TARGET} --with-sysroot=${SYSROOT} && make && make install && echo ok (如果最后一行显示ok则表示安装成功)
3、建立内核头文件
cd ${PREFIX}/src
tar zxvf linux-2.6.10.tar.gz
ln -s linux-2.6.10 linux
zcat 2.6.10-at91.patch.gz | patch -d linux -p1
cd linux
make at91rm9200dk_defconfig
make include/linux/version.h
mkdir -p ${SYSROOT}/usr/include
cp -a ${PREFIX}/src/linux/include/linux ${SYSROOT}/usr/include/linux
cp -a ${PREFIX}/src/linux/include/asm-arm ${SYSROOT}/usr/include/asm
cp -a ${PREFIX}/src/linux/include/asm-generic ${SYSROOT}/usr/include/asm-generic
4、安装glibc头文件
cd ${PREFIX}/src
tar zxvf glibc-2.3.5.tar.gz
patch -d glibc-2.3.5 -p1 <ioperm.c.diff
cd glibc-2.3.5
tar xvfz ../glibc-linuxthreads-2.3.5.tar.gz
cd ..
mkdir -p BUILD/glibc-2.3.5-headers
cd BUILD/glibc-2.3.5-headers
../../glibc-2.3.5/configure --prefix=/usr --host=${TARGET} --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include && make cross-compiling=yes install_root=${SYSROOT} install-headers && echo ok
touch ${SYSROOT}/usr/include/gnu/stubs.h
touch ${SYSROOT}/usr/include/bits/stdio_lim.h
5、建立初始编译器
cd ${PREFIX}/src
tar jxvf gcc-3.4.4.tar.bz2
patch -d gcc-3.4.4 -p1 < flow.c.diff
patch -d gcc-3.4.4 -p1 < t-linux.diff
mkdir -p BUILD/gcc-3.4.4-stage1
cd BUILD/gcc-3.4.4-stage1
../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c --with-sysroot=${SYSROOT} && make && make install && echo ok
6、建立c库
cd ${PREFIX}/src
mkdir -p BUILD/glibc-2.3.5
cd BUILD/glibc-2.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 ../../glibc-2.3.5/configure --prefix=/usr --build=i386-redhat-linux --host=arm-linux --target=arm-linux --without-__thread --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include && make && make install_root=${SYSROOT} install && echo ok
7、建立全套编译器
cd ${PREFIX}/src
mkdir -p BUILD/gcc-3.4.4
cd BUILD/gcc-3.4.4
../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --with-sysroot=${SYSROOT} && make && make install && echo ok
8、测试
1)编写一个HelloWorld程序,然后arm-linux-gcc helloworld.c -o helloworld
2)file helloworld
aa: ELF 32-bit LSB executable, ARM, version 1, for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped
如果显示出上面的输出,说明你编译了一个能在arm体系结构下运行的helloworld,证明你的编译工具做成功了。
二、u-boot移植
BootLoader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状 态,以便为最终调用操作系统内核准备好正确的环境。BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。
由于 BootLoader的实现依赖于CPU的体系结构,因此大多数BootLoader都分为stage1和stage2两大部分。依赖于CPU体系结构的 代码,比如设备初始化代码等,通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而stage2则通常用C语言来实现,这样 可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。
BootLoader的stage1通常包括以下步骤(以执行的先后顺序):
1、硬件设备初始化。
2、为加载BootLoader的stage2准备RAM空间。
3、 拷贝BootLoader的stage2到RAM空间中。(注:由于stage2通常是C语言执行代码,因此在考虑空间大小时,除了stage2可执行映 象的大小外,还必须把堆栈空间也考虑进来。一般情况下都是分出1M的RAM给它们,我的习惯是把RAM顶层的1M空间空出来分给它们,即 0x21f00000到0x21ffffff,当然也可以把RAM起始位置的1M空间分给他们)
4、设置好堆栈。
5、跳转到stage2的C入口点。
BootLoader的stage2通常包括以下步骤(以执行的先后顺序):
1、初始化本阶段要使用到的硬件设备。
2、检测系统内存映射(memory map)。
3、将kernel映像和根文件系统映像从flash上读到RAM空间中。
4、为内核设置启动参数。
5、调用内核。
如今能支持RAM cpu的BootLoader有好多个,其中支持类型最多,且最出名的是blob和u-boot,本篇就介绍一下我用u-boot往at91rm9200开发板上移植的过程:
1、cp -R at91rm9200dk myboard
1)cp at91rm9200dk.c myboard.c
2)vi Makefle
将COBJS := at91rm9200dk.o at45.o flash.o 改为 COBJS := myboard.o at45.o flash.o
3)添加Nor Flash驱动,芯片型号是MBM29LV320BE(FUJITSU)
vi flash.c
1>由于这个型号的Nor Flash有71个扇区,且前9个是8K,后62个是64K,因此加入
OrgDef OrgMBM29LV320BE[] =
{
{ 8, 8*1024 }, /* 8 * 8 kBytes sectors */
{ 63, 64*1024 }, /* 63 * 64 kBytes sectors */
};
2>加入
#define RESET 0xF0
3>
在函数void flash_identification (flash_info_t * info)中加入:
/* Read Reset */
MEM_FLASH_ADDR1 = FLASH_CODE1;
MEM_FLASH_ADDR2 = FLASH_CODE2;
MEM_FLASH_ADDR1 = RESET;
/* Go to Autoselect mode */
MEM_FLASH_ADDR1 = FLASH_CODE1;
MEM_FLASH_ADDR2 = FLASH_CODE2;
MEM_FLASH_ADDR1 = ID_IN_CODE;
/* Vendor type */
info->flash_id = FUJ_MANUFACT & FLASH_VENDMASK;
printf("FUJ and AMD\n");
/* AMD Flash */
info->flash_id |= AMD_ID_LV320B & FLASH_TYPEMASK;
printf("MBM29LV320B (32Mbit)\n");
4>
在函数ulong flash_init (void)中加入:
/* MBM29LV320BE Flash */
pOrgDef = OrgMBM29LV320BE;
flash_nb_blocks = sizeof (OrgMBM29LV320BE) / sizeof (OrgDef);
5>
在函数void flash_print_info (flash_info_t * info)中加入:
case (FUJ_MANUFACT & FLASH_VENDMASK):
printf("FUJ");
break;
case (AMD_ID_LV320B & FLASH_TYPEMASK):
printf("MBM29LV320BE (32Mbit\n)");
break;
6>
在函数int flash_erase (flash_info_t * info, int s_first, int s_last)中加入:
if ((info->flash_id & FLASH_VENDMASK) != (FUJ_MANUFACT & FLASH_VENDMASK))
{
return ERR_UNKNOWN_FLASH_VENDOR;
}
2、回到u-boot目录下,打开Makefile文件,加入(为了能make myboard_config):
myboard_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t myboard NULL at91rm9200
3、在u-boot目录下,打开MAKEALL文件,在
LIST_ARM9=" \
at91rm9200dk cmc_pu2 \
ap920t ap922_XA10 ap926ejs ap946es \
ap966 cp920t cp922_XA10 cp926ejs \
cp946es cp966 lpd7a400 mp2usb \
mx1ads mx1fs2 netstar omap1510inn \
omap1610h2 omap1610inn omap730p2 sbc2410x \
scb9328 smdk2400 smdk2410 trab \
VCMA9 versatile versatileab versatilepb \
voiceblue \
"
加入 myboard,即:
LIST_ARM9=" \
at91rm9200dk cmc_pu2 \
ap920t ap922_XA10 ap926ejs ap946es \
ap966 cp920t cp922_XA10 cp926ejs \
cp946es cp966 lpd7a400 mp2usb \
mx1ads mx1fs2 netstar omap1510inn \
omap1610h2 omap1610inn omap730p2 sbc2410x \
scb9328 smdk2400 smdk2410 trab \
VCMA9 versatile versatileab versatilepb \
voiceblue myboard \
"
4、cd include/configs,cp at91rm9200dk.h myboard.h,打开myboard.h文件
1)加入#define CONFIG_SKIP_LOWLEVEL_INIT (由于板子会自动进行初始化,所以此处要跳过去,否则会成为死循环)
2)由于我的板子上的Nor Flash是4M,所以把
#define PHYS_FLASH_SIZE 0x200000
改为
#define PHYS_FLASH_SIZE 0x400000
3)由于我的板子上的Nor Flash共71个扇区,所以把
#define CFG_MAX_FLASH_SECT 256
改为
#define CFG_MAX_FLASH_SECT 71
5、
export BUILD_DIR=/home/lb/abc
make distclean
make myboard_config
make all
在/home/lb/abc中会生成三个文件u-boot.bin、u-boot和u-boot.srec,我只需要u-boot.bin文件。
三、编译内核
Bootloader将内核加载到内存中,设定一些寄存器,然后将控制权交由内核,该过程中,关闭MMU功能。通常,内核都是以压缩的方式存放,如zImage,这里有两种解压方法:
1、使用内核自解压程序。
2、在Bootloader中增加解压功能。
使用该方法时内核不需要带有自解压功能,而使用Bootloader中的解压程序代替内核自解压程序。其工作过程与内核自解压过程相似:Bootloader把压缩方式的内核解压到内存中,然后跳转到内核入口处开始执行。
内核有多种启动方式,如下:
XIP(EXECUTE IN PLACE)是指直接从存放代码的位置上启动运行。
1、非压缩,非XIP
非XIP方式是指在运行之前需对代码进行重定位。该类型的内核以非压缩方式存放在Flash中,启动时由Bootloader加载到内存后运行。
2、非压缩,XIP
该 类型的内核以非压缩格式存放在ROM/Flash中,不需要加载到内存就能运行,Bootloader直接跳转到其存放地址执行。Data段复制和BSS 段清零的工作由内核自己完成。这种启动方式常用于内存空间有限的系统中,另外,程序在ROM/Flash中运行的速度相对较慢。
3、RAM自解压
压 缩格式的内核由开头一段自解压代码和压缩内核数据组成,由于以压缩格式存放,内核只能以非XIP方式运行。RAM自解压过程如下:压缩内核存放于 ROM/Flash中,Bootloader启动后加载到内存中的临时空间,然后跳转到压缩内核入口地址执行自解压代码,内核被解压到最终的目的地址然后 运行。压缩内核所占据的临时空间随后被Linux回收利用。这种方式的内核在嵌入式产品中较为常见。
4、ROM自解压
解压缩代码也能够以 XIP的方式在ROM/Flash中运行。ROM自解压过程如下:压缩内核存放在ROM/Flash中,不需要加载到内存就能运行,Bootloader 直接跳转到其存放地址执行其自解压代码,将压缩内核解压到最终的目的地址并运行。ROM自解压方式存放的内核解压缩速度慢,而且也不能节省内存空间。
先下载一个内核原文件和相对应的ARM内核补丁。通常情况下ARM内核不要超过1M,所以对自己没有用的选项都可以不选。
1、
cd linux-2.6.*
zcat ../2.6.*-at91.patch.gz |patch -p1
2、
vi Makefile
把
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为
ARCH ?= arm
CROSS_COMPILE ?= 相应交叉编译环境 (我的是arm-linux-)
3、
make at91rm9200dk_defconfig
make menuconfig
(注:配置ARMlinux的方法和配置官方Linux内核差不多,以下是我对内核的配置,可供大家参考:
[System Type] 平台支持
选择 ARM system type 为 Atmel AT91
选择 Atmel AT91 System-on-Chip==>Atmel AT91 Processor 为 AT91RM9200
其它选项都是用默认
[Gernel setup]通用配置
选择 Sysctl support
选择 System V IPC
这两个选项我也没有深入研究,不知不选是不是也可以?其它的都不要选了。
[Memory Technology Devices(MTD)] MTD 配置
选择 <*>Memory Technology Device(MTD) support 记着选择为“built-in”而不是“module”(前面的选项为“*”而不是“M”)
选择 <*>Mtd partitioning support MTD 分区支持
选择 <*>Caching block device access to MTD devices 支持 MTD作为BLOCK设备访问
进入【RAM/ROM/FLASH chip drivers- 】选项选择加载 FLASH 的驱动
选择 <*> Detect flash chips by Common Flash Interface (CFI) probe自动探测 CFI 接口的 FLASH 设备
选择 <*> Support for AMD/Fujistu flash chips 选择对 AMD/Fujistu FLASH 设备的支持
选择 <*> Support for ROM chips in bus mapping 支持 ROM 设备总线 MAP
其它选项不选,退回到上一级。
进入【Mapping drivers for chip access- 】选项
选择 <*> CFI Flash device mapped on ARM Integrator/P720T 支持 ARM 的 FLASH 分区
其它选项都不用选中。
[Networking Options] 网络选项
本选项全部为 built-in 方式。
选择<*> Packet socket
选择<*> Kernel/User netlink socket
选择<*> Unix domain sockets
选择<*> TCP/IP networking
选择<*> IP: multicasting 支持组播
选择<*> IP: kernel level autoconfiguration
选择<*> IP: DHCP support
选择<*> IP: BOOTP support
选择<*> IP: RARP support
其它的都可以不选。
[File systems] 文件系统
该目录下包含内核对各种文件系统的支持,可以根据需要选择想要的文件系统。
选择<*> Second extended fs support
选择<*> JFS filesystem support
进入[Miscellaneous filesystems]选项
选择<*> Jouralling Flash File System V2 (JFFS2) support内核支持 JFFS 和 JFFS2 文件系统
进入【Network File Systems- 】 网络文件系统子选项
选择<*> NFS file system support NFS 网络文件系统支持
选择<*> Provide NFSv3 client support 支持 NFS 版本 3 客户端
选择<*> Root file system on NFS 根文件系统采用 NFS
退回上级菜单,其它的都没有选中。
其它的配置可以根据目标系统的不同灵活配置,像IDE、Sound等和目标系统没关系的选项都可以去掉,因“板”而异吗。
)
make
4、
cp linux2.6.*/vmlinux /home/lb/kernel
cp linux2.6.*/arch/arm/boot/zImage /home/lb/kernel
5、
cd /home/lb/kernel
1)arm-linux-objcopy -O binary -S vmlinux linux.bin
2)gzip -v9 linux.bin
3)/home/lb/abc/tools/mkimage -A arm -O linux -T kernel -C gzip -a 0x20008000 -e 0x20008000 -d linux.bin.gz uImage
(
注:uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。
mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置,入口点在内存的那个位置以及映象名是什么。
参数说明:
-A 指定CPU的体系结构:
alpha Alpha
arm ARM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64Bit
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 指定制作映象的源文件
)
得到了内核映射文件uImage
四、构建文件系统
在嵌入式Linux开发中, 往往需要为目标系统设置根文件系统, 这包括: 准备好根文件系统所需的内容, 选择目标系统的文件系统类型, 将根文件系统的内容转换为所用文件系统的格式, 将根文件系统安装到目标系统上。
常用的文件系统有:
1、ramdisk
ramdisk的优点: 读写速度非常快, 适合用来制作initrd。
ramdisk的缺点: 不具有永久性, 断电后无法保存. 且ramdisk大小不可更改, 浪费ram。
2、tmpfs
tmpfs是一个以虚拟内存为基础的文件系统,它的大小不是固定的, 这都是它区别于ramdisk的优点。
tmpfs以虚拟内存为基础, 所以它不同于ramdisk,ramdisk只能位于ram中, 而tmpfs可能位于交换分区中(Linux内核的虚拟内存资源同时来源于RAM和交换分区)。
tmpfs是个文件系统, 而不是块设备,同样和ramdisk比较: ramdisk是个块设备, 需要一个mkfs之类的命令将个做成某个格式的文件系统才能使用,而tmpfs是一个文件系统不是块设备,mount它即可使用。
3、cramfs
1)采用实时解压缩方式,但解压缩的时侯有延迟。
2)cramfs的数据都是经过处理、打包的,对其进行写操作有一定困难。所以cramfs不支持写操作,这个特性刚好适合嵌入式应用中使用Flash存储文件系统的场合。
3)在cramfs中,文件最大不能超过16MB。
4)支持组标识(gid),但是mkcramfs只将gid的低8位保存下来,因此只有这8位是有效的。
5)支持硬链接。但是cramfs并没有完全处理好,硬链接的文件属性中,链接数仍然为1.
6)cramfs的目录中,没有“.”和“..”这两项。因此,cramfs中的目录的链接数通常也仅有一个。
7) cramfs中,不会保存文件的时间戳(timestamps)信息。当然,正在使用的文件由于inode保存在内存中,因此其时间可以暂时地变更为最新时间,但是不会保存到cramfs文件系统中去。
8)当前版本的cramfs只支持PAGE_CACHE_SIZE为4096的内核。因此,如果发现cramfs不能正常读写的时侯,可以检查一下内核的参数设置。
在 嵌入式的环境之下,内存和外存资源都需要节约使用。如果使用ramdisk方式来使用文件系统,那么在系统运行之后,首先要把外存(Flash)上的映像 文件解压缩到内存中,构造起ramdisk环境,才可以开始运行程序。但是它也有很致命的弱点。在正常情况下,同样的代码不仅在外存中占据了空间(以压缩 后的形式存在),而且还在内存中占用了更大的空间(以解压缩之后的形式存在),这违背了嵌入式环境下尽量节省资源的要求。
使用cramfs就是一 种解决这个问题的方式。cramfs是一个压缩式的文件系统,它并不需要一次性地将文件系统中的所有内容都解压缩到内存之中,而只是在系统需要访问某个位 置的数据的时侯,马上计算出该数据在cramfs中的位置,将其实时地解压缩到内存之中,然后通过对内存的访问来获取文件系统中需要读取的数据。 cramfs中的解压缩以及解压缩之后的内存中数据存放位置都是由cramfs文件系统本身进行维护的,用户并不需要了解具体的实现过程,因此这种方式增 强了透明度,对开发人员来说,既方便,又节省了存储空间。
我选择的文件系统是ramdsik:
要先安装mtd(memory technology device),debian中安装mtd-tools,gentoo中安装mtd-utils。
1、建立内存映像文件ramdisk
1)mkdir -p /mnt/loop
2)dd if=/dev/zero of=/tmp/loop_tmp bs=1k count=3072
3)/sbin/losetup /dev/loop0 /tmp/loop_tmp
将设备与临时文件联系起来。如果出现“ioctl: LOOP_SET_FD: 设备或资源忙”的提示,说明设备还和一文件联系,可以用/sbin/losetup /dev/loop0来看,并可用-d来删除。
4)mkfs.ext2 –m0 /dev/loop0
mkfs.ext2将会自动判断设备容量的大小并相应地配置自身,-m0参数防止它给root保留空,这样会腾出更多地有用空间。
5)mount -t ext2 /dev/loop0 /mnt/loop
6)mkdir {bin,sbin,usr,dev,etc,lib,home,opt,root,src,tmp,var,mnt,proc,sys,initrd}
7)umount /mnt/loop
卸载此文件系统,得到的/tmp/loop_tmp就是ramdisk,可以将其改名为ramdisk
8)gzip - v9 /tmp/ramdisk
在/tmp中生成一个ramdisk.gz,这样一个内存映像文件就生成了。
2、编译busybox
1)
make defconfig
make menuconfig
2)busybox设置
1>在Build Options中的Build BusyBox as a static binary (no shared libs)是问是否将busybox静态链接,如果是glibc的话不选,如果是uclibc的话要选。
2>在Installation Options选项中,默认地, 运行 make install之后, BusyBox将被安装到./_install目录。
3>NFS是肯定要选的, 使用NFS将宿主机的文件系统mount到目标板上, 这是嵌入式Linux程序开发的一个重要方面。
4>由于可使用NFS, 能在宿主机上实现的功能就都不需要在目标板上实现了。
5>Debian Utilities 全不选, Editors全不选, System Logging Utilities全不选。
6>解压缩工具只安装解压工具,gzip、bzip2、tar工具(要求目标板能解压缩tar.bz2和tar.gz文件)。
7>shell使用ash。
3)编译及安装
make TARGET_ARCH=arm CROSS=arm-linux- -j2
make install
3、用busybox给ramdisk增加命令
1)
gunzip ramdisk.gz
mount -o loop ramdisk /mnt/ramdisk
2)
cd busybox1.4.1/_install
cp -rfv * /mnt/ramdisk
umount /mnt/ramdisk
gzip -v9 ramdisk
生 成最后带有busybox命令的内存映像文件ramdisk.gz,不过此时的ramdisk文件系统内仍缺少一些必需的东西,如/lib下的库文件、 /etc下的一些配置文件、/dev下的一些块设备和文件系统等,这都需要自己添加,如果觉得麻烦,可以下载一个现成的,然后在它的基础上作一些修改。
(注:BusyBox 将数以百计的常用Unix/Linux命令集成到一个可执行文件中(名为busybox)。它体积小巧, 功能却不失强大,常用Linux命令实现的功能它都能提供,它甚至还提供了tftp, http服务程序,尽管少数的Linux命令的某些选项BusyBox没能提供, 但这并不影响它在嵌入式Linux系统中的流行。
BusyBox 可以与glibc或uClibc库进行链接编译, 可以采用动态链接或静态链接,即便采用与glibc的静态链接, 最终生成的busybox文件大小也能轻易控制在1MB之内,而采用uClibc动态链接的可执行文件就更小了,这非常适于存储空间紧张的嵌入式 Linux系统。由此, 有人将BusyBox称为嵌入式系统中的瑞士军刀,更为形象的比喻是: Linux系统中的单个命令是电路中的分立式元件, 而BusyBox是将它们集成在一起的IC: 功能不变, 体积却大为减小。)
一、构建自己的交叉编译环境
嵌 入式设备由于不具备一定的处理器能力和存储空间,程序开发一般用PC来完成,然后将可执行文件下载到嵌入式系统中运行。这是目前嵌入式程序开发的不二选择 ——Host/target模式。但这引发了一个问题:由于Host和Target的处理器体系结构不同,我们不能直接用PC上既有的程序开发工具,必须 使用跨平台开发工具,即在Host上生成能在Target上运行格式的目标文件。以下我会简单的说一下怎么构建交叉编译环境,当然如果不想麻烦也可以到网 上去下载。
先下载binutils、gcc、glibc、linux-kernel等包和几个插件,可到 http://weintroub.com/~coldwell/toolchain/处下载,先解压glibc-2.3.5,打开INSTALL文件, 看其中对gcc、awk、sed等软件的要求,此处为:
GNU `make' 3.79 or newer
GCC 3.2 or newer
GNU `binutils' 2.13 or later
GNU `texinfo' 3.12f
GNU `awk' 3.0, or some other POSIX awk
Perl 5
GNU `sed' 3.02 or newer
GNU `autoconf' 2.53 or higher
GNU `gettext' 0.10.36 or later
1、设置环境变量
TARGET=arm-linux
PREFIX=/usr/arm
SYSROOT=${PREFIX}/sysroot
export ARCH=arm
export CROSS_COMPILE=${TARGET}-
export PATH=$PATH:${PREFIX}/bin
2、建立二进制工具
mkdir -p ${PREFIX}/src
cd ${PREFIX}/src
tar zxvf binutils-2.16.tar.gz
mkdir -p BUILD/binutils-2.16
cd BUILD/binutils-2.16
../../binutils-2.16/configure --prefix=${PREFIX} --target=${TARGET} --with-sysroot=${SYSROOT} && make && make install && echo ok (如果最后一行显示ok则表示安装成功)
3、建立内核头文件
cd ${PREFIX}/src
tar zxvf linux-2.6.10.tar.gz
ln -s linux-2.6.10 linux
zcat 2.6.10-at91.patch.gz | patch -d linux -p1
cd linux
make at91rm9200dk_defconfig
make include/linux/version.h
mkdir -p ${SYSROOT}/usr/include
cp -a ${PREFIX}/src/linux/include/linux ${SYSROOT}/usr/include/linux
cp -a ${PREFIX}/src/linux/include/asm-arm ${SYSROOT}/usr/include/asm
cp -a ${PREFIX}/src/linux/include/asm-generic ${SYSROOT}/usr/include/asm-generic
4、安装glibc头文件
cd ${PREFIX}/src
tar zxvf glibc-2.3.5.tar.gz
patch -d glibc-2.3.5 -p1 <ioperm.c.diff
cd glibc-2.3.5
tar xvfz ../glibc-linuxthreads-2.3.5.tar.gz
cd ..
mkdir -p BUILD/glibc-2.3.5-headers
cd BUILD/glibc-2.3.5-headers
../../glibc-2.3.5/configure --prefix=/usr --host=${TARGET} --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include && make cross-compiling=yes install_root=${SYSROOT} install-headers && echo ok
touch ${SYSROOT}/usr/include/gnu/stubs.h
touch ${SYSROOT}/usr/include/bits/stdio_lim.h
5、建立初始编译器
cd ${PREFIX}/src
tar jxvf gcc-3.4.4.tar.bz2
patch -d gcc-3.4.4 -p1 < flow.c.diff
patch -d gcc-3.4.4 -p1 < t-linux.diff
mkdir -p BUILD/gcc-3.4.4-stage1
cd BUILD/gcc-3.4.4-stage1
../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c --with-sysroot=${SYSROOT} && make && make install && echo ok
6、建立c库
cd ${PREFIX}/src
mkdir -p BUILD/glibc-2.3.5
cd BUILD/glibc-2.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 ../../glibc-2.3.5/configure --prefix=/usr --build=i386-redhat-linux --host=arm-linux --target=arm-linux --without-__thread --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include && make && make install_root=${SYSROOT} install && echo ok
7、建立全套编译器
cd ${PREFIX}/src
mkdir -p BUILD/gcc-3.4.4
cd BUILD/gcc-3.4.4
../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --with-sysroot=${SYSROOT} && make && make install && echo ok
8、测试
1)编写一个HelloWorld程序,然后arm-linux-gcc helloworld.c -o helloworld
2)file helloworld
aa: ELF 32-bit LSB executable, ARM, version 1, for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped
如果显示出上面的输出,说明你编译了一个能在arm体系结构下运行的helloworld,证明你的编译工具做成功了。
二、u-boot移植
BootLoader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状 态,以便为最终调用操作系统内核准备好正确的环境。BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。
由于 BootLoader的实现依赖于CPU的体系结构,因此大多数BootLoader都分为stage1和stage2两大部分。依赖于CPU体系结构的 代码,比如设备初始化代码等,通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而stage2则通常用C语言来实现,这样 可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。
BootLoader的stage1通常包括以下步骤(以执行的先后顺序):
1、硬件设备初始化。
2、为加载BootLoader的stage2准备RAM空间。
3、 拷贝BootLoader的stage2到RAM空间中。(注:由于stage2通常是C语言执行代码,因此在考虑空间大小时,除了stage2可执行映 象的大小外,还必须把堆栈空间也考虑进来。一般情况下都是分出1M的RAM给它们,我的习惯是把RAM顶层的1M空间空出来分给它们,即 0x21f00000到0x21ffffff,当然也可以把RAM起始位置的1M空间分给他们)
4、设置好堆栈。
5、跳转到stage2的C入口点。
BootLoader的stage2通常包括以下步骤(以执行的先后顺序):
1、初始化本阶段要使用到的硬件设备。
2、检测系统内存映射(memory map)。
3、将kernel映像和根文件系统映像从flash上读到RAM空间中。
4、为内核设置启动参数。
5、调用内核。
如今能支持RAM cpu的BootLoader有好多个,其中支持类型最多,且最出名的是blob和u-boot,本篇就介绍一下我用u-boot往at91rm9200开发板上移植的过程:
1、cp -R at91rm9200dk myboard
1)cp at91rm9200dk.c myboard.c
2)vi Makefle
将COBJS := at91rm9200dk.o at45.o flash.o 改为 COBJS := myboard.o at45.o flash.o
3)添加Nor Flash驱动,芯片型号是MBM29LV320BE(FUJITSU)
vi flash.c
1>由于这个型号的Nor Flash有71个扇区,且前9个是8K,后62个是64K,因此加入
OrgDef OrgMBM29LV320BE[] =
{
{ 8, 8*1024 }, /* 8 * 8 kBytes sectors */
{ 63, 64*1024 }, /* 63 * 64 kBytes sectors */
};
2>加入
#define RESET 0xF0
3>
在函数void flash_identification (flash_info_t * info)中加入:
/* Read Reset */
MEM_FLASH_ADDR1 = FLASH_CODE1;
MEM_FLASH_ADDR2 = FLASH_CODE2;
MEM_FLASH_ADDR1 = RESET;
/* Go to Autoselect mode */
MEM_FLASH_ADDR1 = FLASH_CODE1;
MEM_FLASH_ADDR2 = FLASH_CODE2;
MEM_FLASH_ADDR1 = ID_IN_CODE;
/* Vendor type */
info->flash_id = FUJ_MANUFACT & FLASH_VENDMASK;
printf("FUJ and AMD\n");
/* AMD Flash */
info->flash_id |= AMD_ID_LV320B & FLASH_TYPEMASK;
printf("MBM29LV320B (32Mbit)\n");
4>
在函数ulong flash_init (void)中加入:
/* MBM29LV320BE Flash */
pOrgDef = OrgMBM29LV320BE;
flash_nb_blocks = sizeof (OrgMBM29LV320BE) / sizeof (OrgDef);
5>
在函数void flash_print_info (flash_info_t * info)中加入:
case (FUJ_MANUFACT & FLASH_VENDMASK):
printf("FUJ");
break;
case (AMD_ID_LV320B & FLASH_TYPEMASK):
printf("MBM29LV320BE (32Mbit\n)");
break;
6>
在函数int flash_erase (flash_info_t * info, int s_first, int s_last)中加入:
if ((info->flash_id & FLASH_VENDMASK) != (FUJ_MANUFACT & FLASH_VENDMASK))
{
return ERR_UNKNOWN_FLASH_VENDOR;
}
2、回到u-boot目录下,打开Makefile文件,加入(为了能make myboard_config):
myboard_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t myboard NULL at91rm9200
3、在u-boot目录下,打开MAKEALL文件,在
LIST_ARM9=" \
at91rm9200dk cmc_pu2 \
ap920t ap922_XA10 ap926ejs ap946es \
ap966 cp920t cp922_XA10 cp926ejs \
cp946es cp966 lpd7a400 mp2usb \
mx1ads mx1fs2 netstar omap1510inn \
omap1610h2 omap1610inn omap730p2 sbc2410x \
scb9328 smdk2400 smdk2410 trab \
VCMA9 versatile versatileab versatilepb \
voiceblue \
"
加入 myboard,即:
LIST_ARM9=" \
at91rm9200dk cmc_pu2 \
ap920t ap922_XA10 ap926ejs ap946es \
ap966 cp920t cp922_XA10 cp926ejs \
cp946es cp966 lpd7a400 mp2usb \
mx1ads mx1fs2 netstar omap1510inn \
omap1610h2 omap1610inn omap730p2 sbc2410x \
scb9328 smdk2400 smdk2410 trab \
VCMA9 versatile versatileab versatilepb \
voiceblue myboard \
"
4、cd include/configs,cp at91rm9200dk.h myboard.h,打开myboard.h文件
1)加入#define CONFIG_SKIP_LOWLEVEL_INIT (由于板子会自动进行初始化,所以此处要跳过去,否则会成为死循环)
2)由于我的板子上的Nor Flash是4M,所以把
#define PHYS_FLASH_SIZE 0x200000
改为
#define PHYS_FLASH_SIZE 0x400000
3)由于我的板子上的Nor Flash共71个扇区,所以把
#define CFG_MAX_FLASH_SECT 256
改为
#define CFG_MAX_FLASH_SECT 71
5、
export BUILD_DIR=/home/lb/abc
make distclean
make myboard_config
make all
在/home/lb/abc中会生成三个文件u-boot.bin、u-boot和u-boot.srec,我只需要u-boot.bin文件。
三、编译内核
Bootloader将内核加载到内存中,设定一些寄存器,然后将控制权交由内核,该过程中,关闭MMU功能。通常,内核都是以压缩的方式存放,如zImage,这里有两种解压方法:
1、使用内核自解压程序。
2、在Bootloader中增加解压功能。
使用该方法时内核不需要带有自解压功能,而使用Bootloader中的解压程序代替内核自解压程序。其工作过程与内核自解压过程相似:Bootloader把压缩方式的内核解压到内存中,然后跳转到内核入口处开始执行。
内核有多种启动方式,如下:
XIP(EXECUTE IN PLACE)是指直接从存放代码的位置上启动运行。
1、非压缩,非XIP
非XIP方式是指在运行之前需对代码进行重定位。该类型的内核以非压缩方式存放在Flash中,启动时由Bootloader加载到内存后运行。
2、非压缩,XIP
该 类型的内核以非压缩格式存放在ROM/Flash中,不需要加载到内存就能运行,Bootloader直接跳转到其存放地址执行。Data段复制和BSS 段清零的工作由内核自己完成。这种启动方式常用于内存空间有限的系统中,另外,程序在ROM/Flash中运行的速度相对较慢。
3、RAM自解压
压 缩格式的内核由开头一段自解压代码和压缩内核数据组成,由于以压缩格式存放,内核只能以非XIP方式运行。RAM自解压过程如下:压缩内核存放于 ROM/Flash中,Bootloader启动后加载到内存中的临时空间,然后跳转到压缩内核入口地址执行自解压代码,内核被解压到最终的目的地址然后 运行。压缩内核所占据的临时空间随后被Linux回收利用。这种方式的内核在嵌入式产品中较为常见。
4、ROM自解压
解压缩代码也能够以 XIP的方式在ROM/Flash中运行。ROM自解压过程如下:压缩内核存放在ROM/Flash中,不需要加载到内存就能运行,Bootloader 直接跳转到其存放地址执行其自解压代码,将压缩内核解压到最终的目的地址并运行。ROM自解压方式存放的内核解压缩速度慢,而且也不能节省内存空间。
先下载一个内核原文件和相对应的ARM内核补丁。通常情况下ARM内核不要超过1M,所以对自己没有用的选项都可以不选。
1、
cd linux-2.6.*
zcat ../2.6.*-at91.patch.gz |patch -p1
2、
vi Makefile
把
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为
ARCH ?= arm
CROSS_COMPILE ?= 相应交叉编译环境 (我的是arm-linux-)
3、
make at91rm9200dk_defconfig
make menuconfig
(注:配置ARMlinux的方法和配置官方Linux内核差不多,以下是我对内核的配置,可供大家参考:
[System Type] 平台支持
选择 ARM system type 为 Atmel AT91
选择 Atmel AT91 System-on-Chip==>Atmel AT91 Processor 为 AT91RM9200
其它选项都是用默认
[Gernel setup]通用配置
选择 Sysctl support
选择 System V IPC
这两个选项我也没有深入研究,不知不选是不是也可以?其它的都不要选了。
[Memory Technology Devices(MTD)] MTD 配置
选择 <*>Memory Technology Device(MTD) support 记着选择为“built-in”而不是“module”(前面的选项为“*”而不是“M”)
选择 <*>Mtd partitioning support MTD 分区支持
选择 <*>Caching block device access to MTD devices 支持 MTD作为BLOCK设备访问
进入【RAM/ROM/FLASH chip drivers- 】选项选择加载 FLASH 的驱动
选择 <*> Detect flash chips by Common Flash Interface (CFI) probe自动探测 CFI 接口的 FLASH 设备
选择 <*> Support for AMD/Fujistu flash chips 选择对 AMD/Fujistu FLASH 设备的支持
选择 <*> Support for ROM chips in bus mapping 支持 ROM 设备总线 MAP
其它选项不选,退回到上一级。
进入【Mapping drivers for chip access- 】选项
选择 <*> CFI Flash device mapped on ARM Integrator/P720T 支持 ARM 的 FLASH 分区
其它选项都不用选中。
[Networking Options] 网络选项
本选项全部为 built-in 方式。
选择<*> Packet socket
选择<*> Kernel/User netlink socket
选择<*> Unix domain sockets
选择<*> TCP/IP networking
选择<*> IP: multicasting 支持组播
选择<*> IP: kernel level autoconfiguration
选择<*> IP: DHCP support
选择<*> IP: BOOTP support
选择<*> IP: RARP support
其它的都可以不选。
[File systems] 文件系统
该目录下包含内核对各种文件系统的支持,可以根据需要选择想要的文件系统。
选择<*> Second extended fs support
选择<*> JFS filesystem support
进入[Miscellaneous filesystems]选项
选择<*> Jouralling Flash File System V2 (JFFS2) support内核支持 JFFS 和 JFFS2 文件系统
进入【Network File Systems- 】 网络文件系统子选项
选择<*> NFS file system support NFS 网络文件系统支持
选择<*> Provide NFSv3 client support 支持 NFS 版本 3 客户端
选择<*> Root file system on NFS 根文件系统采用 NFS
退回上级菜单,其它的都没有选中。
其它的配置可以根据目标系统的不同灵活配置,像IDE、Sound等和目标系统没关系的选项都可以去掉,因“板”而异吗。
)
make
4、
cp linux2.6.*/vmlinux /home/lb/kernel
cp linux2.6.*/arch/arm/boot/zImage /home/lb/kernel
5、
cd /home/lb/kernel
1)arm-linux-objcopy -O binary -S vmlinux linux.bin
2)gzip -v9 linux.bin
3)/home/lb/abc/tools/mkimage -A arm -O linux -T kernel -C gzip -a 0x20008000 -e 0x20008000 -d linux.bin.gz uImage
(
注:uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。
mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置,入口点在内存的那个位置以及映象名是什么。
参数说明:
-A 指定CPU的体系结构:
alpha Alpha
arm ARM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64Bit
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 指定制作映象的源文件
)
得到了内核映射文件uImage
四、构建文件系统
在嵌入式Linux开发中, 往往需要为目标系统设置根文件系统, 这包括: 准备好根文件系统所需的内容, 选择目标系统的文件系统类型, 将根文件系统的内容转换为所用文件系统的格式, 将根文件系统安装到目标系统上。
常用的文件系统有:
1、ramdisk
ramdisk的优点: 读写速度非常快, 适合用来制作initrd。
ramdisk的缺点: 不具有永久性, 断电后无法保存. 且ramdisk大小不可更改, 浪费ram。
2、tmpfs
tmpfs是一个以虚拟内存为基础的文件系统,它的大小不是固定的, 这都是它区别于ramdisk的优点。
tmpfs以虚拟内存为基础, 所以它不同于ramdisk,ramdisk只能位于ram中, 而tmpfs可能位于交换分区中(Linux内核的虚拟内存资源同时来源于RAM和交换分区)。
tmpfs是个文件系统, 而不是块设备,同样和ramdisk比较: ramdisk是个块设备, 需要一个mkfs之类的命令将个做成某个格式的文件系统才能使用,而tmpfs是一个文件系统不是块设备,mount它即可使用。
3、cramfs
1)采用实时解压缩方式,但解压缩的时侯有延迟。
2)cramfs的数据都是经过处理、打包的,对其进行写操作有一定困难。所以cramfs不支持写操作,这个特性刚好适合嵌入式应用中使用Flash存储文件系统的场合。
3)在cramfs中,文件最大不能超过16MB。
4)支持组标识(gid),但是mkcramfs只将gid的低8位保存下来,因此只有这8位是有效的。
5)支持硬链接。但是cramfs并没有完全处理好,硬链接的文件属性中,链接数仍然为1.
6)cramfs的目录中,没有“.”和“..”这两项。因此,cramfs中的目录的链接数通常也仅有一个。
7) cramfs中,不会保存文件的时间戳(timestamps)信息。当然,正在使用的文件由于inode保存在内存中,因此其时间可以暂时地变更为最新时间,但是不会保存到cramfs文件系统中去。
8)当前版本的cramfs只支持PAGE_CACHE_SIZE为4096的内核。因此,如果发现cramfs不能正常读写的时侯,可以检查一下内核的参数设置。
在 嵌入式的环境之下,内存和外存资源都需要节约使用。如果使用ramdisk方式来使用文件系统,那么在系统运行之后,首先要把外存(Flash)上的映像 文件解压缩到内存中,构造起ramdisk环境,才可以开始运行程序。但是它也有很致命的弱点。在正常情况下,同样的代码不仅在外存中占据了空间(以压缩 后的形式存在),而且还在内存中占用了更大的空间(以解压缩之后的形式存在),这违背了嵌入式环境下尽量节省资源的要求。
使用cramfs就是一 种解决这个问题的方式。cramfs是一个压缩式的文件系统,它并不需要一次性地将文件系统中的所有内容都解压缩到内存之中,而只是在系统需要访问某个位 置的数据的时侯,马上计算出该数据在cramfs中的位置,将其实时地解压缩到内存之中,然后通过对内存的访问来获取文件系统中需要读取的数据。 cramfs中的解压缩以及解压缩之后的内存中数据存放位置都是由cramfs文件系统本身进行维护的,用户并不需要了解具体的实现过程,因此这种方式增 强了透明度,对开发人员来说,既方便,又节省了存储空间。
我选择的文件系统是ramdsik:
要先安装mtd(memory technology device),debian中安装mtd-tools,gentoo中安装mtd-utils。
1、建立内存映像文件ramdisk
1)mkdir -p /mnt/loop
2)dd if=/dev/zero of=/tmp/loop_tmp bs=1k count=3072
3)/sbin/losetup /dev/loop0 /tmp/loop_tmp
将设备与临时文件联系起来。如果出现“ioctl: LOOP_SET_FD: 设备或资源忙”的提示,说明设备还和一文件联系,可以用/sbin/losetup /dev/loop0来看,并可用-d来删除。
4)mkfs.ext2 –m0 /dev/loop0
mkfs.ext2将会自动判断设备容量的大小并相应地配置自身,-m0参数防止它给root保留空,这样会腾出更多地有用空间。
5)mount -t ext2 /dev/loop0 /mnt/loop
6)mkdir {bin,sbin,usr,dev,etc,lib,home,opt,root,src,tmp,var,mnt,proc,sys,initrd}
7)umount /mnt/loop
卸载此文件系统,得到的/tmp/loop_tmp就是ramdisk,可以将其改名为ramdisk
8)gzip - v9 /tmp/ramdisk
在/tmp中生成一个ramdisk.gz,这样一个内存映像文件就生成了。
2、编译busybox
1)
make defconfig
make menuconfig
2)busybox设置
1>在Build Options中的Build BusyBox as a static binary (no shared libs)是问是否将busybox静态链接,如果是glibc的话不选,如果是uclibc的话要选。
2>在Installation Options选项中,默认地, 运行 make install之后, BusyBox将被安装到./_install目录。
3>NFS是肯定要选的, 使用NFS将宿主机的文件系统mount到目标板上, 这是嵌入式Linux程序开发的一个重要方面。
4>由于可使用NFS, 能在宿主机上实现的功能就都不需要在目标板上实现了。
5>Debian Utilities 全不选, Editors全不选, System Logging Utilities全不选。
6>解压缩工具只安装解压工具,gzip、bzip2、tar工具(要求目标板能解压缩tar.bz2和tar.gz文件)。
7>shell使用ash。
3)编译及安装
make TARGET_ARCH=arm CROSS=arm-linux- -j2
make install
3、用busybox给ramdisk增加命令
1)
gunzip ramdisk.gz
mount -o loop ramdisk /mnt/ramdisk
2)
cd busybox1.4.1/_install
cp -rfv * /mnt/ramdisk
umount /mnt/ramdisk
gzip -v9 ramdisk
生 成最后带有busybox命令的内存映像文件ramdisk.gz,不过此时的ramdisk文件系统内仍缺少一些必需的东西,如/lib下的库文件、 /etc下的一些配置文件、/dev下的一些块设备和文件系统等,这都需要自己添加,如果觉得麻烦,可以下载一个现成的,然后在它的基础上作一些修改。
(注:BusyBox 将数以百计的常用Unix/Linux命令集成到一个可执行文件中(名为busybox)。它体积小巧, 功能却不失强大,常用Linux命令实现的功能它都能提供,它甚至还提供了tftp, http服务程序,尽管少数的Linux命令的某些选项BusyBox没能提供, 但这并不影响它在嵌入式Linux系统中的流行。
BusyBox 可以与glibc或uClibc库进行链接编译, 可以采用动态链接或静态链接,即便采用与glibc的静态链接, 最终生成的busybox文件大小也能轻易控制在1MB之内,而采用uClibc动态链接的可执行文件就更小了,这非常适于存储空间紧张的嵌入式 Linux系统。由此, 有人将BusyBox称为嵌入式系统中的瑞士军刀,更为形象的比喻是: Linux系统中的单个命令是电路中的分立式元件, 而BusyBox是将它们集成在一起的IC: 功能不变, 体积却大为减小。)
You're so cool! I don't suppose I have read through a single thing like this before. So great to find someone with some genuine thoughts on this subject. Really.. many thanks for starting this up. This site is something that's needed on the internet, someone with a bit of originality!
ReplyDeleteWe absolutely love your blog and find a lot of your post's to be just what I'm looking for. Does one offer guest writers to write content for yourself? I wouldn't mind writing a post or elaborating on a few of the subjects you write about here. Again, awesome weblog!
ReplyDelete