环境 arm-linux-gcc 3.4.1
1.linux根文件系统概述
linux系统可以将磁盘,flash等存储设备划分为若该个分区,但是linux系统需要在一个分区上存放系统启动的所有文件,比如内核镜像、内核启动的第一个进程init进程、根文件系统等。系统在启动时会自动mount该文件系统。
linux系统上FHS :
/
|-- arm-linux-gcc-3.3.2.tar.bz2
|-- bin
|-- boot
|-- cdrom -> media/cdrom
|-- dev
|-- etc
|-- home
|-- host
|-- initrd.img -> boot/initrd.img-2.6.28-18-generic
|-- initrd.img.old -> boot/initrd.img-2.6.28-16-generic
|-- lib
|-- lost+found
|-- media
|-- mnt
|-- opt
|-- proc
|-- root
|-- sbin
|-- selinux
|-- srv
|-- sys
|-- tmp
|-- usr
|-- var
|-- vmlinuz -> boot/vmlinuz-2.6.28-18-generic
`-- vmlinuz.old -> boot/vmlinuz-2.6.28-16-generic
21 directories, 5 files
所谓的构建跟文件系统就是指构建符合FHS标准的文件夹,然后使用特定工具将上面生成的文件夹压制成某个特定的格式。
2.busybox使用
使用busybox的主要目的是构建以下的两个目录 /bin和/sbin。如果是创建最小根文件系统的话,另外还需要作的工作是:在/dev目录下创建设备节点,在/etc下创建配置文件,如果busybox使用动态连接库的话,还需要在/lib下放置需要的动态连接库。
init进程简介
init进程是内核启动之后第一个运行的进程,在init/main.c中启动。
/* This is a non __init function. Force it to be noinline otherwise gcc
* makes it inline to init() and it becomes part of init.text section
*/
static int noinline init_post(void)
{
...
// 试图打开/dev/console,如果成功,将/dev/console设置成init进程的标准输入
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console./n");
(void) sys_dup(0);
(void) sys_dup(0);
// ramdisk_execute_command变量指定要运行的程序
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s/n",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
// execute_command指定要运行的程序
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults.../n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
busybox的init进程在启动起来之后,会自动解析/etc/inittab中所列出的各项,其中每一条目定义一个子进程,格式如下<id>:<runlevel>:<action>:<process>。例如;
ttySACO::askfirst:-/bin/sh
id字段表示使用控制台,runlevel对于此字段没有意义,askfirst表示在启动该进程之前,输出“Please press Enter to activate this console”,/bin/sh需要启动的进程,“-”字符表示该进程是交互进程。
编译时出现:
miscutils/taskset.c:17: error: parse error before '*' token
miscutils/taskset.c:18: warning: function declaration isn't a prototype
miscutils/taskset.c: In function `__from_cpuset':
miscutils/taskset.c:22: error: `CPU_SETSIZE' undeclared (first use in this function)
miscutils/taskset.c:22: error: (Each undeclared identifier is reported only once
miscutils/taskset.c:22: error: for each function it appears in.)
miscutils/taskset.c:26: warning: implicit declaration of function `CPU_ISSET'
miscutils/taskset.c:26: error: `mask' undeclared (first use in this function)
miscutils/taskset.c: In function `taskset_main':
miscutils/taskset.c:47: error: `cpu_set_t' undeclared (first use in this function)
miscutils/taskset.c:47: error: parse error before "mask"
miscutils/taskset.c:68: warning: implicit declaration of function `CPU_ZERO'
miscutils/taskset.c:68: error: `new_mask' undeclared (first use in this function)
miscutils/taskset.c:69: error: `CPU_SETSIZE' undeclared (first use in this function)
miscutils/taskset.c:71: warning: implicit declaration of function `CPU_SET'
miscutils/taskset.c:78: error: `mask' undeclared (first use in this function)
make[1]: *** [miscutils/taskset.o] Error 1
make: *** [miscutils] Error 2
google得到:http://hi.baidu.com/zengzhaonong/blog/item/b0895436d24c33dea2cc2b03.html解决方案。
之后有出现:
Trying libraries: crypt m
Library crypt is needed
Library m is needed
Final link with: crypt m
http://blog.csdn.net/gnuhpc/archive/2009/07/05/4322521.aspx
这里说道可以不必理会直接make install。试之,果然在该目录下生成_install目录。ls -al ./bin :
drwxr-xr-x 2 xuqiang xuqiang 4096 2010-04-07 18:38 .
drwxr-xr-x 6 xuqiang xuqiang 4096 2010-04-07 18:41 ..
lrwxrwxrwx 1 xuqiang xuqiang 7 2010-04-07 18:38 addgroup -> busybox
lrwxrwxrwx 1 xuqiang xuqiang 7 2010-04-07 18:38 adduser -> busybox
lrwxrwxrwx 1 xuqiang xuqiang 7 2010-04-07 18:38 ash -> busybox
-rwxr-xr-x 1 xuqiang xuqiang 483424 2010-04-07 18:38 busybox
lrwxrwxrwx 1 xuqiang xuqiang 7 2010-04-07 18:38 cat -> busybox
...
说明这些可执行文件都是busybox的连接文件。
由于上面使用的是shared library,所以需要将程序中使用的库文件添加到/lib中。glibc套件包含若干个动态连接库。一般在安装/usr/local/arm/3.4.1/arm-linux/lib/目录下。
一般而言,开发板中只需要加载器和动态库即可,可以根据程序的以来关系得到需要保留的动态库。需要使用ldd.host来查看。
下载ulibc : http://ftp.ntu.edu.tw/linux/libs/uclibc/
cd uClibc-0.9.28/utils
make
生成ldd.host,可以使用ldd.host来查看以来关系。
xuqiang@ubuntu:~/Embedded/docs/Linux-Embedded/system/mini_fs/bin$ ldd.host busybox
libcrypt.so.1 => /lib/libcrypt.so.1 (0x00000000)
libm.so.6 => /lib/libm.so.6 (0x00000000)
libc.so.6 => /lib/libc.so.6 (0x00000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
经过上面的步骤的话,bin,sbin,lib目录已经构建好了,下面开始构建etc目录。
1.创建/etc/inittab
# /etc/inittab
::sysinit:/etc/init.d/rcS
ttySAC0:askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
说明 :mount -a [-t|-O] ... : mount all stuff from /etc/fstab
2.创建/etc/init.d/rcS,这是个脚本文件,在其中放置需要自动执行的命令。
#!/bin/sh
# ifconfig eth0 192.168.1.17
mount -a
3.创建/etc/fstab,每种文件系统都对应一个独立的行,每行中的字段都有空格或tab键分开。
# maybe the blank is not correct
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
构建设备dev目录。这里使用的是mdev来动态的构建。mdev是在busybox中生成,在/sbin/下。
修改fstab文件:
# maybe the blank is not correct
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
修改rcS文件:
#!/bin/sh
# ifconfig eth0 192.168.1.17
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
使用medv生辰的串口名是s3c2410_serial0,所以修改inittab文件:
s3c2410_serial0:askfirst:-/bin/sh
手动创建console,null设备。
mkdir dev
sudo mknod console c 5 1
sudo mknod null c 1 3
构建其他的空文件夹。
制作yaffs文件镜像。
下载源码,在utils文件夹中,执行make命令来生成。由于在内核的配置中没有设置CONFIG_YAFFS_DOES_ECC, 所以使用ecc校验函数是:内核源码的drivers/mtd/nand/nand_ecc.c中nand_calculate_ecc函数来实现。所以需要修改mkyaffsimage源码。
mkyaffsimage.c
///////////////////////////////////////////////////////
#include "yaffs_packedtags1.h"
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
#ifdef CONFIG_YAFFS_9BYTE_TAGS
yaffs_Tags t;
yaffs_Spare s;
error = write(outFile,data,512);
if(error < 0) return error;
memset(&t,0xff,sizeof (yaffs_Tags));
memset(&s,0xff,sizeof (yaffs_Spare));
t.chunkId = chunkId;
t.serialNumber = 0;
t.byteCount = nBytes;
t.objectId = objId;
if (convert_endian)
{
little_to_big_endian(&t);
}
yaffs_CalcTagsECC(&t);
yaffs_LoadTagsIntoSpare(&s,&t);
yaffs_CalcECC(data,&s);
nPages++;
return write(outFile,&s,sizeof(yaffs_Spare));
#else
yaffs_PackedTags1 pt1;
yaffs_ExtendedTags etags;
__u8 ecc_code[6];
__u8 oobbuf[16];
error = write (outFile, data, 512);
if(error < 0)
{
return error;
}
etags.chunkId = chunkId;
etags.serialNumber = 0;
etags.byteCount = nBytes;
etags.objectId = objId;
etags.chunkDeleted = 0;
yaffs_PackTags1(&pt1, &etags);
yaffs_CalcTagsECC((yaffs_Tags*)&pt1);
memset (oobbuf, 0xff, 16);
memset (oobbuf + 8, &pt1, 8);
nand_calculate_ecc (data, &ecc_code[0]);
nand_calculate_ecc (data + 256, &ecc_code[3]);
oobbuf[0] = ecc_code [0];
oobbuf[1] = ecc_code[1];
oobbuf[2] = ecc_code[2];
oobbuf[3] = ecc_code[3];
oobbuf[6] = ecc_code[4];
oobbuf[7] = ecc_code[5];
nPages++;
return write (outFile, oobbuf, 16);
#endif
}
将上层的文件yaffs_packedtags1.c拷贝到utils中。
修改Makefile
/////////////////////////////////////////////////////
MKYAFFSSOURCES = mkyaffsimage.c nand_ecc.c yaffs_packedtags1.c
MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o)
将drivers/mtd/nand/nand_ecc.c拷贝到utils中,并修改成(该文件已经修改):
///////////////////////////////////////////////////////////////////////////////
/*
* This file contains an ECC algorithm from Toshiba that detects and
* corrects 1 bit errors in a 256 byte block of data.
*
* drivers/mtd/nand/nand_ecc.c
*
* Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
* Toshiba America Electronics Components, Inc.
*
* Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
*
* $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 or (at your option) any
* later version.
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this file; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* As a special exception, if other files instantiate templates or use
* macros or inline functions from these files, or you compile these
* files and link them with other works to produce a work based on these
* files, these files do not by themselves cause the resulting work to be
* covered by the GNU General Public License. However the source code for
* these files must still be made available in accordance with section (3)
* of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*/
//////////////////////////////////////////////////
#include "linux/types.h"
#include <linux/kernel.h>
// #include <linux/module.h>
// #include <linux/mtd/nand_ecc.h>
////////////////////////////////////////////////
#include <inttypes.h>
/*
* Pre-calculated 256-way 1 byte column parity
*/
static const unsigned char nand_ecc_precalc_table[] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
};
/**
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
* @mtd: MTD block structure
* @dat: raw data
* @ecc_code: buffer for ECC
*/
int nand_calculate_ecc(const unsigned char *dat,
unsigned char* ecc_code)
{
uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
int i;
/* Initialize variables */
reg1 = reg2 = reg3 = 0;
/* Build up column parity */
for(i = 0; i < 256; i++) {
/* Get CP0 - CP5 from table */
idx = nand_ecc_precalc_table[*dat++];
reg1 ^= (idx & 0x3f);
/* All bit XOR = 1 ? */
if (idx & 0x40) {
reg3 ^= (uint8_t) i;
reg2 ^= ~((uint8_t) i);
}
}
/* Create non-inverted ECC code from line parity */
tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
#ifdef CONFIG_MTD_NAND_ECC_SMC
ecc_code[0] = ~tmp2;
ecc_code[1] = ~tmp1;
#else
ecc_code[0] = ~tmp1;
ecc_code[1] = ~tmp2;
#endif
ecc_code[2] = ((~reg1) << 2) | 0x03;
return 0;
}
最后make一下,生成mkyaffsimage和mkyaffs2image,使用mkyaffsimage来生成yaffs镜像。
mkyaffsimage mini_fs mini_fs.yaffs