uboot启动内核学习笔记

===============================================================================
        uboot启动内核  
===============================================================================
命令行中输入print 得到信息bootcmd=nand read.i c0008000 80000 500000;bootm c0008000

mini6410.h中定义的部分代码:
    
    #ifdef CONFIG_ENABLE_MMU
    #define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000
    #define CONFIG_BOOTCOMMAND "nand read 0xc0018000 0x60000 0x1c0000;" \
        "bootm 0xc0018000"
    #else
    #define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE
    #define CONFIG_BOOTCOMMAND "nand read 0x50018000 0x60000 0x1c0000;" \
        "bootm 0x50018000"
        
    
    
1 从NAND读出内核:bootcmd=nand read.i c0008000 80000 500000
    flash上存的内核:uImage
                 头部+真正的内核
                     
    头部的结构体:在/include/Image.h中
    示例代码如下:
    /*
     * Legacy format image header,
     * all data in network byte order (aka natural aka bigendian).
     */
    typedef struct image_header {
     uint32_t ih_magic; /* Image Header Magic Number */
     uint32_t ih_hcrc; /* Image Header CRC Checksum */
     uint32_t ih_time; /* Image Creation Timestamp */
     uint32_t ih_size; /* Image Data Size  */
     uint32_t ih_load; /* Data  Load  Address  加载地址*/
     uint32_t ih_ep;  /* Entry Point Address  入口地址*/
     uint32_t ih_dcrc; /* Image Data CRC Checksum */
     uint8_t  ih_os;  /* Operating System  */
     uint8_t  ih_arch; /* CPU architecture  */
     uint8_t  ih_type; /* Image Type   */
     uint8_t  ih_comp; /* Compression Type  */
     uint8_t  ih_name[IH_NMLEN]; /* Image Name  */
    } image_header_t;
2 启动内核: bootm c0008000
  (1)bootm根据头部,将内核移动到合适的地方
  (2)启动
