u-boot 2011.09 调用kernel 的流程

 

这段时候我总是觉得有个问题,u-boot 的存在是不是就是为了调用kernel 而存在的。

所以,粗浅的跟了一下这个流程,还有很多细节上的东西没有做好,往指正。

 

u-boot-2011.9 调用内核代码跟踪
1. _start  board_init_r  main_loop.
这个流程是u-boot 的一个整体的流程。

2. main_loop()
这个函数主要执行一些u-boot 最后的一些工作,

 347 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)                        
 348     s = getenv ("bootdelay");                                                   
 349     bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;         
 350                                                                                 
 351     debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);               
 352                                                                                 

这里是设置系统的启动延时的时间。
如果在include/configs/ok335x.h 里面设置了宏定义CONFIG_BOOTDELAY大于零
那么在延时期间中断便可进入shell 终端界面。

 371         s = getenv ("bootcmd");                                                 
 372                                                                                 
 373     debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");           
 374                                                                                 
 375     if (bootdelay >= 0 && s && !abortboot (bootdelay)) {                        
 376 # ifdef CONFIG_AUTOBOOT_KEYED                                                   
 377         int prev = disable_ctrlc(1);    /* disable Control C checking */        
 378 # endif                                                                         
 379                                                                                 
 380 # ifndef CONFIG_SYS_HUSH_PARSER                                                 
 381         run_command (s, 0);                                                     

这里面就有关于u-boot 调用kernel 的方法。
Bootcmd 的定义在common/env_common.c 里面。

 51 #ifdef  CONFIG_BOOTARGS                                                         
 52     "bootargs=" CONFIG_BOOTARGS         "\0"                                    

这是关于bootcmd 的定义。
在c语言中一个字符串其实本质上代表的就是的指针。
Bootcmd 指向的是CONFIG_BOOTCOMMAND 这个地址。

 

 

CONFIG_BOOTCOMMAND 这个宏的定义在include/configs/ok335x.h 里面。

193 #define CONFIG_BOOTCOMMAND \                                                    
194     " if test $bootdev = MMC; then " \                                          
195         "mmc dev ${mmcdev}; mmc rescan;"\                                       
196         "echo SD/MMC found on device ${mmcdev};" \                              
197         "if run loadbootenv; then " \                                           
198             "echo Loaded environment from ${bootenv};" \                        
199             "run importbootenv;" \                                              
200         "fi;" \                                                                 
201         "if test -n $uenvcmd; then " \                                          
202             "echo Running uenvcmd ...;" \                                       
203             "run uenvcmd;" \                                                    
204         "fi;" \                                                                 
205         "if run loaduimagefat; then " \                                         
206             "run mmcboot;" \                                                    
207         "elif run loaduimage; then " \                                          
208             "run mmcboot;" \                                                    
209         "else " \                                                               
210             "echo Could not find ${bootfile} ;" \                               
211         "fi;" \                                                                 
212     "else " \                                                                   
213         "run nandboot;" \                                                       
214     "fi;" \                                                                     

 

 

这边的话我们是直接运行run nandboot ;

149     "nandboot=echo Booting from nand ...; " \                                   
150         "run nandargs; " \                                                      
151         "nandecc hw 2;"\                                                        
152         "nand read ${loadaddr} ${nandsrcaddr} ${nandimgsize}; " \               
153         "bootm ${loadaddr}\0" \                                                 

最后运行bootm ${loadaddr} ,就可以运行kernel 。

 

 

3. run_command() 函数
这个函数的实现在common/main.c 里面。
运行run_command 函数,如果成功运行,返回1或者0,如果没有运行则返回-1。
命令结构体。

 46 struct cmd_tbl_s {                                                              
 47     char        *name;      /* Command Name         */                          
 48     int     maxargs;    /* maximum number of arguments  */                      
 49     int     repeatable; /* autorepeat allowed?      */                          
 50                     /* Implementation function  */                              
 51     int     (*cmd)(struct cmd_tbl_s *, int, int, char * const []);              
 52     char        *usage;     /* Usage message    (short) */                      
 53 #ifdef  CONFIG_SYS_LONGHELP                                                     
 54     char        *help;      /* Help  message    (long)  */                      
 55 #endif                                                                          
 56 #ifdef CONFIG_AUTO_COMPLETE                                                     
 57     /* do auto completion on the arguments */                                   
 58     int     (*complete)(int argc, char * const argv[], char last_char, int maxv, char *c    mdv[]);
 59 #endif                                                                          
 60 };                                                                              
 61                                                                                 
 62 typedef struct cmd_tbl_s    cmd_tbl_t;                                          


最后运行这条命令。

1372         /* OK - call function to do the command */                              
1373         if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {                      
1374             rc = -1;                                                            
1375         }                                                                       

 

4. bootm 命令分析

在run_command 里面,以及前面的分析可以得出,最终,他会调用
bootm 命令,并且指向kernel 的地址。
bootm 命令的实现是在common/cmd_bootm.c 中实现。

 585 /*******************************************************************/           
 586 /* bootm - boot application image from image in memory */                       
 587 /*******************************************************************/           
 588                                                                                 
 589 int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])        
 590 {                                                                               

 


其实这个函数做了三个很重要的功能。
bootm_start : 内核启动前的准备工作,获取内核的信息并检查。
bootm_load_os : 检查内核的文件格式,是否需要解压。
boot_fn : 内核启动函数的调用, 我们调用的是do_bootm_linux 函数。

 

1) bootm_start
从do_bootm 调用了这一个函数。

 625     if (bootm_start(cmdtp, flag, argc, argv))                                   
 626         return 1;                                                               

 


