grub2 中的boot命令

来源:互联网 发布:微信派单系统源码下载 编辑:程序博客网 时间:2024/05/22 01:37
boot命令的调用flow如下:
grub_enter_normal_mode ->grub_normal_execute->grub_show_menu->show_menu->grub_menu_execute_entry
grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
{
   if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
    /* Implicit execution of boot, only if something is loaded.  */
    grub_command_execute ("boot", 0, 0);


}
如果前面执行没有错误,且kennel已经被装载到dram中,这个是通过grub_loader_is_loaded来判断的
grub_loader_is_loaded (void)
{
  return grub_loader_loaded;
}
既判断是否为1,而是在执行linux命令的时候调用grub_loader_set来设定的
grub_loader_set (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int flags)
{
  grub_loader_loaded = 1;
}
如果都ok就调用grub_command_execute来执行boot命令
GRUB_MOD_INIT(boot)
{
  cmd_boot =
    grub_register_command ("boot", grub_cmd_boot,
  0, N_("Boot an operating system."));
}
可见boot的回调函数是grub_cmd_boot
grub_cmd_boot (struct grub_command *cmd __attribute__ ((unused)),
   int argc __attribute__ ((unused)),
   char *argv[] __attribute__ ((unused)))
{
  return grub_loader_boot ();
}
grub_loader_boot (void)
{
    err = (grub_loader_boot_func) ();


  for (cur = preboots_tail; cur; cur = cur->prev)
    if (! err)
      err = cur->preboot_rest_func ();
    else
      cur->preboot_rest_func ();


  return err;
}
grub_loader_boot 最重要是调用grub_loader_boot_func来boot kernel,如果failed的话,就会执行preboots_tail
list中注册的函数,但是正常的flow是调用grub_loader_boot_func后就不会再返回了
grub_loader_boot_func函数也是在linux 命令中通过grub_loader_set来指定的
grub_loader_boot_func = grub_linux_boot
static grub_err_t
grub_linux_boot (void)
{
  if (finalize_params_linux () != GRUB_ERR_NONE)
    return grub_errno;


  return (grub_arm64_uefi_boot_image((grub_addr_t)kernel_addr,
                                     kernel_size, linux_args));
}
直接调用grub_arm64_uefi_boot_image起形参就是kernel在dram中的地址和size,以及要传给kernel的cmdline
grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
{
  grub_efi_memory_mapped_device_path_t *mempath;
  grub_efi_handle_t image_handle;
  grub_efi_boot_services_t *b;
  grub_efi_status_t status;
  grub_efi_loaded_image_t *loaded_image;
  int len;


   b = grub_efi_system_table->boot_services;
  status = b->load_image (0, grub_efi_image_handle,
 (grub_efi_device_path_t *) mempath,
 (void *) addr, size, &image_handle);
  
  grub_dprintf ("linux", "linux command line: '%s'\n", args);


  /* Convert command line to UCS-2 */
  loaded_image = grub_efi_get_loaded_image (image_handle);
  loaded_image->load_options_size = len =
    (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
  loaded_image->load_options =
    grub_efi_allocate_pages (0,
    GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
  if (!loaded_image->load_options)
    return grub_errno;


  loaded_image->load_options_size =
    2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
   (grub_uint8_t *) args, len, NULL);


  grub_dprintf ("linux", "starting image %p\n", image_handle);
  status = b->start_image (image_handle, 0, NULL);
}
这个函数首先通过uefi的system_table找到boot_services
然后通过load_image来讲kernel image装载到dram中,在linux命令中其实病没有
真正将kernel image从flash等中copy到dram,而这里是真正调用bios的 boot_services
来做这件事情。
最后还是调用boot_services的start_image返回到bios中继续执行启动kernel的工作.





0 0
原创粉丝点击