U-boot(六):命令体系,环境变量,iNand/SD卡驱动

        本文主要探讨210的uboot命令体系,黄金变量,iNand/SD卡驱动相关知识。

命令体系

        uboot命令体系
                
位置:uboot/common/
                参数:uboot命令支持传递参数(argc,argv)
                函数:xxx命令的实现算数为do_xxx

/** Use puts() instead of printf() to avoid printf buffer overflow* for long help messages*/
int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{int i;int rcode = 0;if (argc == 1) {	/*show list of commands */int cmd_items = &__u_boot_cmd_end -&__u_boot_cmd_start;	/* pointer arith! */cmd_tbl_t *cmd_array[cmd_items];int i, j, swaps;/* Make array of commands from .uboot_cmd section */cmdtp = &__u_boot_cmd_start;for (i = 0; i < cmd_items; i++) {cmd_array[i] = cmdtp++;}/* Sort command list (trivial bubble sort) */for (i = cmd_items - 1; i > 0; --i) {swaps = 0;for (j = 0; j < i; ++j) {if (strcmp (cmd_array[j]->name,cmd_array[j + 1]->name) > 0) {cmd_tbl_t *tmp;tmp = cmd_array[j];cmd_array[j] = cmd_array[j + 1];cmd_array[j + 1] = tmp;++swaps;}}if (!swaps)break;}/* print short help (usage) */for (i = 0; i < cmd_items; i++) {const char *usage = cmd_array[i]->usage;/* allow user abort */if (ctrlc ())return 1;if (usage == NULL)continue;puts (usage);}return 0;}/** command help (long version)*/for (i = 1; i < argc; ++i) {if ((cmdtp = find_cmd (argv[i])) != NULL) {
#ifdef	CFG_LONGHELP/* found - print (long) help info */puts (cmdtp->name);putc (' ');if (cmdtp->help) {puts (cmdtp->help);} else {puts ("- No help available.\n");rcode = 1;}putc ('\n');
#else	/* no long help available */if (cmdtp->usage)puts (cmdtp->usage);
#endif	/* CFG_LONGHELP */} else {printf ("Unknown command '%s' - try 'help'"" without arguments for list of all"" known commands\n\n", argv[i]);rcode = 1;}}return rcode;
}

        命令解析和执行

                uboot二阶段初始化完成进入main_loop循环,main_loop执行一次为一条命令的获取,解析,执行(run_command)的过程

/* main_loop() can return to retry autoboot, if so just run it again. */for (;;) {main_loop ();}


                run_command

                        控制台命令获取 
                        命令解析(parse_line)为命令和参数
                        执行命令:用函数指针方式调用命令函数

/***************************************************************************** returns:*    1  - command executed, repeatable*    0  - command executed but not repeatable, interrupted commands are*         always considered not repeatable*    -1 - not executed (unrecognized, bootd recursion or too many args)*           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is*           considered unrecognized)** WARNING:** We must create a temporary copy of the command since the command we get* may be the result from getenv(), which returns a pointer directly to* the environment data, which may change magicly when the command we run* creates or modifies environment variables (like "bootp" does).*/int run_command (const char *cmd, int flag)
{cmd_tbl_t *cmdtp;char cmdbuf[CFG_CBSIZE];    /* working copy of cmd        */char *token;            /* start of token in cmdbuf    */char *sep;            /* end of token (separator) in cmdbuf */char finaltoken[CFG_CBSIZE];char *str = cmdbuf;char *argv[CFG_MAXARGS + 1];    /* NULL terminated    */int argc, inquotes;int repeatable = 1;int rc = 0;#ifdef DEBUG_PARSERprintf ("[RUN_COMMAND] cmd[%p]=\"", cmd);puts (cmd ? cmd : "NULL");    /* use puts - string may be loooong */puts ("\"\n");
#endifclear_ctrlc();        /* forget any previous Control C */if (!cmd || !*cmd) {return -1;    /* empty command */}if (strlen(cmd) >= CFG_CBSIZE) {puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);/* Process separators and check for invalid* repeatable commands*/#ifdef DEBUG_PARSERprintf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endifwhile (*str) {/** Find separator, or string end* Allow simple escape of ';' by writing "\;"*/for (inquotes = 0, sep = str; *sep; sep++) {if ((*sep=='\'') &&(*(sep-1) != '\\'))inquotes=!inquotes;if (!inquotes &&(*sep == ';') &&    /* separator        */( sep != str) &&    /* past string start    */(*(sep-1) != '\\'))    /* and NOT escaped    */break;}/** Limit the token to data between separators*/token = str;if (*sep) {str = sep + 1;    /* start of command for next pass */*sep = '\0';}elsestr = sep;    /* no more commands for next pass */
#ifdef DEBUG_PARSERprintf ("token: \"%s\"\n", token);
#endif/* find macros in this token and replace them */process_macros (token, finaltoken);/* Extract arguments */if ((argc = parse_line (finaltoken, argv)) == 0) {rc = -1;    /* no command at all */continue;}/* Look up command in command table */if ((cmdtp = find_cmd(argv[0])) == NULL) {printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1;    /* give up after bad command */continue;}/* found - check max args */if (argc > cmdtp->maxargs) {printf ("Usage:\n%s\n", cmdtp->usage);rc = -1;continue;}#if defined(CONFIG_CMD_BOOTD)/* avoid "bootd" recursion */if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSERprintf ("[%s]\n", finaltoken);
#endifif (flag & CMD_FLAG_BOOTD) {puts ("'bootd' recursion detected\n");rc = -1;continue;} else {flag |= CMD_FLAG_BOOTD;}}
#endif/* OK - call function to do the command */if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {rc = -1;}repeatable &= cmdtp->repeatable;/* Did the user stop this? */if (had_ctrlc ())return -1;    /* if stopped then not repeatable */}return rc ? rc : repeatable;
}/****************************************************************************/#if defined(CONFIG_CMD_RUN)
int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{int i;if (argc < 2) {printf ("Usage:\n%s\n", cmdtp->usage);return 1;}for (i=1; i<argc; ++i) {char *arg;if ((arg = getenv (argv[i])) == NULL) {printf ("## Error: \"%s\" not defined\n", argv[i]);return 1;}
#ifndef CFG_HUSH_PARSERif (run_command (arg, flag) == -1)return 1;
#elseif (parse_string_outer(arg,FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)return 1;
#endif}return 0;
}

        uboot管理命令集

        uboot每个命令对应cmd_tbl_t结构体的一个实例,输入命令结构体实例中查找对应的结构体,找到后调用命令函数执行命令

struct cmd_tbl_s {char        *name;        /* Command Name            */int        maxargs;    /* maximum number of arguments    */int        repeatable;    /* autorepeat allowed?        *//* Implementation function    */int        (*cmd)(struct cmd_tbl_s *, int, int, char *[]);char        *usage;        /* Usage message    (short)    */
#ifdef    CFG_LONGHELPchar        *help;        /* Help  message    (long)    */
#endif
#ifdef CONFIG_AUTO_COMPLETE/* do auto completion on the arguments */int        (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s    cmd_tbl_t;

                name:命令名称
                maxargs:命令最多接收参数
                repeatable:命令是否可重复执行(回车重复上条命令)
                cmd:命令对应函数,使用函数指针调用命令
                usage:命令短介绍
                help:命令长介绍
                complete:命令自动补(函数指针)


        uboot命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性内容链接在一起排列(类似命令结构体数组)
        uboot重定位时将该段整体加载到DDR中,段起始和结束地址(链接地址在u-boot.lds)对应命令集开始和结束地址

   

__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;


         U_BOOT_CMD宏(uboot/common/command.h)

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
U_BOOT_CMD(version,    1,        1,    do_version,"version - print monitor version\n",NULL
);宏被替换为:cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}find_cmd

        查找命令

/**************************************************************************** find command table entry for a command*/
cmd_tbl_t *find_cmd (const char *cmd)
{cmd_tbl_t *cmdtp;cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;    /*Init value */const char *p;int len;int n_found = 0;/** Some commands allow length modifiers (like "cp.b");* compare command name only until first dot.*/len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);for (cmdtp = &__u_boot_cmd_start;cmdtp != &__u_boot_cmd_end;cmdtp++) {if (strncmp (cmd, cmdtp->name, len) == 0) {if (len == strlen (cmdtp->name))return cmdtp;    /* full match */cmdtp_temp = cmdtp;    /* abbreviated command ? */n_found++;}}if (n_found == 1) {            /* exactly one match */return cmdtp_temp;}return NULL;    /* not found or ambiguous command */
}

                find_cmd函数是在uboot命令集中查找命令并返回命令结构体指针,未找到返回NULL

环境变量

        uboot环境变量(uboot/common/env_common.c)
    
            优先级:环境变量为空则使用代码中环境变量(代码中定义了环境变量的值),不为空则使用环境变量
                machid(机器码定义在x210_sd.h)为2456,可在定义处修改重编译或修改环境变量(set) 
                SD卡中有变量分区用于存储环境变量,uboot运行时将环境变量读到DDR中,save时将环境变量保存到SD卡
                default_environment初始化环境变量(默认),二阶段SD卡的env分区crc校验通过,env_relocate读取SD卡环境变量覆盖default_environment,后面使用的都为SD卡环境变量
默认环境变量存储在default_environment字符数组,大小为CFG_ENV_SIZE(16kb)相邻环境变量用'\0'分隔

void env_crc_update (void)
{env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
}void env_relocate (void)
{DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,gd->reloc_off);#ifdef CONFIG_AMIGAONEG3SEenable_nvram();
#endif#ifdef ENV_IS_EMBEDDED/** The environment buffer is embedded with the text segment,* just relocate the environment pointer*/env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else/** We must allocate a buffer for the environment*/env_ptr = (env_t *)malloc (CFG_ENV_SIZE);DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endifif (gd->env_valid == 0) {
#if defined(CONFIG_GTH)    || defined(CFG_ENV_IS_NOWHERE)    /* Environment not changable */puts ("Using default environment\n\n");
#elseputs ("*** Warning - bad CRC, using default environment\n\n");show_boot_progress (-60);
#endifset_default_env();}else {env_relocate_spec ();}gd->env_addr = (ulong)&(env_ptr->data);#ifdef CONFIG_AMIGAONEG3SEdisable_nvram();
#endif
}/************************************************************************* Default settings to be used when no valid environment is found*/
#define XMK_STR(x)    #x
#define MK_STR(x)    XMK_STR(x)#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430) || defined(CONFIG_S5P6440) || defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)
uchar default_environment[CFG_ENV_SIZE] = {
#else
uchar default_environment[] = {
#endif
#ifdef    CONFIG_BOOTARGS"bootargs="    CONFIG_BOOTARGS            "\0"
#endif
#ifdef    CONFIG_BOOTCOMMAND"bootcmd="    CONFIG_BOOTCOMMAND        "\0"
#endif
#if 0    /* for fast booting */"verify="        MK_STR(no)                    "\0"
#endif
#ifdef    CONFIG_MTDPARTITION"mtdpart="    CONFIG_MTDPARTITION        "\0"
#endif
#ifdef    CONFIG_RAMBOOTCOMMAND"ramboot="    CONFIG_RAMBOOTCOMMAND        "\0"
#endif
#ifdef    CONFIG_NFSBOOTCOMMAND"nfsboot="    CONFIG_NFSBOOTCOMMAND        "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)"bootdelay="    MK_STR(CONFIG_BOOTDELAY)    "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)"baudrate="    MK_STR(CONFIG_BAUDRATE)        "\0"
#endif
#ifdef    CONFIG_LOADS_ECHO"loads_echo="    MK_STR(CONFIG_LOADS_ECHO)    "\0"
#endif
#ifdef    CONFIG_ETHADDR"ethaddr="    MK_STR(CONFIG_ETHADDR)        "\0"
#endif
#ifdef    CONFIG_ETH1ADDR"eth1addr="    MK_STR(CONFIG_ETH1ADDR)        "\0"
#endif
#ifdef    CONFIG_ETH2ADDR"eth2addr="    MK_STR(CONFIG_ETH2ADDR)        "\0"
#endif
#ifdef    CONFIG_ETH3ADDR"eth3addr="    MK_STR(CONFIG_ETH3ADDR)        "\0"
#endif
#ifdef    CONFIG_IPADDR"ipaddr="    MK_STR(CONFIG_IPADDR)        "\0"
#endif
#ifdef    CONFIG_SERVERIP"serverip="    MK_STR(CONFIG_SERVERIP)        "\0"
#endif
#ifdef    CFG_AUTOLOAD"autoload="    CFG_AUTOLOAD            "\0"
#endif
#ifdef    CONFIG_PREBOOT"preboot="    CONFIG_PREBOOT            "\0"
#endif
#ifdef    CONFIG_ROOTPATH"rootpath="    MK_STR(CONFIG_ROOTPATH)        "\0"
#endif
#ifdef    CONFIG_GATEWAYIP"gatewayip="    MK_STR(CONFIG_GATEWAYIP)    "\0"
#endif
#ifdef    CONFIG_NETMASK"netmask="    MK_STR(CONFIG_NETMASK)        "\0"
#endif
#ifdef    CONFIG_HOSTNAME"hostname="    MK_STR(CONFIG_HOSTNAME)        "\0"
#endif
#ifdef    CONFIG_BOOTFILE"bootfile="    MK_STR(CONFIG_BOOTFILE)        "\0"
#endif
#ifdef    CONFIG_LOADADDR"loadaddr="    MK_STR(CONFIG_LOADADDR)        "\0"
#endif
#ifdef  CONFIG_CLOCKS_IN_MHZ"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)"pcidelay="    MK_STR(CONFIG_PCI_BOOTDELAY)    "\0"
#endif
#ifdef  CONFIG_EXTRA_ENV_SETTINGSCONFIG_EXTRA_ENV_SETTINGS
#endif"\0"
};

        环境变量命令(cmd_nvedit.c)

                printenv

/************************************************************************* Command interface: print one or all environment variables*/int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){int i, j, k, nxt;int rcode = 0;if (argc == 1) {        /* Print all env variables    */for (i=0; env_get_char(i) != '\0'; i=nxt+1) {for (nxt=i; env_get_char(nxt) != '\0'; ++nxt);for (k=i; k<nxt; ++k)putc(env_get_char(k));putc  ('\n');if (ctrlc()) {puts ("\n ** Abort\n");return 1;}}printf("\nEnvironment size: %d/%ld bytes\n",i, (ulong)ENV_SIZE);return 0;}for (i=1; i<argc; ++i) {    /* print single env variables    */char *name = argv[i];k = -1;for (j=0; env_get_char(j) != '\0'; j=nxt+1) {for (nxt=j; env_get_char(nxt) != '\0'; ++nxt);k = envmatch((uchar *)name, j);if (k < 0) {continue;}puts (name);putc ('=');while (k < nxt)putc(env_get_char(k++));putc ('\n');break;}if (k < 0) {printf ("## Error: \"%s\" not defined\n", name);rcode ++;}}return rcode;
}

                        argc=1打印所有环境变量出来,argc不为1,打印参数环境变量

                setenv

                        遍历DDR中环境变量,存在则修改,不存在则新建,环境变量为baudrate、ipaddr等全局变量在修改时,同时也需修改gd

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\"\n", 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) {
#ifndef CONFIG_ENV_OVERWRITE/** Ethernet Address and serial# can be set only once,* ver is readonly.*/if (
#ifdef CONFIG_HAS_UID/* Allow serial# forced overwrite with 0xdeaf4add flag */((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
#else(strcmp (name, "serial#") == 0) ||
#endif((strcmp (name, "ethaddr") == 0)
#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)&& (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif    /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */) ) {printf ("Can't overwrite \"%s\"\n", name);return 1;}
#endif/* 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\"\n", name);return 1;}/* Try assigning specified device */if (console_assign (console, argv[2]) < 0)return 1;#ifdef CONFIG_SERIAL_MULTIif (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\n",baudrate);return 1;}printf ("## Switch baudrate to %d bps and press ENTER ...\n",baudrate);udelay(50000);gd->baudrate = baudrate;
#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)gd->bd->bi_baudrate = baudrate;
#endifserial_setbrg ();udelay(50000);for (;;) {if (getc() == '\r')break;}}if (*++nxt == '\0') {if (env > env_data) {env--;} else {*env = '\0';}} else {for (;;) {*env = *nxt++;if ((*env == '\0') && (*nxt == '\0'))break;++env;}}*++env = '\0';}#ifdef CONFIG_NET_MULTIif (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" +"\0\0"  > 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\n", name);return 1;}while ((*env = *name++) != '\0')env++;for (i=2; i<argc; ++i) {char *val = argv[i];*env = (i==2) ? '=' : ' ';while ((*++env = *val++) != '\0');}/* end is marked with double '\0' */*++env = '\0';/* 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_MULTIeth_set_enetaddr(0, argv[2]);
#endifreturn 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_AMIGAONEG3SEif (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;
}

                saveenv

