Chinaunix首页 | 论坛 | 博客
  • 博客访问: 77641
  • 博文数量: 28
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 351
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-15 13:18
个人简介

I bet you dont want to know.

文章分类

全部博文(28)

分类: LINUX

2008-08-01 23:42:53

do_bootm_linux函数源码分析(PPC)
static void do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
  int argc, char *argv[],
  ulong addr,
  ulong *len_ptr,
  int verify)
{
 DECLARE_GLOBAL_DATA_PTR;
 ulong sp;
 ulong len, checksum;
 ulong initrd_start, initrd_end;
 ulong cmd_start, cmd_end;
 ulong initrd_high;
 ulong data;
 int initrd_copy_to_ram = 1;
 char    *cmdline;
 char *s;
 bd_t *kbd;
 void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); // 内核启动函数指针
 image_header_t *hdr = &header;
 …
 /*
  * Booting a (Linux) kernel image
  *
  * Allocate space for command line and board info - the
  * address should be as high as possible within the reach of
  * the kernel (see CFG_BOOTMAPSZ settings), but in unused
  * memory, which means far enough below the current stack
  * pointer.
  */
 asm( "mr %0,1": "=r"(sp) : );  // 获取当前堆栈地址
 sp -= 2048;      // 为了不破坏Uboot的堆栈地址, 向下移动2K
 // CFG_BOOTMAPSZ是linux内核启动代码可以做重新映射的最大地址, 所有的可以
 // 被linux处理的数据都必须放在这个地址空间以内! 故当上面得到的地址大于
 // CFG_BOOTMAPSZ时必须使之等于CFG_BOOTMAPSZ.
 if (sp > CFG_BOOTMAPSZ)  // 保证sp指针位于CFG_BOOTMAPSZ内
  sp = CFG_BOOTMAPSZ;
 sp &= ~0xF;      // 堆栈指针16字节对齐
 debug ("=> set upper limit to 0x%08lX\n", sp);  // 打印堆栈上限地址
// 设置命令行地址(CFG_BARGSIZE=256), 基本上是在地址的最顶端了
 cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF); // 16字节对齐
 kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); // kbd设置在命令行的下面
 if ((s = getenv("bootargs")) == NULL)    // 读取保存的命令行参数
  s = "";
 strcpy (cmdline, s);     // 拷贝命令行参数到cmdline处
 cmd_start    = (ulong)&cmdline[0];  // 取命令行的起始和结束地址
 cmd_end      = cmd_start + strlen(cmdline); // 命令行结束地址
 *kbd = *(gd->bd);      // 拷贝开发板相关的参数到kbd中
 if ((s = getenv ("clocks_in_mhz")) != NULL) { // 设置系统频率(MHz)
  kbd->bi_intfreq /= 1000000L;
  kbd->bi_busfreq /= 1000000L;
 }
 // 设置内核入口点做为kernel函数的入口
 kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;
 
// 检查参数中是否存在Ramdisk
 if (argc >= 3) {      // bootm的命令行的第三个参数,Ram disk
  …
 } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
  …
 } else {
  SHOW_BOOT_PROGRESS (14); // 启动的第14阶段
  len = data = 0;     // 设置data为0(不使用Ramdisk)
 }
 if (!data) {       // 不使用 Ram disk
  debug ("No initrd\n");
 }
 if (data) {        // 使用 Ram disk需要加载Ramdisk盘
     if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */
  initrd_start = data;
  initrd_end = initrd_start + len;
     } else {
  initrd_start  = (ulong)kbd - len;
  initrd_start &= ~(4096 - 1); /* align on page */
  if (initrd_high) {
   ulong nsp;
   /*
    * the inital ramdisk does not need to be within
    * CFG_BOOTMAPSZ as it is not accessed until after
    * the mm system is initialised.
    *
    * do the stack bottom calculation again and see if
    * the initrd will fit just below the monitor stack
    * bottom without overwriting the area allocated
    * above for command line args and board info.
    */
   asm( "mr %0,1": "=r"(nsp) : );
   nsp -= 2048;  /* just to be sure */
   nsp &= ~0xF;
   if (nsp > initrd_high) /* limit as specified */
    nsp = initrd_high;
   nsp -= len;
   nsp &= ~(4096 - 1); /* align on page */
   if (nsp >= sp)
    initrd_start = nsp;
  }
  SHOW_BOOT_PROGRESS (12);
  debug ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
   data, data + len - 1, len, len);
  initrd_end    = initrd_start + len;
  printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
   initrd_start, initrd_end);
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
  {
   size_t l = len;
   void *to = (void *)initrd_start;
   void *from = (void *)data;
   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 *)initrd_start, (void *)data, len);
#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
  puts ("OK\n");
     }
 } else {
  initrd_start = 0;
  initrd_end = 0;
 }

 debug ("## Transferring control to Linux (at address %08lx) ...\n",
  (ulong)kernel);
 SHOW_BOOT_PROGRESS (15);   // 第15阶段就开始转动内核执行了
 // 传递给内核的参数列表:
 // r3: 开发板相关信息
 // r4: Ramdisk起始地址, 不使用则直接置0
 // r5: Ramdisk结束地址, 不使用则直接置0
 // r6: 命令行参数起始地址
 // r7: 命令行参数结束地址
 (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); // 启动内核
}

(本文章发表于psbec的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如有任何问题,请留言或者发邮件给psbec,地址)
阅读(1530) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~