zoukankan      html  css  js  c++  java
  • 1.移植3.4内核-分析内核启动过程,重新分区,烧写jffs2文件系统

    1.在上章-移植uboot里.我们来分析下uboot是如何进入到内核的

    首先,uboot启动内核是通过bootcmd命令行实现的,在我们之前移植的bootcmd命令行如下所示:

    bootcmd=nand read  0x30000000 kernel; bootm 0x30000000        //bootm:从0x30000000处启动内核

    1.1然后我们进入cmd_bootm.c,找到对应的bootm命令对应的do_bootm():

    int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    {
    boot_os_fn *boot_fn;             //boot_fn是个数组函数
     ... ..
    
    boot_fn(0, argc, argv, &images); //调用数组函数
     ... ...
    }

    上面的boot_os_fn是个typedef型,如下图所示:

     

    1.2由于定义了宏CONFIG_BOOTM_LINUX,最终会跳转到do_bootm ->do_bootm_linux()

    代码如下所示:

    int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
    {
             /* No need for those on ARM */
             if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
                       return -1;
             if (flag & BOOTM_STATE_OS_PREP) {
                       boot_prep_linux(images);
                       return 0;
             }
             if (flag & BOOTM_STATE_OS_GO) {
                       boot_jump_linux(images);
                       return 0;
             }
    
     
             boot_prep_linux(images);      //该函数会将各个tag参数保存在指定位置,比如:内存tag、bootargs环境变量tag、串口tag等
             boot_jump_linux(images);      //该函数会跳转到内核起始地址
             return 0;
    }

    1.3最终跳转到do_bootm ->do_bootm_linux-> boot_jump_linux()

    代码如下所示:

    static void boot_jump_linux(bootm_headers_t *images)
    {
             unsigned long machid = gd->bd->bi_arch_number;     //获取机器ID
             char *s;
             void (*kernel_entry)(int zero, int arch, uint params);
             unsigned long r2;
             kernel_entry = (void (*)(int, int, uint))images->ep;  //设置kernel_entry()的地址为0x30000000
             s = getenv("machid");                     //判断环境变量machid是否设置,若设置则使用环境变量里的值   
             if (s) {       
                       strict_strtoul(s, 16, &machid);      //重新获取机器ID
                       printf("Using machid 0x%lx from environment
    ", machid);  //使用环境变量的machid
             }
         ... ...
    r2 = gd->bd->bi_boot_params; //获取tag参数地址, gd->bd->bi_boot_params在setup_start_tag()函数里被设置 kernel_entry(0, machid, r2); //跳转到0x30000000,r0=0,r1=机器ID,r2=tag参数地址 }

     上面的machid默认值为MACH_TYPE_SMDK2410(也就是193),我们也可以在环境变量里设置machid变量

    1.4最终,便跳到内核执行代码,步骤如下所示:

    • 1)根据R1(机器ID),来判断内核是否支持该机器,若支持则初始化机器相关函数
    • 2)解析TAG参数,初始化串口,设置内存等
    • 3)挂载根文件系统,并执行应用程序

    2.接下来便从网上下载3.4.2内核来移植.

    2.1修改Makefile,修改配置

    tar xjf linux-3.4.2.tar.bz2 
    cd linux-3.4.2/
    vi Makefile 

    找到下面这句话:

    ARCH            ?= $(SUBARCH)
    CROSS_COMPILE   ?= $(CONFIG_CROSS_COMPILE:"%"=%)

     改为:

    ARCH            ?= arm
    CROSS_COMPILE   ?= arm-linux-

     (PS:我使用的是4.3.2,若交叉编译工具版本太低,可能无法编译)

    2.2 配置编译

    cd arch/arm/configs                //由于我们板子是arm板,进入该目录
    ls  *2440*                            //找到有mini2440_defconfig、
    ls  *2410*                            //找到有s3c2410_defconfig

    cd ../../.. make s3c2410_defconfig //配置2410, 更新.config配置文件 make uImage //编译,生成uImage cp uImage /work/nfs_root/ uImage_new //用nfs下载

    3进入uboot烧写

    nfs 32000000 192.168.2.106:/work/nfs_root/uImage_new
    bootm 32000000  

    如下图所示,发现串口输出乱码:

     

    出现这个问题,可以先看看bootargs命令行的串口设置是否正确、uboot传递的机器ID是否正确.

    3.1找到bootargs命令行的串口没有设置波特率,修改bootargs:

    set bootargs root=/dev/mtdblock3 console=ttySAC0,115200 

    3.2 测试机器ID是否正确

    在我们1.3小节代码分析里,讲到过uboot传递进来的机器ID可以通过环境变量machid来设置

    所以任意设置一个ID,这样再次启动内核时,内核识别不出来,就会打印出所有设备对应的机器ID

    进入uboot,输入:

    set machid 33333
    tftp 32000000 uImage
    bootm 32000000

    如下图所示,由于内核不支持这个机器ID,所以打印出内核能支持的ID表:

     

    由于我们板子是2440,所以测试7cf(mini2440)以及16a(smdk2440)这两个机器ID,是否支持我们开发板

    发现只有7cf(mini2440)这个ID,有串口输出正常.

    来看看16a(smdk2440)为什么串口乱码,进入mach-smdk2440.c( 位于arch/arm/mach-s3c24xx)

    找到问题出在smdk2440_map_io():

    static void __init smdk2440_map_io(void)
    {
             s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
             s3c24xx_init_clocks(16934400);             //初始化时钟clock
             s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
    }

    由于我们板子上的晶振是12Mhz,而mdk2440_map_io()里,初始化的时钟是基于16934400hz的晶振.

    所以将:

    s3c24xx_init_clocks(16934400);             //初始化时钟clock

    改为:

    s3c24xx_init_clocks(12000000);             //初始化时钟clock

    然后重新编译uImage:

    make  s3c2410_defconfig             //将mach-s3c2440.c配置进内核
    make  uImage
    cp uImage /work/nfs_root/ uImage_new

    进入uboot,输入:

    set machid 16a
    nfs 32000000 192.168.2.106:/work/nfs_root/uImage_new
    boom 32000000

    启动内核,打印如下图所示:

     

    如上图所示,内核创建了8个分区,而我们移植的uboot只有4个分区,代码如下:

    0x00000000-0x00040000 : "bootloader"            //存放uboot
    0x00040000-0x00060000 : "params"                //存放环境变量
    0x00060000-0x00260000 : "kernel"                //存放内核
    0x00260000-0x10000000 : "rootfs"                  //存放文件系统

    uboot传递的文件系统路径root=/dev/mtdblock3,所以内核便卡死在启动文件系统上

     

    4.所以接下来我们来修改内核分区

    4.1在si里搜索上图出现的”S3C2410 flash partition”字段

    如下图所示:

     

    找到位于common-smdk.c中,里面有个数组smdk_default_nand_part[],内容如下所示:

     

    4.2接下来便修改smdk_default_nand_part[]数组(位于arch/arm/mach-s3c24xx/common-smdk.c)

    修改为:

    static struct mtd_partition smdk_default_nand_part[] = {
             [0] = {
                       .name         = "bootloader",            //0x00000000-0x00040000  
                       .size  = SZ_256K,                      
                       .offset         = 0,
             },
    
             [1] = {
                       .name         = "params",                 //0x00040000-0x00060000
                       .offset = MTDPART_OFS_APPEND, 
                       .size  = SZ_128K,
             },
    
             [2] = {
                       .name         = "kernel",                  //0x00060000-0x00260000
                       .offset = MTDPART_OFS_APPEND,
                       .size  = SZ_2M,
             },
    
             [3] = {
                       .name         = "rootfs",                 //0x00260000-0x10000000
                       .offset         = MTDPART_OFS_APPEND,
                       .size  = MTDPART_SIZ_FULL,
             }
    };

    上面部分宏的定义,如下所示:

    • MTDPART_OFS_RETAIN:    填在offset里,表示先后保留多少size空间大小
    • MTDPART_OFS_NXTBLK:   填在offset里,表示从下一个块开始
    • MTDPART_OFS_APPEND:  填在offset里,表示该分区位置附加在上个分区结束的地址上
    • MTDPART_SIZ_FULL:         填在size里,表示剩下的内存size都归于该分区

    4.3若需要mini2440的机器ID,则还需要修改mini2440单板对应的mach-mini2440.c

    因为该单板的mtd分区也不对,将里面的mini2440_default_nand_part[]内容改为和上面一样

    4.4改好后,重启内核,发现内核还是启动不了以前的yaffs文件系统

    如下图所示:

     

    表示不支持该内核不支持yaffs文件系统,然后尝试使用ext3 ext2 cramfs vfat msdos iso9660等来挂载

    4.5 尝试使用以前的jffs2文件系统

    重新烧写jffs2,设置uboot环境变量,启动内核,打印如下图:

     

    上图,表示jffs2已挂载,但是找不到init程序,因为这个文件系统的glibc库是交叉编译3.4版本的,由于3.4内核的交叉编译是4.3版本,所以不支持,接下来我们便重新制作文件系统

    5.构造根文件系统

    5.1首先编译安装busybox(参考以前的busybox安装章节)

    进入https://busybox.net/下载busybox 1.20.0

    tar -xjf busybox-1.20.0.tar.bz2
    cd busybox-1.20.0
    make menuconfig          //设置交叉编译前缀

    进入Busybox Settings --->Build Options --->

    () Cross Compiler prefix

    在弹出的对话框里面写入:arm-linux-

    make          //编译
    mkdir   /work/nfs_root/fs_mini_mdev_new            //创建要安装的文件系统目录      
    make install CONFIG_PREFIX=/work/nfs_root/fs_mini_mdev_new   //指定安装位置

    5.2 安装glibc库

    输入$PATH找到交叉编译位于/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2位置,

    通过find -name lib,找到有以下几个lib

     

    由于ARM9属于ARMv4T架构,所以拷贝上面两条红线处的lib到fs_mini_mdev_new里

    mkdir /work/nfs_root/fs_mini_mdev_new/lib
    mkdir /work/nfs_root/fs_mini_mdev_new/usr/lib -p  
    cp arm-none-linux-gnueabi/libc/armv4t/usr/lib/*.so* /work/nfs_root/fs_mini_mdev_new/usr/lib -d           /* -d:保持链接 */
    cp arm-none-linux-gnueabi/libc/armv4t/lib/*.so* /work/nfs_root/fs_mini_mdev_new/lib -d

    5.3 构造etc目录

    在etc目录下,需要构造以下3个文件

    • etc/inittab     : init进程会根据inittab文件里,来创建其它子进程,比如
    • etc/init.d/rcS:脚本文件,里面用来执行命令,比如设置网卡,使用mount -a来装载/etc/fstab中的文件系统
    • etc/fstab      :里面保存要被挂载的哪个文件系统,比如proc、sysfs、tmpfs、devpts等系统

    1)构造/etc/inittab

    cd  cd /work/nfs_root/fs_mini_mdev_new/
    mkdir etc/
    vi etc/inittab

    添加以下几句:

    ::sysinit:/etc/init.d/rcS    //内核启动时,执行/etc/init.d/rcS
    console::askfirst:-/bin/sh  //启动console对应的-/bin/sh进程之前,等待用户按enter键
    ::ctrlaltdel:/sbin/reboot   //按下ctrl+alt+del组合键时,启动reboot命令
    ::shutdown:/bin/umount -a -r  //系统关机前,卸载所有文件系统

    2)构造etc/init.d/rcS

    mkdir etc/init.d/   
    vi  etc/init.d/rcS

    添加以下几句:

    mount -a               //装载/etc/fstab中的文件系统
    echo /sbin/mdev > /proc/sys/kernel/hotplug  //使/sbin/medv指向hotplug,从而支持热拔插
    mdev -s                //使用medv命令自动创建/dev下的所有设备节点

    并给rcS加上可执行权限:

    sudo chmod +x etc/init.d/rcS               //使脚本rcS能够执行命令

    3)构造etc/fstab

    PS:使用mdev命令需要sysfs、tmpfs、devpts这3个文件系统的支持

    mkdir proc/                            //创建proc要挂载的目录
    mkdir sys/                       //创建sysfs要挂载的目录,
    mkdir dev/pts -p              //创建devpts要挂载的目录
    vi  etc/fstab

    添加以下几句

    # 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
    devpts         /dev/pts     devpts   defaults      0     0

    5.4构造其它文件/目录

    1)创建终端文件(dev/console和dev/null)

    sudo mknod –m 660  dev/console c 5 1
    sudo mknod –m 660 dev/null c 1 3 

    2)创建其它目录

    mkdir mnt tmp root

    6.制作jffs2映像文件

    由于mkfs.jffs2工具之前已经安装好了,所以直接使用mkfs.jffs2命令:

    cd /work/nfs_root/                 //返回到上个目录
    mkfs.jffs2 -n  -s 2048  -e 128KiB  -d fs_mini_mdev_new  -o fs_mini_mdev_new.jffs2
    //-n:表示每块不添加清除标记,-s:NAND的每页为2k,-e: NAND的每块为128kb
    //-d fs_mini_mdev_new:表示要制作的根文件系统文件
    //-o fs_mini_mdev_new.jffs2:表示生成的映像文件

    7.烧写jffs2,启动内核

    nfs 30000000 192.168.2.106:/work/nfs_root/fs_mini_mdev_new.jffs2
    nand erase.part rootfs
    nand write.jffs2 30000000 260000  $filesize
    set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
    nfs 32000000 192.168.2.106:/work/nfs_root/uImage_new
    bootm 32000000

    7.1启动内核

    打印如下图所示:

     

    进入si,搜索exitcode,找到0x00000004对应的宏定义是SIGILL,表示非法指令

    是因为arm-linux-gcc-4.3.2是使用的EABI接口,内核由于未配置,所以出现非法

    7.2 配置内核支持EABI
    输入make menuconfig,搜索EABI,找到位于:

    kernel feature->

    [*] Use the ARM EABI to compile the kernel         
    make uImage

    重新编译烧写内核就没问题了

     

    未完待续,下章学习如何使内核支持yaffs系统

     

  • 相关阅读:
    解决SecureCRT中文显示乱码
    最新ubuntu10.10更新源
    向linux内核添加系统调用新老内核比较
    Field requires API level 5 (current min is 1) 问题的解决
    ubuntu 搜索文件方法(find命令)
    ubuntu12.04终端全屏
    .classpath 文件中的excluding属性
    eclipse中的.project 和 .classpath文件的具体作用
    Windows Mobile项目编译很慢情况的解决(VS2008)
    windowsphone7高级编程中提到的地址
  • 原文地址:https://www.cnblogs.com/lifexy/p/8337453.html
Copyright © 2011-2022 走看看