int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{extern char * env_name_spec;printf ("Saving Environment to %s...\n", env_name_spec);return (saveenv() ? 1 : 0);
}int saveenv(void)
{
#if defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)if (INF_REG3_REG == 2)saveenv_nand();else if (INF_REG3_REG == 3)saveenv_movinand();else if (INF_REG3_REG == 1)saveenv_onenand();else if (INF_REG3_REG == 4)saveenv_nor();
#elif    defined(CONFIG_SMDK6440)if (INF_REG3_REG == 3)saveenv_nand();else if (INF_REG3_REG == 4 || INF_REG3_REG == 5 || INF_REG3_REG == 6)saveenv_nand_adv();else if (INF_REG3_REG == 0 || INF_REG3_REG == 1 || INF_REG3_REG == 7)saveenv_movinand();
#else   // othersif (INF_REG3_REG == 2 || INF_REG3_REG == 3)saveenv_nand();else if (INF_REG3_REG == 4 || INF_REG3_REG == 5 || INF_REG3_REG == 6)saveenv_nand_adv();else if (INF_REG3_REG == 0 || INF_REG3_REG == 7)saveenv_movinand();else if (INF_REG3_REG == 1)saveenv_onenand();
#endifelseprintf("Unknown boot device\n");return 0;
}
int saveenv_movinand(void)
{
#if defined(CONFIG_CMD_MOVINAND)movi_write_env(virt_to_phys((ulong)env_ptr));puts("done\n");return 1;
#elsereturn 0;
#endif    /* CONFIG_CMD_MOVINAND */
}void movi_write_env(ulong addr)
{movi_write(raw_area_control.image[2].start_blk,raw_area_control.image[2].used_blk, addr);
}
typedef struct raw_area {uint magic_number; /* to identify itself */uint start_blk; /* compare with PT on coherency test */uint total_blk;uint next_raw_area; /* should be sector number */char description[16];member_t image[15];
} raw_area_t;

                        raw_area_control是uboot中规划iNnad/SD卡的原始分区表


                 getenv和getenv_r
                        getenv不可重入,getenv_r可重入
                        getenv函数是返回环境变量在DDR的地址,getenv_r复制DDR环境变量给buf,getenv_r更安全

