zoukankan      html  css  js  c++  java
  • UBOOT——环境变量的实现原理

    uboot 环境变量实现原理:

    首先我们先要搞清楚uboot中环境变量的作用,uboot中环境变量的作用就是在不改变源码、不用重新编译的情况下,可以使我们通过

    设置环境变量的值来改变uboot的一些设置,如bootdelay时间、机器码的值等等。

    下面我们来具体看一下uboot中环境变量如何实现

    首先看一下环境变量的初始化函数:

      env_init定义在commen/env_movi.c中 函数中实际执行的就是把default_environment的地址赋值给全局变量gd中的env_addr 和env_valid两个值;

      

    int env_init(void)
    {
    #if defined(ENV_IS_EMBEDDED)
       #else /* ENV_IS_EMBEDDED */
        gd->env_addr  = (ulong)&default_environment[0];
        gd->env_valid = 1;
    #endif /* ENV_IS_EMBEDDED */
    
        return (0);
    }

    来看一下default_environment数组

    在来看一下env_relocate  这个函数

    重点是一下两句代码

          env_ptr = (env_t *)malloc (CFG_ENV_SIZE); 这句代码作用是给uboot环境变量开辟一块16k大小的内存

          env_relocate_spec ();  这句代码的作用是把sd卡中的uboot环境变量整个分区复制到开辟的这个内存地址处;      

    void env_relocate (void)
    {
       
    
    #ifdef ENV_IS_EMBEDDED
       #else
        /*
         * We must allocate a buffer for the environment
         */
        env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
        DEBUGF ("%s[%d] malloced ENV at %p
    ", __FUNCTION__,__LINE__,env_ptr);
    #endif
    
        if (gd->env_valid == 0) {
    
        }
        else {
            env_relocate_spec ();
        }
        gd->env_addr = (ulong)&(env_ptr->data);
    
    
    }

    通过movi_read_env函数把sd卡中的环境变量复制到内存中

    主药用到的是   movi_read_env(virt_to_phys((ulong)env_ptr)); 函数   

            crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc 

            use_default()

    三个函数: movi_read_env把sd卡中的uboot的环境变量分区复制到env_ptr中;

         crc32 计算内存中环境变量的crc的值,如果不相等则执行

         use_default函数 

    void env_relocate_spec (void)
    {
    #if !defined(ENV_IS_EMBEDDED)
        uint *magic = (uint*)(PHYS_SDRAM_1);
    
        if ((0x24564236 != magic[0]) || (0x20764316 != magic[1]))
            movi_read_env(virt_to_phys((ulong)env_ptr));
    
        if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
            return use_default();
    #endif /* ! ENV_IS_EMBEDDED */
    }

    下面看一下use_default函数的代码:

    1:输出*** Warning - bad CRC or moviNAND, using default environment:

    2:清0环境变量内存,把default_environment中的值复制到环境变量内存

    3:计算crc,写入内存中的crc位

    4:设置gd中的env_valid为1;

    static void use_default()
    {
        puts ("*** Warning - bad CRC or moviNAND, using default environment
    
    ");
    
        if (default_environment_size > CFG_ENV_SIZE){
            puts ("*** Error - default environment is too large
    
    ");
            return;
        }
    
        memset (env_ptr, 0, sizeof(env_t));
        memcpy (env_ptr->data,
                default_environment,
                default_environment_size);
        env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
        gd->env_valid = 1;
    }

    这样环境变量初始化算是完成了;

    我们在回顾一下环境变量初始化都做了哪些工作:

    1:在uboot还没有初始化flash设备(nand movinand 等flash)的时候,先进行环境变量初级初始化,即把gd全局变量中的 env_valid = 1; env_addr 等于全局变量default_enviroment数组的首地址

    2:初始化完flash设置以后就要进行环境变量的重定位工作了,即把环境变量从flash中copy到内存中,用一个全局变量env_ptr指向这段内存;复制工作时通过movi_read_env这个函数实现的,实际就是把sd卡中

    环境变量分区全部复制到env_ptr指向的这段内存中,然后在对这段内存中的环境变量进行crc校验,如果失败的话,则把default_enviroment中的环境变量复制到这里;

    (这里对代码分析env_relocate函数中用malloc设置了一段内存来存放环境变量,一直没有用free来释放这段内存,这里是否存在安全隐患?)

    ------------------------------------------------------------------------------------------------------------

    接下来我们在看一下uboot中关于环境变量的一些命令

    第一个 printenv 实现函数为do_printfenv

    代码如下:

     1 int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
     2 {
     3     int i, j, k, nxt;
     4     int rcode = 0;
     5 
     6     if (argc == 1) {        /* Print all env variables    */
     7         for (i=0; env_get_char(i) != ''; i=nxt+1) {
     8             for (nxt=i; env_get_char(nxt) != ''; ++nxt)
     9                 ;
    10             for (k=i; k<nxt; ++k)
    11                 putc(env_get_char(k));
    12             putc  ('
    ');
    13 
    14             if (ctrlc()) {
    15                 puts ("
     ** Abort
    ");
    16                 return 1;
    17             }
    18         }
    19 
    20         printf("
    Environment size: %d/%ld bytes
    ",
    21             i, (ulong)ENV_SIZE);
    22 
    23         return 0;
    24     }
    25 
    26     for (i=1; i<argc; ++i) {    /* print single env variables    */
    27         char *name = argv[i];
    28 
    29         k = -1;
    30 
    31         for (j=0; env_get_char(j) != ''; j=nxt+1) {
    32 
    33             for (nxt=j; env_get_char(nxt) != ''; ++nxt)
    34                 ;
    35             k = envmatch((uchar *)name, j);
    36             if (k < 0) {
    37                 continue;
    38             }
    39             puts (name);
    40             putc ('=');
    41             while (k < nxt)
    42                 putc(env_get_char(k++));
    43             putc ('
    ');
    44             break;
    45         }
    46         if (k < 0) {
    47             printf ("## Error: "%s" not defined
    ", name);
    48             rcode ++;
    49         }
    50     }
    51     return rcode;
    52 }
    uchar env_get_char_memory (int index)
    {
        if (gd->env_valid) {
            return ( *((uchar *)(gd->env_addr + index)) );
        } else {
            return ( default_environment[index] );
        }
    }

    第二个命令:setenv命令对用的函数是do_setenv 命令,实际上调用的是_do_setenv函数

    下面我们来分析一下这个函数

    int _do_setenv (int flag, int argc, char *argv[])
    {
        int   i, len, oldval;
        int   console = -1;
        uchar *env, *nxt = NULL;
        char *name;
        bd_t *bd = gd->bd;
    
        uchar *env_data = env_get_addr(0);
    
        if (!env_data)    /* need copy in RAM */
            return 1;
    
        name = argv[1];
    
        if (strchr(name, '=')) {
            printf ("## Error: illegal character '=' in variable name "%s"
    ", name);
            return 1;
        }
    
        /*
         * search if variable with this name already exists
         */
        oldval = -1;
        for (env=env_data; *env; env=nxt+1) {
            for (nxt=env; *nxt; ++nxt)
                ;
            if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)
                break;
        }
    
        /*
         * Delete any existing definition
         */
        if (oldval >= 0) {
    
    
            /* Check for console redirection */
            if (strcmp(name,"stdin") == 0) {
                console = stdin;
            } else if (strcmp(name,"stdout") == 0) {
                console = stdout;
            } else if (strcmp(name,"stderr") == 0) {
                console = stderr;
            }
    
            if (console != -1) {
                if (argc < 3) {        /* Cannot delete it! */
                    printf("Can't delete "%s"
    ", name);
                    return 1;
                }
    
                /* Try assigning specified device */
                if (console_assign (console, argv[2]) < 0)
                    return 1;
    
    #ifdef CONFIG_SERIAL_MULTI
                if (serial_assign (argv[2]) < 0)
                    return 1;
    #endif
            }
    
            /*
             * Switch to new baudrate if new baudrate is supported
             */
            if (strcmp(argv[1],"baudrate") == 0) {
                int baudrate = simple_strtoul(argv[2], NULL, 10);
                int i;
                for (i=0; i<N_BAUDRATES; ++i) {
                    if (baudrate == baudrate_table[i])
                        break;
                }
                if (i == N_BAUDRATES) {
                    printf ("## Baudrate %d bps not supported
    ",
                        baudrate);
                    return 1;
                }
                printf ("## Switch baudrate to %d bps and press ENTER ...
    ",
                    baudrate);
                udelay(50000);
                gd->baudrate = baudrate;
    
    
                serial_setbrg ();
                udelay(50000);
                for (;;) {
                    if (getc() == '
    ')
                          break;
                }
            }
    
            if (*++nxt == '') {
                if (env > env_data) {
                    env--;
                } else {
                    *env = '';
                }
            } else {
                for (;;) {
                    *env = *nxt++;
                    if ((*env == '') && (*nxt == ''))
                        break;
                    ++env;
                }
            }
            *++env = '';
        }
    
    #ifdef CONFIG_NET_MULTI
        if (strncmp(name, "eth", 3) == 0) {
            char *end;
            int   num = simple_strtoul(name+3, &end, 10);
    
            if (strcmp(end, "addr") == 0) {
                eth_set_enetaddr(num, argv[2]);
            }
        }
    #endif
    
    
        /* Delete only ? */
        if ((argc < 3) || argv[2] == NULL) {
            env_crc_update ();
            return 0;
        }
    
        /*
         * Append new definition at the end
         */
        for (env=env_data; *env || *(env+1); ++env)
            ;
        if (env > env_data)
            ++env;
        /*
         * Overflow when:
         * "name" + "=" + "val" +""  > ENV_SIZE - (env-env_data)
         */
        len = strlen(name) + 2;
        /* add '=' for first arg, ' ' for all others */
        for (i=2; i<argc; ++i) {
            len += strlen(argv[i]) + 1;
        }
        if (len > (&env_data[ENV_SIZE]-env)) {
            printf ("## Error: environment overflow, "%s" deleted
    ", name);
            return 1;
        }
        while ((*env = *name++) != '')
            env++;
        for (i=2; i<argc; ++i) {
            char *val = argv[i];
    
            *env = (i==2) ? '=' : ' ';
            while ((*++env = *val++) != '')
                ;
        }
    
        /* end is marked with double '' */
        *++env = '';
    
        /* Update CRC */
        env_crc_update ();
    
        /*
         * Some variables should be updated when the corresponding
         * entry in the enviornment is changed
         */
    
        if (strcmp(argv[1],"ethaddr") == 0) {
            char *s = argv[2];    /* always use only one arg */
            char *e;
            for (i=0; i<6; ++i) {
                bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
                if (s) s = (*e) ? e+1 : e;
            }
    #ifdef CONFIG_NET_MULTI
            eth_set_enetaddr(0, argv[2]);
    #endif
            return 0;
        }
    
        if (strcmp(argv[1],"ipaddr") == 0) {
            char *s = argv[2];    /* always use only one arg */
            char *e;
            unsigned long addr;
            bd->bi_ip_addr = 0;
            for (addr=0, i=0; i<4; ++i) {
                ulong val = s ? simple_strtoul(s, &e, 10) : 0;
                addr <<= 8;
                addr  |= (val & 0xFF);
                if (s) s = (*e) ? e+1 : e;
            }
            bd->bi_ip_addr = htonl(addr);
            return 0;
        }
        if (strcmp(argv[1],"loadaddr") == 0) {
            load_addr = simple_strtoul(argv[2], NULL, 16);
            return 0;
        }
    #if defined(CONFIG_CMD_NET)
        if (strcmp(argv[1],"bootfile") == 0) {
            copy_filename (BootFile, argv[2], sizeof(BootFile));
            return 0;
        }
    #endif
    
    #ifdef CONFIG_AMIGAONEG3SE
        if (strcmp(argv[1], "vga_fg_color") == 0 ||
            strcmp(argv[1], "vga_bg_color") == 0 ) {
            extern void video_set_color(unsigned char attr);
            extern unsigned char video_get_attr(void);
    
            video_set_color(video_get_attr());
            return 0;
        }
    #endif    /* CONFIG_AMIGAONEG3SE */
    
        return 0;
    }
  • 相关阅读:
    博客诞生感言~
    java 字符串锁
    oracle三种表连接方式
    两张超级大表join优化
    docker安装配置gitlab详细过程
    docker安装应用
    docker安装教程-centos
    JVM参数调优
    java向word中插入Excel附件
    application.properties参数详解
  • 原文地址:https://www.cnblogs.com/biaohc/p/6398515.html
Copyright © 2011-2022 走看看