根文件系统制作

时间:2022-07-25 09:05:43

环境 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