/************************************************************************* Look up variable from environment,* return address of storage for that variable,* or NULL if not found*/char *getenv (char *name)
{int i, nxt;WATCHDOG_RESET();for (i=0; env_get_char(i) != '\0'; i=nxt+1) {int val;for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {if (nxt >= CFG_ENV_SIZE) {return (NULL);}}if ((val=envmatch((uchar *)name, i)) < 0)continue;return ((char *)env_get_addr(val));}return (NULL);
}
int getenv_r (char *name, char *buf, unsigned len)
{int i, nxt;for (i=0; env_get_char(i) != '\0'; i=nxt+1) {int val, n;for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {if (nxt >= CFG_ENV_SIZE) {return (-1);}}if ((val=envmatch((uchar *)name, i)) < 0)continue;/* found; copy out */n = 0;while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0');if (len == n)*buf = '\0';return (n);}return (-1);
}

iNand/SD驱动(start_armboot)

        cpu目录下驱动相关文件用于初始化soc内部关于iNand/SD控制器,drivers下用于初始化iNand/SD的内部控制器

        mmc_initialize(uboot/drivers/mmc/mmc.c)

int mmc_initialize(bd_t *bis)
{struct mmc *mmc;int err;INIT_LIST_HEAD(&mmc_devices);cur_dev_num = 0;if (board_mmc_init(bis) < 0)cpu_mmc_init(bis);#if defined(DEBUG_S3C_HSMMC)print_mmc_devices(',');
#endif#ifdef CONFIG_CHECK_X210CV3mmc = find_mmc_device(1);//lqm
#elsemmc = find_mmc_device(0);
#endifif (mmc) {err = mmc_init(mmc);if (err)err = mmc_init(mmc);if (err) {printf("Card init fail!\n");return err;}}printf("%ldMB\n", (mmc->capacity/(1024*1024/(1<<9))));return 0;
}
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_S3C_HSMMCsetup_hsmmc_clock();setup_hsmmc_cfg_gpio();return smdk_s3c_hsmmc_init();
#elsereturn 0;
#endif
}
int smdk_s3c_hsmmc_init(void)
{......#ifdef USE_MMC0err = s3c_hsmmc_initialize(0);if(err)return err;#endif......#ifdef USE_MMC2err = s3c_hsmmc_initialize(2);if(err)return err;#endif......
}
static int s3c_hsmmc_initialize(int channel)
{struct mmc *mmc;mmc = &mmc_channel[channel];sprintf(mmc->name, "S3C_HSMMC%d", channel);mmc->priv = &mmc_host[channel];mmc->send_cmd = s3c_hsmmc_send_command;mmc->set_ios = s3c_hsmmc_set_ios;mmc->init = s3c_hsmmc_init;mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
#if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)mmc->host_caps |= MMC_MODE_8BIT;
#endifmmc->f_min = 400000;mmc->f_max = 52000000;mmc_host[channel].clock = 0;switch(channel) {case 0:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE;break;case 1:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_1_BASE;break;case 2:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE;break;
#ifdef USE_MMC3case 3:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_3_BASE;break;
#endifdefault:printk("mmc err: not supported channel %d\n", channel);}return mmc_register(mmc);
}
struct mmc {struct list_head link;char name[32];void *priv;uint voltages;uint version;uint f_min;uint f_max;int high_capacity;uint bus_width;uint clock;uint card_caps;uint host_caps;uint ocr;uint scr[2];uint csd[4];uint cid[4];ushort rca;uint tran_speed;uint read_bl_len;uint write_bl_len;u32 capacity;struct mmc_ext_csd    ext_csd;    /* mmc v4 extended card specific */block_dev_desc_t block_dev;int (*send_cmd)(struct mmc *mmc,struct mmc_cmd *cmd, struct mmc_data *data);void (*set_ios)(struct mmc *mmc);int (*init)(struct mmc *mmc);
};


                setup_hsmmc_clock初始化SoC中MMC控制器时钟
                setup_hsmmc_cfg_gpio配置SoC中MMC控制器GPIO
                smdk_s3c_hsmmc_init通过USE_MMCx来调用s3c_hsmmc_initialize函数
                s3c_hsmmc_initialize定义并且实例化struct mmc类型对象(成员为驱动相关配置)
                mmc_register进行mmc设备的注册.即将struct mmc使用链表连接到mmc_devices全局变量中


        find_mmc_device

