u-boot启动之第2阶段浅析

          在第一阶段分析中已经知道,经过一系列板级初始化后最后是调用函数start_armboot (void),这个告诉我们第2阶段应该是从这个函数开始进行分析,这个函数是在/lib_arm/board.c文件中。

  1. /* Pointer is writable since we allocated a register for it */
  2.  gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));    //这里的gd_t*是一个结构体的指针,直接给它分配一段内存,在完全手册的图
  3.  /* compiler optimization barrier needed for GCC >= 3.4 */
  4.  __asm__ __volatile__("": : :"memory");
  5.  memset ((void*)gd, 0, sizeof (gd_t));
  6.  gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));                 //分配内存块大小          
  7.  memset (gd->bd, 0, sizeof (bd_t));
  8.  monitor_flash_len = _bss_start - _armboot_start;
  9.  for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {       //调用函数初始化指针
  10.                    if ((*init_fnc_ptr)() != 0)
  11.                               {
  12.                                             hang ();
  13.                               }

                                             
这个结构体gd_t*在u-boot内存中的指向就是在128  Bytes的内存CFG_GBL_DATA_SIZE。函数init_sequence是一系列函数指针:

  1. init_fnc_t *init_sequence[] = {

  2.                cpu_init,  /* basic cpu dependent setup */                     

  3.                board_init,  /* basic board dependent setup */                 //单板初始化

  4.                interrupt_init,  /* set up exceptions */

  5.               env_init,  /* initialize environment */                                    //环境变量初始化

  6.               init_baudrate,  /* initialze baudrate settings */

  7.               serial_init,  /* serial communications setup */

  8.               console_init_f,  /* stage 1 init of console */

  9.              display_banner,  /* say that we are here */

  10. #if defined(CONFIG_DISPLAY_CPUINFO)

  11.              print_cpuinfo,  /* display cpu info (and speed) */

  12. #endif

比如CPU的初始化就是在cpu/arm920t/cpu.c中:

  1. int cpu_init (void)
  2. {
  3.  /*
      * setup up stacks if necessary
      */
  4. #ifdef CONFIG_USE_IRQ
  5.              IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
  6.              FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
  7.              FREE_RAM_END = FIQ_STACK_START - CONFIG_STACKSIZE_FIQ - CONFIG_STACKSIZE;
  8.              FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1;
  9. #else 
     
                FREE_RAM_END = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4 - CONFIG_STACKSIZE;
  10.             FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1;
  11. #endif
  12.             return 0;
  13. }

 单板初始化函数 board_init()就是在board/open24x0/open24x0.c中:

 /*
 * Miscellaneous platform dependent initialisations
 */

  1. int board_init (void)
  2.             {
  3.                          S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
  4.                          S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
  5.     /* set up the I/O ports */
  6.                         gpio->GPACON = 0x007FFFFF;      //参考数据手册来设置
  7.                         gpio->GPBCON = 0x00044555;
  8.                         gpio->GPBUP = 0x000007FF;
  9.                         gpio->GPCCON = 0xAAAAAAAA;
  10.                         gpio->GPCUP = 0x0000FFFF;
  11.                         gpio->GPDCON = 0xAAAAAAAA;
  12.                         gpio->GPDUP = 0x0000FFFF;
  13.                         gpio->GPECON = 0xAAAAAAAA;
  14.                         gpio->GPEUP = 0x0000FFFF;
  15.                         gpio->GPFCON = 0x000055AA;
  16.                         gpio->GPFUP = 0x000000FF;
  17.                         gpio->GPGCON = 0xFF95FFBA;
  18.                         gpio->GPGUP = 0x0000FFFF;
  19.                         gpio->GPHCON = 0x002AFAAA;
  20.                         gpio->GPHUP = 0x000007FF;
  21.     /* support both of S3C2410 and S3C2440, by www.arm9.net */
  22.                         if ((gpio->GSTATUS1 == 0x32410000) || (gpio->GSTATUS1 == 0x32410002))
  23.                                 {
  24.         /* arch number of SMDK2410-Board */
  25.                                           gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
  26.                                  }
  27.     else
  28.                 {
  29.         /* arch number of SMDK2440-Board */
  30.                          gd->bd->bi_arch_number = MACH_TYPE_S3C2440;         //arch_number 架构数字就是机器码,显然这个在启动内核时要传递给内核才能正确启动
  31.                  }                                                                                                              //否则会有提示start  kernel..........就停在这里不动
  32.     /* adress of boot parameters */
  33.                         gd->bd->bi_boot_params = 0x30000100;          //启动参数在启动内核时也要传递给内核,0x30000100就是存放地址,内核从这里读取参数
  34.                         icache_enable();
  35. #if 0
                          dcache_enable();
    #endif
  36.                       return 0;
  37.               }

这些寄存器的初化都是跟板级的处理器有非常密切关系,不同的开发板不同处理器一般会有不同的参数,在移植的时候可以借鉴这个思路,参考相关的手册就可以移植。回到我们主题,要想从Nand Flash中读取内核数据,首先是要能够执行读操作,也就是u-boot必须支持读命令这样才能正常读取数据。现在很多的u-boot为了方便开发,在其中加了了可以写的功能函数。

 

2.   对Flash 初始化,在Board.c中

  1. #ifndef CFG_NO_FLASH
  2.  /* configure available FLASH banks */
  3.                     size = flash_init ();                                   //对flash的初化函数                   
  4.                     display_flash_config (size);
  5. #endif /* CFG_NO_FLASH */

下面的代码是具体的初始化代码,在drivers/cfi_flash.c中:

这个函数可以识别不同的Flash,具体的实现过程参考相关手册。

  1. /*-----------------------------------------------------------------------
     */
    unsigned long flash_init (void)
  2.             {
  3.                      unsigned long size = 0;
  4.                      int i;
  5. #ifdef CFG_FLASH_PROTECTION
  6.                      char *s = getenv("unlock");
  7. #endif
  8.  /* Init: no FLASHes known */
  9.                     for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
  10.                     flash_info[i].flash_id = FLASH_UNKNOWN;
  11.                     size += flash_info[i].size = flash_get_size (bank_base[i], i);
  12.   if (flash_info[i].flash_id == FLASH_UNKNOWN) {                            //用于识别不同的Flash
  13. #ifndef CFG_FLASH_QUIET_TEST
  14.    printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
        i, flash_info[i].size, flash_info[i].size << 20);
  15. #endif /* CFG_FLASH_QUIET_TEST */
                  }
    #ifdef CFG_FLASH_PROTECTION
  16.   else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
  17.    /*
        * Only the U-Boot image and it's environment is protected,
        * all other sectors are unprotected (unlocked) if flash
        * hardware protection is used (CFG_FLASH_PROTECTION) and
        * the environment variable "unlock" is set to "yes".
        */
  18.                    if (flash_info[i].legacy_unlock) {
  19.                    int k;
  20.     /*
         * Disable legacy_unlock temporarily, since
         * flash_real_protect would relock all other sectors
         * again otherwise.
         */
  21.                    flash_info[i].legacy_unlock = 0;
  22.     /*
         * Legacy unlocking (e.g. Intel J3) -> unlock only one
         * sector. This will unlock all sectors.
         */
  23.                     flash_real_protect (&flash_info[i], 0, 0);
  24.                     flash_info[i].legacy_unlock = 1;
  25.     /*
         * Manually mark other sectors as unlocked (unprotected)
         */
  26.                     for (k = 1; k < flash_info[i].sector_count; k++)
  27.                     flash_info[i].protect[k] = 0;
  28.                     } else {
  29.     /*
         * No legancy unlocking -> unlock all sectors
         */
  30.                                          flash_protect (FLAG_PROTECT_CLEAR,
  31.                                          flash_info[i].start[0],
  32.                                          flash_info[i].start[0] + flash_info[i].size - 1,
  33.                                          &flash_info[i]);
  34.                                 }
  35.       }
  36. #endif /* CFG_FLASH_PROTECTION */
  37.                }
  38.  /* Monitor protection ON by default */
  39. #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
  40.                       flash_protect (FLAG_PROTECT_SET,
  41.                                 CFG_MONITOR_BASE,
  42.                                 CFG_MONITOR_BASE + monitor_flash_len  - 1,
  43.                                 flash_get_info(CFG_MONITOR_BASE));
  44. #endif
  45.  /* Environment protection ON by default */
  46. #ifdef CFG_ENV_IS_IN_FLASH
  47.                     flash_protect (FLAG_PROTECT_SET,
  48.                                CFG_ENV_ADDR,
  49.                                CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
  50.                                flash_get_info(CFG_ENV_ADDR));
  51. #endif
  52.  /* Redundant environment protection ON by default */
  53. #ifdef CFG_ENV_ADDR_REDUND
  54.                  flash_protect (FLAG_PROTECT_SET,
  55.                               CFG_ENV_ADDR_REDUND,
  56.                               CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
  57.                                flash_get_info(CFG_ENV_ADDR_REDUND));
  58. #endif
  59.                         return (size);
  60.           }

             /* armboot_start is defined in the board-specific linker script */

               mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);         //这个是给内存分配空间,对应上面内存图中192K字节空间-----CFG_MALLOC_LEN.在这里实现

                                                                                                                               //堆空间的分配和释放 

 

 继续往下看:

  1. #if (CONFIG_COMMANDS & CFG_CMD_NAND)
  2.  puts ("NAND:  ");
  3.  nand_init();                   /* go init the NAND */
  4. #endif

