Linux每周一记(2014-6-25)

时间:2022-02-10 08:07:10

构建根文件系统

创建根文件系统主目录/nfsroot/rootfs  (/nfsroot问nfs文件系统共享目录,开发板可将他作为网络根文件系统直接启动)

mkdir -p /nfsroot/rootfs (-p表示如果创建目录的父目录不存在,则创建父目录)

cd /nfsroot/rootfs

mkdir bin dev etc lib proc sbin sys usr mnt tmp var

mkdir usr/bin usr/sbin usr/lib lib/modules


创建设备文件(可自行创建,或者通过mdev生成)

内核在引导时,设备节点console,null必须存在(使用mdev的情况下,不使用mdev还要创建其他设备文件)

mknod -m 666 console c 5 1

mknod -m 555 null c 1 3


构建etc目录

init进程根据/etc/inittab文件来创建其他子进程。

仿照busybox的examples/inittab文件(ubuntu默认不创建,所以找不到这个文件,但可自行创建,系统还是首先搜索inittab进行配置)

#格式(<id>:<runlevels>:<action>:<process>)
#id:子进程要使用的控制台(标准输入、标准输出、标准错误设备),如果省略,则使用与init进程一样的控制台
#runlevels:对于busybox init无意义
#action:表示init进程如何控制这个子进程(sysinit\wait\once\respawn\askfirst\shutdown\restart\ctrlaltdel)
#process:要执行的程序,可执行程序或者脚本(如字段前有“-”字符,程序为”交互的“)

# /etc/inittab
#init进程启动的第一个子进程,是一个脚本,可以在里面指定用户想执行的操作,如挂接其他文件系统,配置网络等
#脚本文件,可在rcS中添加想自动执行的命令
::sysinit:/etc/init.d/rcS
#启动shell,已/dev/ttySAC0为控制台(如果通过mdev生成,则为s3c2440_serial0)
ttySAC0::askfirst:-/bin/sh
#按下ctrl+alt+del之后执行的程序
::ctrlaltdel:/sbin/reboot
#重启、关机前执行的程序
::shutdown:/bin/umount -a -r    

创建etc/init.d/rcS文件

脚本文件,可在里面添加想自动执行的命令

#表示这是一个脚本文件,运行时用/bin/sh解析
#!/bin/sh                            
#用来配置ip地址                                                     
ifconfig eth0 192.168.1.17
#挂接/etc/fstab文件指定的所有文件系统
mount -a
          

创建etc/fstab文件

#device 要挂接的设备
#如/dev/hda2、/dev/mtdblock1等设备文件;对于proc文件系统。此字段无意义,可是任意值;对于NFS文件系统,此字段为<host>:<dir>
#proc文件系统为伪文件系统,存储内核当前运行状态的一系列特殊文件
#mount-point 挂接点
#type 文件系统类型
#option 挂接参数
#device     mount-point     type        options     dump        fsck order
proc        /proc       proc        defaults        0       0
tmpfs       /tmp        tmpfs       defaults        0       0   

也可参考busybox中的/docs/mdev.txt使用mdev创建设备文件。

解释语句:

#mdev需要内核支持sysfs文件系统,使用tmpfs减少对Flash的读写
mount -t tmpfs mdev /dev
#dev/pts用来支持外部网络连接的虚拟终端
mkdir /dev/pts
mount -t devpts devpts /dev/pts
#通过sysfs文件系统获得设备信息
mount -t sysfs sysfs /sys
#设置内核,当有设备拔插时调用/bin/mdev程序
echo /bin/mdev > /proc/sys/kernel/hotplug
#在/dev目录下生成内核支持的所有设备的节点
mdev -s

制作ysffs文件系统映像文件(Yet Another Flash File System)

make出现错误,暂不能解决


Linux启动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 noinline int init_post(void)
{
    /* need to finish all async __init code before freeing the memory */
    async_synchronize_full();
    free_initmem();
    unlock_kernel();
    mark_rodata_ro();
    system_state = SYSTEM_RUNNING;
    numa_default_policy();
    //在这里打开/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");
    //将文件描述符0赋给标准输出、标准错误,则标准输入,输出,错误,对应同一设备
    (void) sys_dup(0);//1 
    (void) sys_dup(0);//2    
    current->signal->flags |= SIGNAL_UNKILLABLE;
 if (ramdisk_execute_command) {  //ramdisk_execute_command指定要运行的程序
    //1、命令行参数指定了“rdinit=”,则ramdisk_execute_command等于参数指定程序
    //2、如果/init程序存在,则XXX等于“/init”
    //3、不满足上面2条件,XXX为空
        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.
     */
    if (execute_command) {//如果命令行参数中指定了“init=...”,则execute_command等于这个参数指定的程序,否则为空
        run_init_process(execute_command);
        printk(KERN_WARNING "Failed to execute %s.  Attempting "
                    "defaults...\n", execute_command);
    }
//依次尝试执行/sbin/init、/etc/init、/bin/init、/bin/sh
    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.");
}
  
static static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };//程序名                         
char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };//执行/sbin/init的环境参数

void run_init_process(char *init_filename)                                         
{
    argv_init[0] = init_filename;
    kernel_execve(init_filename, argv_init, envp_init);
}

busybox init启动情况

static void console_init(void)  
{
    struct serial_struct sr;
    char *s;

    s = getenv("CONSOLE");   //如果有设置环境变量CONSOLE或者console则根据环境变量使用指定设备
    if (!s) s = getenv("console");
    if (s) {
        int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY);
        if (fd >= 0) {
            dup2(fd, 0); //使标准输入输出错误联系到同一设备
            dup2(fd, 1);
            dup2(fd, 2);
            while (fd > 2) close(fd--);//除上述句柄,关闭其他句柄
        }
        messageD(L_LOG, "console='%s'", s);
    } else {
        /* Make sure fd 0,1,2 are not closed */
        bb_sanitize_stdio();
    }

    s = getenv("TERM");
    if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
        /* Force the TERM setting to vt102 for serial console --
         * if TERM is set to linux (the default) */
        if (!s || strcmp(s, "linux") == 0)
            putenv((char*)"TERM=vt102");
#if !ENABLE_FEATURE_INIT_SYSLOG
        log_console = NULL;//如果上述设备不能打开,则使用/dev/null
#endif
    } else if (!s)
        putenv((char*)"TERM=linux");
}

编译busybox,执行

make CONFIG_PREFIX=/nfsroot/rootfs install

将busybox安装到/rootfs目录下

目标目录下sbin bin下的命令都是busybox的软连接


使用glibc库

在开发板上只需要加载器和动态库(基本含有so字符的都属于两者之一)

进入交叉编译器源目录中的lib将其中的加载器和动态库拷贝至根目录文件的lib中


使用mkyaffsimage制作yaffs映像文件

进入根文件目录

sudo mkyaffsimage rootfs rootfs.yaffs