有时候我们加载内核不成功,很多时候会报can’t get kernel image就是在这里报的。
从下可以看到,我们又调用了boot_get_kernel 函数。

 214 static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 215 {                                                                               
 216     void        *os_hdr;                                                        
 217     int     ret;                                                                
 218                                                                                 
 219     memset ((void *)&images, 0, sizeof (images));                               
 220     images.verify = getenv_yesno ("verify");                                    
 221                                                                                 
 222     bootm_start_lmb();                                                          
 223                                                                                 
 224     /* get kernel image header, start address and length */                     
 225     os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,                          
 226             &images, &images.os.image_start, &images.os.image_len);             
 227     if (images.os.image_len == 0) {                                             
 228         puts ("ERROR: can't get kernel image!\n");                              
 229         return 1;                                                               
 230     }                                                                           

 

 

这个函数的作用其实是:找到kernel 镜像。

 839 static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]     ,           
 840         bootm_headers_t *images, ulong *os_data, ulong *os_len)                 
 841 {                                                                               
 842     image_header_t  *hdr;                                                       
 843     ulong       img_addr;                                                       
 869     } else {                                                                    
 870         img_addr = simple_strtoul(argv[1], NULL, 16);                           
 871         debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);       
 872     }                                                                           
 873                                                                                 
 874     show_boot_progress (1);                                                     
 875                                                                                 
 876     /* copy from dataflash if needed */                                         
 877     img_addr = genimg_get_image (img_addr);                                     
 878                                                                                 
 879     /* check image type, for FIT images get FIT kernel node */                  
 880     *os_data = *os_len = 0;                                                     
 881     switch (genimg_get_format ((void *)img_addr)) {                             
 882     case IMAGE_FORMAT_LEGACY:                                                   
 883         printf ("## Booting kernel from Legacy Image at %08lx ...\n",           
 884                 img_addr);                                                      
 885         hdr = image_get_kernel (img_addr, images->verify);                      

打印一句调试信息。
然后通过image_get_kernel 获取kernel.

 741 static image_header_t *image_get_kernel (ulong img_addr, int verify)            
 742 {                                                                               
 743     image_header_t *hdr = (image_header_t *)img_addr;                           
 744                                                                                 
 745     if (!image_check_magic(hdr)) {                                              
 746         puts ("Bad Magic Number\n");                                            
 747         show_boot_progress (-1);                                                
 748         return NULL;                                                            
 749     }                                                                           
 750     show_boot_progress (2);                                                     
 751                                                                                 
 752     if (!image_check_hcrc (hdr)) {                                              
 753         puts ("Bad Header Checksum\n");                                         
 754         show_boot_progress (-2);                                                
 755         return NULL;                                                            
 756     }                                                                           
 757                                                                                 
 758     show_boot_progress (3);                                                     
 759     image_print_contents (hdr);                                                 
 760                                                                                 
 761     if (verify) {                                                               
 762         puts ("   Verifying Checksum ... ");                                    
 763         if (!image_check_dcrc (hdr)) {                                          
 764             printf ("Bad Data CRC\n");                                          
 765             show_boot_progress (-3);                                            
 766             return NULL;                                                        
 767         }                                                                       
 768         puts ("OK\n");                                                          
 769     }                                                                           
 770     show_boot_progress (4);                                                     
 771                                                                                 
 772     if (!image_check_target_arch (hdr)) {                                       
 773         printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));       
 774         show_boot_progress (-4);                                                
 775         return NULL;                                                            
 776     }                                                                           
 777     return hdr;                                                                 
 778 }                                                                               

 

 300 void image_print_contents (const void *ptr)                                     
 301 {                                                                               
 302     const image_header_t *hdr = (const image_header_t *)ptr;                    
 303     const char *p;                                                              
 304                                                                                 
 305 #ifdef USE_HOSTCC                                                               
 306     p = "";                                                                     
 307 #else                                                                           
 308     p = "   ";                                                                  
 309 #endif                                                                          
 310                                                                                 
 311     printf ("%sImage Name:   %.*s\n", p, IH_NMLEN, image_get_name (hdr));       
 312 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
 313     printf ("%sCreated:      ", p);                                             
 314     genimg_print_time ((time_t)image_get_time (hdr));                           
 315 #endif                                                                          
 316     printf ("%sImage Type:   ", p);                                             
 317     image_print_type (hdr);                                                     
 318     printf ("%sData Size:    ", p);                                             
 319     genimg_print_size (image_get_data_size (hdr));                              
 320     printf ("%sLoad Address: %08x\n", p, image_get_load (hdr));                 
 321     printf ("%sEntry Point:  %08x\n", p, image_get_ep (hdr));                   
 322                                                                                 
 323     if (image_check_type (hdr, IH_TYPE_MULTI) ||                                
 324             image_check_type (hdr, IH_TYPE_SCRIPT)) {                           
 325         int i;                                                                  
 326         ulong data, len;                                                        
 327         ulong count = image_multi_count (hdr);                                  
 328                                                                                 
 329         printf ("%sContents:\n", p);                                            
 330         for (i = 0; i < count; i++) {                                           
 331             image_multi_getimg (hdr, i, &data, &len);                           
 332                                                                                 
 333             printf ("%s   Image %d: ", p, i);                                   
 334             genimg_print_size (len);                                            
 335                                                                                 
 336             if (image_check_type (hdr, IH_TYPE_SCRIPT) && i > 0) {              
 337                 /*                                                              
 338                  * the user may need to know offsets                            
 339                  * if planning to do something with                             
 340                  * multiple files                                               
 341                  */                                                             
 342                 printf ("%s    Offset = 0x%08lx\n", p, data);                   
 343             }                                                                   
 344         }                                                                       
 345     }                                                                           
 346 }                                                                               
 347                                                                             