nand_init();的具体代码是在drivers/nand/nand.c中,它可以识别在单板中的Nand Flash。

  1. void nand_init(void)
  2. {
  3.  int i;
  4.  unsigned int size = 0;
  5.  for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
  6.   nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
  7.   size += nand_info[i].size;
  8.   if (nand_curr_device == -1)
  9.    nand_curr_device = i;
  10.  }
  11.  printf("%lu MiB\n", size / (1024 * 1024));
  12. #ifdef CFG_NAND_SELECT_DEVICE
  13.  /*
      * Select the chip in the board/cpu specific driver
      */
  14.  board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
  15. #endif
  16. }

其实我们的u-boot就是通过调用这两个函数flash_init (void)和nand_init(void)来实现对内核的数据的读取的,代码过程可以不用理它,只要把它作为一个接口调用即可。

 

  1. #ifdef CONFIG_HAS_DATAFLASH
  2.  AT91F_DataflashInit();
  3.  dataflash_print_info();
  4. #endif
  5.  /* initialize environment */
  6.  env_relocate ();                   //环境变量初始化,一种是在代码中写好了的默认值,一种是在Flash中保存的,这个是修改后的值,启动时先到Flash中看是否有

                                                           //要是有就用最新的环境变量值,没有就用默认的值

 

 

 