bootm的部分代码在/common/cmd_bootm.c文件中
部分代码如下:
        int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
        {
         ulong iflag;
         ulong addr;
         ulong data, len, checksum;
         ulong  *len_ptr = NULL; /* not to make warning. by scsuh */
         uint unc_len = CFG_BOOTM_LEN;
         int i, verify;
         char *name, *s;
         int (*appl)(int, char *[]);
         image_header_t *hdr = &header;
        
         s = getenv ("verify");
         verify = (s && (*s == 'n')) ? 0 : 1;
        
         if (argc < 2) {
          addr = load_addr;
         } else {
          addr = simple_strtoul(argv[1], NULL, 16);
         }
        
        #ifdef CONFIG_ZIMAGE_BOOT
        #define LINUX_ZIMAGE_MAGIC 0x016f2818
         if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC) {//如果加载地址等于内核地址直接启动
          printf("Boot with zImage\n");
          addr = virt_to_phys(addr);
          hdr->ih_os = IH_OS_LINUX;
          hdr->ih_ep = ntohl(addr);
          goto after_header_check;
         }
        #endif
        
         SHOW_BOOT_PROGRESS (1);
         printf ("## Booting image at %08lx ...\n", addr);
        
         /* Copy header so we can blank CRC field for re-calculation */
        #ifdef CONFIG_HAS_DATAFLASH
         if (addr_dataflash(addr)){
          read_dataflash(addr, sizeof(image_header_t), (char *)&header);
         } else
        #endif
         memmove (&header, (char *)addr, sizeof(image_header_t));//否则将内核移动到合适的位置(addr 加载地址)
        
         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
        #ifdef __I386__ /* correct image format not implemented yet - fake it */
          if (fake_header(hdr, (void*)addr, -1) != NULL) {
           /* to compensate for the addition below */
           addr -= sizeof(image_header_t);
           /* turnof verify,
            * fake_header() does not fake the data crc
            */
           verify = 0;
          } else
        #endif /* __I386__ */
             {
        #ifdef CONFIG_IMAGE_BOOT
          printf("Boot with Image\n");
          addr = virt_to_phys(addr);
          hdr->ih_os = IH_OS_LINUX;
          hdr->ih_ep = ntohl(addr);
          hdr->ih_comp = IH_COMP_NONE;
          goto after_header_check;
        #endif
          puts ("Bad Magic Number\n");
          SHOW_BOOT_PROGRESS (-1);
          return 1;
             }
         }
         SHOW_BOOT_PROGRESS (2);
        
         data = (ulong)&header;
         len  = sizeof(image_header_t);
        
         checksum = ntohl(hdr->ih_hcrc);
         hdr->ih_hcrc = 0;
        
         if (crc32 (0, (uchar *)data, len) != checksum) {
          puts ("Bad Header Checksum\n");
          SHOW_BOOT_PROGRESS (-2);
          return 1;
         }
         SHOW_BOOT_PROGRESS (3);
        
        #ifdef CONFIG_HAS_DATAFLASH
         if (addr_dataflash(addr)){
          len  = ntohl(hdr->ih_size) + sizeof(image_header_t);
          read_dataflash(addr, len, (char *)CFG_LOAD_ADDR);
          addr = CFG_LOAD_ADDR;
         }
        #endif
        
        
         /* for multi-file images we need the data part, too */
         print_image_hdr ((image_header_t *)addr);
        
         data = addr + sizeof(image_header_t);
         len  = ntohl(hdr->ih_size);
        
         if (verify) {
          puts ("   Verifying Checksum ... ");
          if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {
           printf ("Bad Data CRC\n");
           SHOW_BOOT_PROGRESS (-3);
           return 1;
          }
          puts ("OK\n");
         }
         SHOW_BOOT_PROGRESS (4);
        
         len_ptr = (ulong *)data;
        
        #if defined(__PPC__)
         if (hdr->ih_arch != IH_CPU_PPC)
        #elif defined(__ARM__)
         if (hdr->ih_arch != IH_CPU_ARM)
        #elif defined(__I386__)
         if (hdr->ih_arch != IH_CPU_I386)
        #elif defined(__mips__)
         if (hdr->ih_arch != IH_CPU_MIPS)
        #elif defined(__nios__)
         if (hdr->ih_arch != IH_CPU_NIOS)
        #elif defined(__M68K__)
         if (hdr->ih_arch != IH_CPU_M68K)
        #elif defined(__microblaze__)
         if (hdr->ih_arch != IH_CPU_MICROBLAZE)
        #elif defined(__nios2__)
         if (hdr->ih_arch != IH_CPU_NIOS2)
        #elif defined(__blackfin__)
         if (hdr->ih_arch != IH_CPU_BLACKFIN)
        #elif defined(__avr32__)
         if (hdr->ih_arch != IH_CPU_AVR32)
        #else
        # error Unknown CPU type
        #endif
         {
          printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch);
          SHOW_BOOT_PROGRESS (-4);
          return 1;
         }
         SHOW_BOOT_PROGRESS (5);
        
         switch (hdr->ih_type) {
         case IH_TYPE_STANDALONE:
          name = "Standalone Application";
          /* A second argument overwrites the load address */
          if (argc > 2) {
           hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));
          }
          break;
         case IH_TYPE_KERNEL:
          name = "Kernel Image";
          break;
         case IH_TYPE_MULTI:
          name = "Multi-File Image";
          len  = ntohl(len_ptr[0]);
          /* OS kernel is always the first image */
          data += 8; /* kernel_len + terminator */
          for (i=1; len_ptr[i]; ++i)
           data += 4;
          break;
         default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
          SHOW_BOOT_PROGRESS (-5);
          return 1;
         }
         SHOW_BOOT_PROGRESS (6);
        
         /*
          * We have reached the point of no return: we are going to
          * overwrite all exception vector code, so we cannot easily
          * recover from any failures any more...
          */
        
         iflag = disable_interrupts();
        
        #ifdef CONFIG_AMIGAONEG3SE
         /*
          * We've possible left the caches enabled during
          * bios emulation, so turn them off again
          */
         icache_disable();
         invalidate_l1_instruction_cache();
         flush_data_cache();
         dcache_disable();
        #endif
        
         switch (hdr->ih_comp) {
         case IH_COMP_NONE:
          if(ntohl(hdr->ih_load) == addr) {
           printf ("   XIP %s ... ", name);
          } else {
        #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
           size_t l = len;
           void *to = (void *)ntohl(hdr->ih_load);
           void *from = (void *)data;
        
           printf ("   Loading %s ... ", name);
        
           while (l > 0) {
            size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
            WATCHDOG_RESET();
            memmove (to, from, tail);
            to += tail;
            from += tail;
            l -= tail;
           }
        #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
           memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
        #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
          }
          break;
         case IH_COMP_GZIP:
          printf ("   Uncompressing %s ... ", name);
          if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,
               (uchar *)data, &len) != 0) {
           puts ("GUNZIP ERROR - must RESET board to recover\n");
           SHOW_BOOT_PROGRESS (-6);
           do_reset (cmdtp, flag, argc, argv);
          }
          break;
        #ifdef CONFIG_BZIP2
         case IH_COMP_BZIP2:
          printf ("   Uncompressing %s ... ", name);
          /*
           * If we've got less than 4 MB of malloc() space,
           * use slower decompression algorithm which requires
           * at most 2300 KB of memory.
           */
          i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),
              &unc_len, (char *)data, len,
              CFG_MALLOC_LEN < (4096 * 1024), 0);
          if (i != BZ_OK) {
           printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
           SHOW_BOOT_PROGRESS (-6);
           udelay(100000);
           do_reset (cmdtp, flag, argc, argv);
          }
          break;
        #endif /* CONFIG_BZIP2 */
         default:
          if (iflag)
           enable_interrupts();
          printf ("Unimplemented compression type %d\n", hdr->ih_comp);
          SHOW_BOOT_PROGRESS (-7);
          return 1;
         }
         puts ("OK\n");
         SHOW_BOOT_PROGRESS (7);
        
         switch (hdr->ih_type) {
         case IH_TYPE_STANDALONE:
          if (iflag)
           enable_interrupts();
        
          /* load (and uncompress), but don't start if "autostart"
           * is set to "no"
           */
          if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {
           char buf[32];
           sprintf(buf, "%lX", len);
           setenv("filesize", buf);
           return 0;
          }
          appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
          (*appl)(argc-1, &argv[1]);
          return 0;
         case IH_TYPE_KERNEL:
         case IH_TYPE_MULTI:
          /* handled below */
          break;
         default:
          if (iflag)
           enable_interrupts();
          printf ("Can't boot image type %d\n", hdr->ih_type);
          SHOW_BOOT_PROGRESS (-8);
          return 1;
         }
         SHOW_BOOT_PROGRESS (8);
        
        #if defined(CONFIG_ZIMAGE_BOOT) || defined(CONFIG_IMAGE_BOOT)
        after_header_check:
        #endif
         switch (hdr->ih_os) {
         default:   /* handled by (original) Linux case */
         case IH_OS_LINUX://启动linux内核 
        #ifdef CONFIG_SILENT_CONSOLE
             fixup_silent_linux();
        #endif
             do_bootm_linux  (cmdtp, flag, argc, argv,
                addr, len_ptr, verify);                 //启动内核的方法: 1 设置启动参数 2 跳到入口地址启动内核
             break;
         case IH_OS_NETBSD:
             do_bootm_netbsd (cmdtp, flag, argc, argv,
                addr, len_ptr, verify);
             break;
        
        #ifdef CONFIG_LYNXKDI
         case IH_OS_LYNXOS:
             do_bootm_lynxkdi (cmdtp, flag, argc, argv,
                addr, len_ptr, verify);
             break;
        #endif
        
         case IH_OS_RTEMS:
             do_bootm_rtems (cmdtp, flag, argc, argv,
                addr, len_ptr, verify);
             break;
        
        #if (CONFIG_COMMANDS & CFG_CMD_ELF)
         case IH_OS_VXWORKS:
             do_bootm_vxworks (cmdtp, flag, argc, argv,
                 addr, len_ptr, verify);
             break;
         case IH_OS_QNX:
             do_bootm_qnxelf (cmdtp, flag, argc, argv,
                 addr, len_ptr, verify);
             break;
        #endif /* CFG_CMD_ELF */
        #ifdef CONFIG_ARTOS
         case IH_OS_ARTOS:
             do_bootm_artos  (cmdtp, flag, argc, argv,
                addr, len_ptr, verify);
             break;
        #endif
         }
        
         SHOW_BOOT_PROGRESS (-9);
        #ifdef DEBUG
         puts ("\n## Control returned to monitor - resetting...\n");
         do_reset (cmdtp, flag, argc, argv);
        #endif
         return 1;
        }  
  
 do_bootm_linux定义在arch/arm/lib/Bootm.c中
 部分代码如下:
      int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
     {
      bd_t *bd = gd->bd;
      char *s;
      int machid = bd->bi_arch_number;
      void (*kernel_entry)(int zero, int arch, uint params);
     
     #ifdef CONFIG_CMDLINE_TAG
      char *commandline = getenv ("bootargs");
     #endif
     
      if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
       return 1;
     
      s = getenv ("machid");
      if (s) {
       machid = simple_strtoul (s, NULL, 16);
       printf ("Using machid 0x%x from environment\n", machid);
      }
     
      show_boot_progress (15);
     
     #ifdef CONFIG_OF_LIBFDT
      if (images->ft_len)
       return bootm_linux_fdt(machid, images);
     #endif
      /*函数指针指向入口地址*/
      kernel_entry = (void (*)(int, int, uint))images->ep;
     
      debug ("## Transferring control to Linux (at address %08lx) ...\n",
             (ulong) kernel_entry);
     /*1 设置启动参数*/
     /*将参数按照指定格式(tag)保存到指定地址(bi_boot_params = PHYS_SDRAM_1 + 0x100;)*/
     #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
         defined (CONFIG_CMDLINE_TAG) || \
         defined (CONFIG_INITRD_TAG) || \
         defined (CONFIG_SERIAL_TAG) || \
         defined (CONFIG_REVISION_TAG)
      setup_start_tag (bd);
     #ifdef CONFIG_SERIAL_TAG
      setup_serial_tag (&params);
     #endif
     #ifdef CONFIG_REVISION_TAG
      setup_revision_tag (&params);
     #endif
     #ifdef CONFIG_SETUP_MEMORY_TAGS
      setup_memory_tags (bd);
     #endif
     #ifdef CONFIG_CMDLINE_TAG
      setup_commandline_tag (bd, commandline);
     #endif
     #ifdef CONFIG_INITRD_TAG
      if (images->rd_start && images->rd_end)
       setup_initrd_tag (bd, images->rd_start, images->rd_end);
     #endif
      setup_end_tag(bd);
     #endif
     
      announce_and_cleanup();
      /*2 启动内核*/
      /*machid 机器id*/
      /*定义在mini6410.h中#define MACH_TYPE  2520*/
      /*bi_boot_params 启动参数*/
      kernel_entry(0, machid, bd->bi_boot_params);
      /* does not return */
     
      return 1;
     }
      
       启动参数的设置:
      1 setup_start_tag (bd);
        位于bootm.c中,部分代码如下:
        static void setup_start_tag (bd_t *bd){
             /*bi_boot_params定义在board/samsung/mini6410/mini6410.c中*/
             /*gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;*/
             /*PHYS_SDRAM_1定义在include/config/mini6410.h中*/
             /*#define PHYS_SDRAM_1  CONFIG_SYS_SDRAM_BASE /* SDRAM Bank #1 */*/
             /*首先存放的是一个tag*/
             params = (struct tag *) bd->bi_boot_params;
             /*teg_header的tag值为 0x54410001*/
             params->hdr.tag = ATAG_CORE;
             /*
              * struct tag_core {
              *  u32 flags;  /* bit 0 = read-only */
              *  u32 pagesize;
              *  u32 rootdev;
              * };
              */
             params->hdr.size = tag_size (tag_core);
            
             params->u.core.flags = 0;
             params->u.core.pagesize = 0;
             params->u.core.rootdev = 0;
            
             params = tag_next (params);
            }            
      2 setup_revision_tag (&params);
      同理
      3 setup_memory_tags (bd);
        也位于bootm.c中,同理:
        static void setup_memory_tags (bd_t *bd)
          {
           int i;
          
           for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
            params->hdr.tag = ATAG_MEM;
            /*
             *  struct tag_mem32 {
             *   u32 size;
             *   u32 start; /* physical start address */
             *  };
               */
            params->hdr.size = tag_size (tag_mem32);
            
            /*开始位置和大小定义在board/samsung\mini6410\mini6410.c中*/
            /*int dram_init(void)
             *  {
             *   DECLARE_GLOBAL_DATA_PTR; 
             *    gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
             *   gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
             *    return 0;
             *  }
              */
          
            params->u.mem.start = bd->bi_dram[i].start;
            params->u.mem.size = bd->bi_dram[i].size;
          
            params = tag_next (params);
           }
          }
        
        如下图  
      
      4 setup_commandline_tag (bd, commandline);
      同理
       bootargs=root=/dev/mtdblock2 rootfstype=yaffs2 init=/linuxrc console=ttySAC0,115200 androidboot.console=s3c2410_serial0
      5 setup_initrd_tag (bd, images->rd_start, images->rd_end);
      同理
      6 setup_end_tag(bd);
      同理
      
      
      
      
      
      
      
      
      
      
      -----------
      -----------
      -----------     <----------------params
      start
      -----------
      size 0x10000000
      -----------
      tag 0x54410002         定义在arch/arm/include/asm中#define ATAG_MEM 0x54410002
      -----------
      size 4
      -----------      <--------------params
      rootdev 0
      -----------
      pagesize  0               tag_core
      -----------
      flags 0
      -----------
      tag  0x54410001       params = (struct tag *) bd->bi_boot_params;
      -----------
      size    5              #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
      -----------      
      
      
      
      
      
      
      
      
      
      
      
   参数存放的格式:
   struct tag {
       /*  定义在arch/arm/include/asm/setup.h
        *  struct tag_header {
         *     u32 size;
              *      u32 tag;
               *    };
               */       
       struct tag_header hdr;
       union {
        struct tag_core  core;
        struct tag_mem32 mem;
        struct tag_videotext videotext;
        struct tag_ramdisk ramdisk;
        struct tag_initrd initrd;
        struct tag_serialnr serialnr;
        struct tag_revision revision;
        struct tag_videolfb videolfb;
        struct tag_cmdline cmdline;
      
        /*
         * Acorn specific
         */
        struct tag_acorn acorn;
      
        /*
         * DC21285 specific
         */
        struct tag_memclk memclk;
       } u;
      };

你可能感兴趣的:(uboot启动内核学习笔记)