• 第1阶段——uboot分析之通过nand命令读内核(8)


    本节主要学习:
    详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0"
    怎么实现nand命令读内核.

    1. nand read.jffs2 0x30007FC0 kernel
    步骤a: 从NAND FILSHE中kernel分区读出
    步骤b: 放到0x30007FC0去

    1.1 kernel分区: 是flash中内核区
    其中在flash中定义了4大分区:
    | bootloader | :一开机直接运行u-boot
    |boot parameters | :存放一些可以设置的参数,供u-boot使用
    | kernel | :存放内核区
    |root filesystem | :根文件系统,挂载(mount)后才能使用文件系统中的应用程序

    这几个分区通过配置文件已在flash地址上是写好了,位于 u-boot-1.1.6/include/configs/100ask24x0.h:

    #define MTDIDS_DEFAULT "nand0=nandflash0"
    #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader),"
    "128k(params),"
    "2m(kernel),"
    "-(root)"

    在100ask24x0.h里定义了一个MTDPARTS_DEFAULT宏定义,
    “mtdparts=nandflash0:”表示mtdparts分区位于nandflash上
    "256k@0(bootloader),"表示从0开始共256kb是bootloader分区
    "128k(params),"表示接下来128kb用来存放参数,是params分区
    "2m(kernel)," 表示接下来2Mb用来存放内核,是kernel分区
    "-(root)" 表示剩下的容量存放根文件系统,是root分区

    1.2 可以通过在uboot界面输入"mtd"命令,查看4个分区的位置情况:
    #: name size offset mask_flags
    0:bootloader 0X00040000 0X00000000 0
    1:params 0X00020000 0X00040000 0
    2:kernel 0X00200000 0X00060000 0
    3:root 0X0fda0000 0X00260000 0

    从上面可以看出bootloader基地址是0x0000 0000,该分区大小为0x0004 000,所以结束地址为0X0003 FFFF。
    为什么0X00040000等于256kb?
    因为在ARM920t中,每隔4个地址保存了一个32位数据(4个字节)
    所以0X00040000=0X00040000个字节=0x100(256)*0x400(1024)=256Kb

    1.3 所以 nand read.jffs2 0x30007FC0 kernel 最终扩展开为:
    nand read.jffs2 0x30007FC0 0X00060000 0X00200000

    1.4 nand命令位于./common/cmd_nand.c(所有命令文件都是存在common中,以cmd_xx.c形式保存)
    其中nand命令执行时调用的是do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])函数
    进入do_nand()函数:

    int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
    { 
    int i, dev, ret;
    ulong addr, off, size;
    char *cmd, *s;
    nand_info_t *nand;
    int quiet = 0;
    const char *quiet_str = getenv("quiet"); //获取环境变量quiet
    
    
    if (argc < 2) //判断nand命令参数个数若小于2,将goto到usage,打印cmdtp->usage(nand命令短的帮助说明)
    goto usage;
    ...
    cmd = argv[1]; //cmd="read.jffs2"
    ...
    if (strcmp(cmd, "info") == 0) //cmd不等于"info",不执行
    {...}
    ...
    if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
    strncmp(cmd, "dump", 4) != 0 &&
    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
    strcmp(cmd, "biterr") != 0 &&
    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
    goto usage; //若argv[1]都不满足的话,表示使用命令在语法上有错误,打印短的帮助说明
    ....
    if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) //cmd==read为真
    {
    int read;
    
    if (argc < 4) // "nand read.jffs2 0x30007FC0 0X00060000 0X00200000"共5个参数,这里不执行
    goto usage;
    
    addr = (ulong)simple_strtoul(argv[2], NULL, 16); //将argv[2]的"0x30007FC0"字符型转换成数值型
    
    read = strncmp(cmd, "read", 4) == 0; 
    //strncmp():判断cmd和"read"前4个字节若相等返回0,不相等返回大于0的数
    //这里cmd与"read"相等,所以strncmp()返回0,read=(0==0)为真,所以read=1 
    printf("
    NAND %s: ", read ? "read" : "write"); //由于read=1,所以打印"
    NAND read:" 
    
    if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
    return 1;
    
    s = strchr(cmd, '.'); //strchr():查找'.'字符,若没找到返回NULL。
    if (s != NULL &&
    (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) //if为真,argv[1]=read.jffs2
    { 
    if (read) { //read==1,执行if
    /* read */
    nand_read_options_t opts;
    memset(&opts, 0, sizeof(opts));
    opts.buffer = (u_char*) addr; //设置buffer=0x30007FC0
    opts.length = size; //设置size=0X00200000=2097152 byte
    opts.offset = off; //设置offset=0X00060000
    opts.quiet = quiet;
    ret = nand_read_opts(nand, &opts); 
    //nand_read_opts():读取nandflash的kernel分区到 buffer地址,如读取成功返回0
    } else {
    /* write */
    ...
    }
    }
    else if ( s != NULL && !strcmp(s, ".yaffs")){
    ...
    }else if ( s != NULL && !strcmp(s, ".raw")){
    ...
    } else {
    ...
    }
    
    printf(" %d bytes %s: %s
    ", size, 
    read ? "read" : "written", ret ? "ERROR" : "OK"); //打印"2097152 bytes read : OK
    "
    
    return ret == 0 ? 0 : 1; //read读取kernel分区成功返回0,失败返回1
    }
  • 相关阅读:
    Java Web三层架构设计深思
    编译C源码软件需要的工具
    Hibernate之表间关系
    CSS之颜色字体
    主流的微服务框架
    CSS布局思考
    Android创建新项目及开发
    Google工程师解析Android系统架构
    java多线程实用操作
    Spring IOC/DI/注解
  • 原文地址:https://www.cnblogs.com/lifexy/p/7310147.html
Copyright © 2020-2023  润新知