下现是网卡和USB等等的一些IP等的初始化:

  1.  /* IP Address */
  2.                  gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
  3.  /* MAC Address */
  4.                         {
  5.                                    int i;
  6.                                    ulong reg;
  7.                                    char *s, *e;
  8.                                    char tmp[64];
  9.                                    i = getenv_r ("ethaddr", tmp, sizeof (tmp));
  10.                                    s = (i > 0) ? tmp : NULL;
  11.                                    for (reg = 0; reg < 6; ++reg) {
  12.                                   gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
  13.                                    if (s)
  14.                                              s = (*e) ? e + 1 : e;
  15.                        }
  16. #ifdef CONFIG_HAS_ETH1
  17.                                  i = getenv_r ("eth1addr", tmp, sizeof (tmp));
  18.                                  s = (i > 0) ? tmp : NULL;
  19.                                  for (reg = 0; reg < 6; ++reg) {
  20.                                 gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
  21.                                  if (s)
  22.                                  s = (*e) ? e + 1 : e;                   //网卡的初始化
  23.                            }
  24. #endif
  25.                       }
  26.                                 devices_init ();                           /* get the devices list going. */
  27. #ifdef CONFIG_CMC_PU2
  28.                                 load_sernum_ethaddr ();
  29. #endif /* CONFIG_CMC_PU2 */
  30.                                 jumptable_init ();
  31.                                console_init_r ();                             /* fully init console as a device */
  32. #if defined(CONFIG_MISC_INIT_R)
  33.  /* miscellaneous platform dependent initialisations */
  34.                                misc_init_r ();
  35. #endif
  36.                                Port_Init();
  37.                                if (!PreLoadedONRAM) {                          //如果用调试器下载的话这个PreLoadedONRAM被制成1
  38.   /* enable exceptions */
  39.                                enable_interrupts ();
  40.      /* add by www.arm9.net */
  41.                                usb_init();                                      //USB设备初始化
  42.  }
  43.     /* Perform network card initialisation if necessary */
  44. #ifdef CONFIG_DRIVER_CS8900
  45.                                 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
  46. #endif
  47. #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
  48.                                if (getenv ("ethaddr")) {                                                    
  49.                                         smc_set_mac_addr(gd->bd->bi_enetaddr);                 //获取MAC地址
  50.  }
  51. #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
  52.  /* Initialize from environment */
  53.                                if ((s = getenv ("loadaddr")) != NULL) {
  54.                                load_addr = simple_strtoul (s, NULL, 16);
  55.  }
  56. #if (CONFIG_COMMANDS & CFG_CMD_NET)
  57.                               if ((s = getenv ("bootfile")) != NULL) {
  58.                                       copy_filename (BootFile, s, sizeof (BootFile));
  59.  }
  60. #endif /* CFG_CMD_NET */
  61. #ifdef BOARD_LATE_INIT
  62.                                board_late_init ();
  63. #endif
  64. #if (CONFIG_COMMANDS & CFG_CMD_NET)
  65. #if defined(CONFIG_NET_MULTI)
  66.                                puts ("Net:   ");
  67. #endif
  68.                                eth_initialize(gd->bd);
  69. #endif
  70.  /* main_loop() can return to retry autoboot, if so just run it again. */
  71.                                  for (;;) {
  72.                                             main_loop ();                      //最终进入这个C语言函数,进行循环,就像在等待输入命令,一个死循环
  73.                     }
  74.  /* NOTREACHED - no way out of command loop except booting */
                     }