打印内核信息。打印校验和校验是否正确。

 


OK,到此从image_get_kernel - > boot_get_kernel 回来。

 772     if (!image_check_target_arch (hdr)) {                                       
 773         printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));       
 774         show_boot_progress (-4);                                                
 775         return NULL;                                                            
 776     }                                                                           
 777     return hdr;                                                                 
 778 }   

返回内核地址。

再从boot_get_kernel 回到bootm_start

 232     /* get image parameters */                                                  
 233     switch (genimg_get_format (os_hdr)) {                                       
 234     case IMAGE_FORMAT_LEGACY:                                                   
 235         images.os.type = image_get_type (os_hdr);                               
 236         images.os.comp = image_get_comp (os_hdr);                               
 237         images.os.os = image_get_os (os_hdr);                                   
 238                                                                                 
 239         images.os.end = image_get_image_end (os_hdr);                           
 240         images.os.load = image_get_load (os_hdr);                               
 241         break;                                                                  

获取内核的参数并保存。

 275     default:                                                                    
 276         puts ("ERROR: unknown image format type!\n");                           
 277         return 1;                                                               

有时候我们加载内核失败会报这个错误。

 280     /* find kernel entry point */                                               
 281     if (images.legacy_hdr_valid) {                                              
 282         images.ep = image_get_ep (&images.legacy_hdr_os_copy);                  

找到内核的入口。

 

 

 297     if (((images.os.type == IH_TYPE_KERNEL) ||                                  
 298          (images.os.type == IH_TYPE_MULTI)) &&                                  
 299         (images.os.os == IH_OS_LINUX)) {                                        
 300         /* find ramdisk */                                                      
 301         ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,            
 302                 &images.rd_start, &images.rd_end);                              
 303         if (ret) {                                                              
 304             puts ("Ramdisk image is corrupt or invalid\n");                     
 305             return 1;                                                           
 306         }                                                                       

获取虚拟磁盘。

 321     images.os.start = (ulong)os_hdr;                                            
 322     images.state = BOOTM_STATE_START;                                           
 323                                                                                 
 324     return 0;                                                                   
 325 }                                                                               

保存内核开启地址,并给开始的状态。

 

从bootm_start 回到do_bootm.

 625     if (bootm_start(cmdtp, flag, argc, argv))                                   
 626         return 1;                                                               

 

正常情况下bootm_start 是返回0,所以不会执行return 1;
2) bootm_load_os 函数

 648     ret = bootm_load_os(images.os, &load_end, 1);                               

 

