uboot学习之BL3的流程
BL2的最后通过汇编调用了board_init_r函数,此时进入BL3的阶段,此时的主要工作:
这一阶段涉及的文件及任务如下
arch/arm/lib/board.c
1. board_init_r()是进入定制板目录的入口
common/main.c
2. main_loop()中关闭中断,执行命令以及加载引导内核
下面分析一下board_init_r函数:
- /*
- ************************************************************************
- *
- * This is the next part if the initialization sequence: we are now
- * running from RAM and have a "normal" C environment, i. e. global
- * data can be written, BSS has been cleared, the stack size in not
- * that critical any more, etc.
- *
- ************************************************************************
- */
- void board_init_r(gd_t *id, ulong dest_addr)
- {
- ...
- bd_t *bd;
- ...
- gd = id;
- bd = gd->bd;
- gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
- monitor_flash_len = _end_ofs;
- ...
- debug("monitor flash len: %08lX\n", monitor_flash_len);
- board_init(); /* Setup chipselects */
上述代码的作用是对gd和bd进行赋值,其中monitor_flash_len为整个U-Boot的长度。
- malloc_start = dest_addr - TOTAL_MALLOC_LEN - sizeof(struct spare_boot_head_t);
- ...
- /* The Malloc area is immediately below the monitor copy in DRAM */
- mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
对SDRAM中的malloc空间进行清零初始化。
- #if !defined(CONFIG_SYS_NO_FLASH)
- puts("Flash: ");
- flash_size = flash_init();
- if (flash_size > ) {
- # ifdef CONFIG_SYS_FLASH_CHECKSUM
- print_size(flash_size, "");
- /*
- * Compute and print flash CRC if flashchecksum is set to 'y'
- *
- * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
- */
- s = getenv("flashchecksum");
- if (s && (*s == 'y')) {
- printf(" CRC: %08X", crc32(,
- (const unsigned char *) CONFIG_SYS_FLASH_BASE,
- flash_size));
- }
- putc('\n');
- # else /* !CONFIG_SYS_FLASH_CHECKSUM */
- print_size(flash_size, "\n");
- # endif /* CONFIG_SYS_FLASH_CHECKSUM */
- } else {
- puts(failed);
- hang();
- }
- #endif
上述代码的作用是计算FLASH的大小,并把它通过串口显示在控制台上。由于没有定义CONFIG_SYS_FLASH_CHECKSUM,所以没有执行CRC的校验和。其中flash_init函数是在drivers/mtd目录下的cfi_flash.c文件内(因为include/configs/smdk2410.h中定义了CONFIG_FLASH_CFI_DRIVER)。
- /* set up exceptions */
- interrupt_init();
- /* enable exceptions */
- enable_interrupts();
interrupt_init函数是建立IRQ中断堆栈,enable_interrupts函数是使能IRQ中断,它们都是在arch/arm/lib目录下的interrupts.c文件中定义的。
- ...
- /* initialize environment */
- env_relocate();
初始化环境变量,由于gd->env_valid等于0,所以在这里设置的是缺省环境变量。env_relocate函数是在common目录下的env_common.c文件中定义的。
- #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
- arm_pci_init();
- #endif
初始化PCI。
- /* IP Address */
- gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
- stdio_init(); /* get the devices list going. */
- jumptable_init();
- #if defined(CONFIG_API)
- /* Initialize API */
- api_init();
- #endif
- console_init_r(); /* fully init console as a device */
上面代码的作用分别对应:
设置IP地址。
初始化各类外设,如IIC、LCD、键盘、USB等,当然只有在定义了这些外设的前提下,才对这些外设进行初始化。该函数是在common目录下的stdio.c文件中定义的。
初始化跳转表gd->jt,该跳转表是一个函数指针数组,它定义了U-Boot中基本的常用函数库。该函数是在common目录下的exports.c文件中定义的。
初始化API。
初始化控制台,即标准输入、标准输出和标准错误,在这里都是串口。该函数是在common目录下的console.c文件中定义的。
- /* Initialize from environment */
- s = getenv("loadaddr");
- if (s != NULL)
- load_addr = simple_strtoul(s, NULL, );
从环境变量中获取loadaddr参数,得到需要加载的地址。
- #if defined(CONFIG_CMD_NET)
- s = getenv("bootfile");
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
- #endif
从环境变量中获取bootfile参数,得到通过TFTP加载的镜像文件名。
- #if defined(CONFIG_CMD_NET)
- #if defined(CONFIG_NET_MULTI)
- puts("Net: ");
- #endif
- eth_initialize(gd->bd);
- #if defined(CONFIG_RESET_PHY_R)
- debug("Reset Ethernet PHY\n");
- reset_phy();
- #endif
- #endif
初始化以太网,其中eth_initialize函数是在net目录下的eth.c文件中定义的。
- ...
- /* main_loop() can return to retry autoboot, if so just run it again. */
- for (;;)
- {
- main_loop();
- }
- hang();
- /* NOTREACHED - no way out of command loop except booting */
- }
board_init_r函数的最后就是执行一个死循环,调用main_loop函数。该函数是在common目录下的main.c文件内定义的。
总结:
3.接下来分析main_loop函数:
- void main_loop (void)
- {
- #ifndef CONFIG_SYS_HUSH_PARSER
- static char lastcommand[CONFIG_SYS_CBSIZE] = { , };
- int len;
- int rc = ;
- int flag;
- #endif
声明一些hush参数。关于hush后面会讲到。
- #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
- char *s;
- int bootdelay;
- #endif
声明启动延时需要的参数。
- #ifdef CONFIG_SYS_HUSH_PARSER
- u_boot_hush_start ();
- #endif
初始化hush功能。稍后再说。
- #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
- s = getenv ("bootdelay");
- bootdelay = s ? (int)simple_strtol(s, NULL, ) : CONFIG_BOOTDELAY;
- debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
- # ifdef CONFIG_BOOT_RETRY_TIME
- init_cmd_timeout ();
- # endif /* CONFIG_BOOT_RETRY_TIME */
- #ifdef CONFIG_POST
- if (gd->flags & GD_FLG_POSTFAIL) {
- s = getenv("failbootcmd");
- }
- else
- #endif /* CONFIG_POST */
- #ifdef CONFIG_BOOTCOUNT_LIMIT
- if (bootlimit && (bootcount > bootlimit)) {
- printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
- (unsigned)bootlimit);
- s = getenv ("altbootcmd");
- }
- else
- #endif /* CONFIG_BOOTCOUNT_LIMIT */
- s = getenv ("bootcmd");
- debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
- if (bootdelay >= && s && !abortboot (bootdelay)) {
- # ifdef CONFIG_AUTOBOOT_KEYED
- int prev = disable_ctrlc(); /* disable Control C checking */
- # endif
- # ifndef CONFIG_SYS_HUSH_PARSER
- run_command (s, );
- # else
- parse_string_outer(s, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
- # endif
- # ifdef CONFIG_AUTOBOOT_KEYED
- disable_ctrlc(prev); /* restore Control C checking */
- # endif
- }
- # ifdef CONFIG_MENUKEY
- if (menukey == CONFIG_MENUKEY) {
- s = getenv("menucmd");
- if (s) {
- # ifndef CONFIG_SYS_HUSH_PARSER
- run_command(s, );
- # else
- parse_string_outer(s, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
- # endif
- }
- }
- #endif /* CONFIG_MENUKEY */
- #endif /* CONFIG_BOOTDELAY */
第2行和第3行的含义是从环境变量中获取bootdelay参数,得到自动启动缺省镜像文件的延时(单位是秒)。
其中bootdelay的作用是:uboot正常启动后,会调用main_loop(void)函数,进入main_loop()之后,如果在规定的时间(CONFIG_BOOTDELAY)内,没有检查到任何按键事件的发生,就会去加载OS,并启动系统。
第8行的含义是初始化命令行超时机制。
第25行的含义是从环境变量中获取bootcmd参数,得到在启动延时过程中自动执行的命令。当我们得到了bootcmd参数,bootdelay参数也是大于等于0,并且在启动延时过程中没有按下任意键时,执行第37行的parse_string_outer函数,该函数的作用是解释bootcmd参数
并执行,它是在common目录下的hush.c文件内定义的。
- /*
- 2 * Main Loop for Monitor Command Processing
- 3 */
- #ifdef CONFIG_SYS_HUSH_PARSER
- parse_file_outer();
- /* This point is never reached */
- for (;;);
- #else
- for (;;) {
- #ifdef CONFIG_BOOT_RETRY_TIME
- if (rc >= ) {
- /* Saw enough of a valid command to
- 13 * restart the timeout.
- 14 */
- reset_cmd_timeout();
- }
- #endif
- len = readline (CONFIG_SYS_PROMPT);
- flag = ; /* assume no special flags for now */
- if (len > )
- strcpy (lastcommand, console_buffer);
- else if (len == )
- flag |= CMD_FLAG_REPEAT;
- #ifdef CONFIG_BOOT_RETRY_TIME
- else if (len == -) {
- /* -2 means timed out, retry autoboot
- 28 */
- puts ("\nTimed out waiting for command\n");
- # ifdef CONFIG_RESET_TO_RETRY
- /* Reinit board to run initialization code again */
- do_reset (NULL, , , NULL);
- # else
- return; /* retry autoboot */
- # endif
- }
- #endif
- if (len == -)
- puts ("<INTERRUPT>\n");
- else
- rc = run_command (lastcommand, flag);
- if (rc <= ) {
- /* invalid command or not repeatable, forget it */
- lastcommand[] = ;
- }
- }
- #endif /*CONFIG_SYS_HUSH_PARSER*/
- }
由于在include/configs/smdk2410.h文件中定义了CONFIG_SYS_HUSH_PARSER,所以上面的代码仅仅执行的是第5行至第7行的内容。第5行的parse_file_outer函数是在common目录下的hush.c文件中定义的,它的含义是依次读取命令序列中的命令并执行之,其中在该
函数还调用了parse_stream_outer函数,这个函数体内有一个do-while循环,只有发生语法错误的时候才会跳出该循环,因此一般情况下永远也不会执行上面代码中的第7行内容,而是始终在那个do-while循环体内。
上面说到过如果在CONFIG_BOOTDELAY时间内,用户按下键盘上的任意一个按键,uboot就会进入与用户交互的状态。如果用户在配置文件中定义了CONFIG_SYS_HUSH_PARSER,就会通过parse_file_outer(),去接收并解析用户命令,否则进入一个for(;;)循环,
通过 readline (CONFIG_SYS_PROMPT)接收用户命令,然后调用run_command(cmd,flag)去解析并执行命令。
当在配置文件中定义了CONFIG_SYS_HUSH_PARSER,main_loop会调用parse_file_outer(),进入hush中。其中parse_file_outer()在u-boot\common\hush.c下。
- #ifndef __U_BOOT__
- static int parse_file_outer(FILE *f)
- #else
- int parse_file_outer(void)
- #endif
- {
- int rcode;
- struct in_str input;
- #ifndef __U_BOOT__
- setup_file_in_str(&input, f);
- #else
- setup_file_in_str(&input);
- #endif
- rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
- return rcode;
- }
- /* most recursion does not come through here, the exeception is
- * from builtin_source() */
- int parse_stream_outer(struct in_str *inp, int flag)
- {
- struct p_context ctx;
- o_string temp=NULL_O_STRING;
- int rcode;
- #ifdef __U_BOOT__
- int code = ;
- #endif
- do {
- ctx.type = flag;
- initialize_context(&ctx);
- update_ifs_map();
- if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", );
- inp->promptmode=;
- rcode = parse_stream(&temp, &ctx, inp, '\n');
- #ifdef __U_BOOT__
- if (rcode == ) flag_repeat = ;
- #endif
- if (rcode != && ctx.old_flag != ) {
- syntax();
- #ifdef __U_BOOT__
- flag_repeat = ;
- #endif
- }
- if (rcode != && ctx.old_flag == ) {
- done_word(&temp, &ctx);
- done_pipe(&ctx,PIPE_SEQ);
- #ifndef __U_BOOT__
- run_list(ctx.list_head);
- #else
- code = run_list(ctx.list_head);
- if (code == -) { /* exit */
- b_free(&temp);
- code = ;
- /* XXX hackish way to not allow exit from main loop */
- if (inp->peek == file_peek) {
- printf("exit not allowed from main input shell.\n");
- continue;
- }
- break;
- }
- if (code == -)
- flag_repeat = ;
- #endif
- } else {
- if (ctx.old_flag != ) {
- free(ctx.stack);
- b_reset(&temp);
- }
- #ifdef __U_BOOT__
- if (inp->__promptme == ) printf("<INTERRUPT>\n");
- inp->__promptme = ;
- #endif
- temp.nonnull = ;
- temp.quote = ;
- inp->p = NULL;
- free_pipe_list(ctx.list_head,);
- }
- b_free(&temp);
- } while (rcode != - && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
- #ifndef __U_BOOT__
- return ;
- #else
- return (code != ) ? : ;
- #endif /* __U_BOOT__ */
- }
hush是uboot中命令接收和解析的工具,与uboot原始的命令解析方法相比,该工具更加智能。
这里会在run_list中调用到hush中的run_pipe_real(struct pipe *pi),在该函数中经过一些列解析,最终会调用到对应的命令执行函数。
- /* run_pipe_real() starts all the jobs, but doesn't wait for anything
- * to finish. See checkjobs().
- *
- * return code is normally -1, when the caller has to wait for children
- * to finish to determine the exit status of the pipe. If the pipe
- * is a simple builtin command, however, the action is done by the
- * time run_pipe_real returns, and the exit code is provided as the
- * return value.
- *
- * The input of the pipe is always stdin, the output is always
- * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
- * because it tries to avoid running the command substitution in
- * subshell, when that is in fact necessary. The subshell process
- * now has its stdout directed to the input of the appropriate pipe,
- * so this routine is noticeably simpler.
- */
- static int run_pipe_real(struct pipe *pi)
- {
- int i;
- #ifndef __U_BOOT__
- int nextin, nextout;
- int pipefds[]; /* pipefds[0] is for reading */
- struct child_prog *child;
- struct built_in_command *x;
- char *p;
- # if __GNUC__
- /* Avoid longjmp clobbering */
- (void) &i;
- (void) &nextin;
- (void) &nextout;
- (void) &child;
- # endif
- #else
- int nextin;
- int flag = do_repeat ? CMD_FLAG_REPEAT : ;
- struct child_prog *child;
- cmd_tbl_t *cmdtp;
- char *p;
- # if __GNUC__
- /* Avoid longjmp clobbering */
- (void) &i;
- (void) &nextin;
- (void) &child;
- # endif
- #endif /* __U_BOOT__ */
- nextin = ;
- #ifndef __U_BOOT__
- pi->pgrp = -;
- #endif
- /* Check if this is a simple builtin (not part of a pipe).
- * Builtins within pipes have to fork anyway, and are handled in
- * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
- */
- if (pi->num_progs == ) child = & (pi->progs[]);
- #ifndef __U_BOOT__
- if (pi->num_progs == && child->group && child->subshell == ) {
- int squirrel[] = {-, -, -};
- int rcode;
- debug_printf("non-subshell grouping\n");
- setup_redirects(child, squirrel);
- /* XXX could we merge code with following builtin case,
- * by creating a pseudo builtin that calls run_list_real? */
- rcode = run_list_real(child->group);
- restore_redirects(squirrel);
- #else
- if (pi->num_progs == && child->group) {
- int rcode;
- debug_printf("non-subshell grouping\n");
- rcode = run_list_real(child->group);
- #endif
- return rcode;
- } else if (pi->num_progs == && pi->progs[].argv != NULL) {
- for (i=; is_assignment(child->argv[i]); i++) { /* nothing */ }
- if (i!= && child->argv[i]==NULL) {
- /* assignments, but no command: set the local environment */
- for (i=; child->argv[i]!=NULL; i++) {
- /* Ok, this case is tricky. We have to decide if this is a
- * local variable, or an already exported variable. If it is
- * already exported, we have to export the new value. If it is
- * not exported, we need only set this as a local variable.
- * This junk is all to decide whether or not to export this
- * variable. */
- int export_me=;
- char *name, *value;
- name = xstrdup(child->argv[i]);
- debug_printf("Local environment set: %s\n", name);
- value = strchr(name, '=');
- if (value)
- *value=;
- #ifndef __U_BOOT__
- if ( get_local_var(name)) {
- export_me=;
- }
- #endif
- free(name);
- p = insert_var_value(child->argv[i]);
- set_local_var(p, export_me);
- if (p != child->argv[i]) free(p);
- }
- return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
- }
- for (i = ; is_assignment(child->argv[i]); i++) {
- p = insert_var_value(child->argv[i]);
- #ifndef __U_BOOT__
- putenv(strdup(p));
- #else
- set_local_var(p, );
- #endif
- if (p != child->argv[i]) {
- child->sp--;
- free(p);
- }
- }
- if (child->sp) {
- char * str = NULL;
- str = make_string((child->argv + i));
- parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
- free(str);
- return last_return_code;
- }
- #ifndef __U_BOOT__
- for (x = bltins; x->cmd; x++) {
- if (strcmp(child->argv[i], x->cmd) == ) {
- int squirrel[] = {-, -, -};
- int rcode;
- if (x->function == builtin_exec && child->argv[i+]==NULL) {
- debug_printf("magic exec\n");
- setup_redirects(child,NULL);
- return EXIT_SUCCESS;
- }
- debug_printf("builtin inline %s\n", child->argv[]);
- /* XXX setup_redirects acts on file descriptors, not FILEs.
- * This is perfect for work that comes after exec().
- * Is it really safe for inline use? Experimentally,
- * things seem to work with glibc. */
- setup_redirects(child, squirrel);
- #else
- /* check ";", because ,example , argv consist from
- * "help;flinfo" must not execute
- */
- if (strchr(child->argv[i], ';')) {
- printf ("Unknown command '%s' - try 'help' or use 'run' command\n",
- child->argv[i]);
- return -;
- }
- /* Look up command in command table */
- if ((cmdtp = find_cmd(child->argv[i])) == NULL) {
- printf ("Unknown command '%s' - try 'help'\n", child->argv[i]);
- return -; /* give up after bad command */
- } else {
- int rcode;
- #if defined(CONFIG_CMD_BOOTD)
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
- if (flag & CMD_FLAG_BOOTD) {
- printf ("'bootd' recursion detected\n");
- return -;
- }
- else
- flag |= CMD_FLAG_BOOTD;
- }
- #endif
- /* found - check max args */
- if ((child->argc - i) > cmdtp->maxargs)
- return cmd_usage(cmdtp);
- #endif
- child->argv+=i; /* XXX horrible hack */
- #ifndef __U_BOOT__
- rcode = x->function(child);
- #else
- /* OK - call function to do the command */
- rcode = (cmdtp->cmd)
- (cmdtp, flag,child->argc-i,&child->argv[i]);
- if ( !cmdtp->repeatable )
- flag_repeat = ;
- #endif
- child->argv-=i; /* XXX restore hack so free() can work right */
- #ifndef __U_BOOT__
- restore_redirects(squirrel);
- #endif
- return rcode;
- }
- }
- #ifndef __U_BOOT__
- }
- for (i = ; i < pi->num_progs; i++) {
- child = & (pi->progs[i]);
- /* pipes are inserted between pairs of commands */
- if ((i + ) < pi->num_progs) {
- if (pipe(pipefds)<) perror_msg_and_die("pipe");
- nextout = pipefds[];
- } else {
- nextout=;
- pipefds[] = -;
- }
- /* XXX test for failed fork()? */
- if (!(child->pid = fork())) {
- /* Set the handling for job control signals back to the default. */
- signal(SIGINT, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGTSTP, SIG_DFL);
- signal(SIGTTIN, SIG_DFL);
- signal(SIGTTOU, SIG_DFL);
- signal(SIGCHLD, SIG_DFL);
- close_all();
- if (nextin != ) {
- dup2(nextin, );
- close(nextin);
- }
- if (nextout != ) {
- dup2(nextout, );
- close(nextout);
- }
- if (pipefds[]!=-) {
- close(pipefds[]); /* opposite end of our output pipe */
- }
- /* Like bash, explicit redirects override pipes,
- * and the pipe fd is available for dup'ing. */
- setup_redirects(child,NULL);
- if (interactive && pi->followup!=PIPE_BG) {
- /* If we (the child) win the race, put ourselves in the process
- * group whose leader is the first process in this pipe. */
- if (pi->pgrp < ) {
- pi->pgrp = getpid();
- }
- if (setpgid(, pi->pgrp) == ) {
- tcsetpgrp(, pi->pgrp);
- }
- }
- pseudo_exec(child);
- }
- /* put our child in the process group whose leader is the
- first process in this pipe */
- if (pi->pgrp < ) {
- pi->pgrp = child->pid;
- }
- /* Don't check for errors. The child may be dead already,
- * in which case setpgid returns error code EACCES. */
- setpgid(child->pid, pi->pgrp);
- if (nextin != )
- close(nextin);
- if (nextout != )
- close(nextout);
- /* If there isn't another process, nextin is garbage
- but it doesn't matter */
- nextin = pipefds[];
- }
- #endif
- return -;
- }
上面关键是这段:
- /* OK - call function to do the command */
- rcode = (cmdtp->cmd)
- (cmdtp, flag,child->argc-i,&child->argv[i]);
- if ( !cmdtp->repeatable )
- flag_repeat = ;
通过这段代码调用对应的命令执行函数。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 * const []);
- char *usage; /* Usage message (short) */
- #ifdef CONFIG_SYS_LONGHELP
- char *help; /* Help message (long) */
- #endif
- #ifdef CONFIG_AUTO_COMPLETE
- /* do auto completion on the arguments */
- int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
- #endif
- };
- typedef struct cmd_tbl_s cmd_tbl_t;
对于uboot支持的每一个命令,是通过U_BOOT_CMD宏定义的,他定义了该命令对应的名称name,支持的最大参数rep,重复次数,实现函数cmd,以及输入help命令时,显示的帮助信息usage。
在执行函数cmd中,第一个参数对应该命令结构本身的指针,第二个参数对应flag标记,第三个参数对应参数数目,第四个参数是指针数组,里面存储的是对应参数的指针。
uboot学习之BL3的流程的更多相关文章
- u-boot bootz 加载kernel 流程分析
u-boot 加载 kernel 的流程分析. image重要结构体头文件 // include/image.h * * Legacy and FIT format headers used by d ...
- app开发学习需要经历哪些流程
app开发学习需要经历哪些流程?如何零基础入门app开发?以下是知乎热心开发者的经验总结,对学习app开发有很好的参考意义 1.如果没有编程基础的,学习基础知识的过程肯定是必须的.2.有了一些基础 ...
- [笔记] 基于nvidia/cuda的深度学习基础镜像构建流程 V0.2
之前的[笔记] 基于nvidia/cuda的深度学习基础镜像构建流程已经Out了,以这篇为准. 基于NVidia官方的nvidia/cuda image,构建适用于Deep Learning的基础im ...
- uboot学习之uboot.bin的运行流程
上篇博客:http://www.cnblogs.com/yeqluofwupheng/p/7347925.html 讲到uboot-spl的工作流程,接下来简述一下uboot.bin的工作流程,这对应 ...
- uboot学习之uboot-spl的程序流程分析
uboot-spl的程序流程主要包含下面的几个函数: _start->reset->save_boot_params->cpu_init_crit->lowlevel_init ...
- uboot学习之uboot启动流程简述
一.uboot启动分为了三个阶段BL0.BL1.BL2:BL0表示上电后运行ROM中固化的一段程序,其中ROM中的程序是厂家写进去的,所以具体功能可能根据厂家芯片而有所不同.功能如下: 初始化系统时钟 ...
- 第二天-uboot学习
源码阅读方法1.源码目录结构2.配置(支持当前使用的硬件)3.编译(Makefile)4.启动流程 工具使用1.在同一文件查找 shitf+8 N n进行上下查找 2.在工程目录中 ctags ubo ...
- uboot学习第一天
Windows操作系统BIOS(设置) Windows系统 文件系统 驱动程序 应用程序 linux操作系统bootloader(引导系统) kernel(内核) 文件系统 驱动程序 应用程序 交叉编 ...
- 1.ok6410移植bootloader,移植u-boot,学习u-boot命令
ok6410移植u-boot 既然是移植u-boot当然首先需要u-boot源码,这里的u-boot代码是由国嵌提供的. 一.配置编译u-boot A. 解压 u-boot 压缩文件 B. 进入解压生 ...
随机推荐
- nessus安装
1.安装注册 (1)从https://www.tenable.com/products/nessus/select-your-operating-system上下载对应操作系统版本的nessus,结果 ...
- spring-boot-plus V1.2.2 发布,5 Minutes Finish CRUD
更新日志 CHANGELOG [V1.2.2-RELEASE] 2019.08.26
- 开发APP必须知道的API集合,来源http://www.cnblogs.com/wikiki/p/7232388.html
笔记 OneNote - OneNote支持获取,复制,创建,更新,导入与导出笔记,支持为笔记添加多媒体内容,管理权限等.提供SDK和Demo. 为知笔记 - 为知笔记Windows客户端开放了大量的 ...
- 【解决】TLS/SSLError问题导致无法使用pip或conda安装软件包
Copy these files from the ./Library/bin to ./DLLs/ :libcrypto-1_1-x64.*libssl-1_1-x64.* 解决 欢迎关注↓↓↓ 头 ...
- MySQL数据库之单表查询中关键字的执行顺序
目录 MySQL数据库之单表查询中关键字的执行顺序 1 语法顺序 2 执行顺序 3 关键字使用语法 MySQL数据库之单表查询中关键字的执行顺序 1 语法顺序 select distinct from ...
- MSIL实用指南-生成for语句
for语句格式是这样的for(<初始化语句>;<条件语句>;<自增减语句>) <循环体> 它可以转换为while语句 if(<条件语句>){ ...
- Mobx-React : 当前适合React的状态管理工具
MobX 简单.可扩展的状态管理 MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商所赞助的. 安装 安装: npm install mobx ...
- Oracle - View
Oracle View的创建 Create Or Replace View ViewName As Select * From Tables/View Where 条件;
- POJ - 3436 ACM Computer Factory 网络流
POJ-3436:http://poj.org/problem?id=3436 题意 组配计算机,每个机器的能力为x,只能处理一定条件的计算机,能输出特定的计算机配置.进去的要求有1,进来的计算机这个 ...
- hdu 5887 Herbs Gathering (dfs+剪枝 or 超大01背包)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5887 题解:这题一看像是背包但是显然背包容量太大了所以可以考虑用dfs+剪枝,贪心得到的不 ...