struct mmc *find_mmc_device(int dev_num)
{struct mmc *m;struct list_head *entry;list_for_each(entry, &mmc_devices) {m = list_entry(entry, struct mmc, link);if (m->block_dev.dev == dev_num)return m;}printf("MMC Device %d not found\n", dev_num);return NULL;
}

                通过mmc设备编号在系统中查找对应mmc设备


        mmc_init

int mmc_init(struct mmc *host)
{int err;err = host->init(host);if (err)return err;/* Reset the Card */err = mmc_go_idle(host);if (err)return err;/* Test for SD version 2 */err = mmc_send_if_cond(host);/* Now try to get the SD card's operating condition */err = mmc_send_app_op_cond(host);/* If the command timed out, we check for an MMC card */if (err == TIMEOUT) {err = mmc_send_op_cond(host);if (err)return UNUSABLE_ERR;} elseif (err)return UNUSABLE_ERR;return mmc_startup(host);
}

                mmc卡初始化,通过向mmc卡发送命令码初始化SD卡/iNand内部控制器

demo:

        自定义uboot命令

cmd_author.c

#include <common.h>
#include <command.h>int do_author (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{if(argc ==2){if(!strcmp(argv[1],"1")){printf("uboot community\n");}else if(!strcmp(argv[1],"2")){printf("blog.csdn.cxb\n");}else{printf("%s\n",cmdtp->help);}}else{printf("%s\n",cmdtp->help);}return 0;
}U_BOOT_CMD(author, 2,      1,      do_author,"author - author 1/2","author - author 1/2"
);

添加流程

cd uboot/common/vim cmd_author.cvim MakefileCOBJS-y += cmd_author.ocd .../mk &>/dev/null &cd sd_fusing./sd_fusing3.sh /dev/sdb

结果示例:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/179354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于mvc电影院售票预订选座系统php+vue+elementui

本影院售票系统主要包括二大功能模块&#xff0c;管理员功能模块和用户功能模块。 &#xff08;1&#xff09;管理员模块&#xff1a;系统中的核心用户管理员登录后&#xff0c;通过管理员功能来管理后台系统。主要功能有&#xff1a;首页、个人中心、电影类型管理、场次时间管…

数据结构 / day04 作业

1. 单链表任意位置删除, 单链表任意位置修改, 单链表任意位置查找, 单链表任意元素查找, 单链表任意元素修改, 单链表任意元素删除, 单链表逆置 // main.c#include "head.h"int main(int argc, const char *argv[]) {Linklist headNULL; //head 是头指针// printf(&q…

【Python 训练营】N_11 模拟进度条

题目 格式化输出进度条&#xff0c;具体格式如下&#xff1a; 分析 需要格式化打印&#xff0c;进度条随时间显示进展&#xff0c;需要用time模块的sleep()函数。 答案 import time # 导入time模块 length 100 # 定义进度长度模块 for i in range(1,length1): # 遍历1&…