获取文件类型,打印调试信息。

 327 #define BOOTM_ERR_RESET     -1                                                  
 328 #define BOOTM_ERR_OVERLAP   -2                                                  
 329 #define BOOTM_ERR_UNIMPLEMENTED -3                                              
 330 static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)   
 331 {                                                                               
 332     uint8_t comp = os.comp;                                                     
 333     ulong load = os.load;                                                       
 334     ulong blob_start = os.start;                                                
 335     ulong blob_end = os.end;                                                    
 336     ulong image_start = os.image_start;                                         
 337     ulong image_len = os.image_len;                                             
 338     uint unc_len = CONFIG_SYS_BOOTM_LEN;                                        
 339 #if defined(CONFIG_LZMA) || defined(CONFIG_LZO)                                 
 340     int ret;                                                                    
 341 #endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */                        
 342                                                                                 
 343     const char *type_name = genimg_get_type_name (os.type);                     
 344                                                                                 
 345     switch (comp) {                                                             
 346     case IH_COMP_NONE:                                                          
 347         if (load == blob_start || load == image_start) {                        
 348             printf ("   XIP %s ... ", type_name);                               
 349         } else {                                                                
 350             printf ("   Loading %s ... ", type_name);                           
 351             memmove_wd ((void *)load, (void *)image_start,                      
 352                     image_len, CHUNKSZ);                                        
 353         }                                                                       
 354         *load_end = load + image_len;                                           
 355         puts("OK\n");                                                           
 356         break;                                                                  
 436     flush_cache(load, (*load_end - load) * sizeof(ulong));                      
 437                                                                                 
 438     puts ("OK\n");                                                              
 439     debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end);    
 440     if (boot_progress)                                                          
 441         show_boot_progress (7);                                                 
 442                                                                                 
 443     if ((load < blob_end) && (*load_end > blob_start)) {                        
 444         debug ("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end     );
 445         debug ("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end);  
 446                                                                                 
 447         return BOOTM_ERR_OVERLAP;                                               
 448     }                                                                           
 449                                                                                 
 450     return 0;                                                                   
 451 }                                                                               

 

从bootm_load_os 回到do_bootm

 648     ret = bootm_load_os(images.os, &load_end, 1);                               
 649                                                                                 
 650     if (ret < 0) {                                                              
 651         if (ret == BOOTM_ERR_RESET)                                             
 652             do_reset (cmdtp, flag, argc, argv);                                 
 653         if (ret == BOOTM_ERR_OVERLAP) {                                         
 654             if (images.legacy_hdr_valid) {                                      
 655                 if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
 656                     puts ("WARNING: legacy format multi component "             
 657                         "image overwritten\n");                                 
 658             } else {                                                            
 659                 puts ("ERROR: new format image overwritten - "                  
 660                     "must RESET the board to recover\n");                       
 661                 show_boot_progress (-113);                                      
 662                 do_reset (cmdtp, flag, argc, argv);                             
 663             }                                                                   
 664         }                                                                       
 665         if (ret == BOOTM_ERR_UNIMPLEMENTED) {                                   
 666             if (iflag)                                                          
 667                 enable_interrupts();                                            
 668             show_boot_progress (-7);                                            
 669             return 1;                                                           
 670         }                                                                       
 671     }                                                                           

如果刚才出错,那么检查错误编号,打印错误信息。

 

 690     boot_fn = boot_os[images.os.os];                                            
 691                                                                                 
 692     if (boot_fn == NULL) {                                                      
 693         if (iflag)                                                              
 694             enable_interrupts();                                                
 695         printf ("ERROR: booting os '%s' (%d) is not supported\n",               
 696             genimg_get_os_name(images.os.os), images.os.os);                    
 697         show_boot_progress (-8);                                                
 698         return 1;                                                               
 699     }                                                                           
 700                                                                                 
 701     arch_preboot_os();                                                          
 702                                                                                 
 703     boot_fn(0, argc, argv, &images);                                            
 704                                                                                 

其实这一步调用的是do_bootm_linux

 134 static boot_os_fn *boot_os[] = {                                                
 135 #ifdef CONFIG_BOOTM_LINUX                                                       
 136     [IH_OS_LINUX] = do_bootm_linux,                                             
 137 #endif                                                                          
 138 #ifdef CONFIG_BOOTM_NETBSD                                                      
 139     [IH_OS_NETBSD] = do_bootm_netbsd,                                           
 140 #endif                                                                          
 141 #ifdef CONFIG_LYNXKDI                                                           
 142     [IH_OS_LYNXOS] = do_bootm_lynxkdi,                                          
 143 #endif                                                                          
 144 #ifdef CONFIG_BOOTM_RTEMS                                                       
 145     [IH_OS_RTEMS] = do_bootm_rtems,                                             
 146 #endif                                                                          
 147 #if defined(CONFIG_BOOTM_OSE)                                                   
 148     [IH_OS_OSE] = do_bootm_ose,                                                 
 149 #endif                                                                          
 150 #if defined(CONFIG_CMD_ELF)                                                     
 151     [IH_OS_VXWORKS] = do_bootm_vxworks,                                         
 152     [IH_OS_QNX] = do_bootm_qnxelf,                                              
 153 #endif                                                                          
 154 #ifdef CONFIG_INTEGRITY                                                         
 155     [IH_OS_INTEGRITY] = do_bootm_integrity,                                     
 156 #endif                                                                          
 157 };                                                                              

do_bootm_linux 函数其实在arch/arm/lib/bootm.c里面

 

 96 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)   
 97 {                                                                               
 98     bd_t    *bd = gd->bd;                                                       
 99     char    *s;                                                                 
100     int machid = bd->bi_arch_number;                                            
101     void    (*kernel_entry)(int zero, int arch, uint params);                   
102                                                                                 
103 #ifdef CONFIG_CMDLINE_TAG                                                       
104     char *commandline = getenv ("bootargs");                                    
105 #endif                                                                          
106                                                                                 
107     if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))                             
108         return 1;                                                               
109                                                                                 
110     s = getenv ("machid");                                                      
111     if (s) {                                                                    
112         machid = simple_strtoul (s, NULL, 16);                                  
113         printf ("Using machid 0x%x from environment\n", machid);                
114     }                                                                           
115                                                                                 
116     show_boot_progress (15);                                                    
117                                                                                 
118 #ifdef CONFIG_OF_LIBFDT                                                         
119     if (images->ft_len)                                                         
120         return bootm_linux_fdt(machid, images);                                 
121 #endif                                                                          
122                                                                                 
123     kernel_entry = (void (*)(int, int, uint))images->ep;                        
124                                                                                 
125     debug ("## Transferring control to Linux (at address %08lx) ...\n",         
126            (ulong) kernel_entry);                                               
127                                                                                 

