📄 elilo.c
字号:
/* * elilo.c - IA-64/IA-32 EFI Linux loader * * Copyright (C) 1999-2003 Hewlett-Packard Co. * Contributed by David Mosberger <davidm@hpl.hp.com>. * Contributed by Stephane Eranian <eranian@hpl.hp.com> * * Copyright (C) 1999-2000 VA Linux Systems * Contributed by Johannes Erdfelt <jerdfelt@valinux.com>. * * This file is part of the ELILO, the EFI Linux boot loader. * * ELILO is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * ELILO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ELILO; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Please check out the elilo.txt for complete documentation on how * to use this program. */#include <efi.h>#include <efilib.h>#include "elilo.h"#include "vars.h"#include "getopt.h"#include "fileops.h"#include "loader.h"#include "config.h" /* for config_init() */#define ELILO_VERSION L"3.4"#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E"elilo_config_t elilo_opt;EFI_SYSTEM_TABLE *systab; /* pointer to EFI system table *//* * Load the Linux kernel in memory from the boot media * Output: * kd = address of kernel entry point * + end address of kernel code+data+bss * + kernel entry point * Return: * ELILO_LOAD_ERROR : if something went wrong * ELILO_LOAD_ABORTED : user interruption while loading * ELILO_LOAD_SUCCESS : otherwise */static INTNdo_kernel_load(CHAR16 *kname, kdesc_t *kd){ loader_ops_t *ldops; EFI_STATUS status; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) { ERR_PRT((L"Kernel file not found %s", kname)); return ELILO_LOAD_ERROR; } fops_close(fd); ldops = loader_probe(kname); if (ldops == NULL) { ERR_PRT((L"Cannot find a loader for %s", kname)); return ELILO_LOAD_ERROR; } VERB_PRT(1,Print(L"Using %s loader\n", ldops->ld_name)); return ldops->ld_load_kernel(kname, kd);}INTNkernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem){ /* * Now let's try to load the kernel ! */ switch(do_kernel_load(kname, kd)) { case ELILO_LOAD_SUCCESS: break; case ELILO_LOAD_ERROR: /* XXX: add fallback support */ return ELILO_LOAD_ERROR; case ELILO_LOAD_ABORTED: /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; /* will go back to interactive selection */ elilo_opt.prompt = 1; elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; elilo_opt.delay = 0; return ELILO_LOAD_RETRY; } VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n", (UINT64)kd->kstart, (UINT64)kd->kend, (UINT64)kd->kentry)); if (elilo_opt.initrd[0]) { if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error; switch(load_initrd(elilo_opt.initrd, imem)) { case ELILO_LOAD_SUCCESS: break; case ELILO_LOAD_ERROR: goto exit_error; case ELILO_LOAD_ABORTED: /* the free_kmem() is the responsibility of the loader */ /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; elilo_opt.prompt = 1; elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; elilo_opt.delay = 0; return ELILO_LOAD_RETRY; } } return ELILO_LOAD_SUCCESS;exit_error: free_kmem(); if (imem->start_addr) free(imem->start_addr); return ELILO_LOAD_ERROR;}static INTNmain_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image){ CHAR16 kname[FILENAME_MAXLEN]; CHAR16 cmdline_tmp[CMDLINE_MAXLEN]; CHAR16 cmdline[CMDLINE_MAXLEN]; VOID *bp; UINTN cookie; EFI_STATUS status = EFI_SUCCESS; kdesc_t kd; memdesc_t imem; INTN r; /* * First place where we potentially do system dependent * operations. It is a one time opportunity before entering * the main loop */ if (sysdeps_preloop_actions(dev, argv, argc, index, image) == -1) return -1; for(;;) { kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL; imem.start_addr = 0; imem.pgcnt = 0; elilo_opt.sys_img_opts = NULL; if (kernel_chooser(argv, argc, index, kname, cmdline_tmp) == -1) goto exit_error; switch (kernel_load(image, kname, &kd, &imem)) { case ELILO_LOAD_SUCCESS: goto do_launch; case ELILO_LOAD_ERROR: goto exit_error; /* otherwise we retry ! */ } } do_launch: r =subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN); VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline)); /* free resources associated with file accesses (before ExitBootServices) */ close_devices(); /* No console output permitted after create_boot_params()! */ if ((bp=create_boot_params(cmdline, &imem, &cookie)) == 0) goto error; /* terminate bootservices */ status = BS->ExitBootServices(image, cookie); if (EFI_ERROR(status)) goto bad_exit; start_kernel(kd.kentry, bp); /* NOT REACHED */ ERR_PRT((L"start_kernel() return !"));bad_exit: /* * we are still in BootService mode */ ERR_PRT((L"ExitBootServices failed %r", status));error: free_kmem(); if (imem.start_addr) free(imem.start_addr); if (bp) free_boot_params(bp);exit_error: return ELILO_LOAD_ERROR;}static VOIDelilo_help(VOID){ Print(L"-d secs timeout in 10th of second before booting\n"); Print(L"-h this help text\n"); Print(L"-V print version\n"); Print(L"-v verbose level(can appear multiple times)\n"); Print(L"-a always check for alternate kernel image\n"); Print(L"-i file load file as the initial ramdisk\n"); Print(L"-C file indicate the config file to use\n"); Print(L"-P parse config file only (verify syntax)\n"); Print(L"-D enable debug prints\n"); Print(L"-p force interactive mode\n"); Print(L"-c name image chooser to use\n"); Print(L"-E do not force EDD30 variable\n"); sysdeps_print_cmdline_opts(); Print(L"\n"); print_config_options();}/* * XXX: hack to work around a problem with EFI command line argument when booted * from network. In this case, it looks like LoadOptions/LoadOptionsSize contain * garbage */static CHAR16 *default_load_options;static UINTN default_load_options_size;static INTN done_fixups;static VOIDfixupargs(EFI_LOADED_IMAGE *info){ EFI_STATUS status; EFI_PXE_BASE_CODE *pxe;#define FAKE_ELILONAME L"elilo-forced" status = BS->HandleProtocol (info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe); if (EFI_ERROR(status)) return; default_load_options = info->LoadOptions; default_load_options_size = info->LoadOptionsSize; info->LoadOptions = FAKE_ELILONAME; info->LoadOptionsSize = StrLen(info->LoadOptions)*sizeof(CHAR16); done_fixups = 1;}/* * we restore the arguments in case we modified them just to make sure * we don't confuse caller. */static VOIDunfixupargs(EFI_LOADED_IMAGE *info){ if (done_fixups == 0) return; info->LoadOptions = default_load_options; info->LoadOptionsSize = default_load_options_size;}/* * in order to get fully detailed EFI path names to devices, EDD3.0 specification must * be turned on. On new versions of EFI, this is the default. An environment variable * called EDD30 reflects the current settings. If true, then EDD3.0 is enabled * and device path names show the detailed device types. If false, then a default * generic name is used instead. This has some implications of ELILO's ability to * provide a better naming scheme for detected devices. If EDD3.0 is enabled * then much more precise names can be used which makes it easy to use. * If EDD3.0 is nont enabled, ELILO will still work but will use very generic names * for devices. * * ELILO will check the value of the variable. If not true, then it will force it to * true. This will require a reboot for EFI to make use of the new value. * Return: * EFI_SUCCESS: if variable is already true or was set to true * EFI error code: otherwise, like when could not forced variable or unrecognized variable content */#define EDD30_GUID \{0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}#define EDD30_ATTR (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_NON_VOLATILE)static EFI_GUID edd30_guid = EDD30_GUID;static INTNcheck_edd30(VOID){ EFI_STATUS status; UINTN l = sizeof(BOOLEAN); UINT8 bool = FALSE; INTN ret = -1; status = RT->GetVariable(L"EDD30", &edd30_guid, NULL, &l, &bool); if (status == EFI_BUFFER_TOO_SMALL || (bool != TRUE && bool != FALSE)) { ERR_PRT((L"Warning: EDD30 EFI variable is not boolean value: forcing it to TRUE")); return -1; } if (status == EFI_SUCCESS && bool == TRUE) { VERB_PRT(3, Print(L"EDD30 is TRUE\n")); elilo_opt.edd30_on = TRUE; ret = 0; } else { VERB_PRT(4, if (status != EFI_SUCCESS) { Print(L"EDD30 EFI variable not defined\n"); } else { Print(L"EDD30 EFI variable is false\n"); } ); } return ret;}static INTN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -