• u-boot之怎么实现分区


    启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0中kernel在哪定义,为什么可以直接引用?针对这个问题展开思考最终定位到了MTD分区的实现。 在u-boot之start_armboot函数分析中提到过实现nand flash的分区。执行run_command("mtdparts default", 0)可以实现分区功能,run_command函数在u-boot之内核是怎么启动的已经详细介绍过,现在只是说明mtdparts命令的执行函数do_jffs2_mtdparts,它位于Cmd_jffs2.c (common)文件下。

    1、环境变量的初始化

    2、mtdparts default命令分析(实现分区)

    3、nand read.jffs2 0x30007FC0 kernel命令中kernel的值

    1、环境变量的初始化

    环境变量的初始化在u-boot之start_armboot函数分析的时候已经粗略的提及过,但是没有具体分析,现在接着详细分析下,首先是在初始化数组中初始化的环境变量:

    env_init,        /* initialize environment *///初始化环境变量,采用默认环境变量  by andy

    具体的函数为:

        int env_init(void)
    {
    #if defined(ENV_IS_EMBEDDED)//ENV_IS_EMBEDDED表示环境变量存放在ram中,不存储在flash上
    /****此处省略******/
    #else /* ENV_IS_EMBEDDED */
        gd->env_addr  = (ulong)&default_environment[0];//取得默认的环境变量地址 
        gd->env_valid = 1;                             //环境变量已经存在标志
    #endif /* ENV_IS_EMBEDDED */
    
        return (0);
    }

    接着继续重新定位环境变量,函数如下

    /* initialize environment */
        env_relocate ();//初始化环境变量,crc有效的话从nand中读取存储的环境变量,否则采用默认的环境变量

    对env_relocate分析

    void env_relocate (void)
    {
        DEBUGF ("%s[%d] offset = 0x%lx
    ", __FUNCTION__,__LINE__,
            gd->reloc_off);
    
    #ifdef ENV_IS_EMBEDDED
    /*******省略*********/
    #else
        /*
         * We must allocate a buffer for the environment
         */
        env_ptr = (env_t *)malloc (CFG_ENV_SIZE);//在RAM中为环境变量的存放分配一个堆区 
        DEBUGF ("%s[%d] malloced ENV at %p
    ", __FUNCTION__,__LINE__,env_ptr);
    #endif
    
        /*
         * After relocation to RAM, we can always use the "memory" functions
         */
        env_get_char = env_get_char_memory;//得到环境变量的地址的函数
    
        if (gd->env_valid == 0) {//如果环境变量在一开始初始化的时候无效,重新定位默认环境变量
    #if defined(CONFIG_GTH)    || defined(CFG_ENV_IS_NOWHERE)    /* Environment not changable */
            puts ("Using default environment
    
    ");
    #else
            puts ("*** Warning - bad CRC, using default environment
    
    ");
            SHOW_BOOT_PROGRESS (-1);
    #endif
    
            if (sizeof(default_environment) > ENV_SIZE)
            {
                puts ("*** Error - default environment is too large
    
    ");
                return;
            }
    
            memset (env_ptr, 0, sizeof(env_t));
            memcpy (env_ptr->data,
                default_environment,
                sizeof(default_environment));
    #ifdef CFG_REDUNDAND_ENVIRONMENT
            env_ptr->flags = 0xFF;
    #endif
            env_crc_update ();
            gd->env_valid = 1;
        }
        else {
            env_relocate_spec ();//从nand中取出有效的数据,如果无效,还是使用默认的环境变量
        }
        gd->env_addr = (ulong)&(env_ptr->data);//取得首个环境变量的地址env_ptr为一个结构体,包含了crc、flags、以及data指针
    }

    2、mtdparts default命令分析(实现分区)

    跟着do_jffs2_mtdparts函数往里看,setenv为设置环境变量函数。

        if (argc == 2) {//如果参数个数为2个
            if (strcmp(argv[1], "default") == 0) {           //默认参数
                setenv("mtdids", (char *)mtdids_default);    //设置mtdids环境变量
                setenv("mtdparts", (char *)mtdparts_default);//设置mtdparts环境变量
                setenv("partition", NULL);                   //设置partition环境变量
    
                mtdparts_init();//分区初始化  by andy
                return 0;
            } else if (strcmp(argv[1], "delall") == 0) {//删除所有分区 
                /* this may be the first run, initialize lists if needed */
                mtdparts_init();
    
                setenv("mtdparts", NULL);
    
                /* devices_init() calls current_save() */
                return devices_init();
            }
        }

    继续往里看mtdparts_init函数,这函数比较复杂,先看一下它的调用层次。

    mtdparts_init();//分区初始化  by andy
            parse_mtdids(ids);    //添加mtdids到mtdids链表 nand0=nandflash0
            parse_mtdparts(parts);//添加分区parts
                devices_init();//0初始化成功,主要是做了删除所有分区设备的工作 
                    device_parse(p, &p, &dev);//添加分区设备,返回的设备为dev,p为从环境变量取得的字符串
                            id_find_by_mtd_id(mtd_id, mtd_id_len - 1);//找到parse_mtdids(ids);中添加的mtdids以及名称nandflash0
                            while (p && (*p != '') && (*p != ';')) {
                            {
                                part_parse(p, &p, &part);//分区解析,填充part,添加解析过后的part的链表。这个函数解析MTDPARTS_DEFAULT然后分区
                            }

    总的来说就是根据MTDIDS_DEFAULT 与MTDPARTS_DEFAULT解析它们然后进行分区

    #define MTDIDS_DEFAULT "nand0=nandflash0"//分区设备为nand
    #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," //bootloader分区
                                "128k(params),"                        //参数分区
                                "2m(kernel),"                          //内核分区
                                "-(root)"                               //用户分区

    3、nand read.jffs2 0x30007FC0 kernel中kernel的值

    实现了分区之后就可以调用分区的名称了,kernel就是其中一个分区的名称。同样的切换到nand命令的运行函数do_nand。同样对它进行层次分析,找到kernel。

    do_nand
        arg_off_size(argc - 3, argv + 3, nand, &off, &size)//5个参数分别代表参数个数、参数位于的地址、分区设备结构地址、返回的偏移值、返回的大小
            find_dev_and_part(argv[0], &dev, &pnum, &part)//查找有哪个设备存在argv[0]分区,即kernel分区,找到分区信息存放在part中
            *off  = part->offset;//找到了nand设备,取得偏移值
            *size = part->size;  //取得大小
  • 相关阅读:
    11.2~11.8 每周总结
    11.30~11.6 每周总结
    架构之美 图书笔记 03
    每周总结 10.26-11.1
    每周总结 10.19-10.25
    每周总结 10.12-10.18
    [Tips] centos下docker服务开机自启动
    [Notes] Linux内网穿透
    [Tips] python 文件读写
    [Tips] python 文件读写
  • 原文地址:https://www.cnblogs.com/andyfly/p/9358928.html
Copyright © 2020-2023  润新知