96.STL-遍历算法 transform

目录 transform 语法&#xff1a; 功能描述&#xff1a; 函数原型&#xff1a; 代码示例&#xff1a; transform 是 C 标准模板库&#xff08;STL&#xff09;中的一个算法&#xff0c;用于对一个范围内的元素进行转换并将结果存储到另一个范围。以下是简要解释和一个示例…

AIGC系列之:Vision Transformer原理及论文解读

目录 相关资料 模型概述 Patch to Token Embedding Token Embedding Position Embedding ViT总结 相关资料 论文链接&#xff1a;https://arxiv.org/pdf/2010.11929.pdf 论文源码&#xff1a;https://github.com/google-research/vision_transformer PyTorch实现代码…

Nacos 端口偏移量说明

因为安全原因&#xff0c;在部署nacos-2.2.3版本时&#xff0c;将nacos的application.properties中的server.port端口值由默认值8848改成了server.port8425 问题&#xff1a;nacos 启动时(sh start.sh -m standalone)报错 如下&#xff1a; 经过分析&#xff0c;原因是 9425 …

深信服防火墙设置应用控制策略(菜鸟必看)

PS&#xff1a;前几天发布了关于深信服防火墙路由部署的流程&#xff1a;深信服防火墙路由模式开局部署-手把手教学&#xff08;小白篇&#xff09;-CSDN博客 昨天晚上有csdn的朋友联系我&#xff0c;说有一个关于ACL访问的问题要帮忙看一下 解决了以后&#xff0c;写个大概的…