经过第二阶段的初始化后,最后进入函数 main_loop (),这个函数是在/comman/main.c中:

  1. #ifdef CONFIG_BOOTCOUNT_LIMIT
  2.  if (bootlimit && (bootcount > bootlimit)) {
  3.                printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
  4.                            (unsigned)bootlimit);
  5.               s = getenv ("altbootcmd");
  6.  }
  7.  else
  8. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  9.                s = getenv ("bootcmd");
  10.  debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
  11.                      if (bootdelay >= 0 && s && !abortboot (bootdelay)) {                   //这里是在u-boot启动时有倒数计时,要是没有空格被按下则会跳到其他分支,下面有说明
  12. # ifdef CONFIG_AUTOBOOT_KEYED
  13.                       int prev = disable_ctrlc(1); /* disable Control C checking */
  14. # endif
  15. # ifndef CFG_HUSH_PARSER
  16. #ifdef CONFIG_SURPORT_WINCE
  17.         if (!TOC_Read())
  18.                     {
  19.                           /* Launch wince */
  20.                              char cmd_buf[16];
  21.                              printf("Booting wince ...\n");
              
                                 strcpy(cmd_buf, "wince");
  22.                             run_command(cmd_buf, 0);
  23.         }
  24.         else
  25. #endif
  26.         {
  27.             printf("Booting Linux ...\n");  
            
             run_command (s, 0);
  28.         }
  29. # else
  30.             parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  31.                       FLAG_EXIT_FROM_LOOP);
  32. # endif
  33. # ifdef CONFIG_AUTOBOOT_KEYED
  34.                     disable_ctrlc(prev); /* restore Control C checking */
    # endif
  35.  }
  36. # ifdef CONFIG_MENUKEY
  37.                      if (menukey == CONFIG_MENUKEY) {                      //要是空格被按下程序就会跳到这里来执行
  38.                              s = getenv("menucmd");
  39.                            if (s) {
  40. # ifndef CFG_HUSH_PARSER
  41.                                                run_command (s, 0);
  42. # else
  43.                                     parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  44.                                     FLAG_EXIT_FROM_LOOP);
  45. # endif
  46.             }
  47.   }
  48. #endif /* CONFIG_MENUKEY */
  49. #endif /* CONFIG_BOOTDELAY */
  50. #ifdef CONFIG_AMIGAONEG3SE
  51.             {
                            extern void video_banner(void);
  52.                         video_banner();
  53.  }
  54. #endif
  55.                        run_command("menu", 0);            //u-boot启动时按下空格键时有个菜单的原因就是执行了这个函数
     /*
      * Main Loop for Monitor Command Processing
      */

  56. PROMPT:
  57. #ifdef CFG_HUSH_PARSER
  58.                  parse_file_outer();
  59.  /* This point is never reached */
  60.                  for (;;);                        //进入菜单后又是一个死循环,等待输入命令,有命令输入后它就会解析命令,没有则显示异常提示信息,因此命令就是u-boot的核心
  61. #else
  62.                 for (;;) {
  63. #ifdef CONFIG_BOOT_RETRY_TIME
  64.                 if (rc >= 0) {
  65.    /* Saw enough of a valid command to
        * restart the timeout.
        */
  66.                            reset_cmd_timeout();
  67.   }
  68. #endif
  69.                           len = readline (CFG_PROMPT);

  70.                           flag = 0; /* assume no special flags for now */
  71.                            if (len > 0)
  72.                                         strcpy (lastcommand, console_buffer);
  73.                                         else if (len == 0)
  74.                                                  flag |= CMD_FLAG_REPEAT;
  75. #ifdef CONFIG_BOOT_RETRY_TIME
  76.                                        else if (len == -2) {
  77.    /* -2 means timed out, retry autoboot
        */
  78.                                         puts ("\nTimed out waiting for command\n");
  79. # ifdef CONFIG_RESET_TO_RETRY
  80.    /* Reinit board to run initialization code again */
  81.                                        do_reset (NULL, 0, 0, NULL);
  82. # else
  83.                                        return;  /* retry autoboot */
  84. # endif
  85.   }
  86. #endif
  87.                                       if (len == -1)
  88.                                                puts ("\n");
  89.   else
  90.                                                rc = run_command (lastcommand, flag);

  91.                                       if (rc <= 0) {
  92.    /* invalid command or not repeatable, forget it */
  93.                                                  lastcommand[0] = 0;
  94.                }
  95.      }
  96. #endif /*CFG_HUSH_PARSER*/
  97. }
  98. #ifdef CONFIG_BOOT_RETRY_TIME

