pe格式的Image boot flow

来源:互联网 发布:金山快译怎么汉化软件 编辑:程序博客网 时间:2024/05/12 06:34
当使用uefi boot kernel的时候,kernel必须是PE格式的,当从UEFI跳到kernel 的入口地址是在efi-entry.s中,然后会call efi_entry。最后再跳到/kernel/arch/arm64/kernel/head.S 中执行
我们平时看到都Booting Linux Kernel 就是在efi_entry 中打印出来的。
从sys_table 中的到dram的最大的地址,
dram_base = get_dram_base(sys_table);
unsigned long get_dram_base(efi_system_table_t *sys_table_arg)
{
efi_status_t status;
unsigned long map_size, buff_size;
unsigned long membase  = EFI_ERROR;
struct efi_memory_map map;
efi_memory_desc_t *md;
struct efi_boot_memmap boot_map;


boot_map.map =(efi_memory_desc_t **)&map.map;
boot_map.map_size =&map_size;
boot_map.desc_size =&map.desc_size;
boot_map.desc_ver =NULL;
boot_map.key_ptr =NULL;
boot_map.buff_size =&buff_size;


status = efi_get_memory_map(sys_table_arg, &boot_map);
if (status != EFI_SUCCESS)
return membase;


map.map_end = map.map + map_size;


for_each_efi_memory_desc_in_map(&map, md) {
if (md->attribute & EFI_MEMORY_WB) {
if (membase > md->phys_addr)
membase = md->phys_addr;
}
}


efi_call_early(free_pool, map.map);


return membase;
}


get_dram_base 首先通过uefi的runtime service 得到boot_map,然后遍历找到最大的phys_addr
然后调用efi_convert_cmdline 将uefi收集到的commandline转成ASCII告诉kernel
secure_boot = efi_get_secureboot(sys_table);
if (secure_boot > 0)
pr_efi(sys_table, "UEFI Secure Boot is enabled.\n");


if (secure_boot < 0) {
pr_efi_err(sys_table,
"could not determine UEFI Secure Boot status.\n");
}
判断是否是secure boot,正常情况下可以看到上面的log
static int efi_get_secureboot(efi_system_table_t *sys_table_arg)
{
static efi_char16_t const sb_var_name[] = {
'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 };
static efi_char16_t const sm_var_name[] = {
'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 };


efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable;
u8 val;
unsigned long size = sizeof(val);
efi_status_t status;


status = f_getvar((efi_char16_t *)sb_var_name, (efi_guid_t *)&var_guid,
 NULL, &size, &val);


if (status != EFI_SUCCESS)
goto out_efi_err;


if (val == 0)
return 0;


status = f_getvar((efi_char16_t *)sm_var_name, (efi_guid_t *)&var_guid,
 NULL, &size, &val);


if (status != EFI_SUCCESS)
goto out_efi_err;


if (val == 1)
return 0;


return 1;
}
可见是通过sys_table_arg->runtime->get_variable 中是否有secureboot 和 setupmode 这两个字符串 来判断是否是secureboot.
if (fdt_addr) {
pr_efi(sys_table, "Using DTB from command line\n");
} else {
/* Look for a device tree configuration table entry. */
fdt_addr = (uintptr_t)get_fdt(sys_table, &fdt_size);
if (fdt_addr)
pr_efi(sys_table, "Using DTB from configuration table\n");
}


if (!fdt_addr)
pr_efi(sys_table, "Generating empty DTB\n");
如果用pe格式的Image的话,不管是否用dtb还是APCI,在efi_entry 中都会创建一个dtb table给kernel。如果uefi中是通过ACPI传递参数给
kerneld的话,就是fdt_addr 是NULL的,
就可以看到“Generating empty DTB” 因此下面的code会生成一个dtb table
new_fdt_addr = fdt_addr;
status = allocate_new_fdt_and_exit_boot(sys_table, handle,
&new_fdt_addr, dram_base + MAX_FDT_OFFSET,
initrd_addr, initrd_size, cmdline_ptr,
fdt_addr, fdt_size);
在allocate_new_fdt_and_exit_boot中通过update_fdt 来更新fdt table.
然后执行来exit boot service,然后在跳到efi-entry.s 中关闭cache和mmu,继续执行到head.S 中
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
exit_boot_func);
0 0
原创粉丝点击