声明一个函数指针。
把镜像入口给kernel_entry 这个函数指针。

 

128 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \                                     
129     defined (CONFIG_CMDLINE_TAG) || \                                           
130     defined (CONFIG_INITRD_TAG) || \                                            
131     defined (CONFIG_SERIAL_TAG) || \                                            
132     defined (CONFIG_REVISION_TAG)                                               
133     setup_start_tag (bd);                                                       
134 #ifdef CONFIG_SERIAL_TAG                                                        
135     setup_serial_tag (&params);                                                 
136 #endif                                                                          
137 #ifdef CONFIG_REVISION_TAG                                                      
138     setup_revision_tag (&params);                                               
139 #endif                                                                          
140 #ifdef CONFIG_SETUP_MEMORY_TAGS                                                 
141     setup_memory_tags (bd);                                                     
142 #endif                                                                          
143 #ifdef CONFIG_CMDLINE_TAG                                                       
144     setup_commandline_tag (bd, commandline);                                    
145 #endif                                                                          
146 #ifdef CONFIG_INITRD_TAG                                                        
147     if (images->rd_start && images->rd_end)                                     
148         setup_initrd_tag (bd, images->rd_start, images->rd_end);                
149 #endif                                                                          
150     setup_end_tag(bd);                                                          
151 #endif                                                                          

初始化开始标签。
初始化串口。
初始化版本信息。
初始化内存。
初始化命令行。
End.

 

153     announce_and_cleanup();                                                     
154                                                                                 
155     kernel_entry(0, machid, bd->bi_boot_params);                                
156     /* does not return */                                                       
157                                                                                 
158     return 1;                                                                   
159 }                                                                               

正式进入内核。

参考:http://blog.csdn.net/g_salamander/article/details/8463854

posted @ 2016-10-09 14:57  陈富林  阅读(1687)  评论(0编辑  收藏  举报