到这里总结一下启动内核是如何调用相关函数的:1.    s = getenv ("altbootcmd");获取环境变量参数

                                                                                        2.    调用 run_command (s, 0);函数

 

而在u-boot的控制界面时:1.   调用readline()函数,读取串口数据

                                                2.   还是调用 run_command (s, 0);函数

 

 

在common/main.c中readline()函数代码如下:

/****************************************************************************/

  1. /*
     * Prompt for input and read a line.
     * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
     * time out when time goes past endtime (timebase time in ticks).
     * Return: number of read characters
     *  -1 if break
     *  -2 if timed out
     */
    int readline (const char *const prompt)
  2.              {
  3. #ifdef CONFIG_CMDLINE_EDITING
  4.                           char *p = console_buffer;
  5.                           unsigned int len=MAX_CMDBUF_SIZE;
  6.                           int rc;
  7.                           static int initted = 0;
  8.                           if (!initted) {
  9.                                    hist_init();
  10.                                    initted = 1;
  11.                                                }
  12.                           puts (prompt);
  13.                           rc = cread_line(p, &len);
  14.                           return rc < 0 ? rc : len;
    #else
  15.                          char   *p = console_buffer;
  16.                           int n = 0;    /* buffer index  */
  17.                          int plen = 0;   /* prompt length */
  18.                          int col;    /* output column cnt */
  19.                          char c;
  20.  /* print prompt */
  21.                         if (prompt) {
  22.                                  plen = strlen (prompt);
  23.                                  puts (prompt);
  24.                                              }
  25.             col = plen;
  26.              for (;;) {
  27. #ifdef CONFIG_BOOT_RETRY_TIME
  28.                while (!tstc()) { /* while no incoming data */
  29.                 if (retry_time >= 0 && get_ticks() > endtime)
  30.                          return (-2); /* timed out */
  31.                                         }
  32. #endif
  33.                   WATCHDOG_RESET();  /* Trigger watchdog, if needed */

  34. #ifdef CONFIG_SHOW_ACTIVITY
  35.                  while (!tstc()) {
  36.                 extern void show_activity(int arg);
  37.                  show_activity(0);
  38.   }
  39. #endif
  40.                 c = getc();
  41.   /*
       * Special character handling
       */
  42.               switch (c) {
  43.                                    case '\r':    /* Enter  */
  44.                                   case '\n':
  45.                                   *p = '\0';
  46.                                  puts ("\r\n");
  47.                                  return (p - console_buffer);
  48.                     case '\0':                                       /* nul   */
  49.                                  continue;
  50.                                  case 0x03:
        /* ^C - break  */
  51.                                 console_buffer[0] = '\0';                       /* discard input */
  52.                                return (-1);
  53.                    case 0x15:
        /* ^U - erase line */
                                    while (col > plen) {
  54.                                 puts (erase_seq);
  55.                                  --col;
  56.        }
  57.                                p = console_buffer;
  58.                                n = 0;
  59.                                continue;
  60.                  case 0x17:
     
       /* ^W - erase word  */
                                  p=delete_char(console_buffer, p, &col, &n, plen);
  61.                                while ((n > 0) && (*p != ' ')) {
  62.                               p=delete_char(console_buffer, p, &col, &n, plen);
  63.    }
  64.                              continue;
  65.                  case 0x08:
        /* ^H  - backspace */
  66.                 case 0x7F:    /* DEL - backspace */
  67.                              p=delete_char(console_buffer, p, &col, &n, plen);
  68.                              continue;
  69.                               default:
  70.    /*
        * Must be a normal character then
        */
  71.                  if (n < CFG_CBSIZE-2) {
  72.                          if (c == '\t') {                                          /* expand TABs  */
  73. #ifdef CONFIG_AUTO_COMPLETE
         /* if auto completion triggered just continue */
  74.      *p = '\0';
  75.                                          if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
  76.                                                      p = console_buffer + n;                                            /* reset */
  77.                                                       continue;
  78.      }
  79. #endif
  80.                                        puts (tab_seq+(col&07));
  81.                                        col += 8 - (col&07);
  82.     } else {
  83.                                        ++col;                                           /* echo input  */
  84.                                         putc (c);
  85.     }
  86.                                         *p++ = c;
  87.                                          ++n;
  88.                                          } else {   /* Buffer full  */
  89.                                         putc ('\a');
  90.    }
  91.   }
  92.  }
  93. #endif /* CONFIG_CMDLINE_EDITING */
  94. }

 

 参考韦东山老师的视频教程!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Linux,bootloader,学习随笔)