Python变量及其使用

无论使用什么语言编程&#xff0c;总要处理数据&#xff0c;处理数据就需要使用变量来保存数据。 形象地看&#xff0c;变量就像一个个小容器&#xff0c;用于“盛装”程序中的数据。常量同样也用于“盛装”程序中的数据。常量与变量的区别是&#xff1a;常量一旦保存某个数据…

Android开源框架--Dagger2详解

功名只向马上取&#xff0c;真是英雄一丈夫 一&#xff0c;定义 我们知道在一个类中&#xff0c;通常会定义其他类型的变量&#xff0c;这个变量就是我们所说的“依赖“。 对一个类的变量进行初始化&#xff0c;有两种方式。第一种&#xff0c;这个类自己进行初始化&#xff…

4.Spring源码解析-loadBeanDefinitions(XmlBeanDefinitionReader)

第一个点进去 发现是空 肯定走的第二个逻辑了 这里在这里已经给属性设置了值&#xff0c;所以肯定不是空能拿到。 1.ClassPathXmlApplicationContext 总结&#xff1a;该loadBeanDefinitions是XmlBeanDefinitionReader设置xml文件在哪。

M3VSNET:无监督多度量多视图立体视觉网络(2021年)

M3VSNET&#xff1a;无监督多度量多视图立体视觉网络&#xff08;2021年&#xff09; 摘要1 引言2 相关工作3 实现方法3.1 网络架构 B. Huang, H. Yi, C. Huang, Y. He, J. Liu and X. Liu, “M3VSNET: Unsupervised Multi-Metric Multi-View Stereo Network,” 2021 IEEE Inte…

