grub2 的linux 和initrd命令

在grub2 中最重要的三个命令就是linux/initrd/boot 命令,那个命令只有linux/initrd 是需要用户在grub.cfg中指定的
boot 命令系统会自动调用。
在grub2中通过GRUB_MOD_INIT来初始化一个模块,就想kernel中的module_init一样
GRUB_MOD_INIT (linux)
{
  cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0,
    N_("Load Linux."));
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0,
     N_("Load initrd."));
  my_mod = mod;
}
这个模块中注册linux/initrd 命令的回调函数,也就是说在grub.cfg中调用linux命令的时候实际会call grub_cmd_linux
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
  if (grub_file_read (file, kernel_addr, kernel_size)
      < (grub_int64_t) kernel_size)
    {
      if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
      goto fail;
    }


  grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);


  cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
  linux_args = grub_malloc (cmdline_size);
  if (!linux_args)
    {
      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
      goto fail;
    }
  grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
  grub_create_loader_cmdline (argc, argv,
     linux_args + sizeof (LINUX_IMAGE) - 1,
     cmdline_size);
 if (grub_errno == GRUB_ERR_NONE)
    {
      grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
      loaded = 1;
    }
 
 
}
这个函数首先通过grub_file_read将kernel image read到kernel_addr,然后在通过grub_create_loader_cmdline 生成传递给kernel的cmdline
这些准备工作做完后,调用grub_loader_set 注册两个回调函数。
void
grub_loader_set (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int flags)
{
  if (grub_loader_loaded && grub_loader_unload_func)
    grub_loader_unload_func ();


  grub_loader_boot_func = boot;
  grub_loader_unload_func = unload;
  grub_loader_flags = flags;


  grub_loader_loaded = 1;
}


这个函调被调用之后
grub_loader_boot_func = grub_linux_boot
grub_loader_unload_func = grub_linux_unload;
grub_loader_flags = 0;
这几个函数会在执行boot的命令的时候用到。


再来看看initrd 命令
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{


  initrd_size = grub_get_initrd_size (&initrd_ctx);
  grub_dprintf ("linux", "Loading initrd\n");


  initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size));
  initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
  if (!initrd_mem)
    {
      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
      goto fail;
    }


  if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
    goto fail;


  initrd_start = (grub_addr_t) initrd_mem;
  initrd_end = initrd_start + initrd_size;
  grub_dprintf ("linux", "[addr=%p, size=0x%x]\n",
(void *) initrd_start, initrd_size);


}
这个函数首先通过grub_efi_allocate_pages 申请initrd_mem,然后通过grub_initrd_load 把initrd 搬到initrd_mem,最后对
initrd_start/initrd_end 这两个全局变量赋值,这样执行boot命令的时候就知道在哪里找到initrd了。

版权声明:本文为tiantao2012原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。