轻巧高效的剃须好工具,DOCO黑刃电动剃须刀上手

剃须刀大家都用过&#xff0c;我比较喜欢电动剃须刀&#xff0c;尤其是多刀头的悬浮剃须刀&#xff0c;感觉用起来很方便&#xff0c;剃须效率也很高。最近我在用一款DOCO小蔻的黑刃电动剃须刀&#xff0c;这款剃须刀轻巧易用&#xff0c;而且性价比超高。 相比于同类产品&…

Keil5 debug

目录 debug调试功能 基本功能&#xff1a; 程序复位&#xff1a;Reset 运行&#xff1a;Run 停止&#xff1a;Stop 断点调试&#xff08;Breakpoint Debugging&#xff09; 单步调试&#xff1a; 单步调试:Step 单步跳过调试&#xff1a;Step Over&#xff1a; 单步返…

Nginx-进程

Nginx-相关问题_01 Windows关闭所有nginx服务 windows 系统下开发调试时不用每次频繁的 启动->任务管理器->查找进程->结束进程&#xff01; 查看nginx的进程占用情况 tasklist | find /i "nginx.exe" || exit关闭nginx的所有进程 taskkill /im nginx.…

09. 智慧商城——订单结算、订单管理

01. 订单结算台 所谓的 “立即结算”&#xff0c;本质就是跳转到订单结算台&#xff0c;并且跳转的同时&#xff0c;需要携带上对应的订单参数。 而具体需要哪些参数&#xff0c;就需要基于 【订单结算台】 的需求来定。 (1) 静态布局 准备静态页面 <template><di…

2023-11-25 LeetCode每日一题(二叉树中的伪回文路径)

2023-11-25每日一题 一、题目编号 1457.二叉树中的伪回文路径二、题目链接 点击跳转到题目位置 三、题目描述 给你一棵二叉树&#xff0c;每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的&#xff0c;当它满足&#xff1a;路径经过的所有节点值的排列中…

scipy 笔记:scipy.spatial.distance

1 pdist 计算n维空间中观测点之间的成对距离。 scipy.spatial.distance.pdist(X, metriceuclidean, *, outNone, **kwargs) 1.1 主要参数 X一个m行n列的数组&#xff0c;表示n维空间中的m个原始观测点metric使用的距离度量out输出数组。如果非空&#xff0c;压缩的距离矩阵…

SpringCloud之服务网关Gateway组件使用——详解

目录 一、网关介绍 1.什么是服务网关 2. 为什么需要网关 3.网关组件在微服务中架构 二、服务网关组件 1. zuul 1.x 2.x(netflix 组件) 1.1 zuul版本说明 2. gateway (spring) 2.1 特性 2.2 开发网关动态路由 2.2.1.创建项目引入网关依赖 2.2.2 快捷方式配置路由 2.2…

Vue3挂载完毕后,隐藏dom再重新加载组件的方法

组件原本是在PC端使用的&#xff0c;现在需要把组件再封装一次&#xff0c;供app调用&#xff0c;但是在app上会显示tag栏&#xff0c;有占位影响空间&#xff0c;所以需求去掉头部tag&#xff0c;只显示下方组件。 实现方法&#xff0c;以前是直接引用的组件&#xff0c;现在改…

简介vue

目录 一、介绍 渐进式框架​ 单文件组件​ 选项式 API (Options API)​ 组合式 API (Composition API)​ 该选哪一个&#xff1f;​ 创建一个 Vue 应用 应用实例​ 根组件​ DOM 中的根组件模板 应用配置​ 多个应用实例​ 一、介绍 Vue (发音为 /vjuː/&#xff…