X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=elilo.c;h=31c7294076b804d8cd55fbb7d91ba7e8d625a0d7;hb=2493c31ec50bffe01fddb3edfa0dd1e9f08e5248;hp=6ae687255e89f7552d7855679127d91774149cb6;hpb=176953673e992bd3812c32dc5d13eb8fa9b3c5b7;p=debian%2Felilo diff --git a/elilo.c b/elilo.c index 6ae6872..31c7294 100644 --- a/elilo.c +++ b/elilo.c @@ -1,5 +1,5 @@ /* - * elilo.c - IA-64/IA-32 EFI Linux loader + * elilo.c - IA-64/IA-32/x86_64 EFI Linux loader * * Copyright (C) 1999-2003 Hewlett-Packard Co. * Contributed by David Mosberger . @@ -8,6 +8,11 @@ * Copyright (C) 1999-2000 VA Linux Systems * Contributed by Johannes Erdfelt . * + * Copyright (C) 2006-2009 Intel Corporation + * Contributed by Fenghua Yu + * Contributed by Bibo Mao + * Contributed by Chandramouli Narayanan + * * This file is part of the ELILO, the EFI Linux boot loader. * * ELILO is free software; you can redistribute it and/or modify @@ -34,19 +39,21 @@ #include "elilo.h" #include "vars.h" +#include "gzip.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 */ +extern INTN wait_timeout (UINTN); + /* * Load the Linux kernel in memory from the boot media * Output: @@ -84,13 +91,23 @@ do_kernel_load(CHAR16 *kname, kdesc_t *kd) } INTN -kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) +kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem) { + CHAR16 kernel[CMDLINE_MAXLEN]; + /* + * Do the vm image switch here + * if there is "vmm=" then elilo should load image specified + * in "vmm=" and then give the "image" to vmm as target kernel image + */ + if (elilo_opt.vmcode[0]) + StrCpy(kernel, elilo_opt.vmcode); + else + StrCpy(kernel, kname); /* * Now let's try to load the kernel ! */ - switch(do_kernel_load(kname, kd)) { + switch(do_kernel_load(kernel, kd)) { case ELILO_LOAD_SUCCESS: break; @@ -101,6 +118,7 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) case ELILO_LOAD_ABORTED: /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; /* will go back to interactive selection */ elilo_opt.prompt = 1; @@ -110,34 +128,77 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) 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)); + VERB_PRT(3, Print(L"kernel loaded in [" PTR_FMT "-" PTR_FMT "] entry=" PTR_FMT "\n", + kd->kstart, kd->kend, kd->kentry)); if (elilo_opt.initrd[0]) { + /* ramdisk image is moved to the top of available extended memory later by start_kernel() */ if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error; - switch(load_initrd(elilo_opt.initrd, imem)) { + switch(load_file(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 */ + free_kmem(); + /* we drop initrd in case we aborted the load */ + elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; + elilo_opt.prompt = 1; + elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; + elilo_opt.delay = 0; + + return ELILO_LOAD_RETRY; + } + } + + if (elilo_opt.vmcode[0]) { + + mmem->start_addr = 0; /* let the allocator decide */ + switch(load_file(kname, mmem)) { + case ELILO_LOAD_SUCCESS: + break; + case ELILO_LOAD_ERROR: + goto exit_error; + case ELILO_LOAD_ABORTED: + if (imem->start_addr) + free(imem->start_addr); + free_kmem(); /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; elilo_opt.prompt = 1; elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; elilo_opt.delay = 0; return ELILO_LOAD_RETRY; } + + /* Test for a compressed image and unzip if found */ + if (gzip_probe(mmem->start_addr, mmem->size) == 0 && + gunzip_image(mmem) != ELILO_LOAD_SUCCESS) { + if (imem->start_addr) + free(imem->start_addr); + free(mmem->start_addr); + free_kmem(); + /* we drop initrd in case we aborted the load */ + elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[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); + if (mmem->start_addr) free(mmem->start_addr); return ELILO_LOAD_ERROR; } @@ -152,8 +213,8 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image UINTN cookie; EFI_STATUS status = EFI_SUCCESS; kdesc_t kd; - memdesc_t imem; - INTN r; + memdesc_t imem, mmem; + INTN r, retries=0; /* * First place where we potentially do system dependent @@ -164,12 +225,12 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image for(;;) { kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL; - imem.start_addr = 0; imem.pgcnt = 0; + imem.start_addr = 0; imem.pgcnt = 0; imem.size = 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)) { + switch (kernel_load(image, kname, &kd, &imem, &mmem)) { case ELILO_LOAD_SUCCESS: goto do_launch; case ELILO_LOAD_ERROR: @@ -183,15 +244,49 @@ do_launch: VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline)); + /* Give user time to see the output before launch */ + if (elilo_opt.debug || elilo_opt.verbose) { + r = wait_timeout(150); + /* have to turn off all console output(except error output) now before final get_mmemap() + * call or it can cause the efi map key to change and the ExitBootSvc call to fail, + * forcing debug and verbose options off is the surest way to enforce this. + */ + elilo_opt.debug=0; + elilo_opt.verbose=0; + } + /* 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; + if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error; + + /* terminate bootservices + * efi ExitBootSvcs spec: *note, get_memmap is called by create_boot_params() + * An EFI OS loader must ensure that it has the system's current memory map at the time + * it calls ExitBootServices(). This is done by passing in the current memory map's + * MapKey value as returned by GetMemoryMap(). Care must be taken to ensure that the + * memory map does not change between these two calls. It is suggested that + * GetMemoryMap()be called immediately before calling ExitBootServices(). */ + +retry: + status = uefi_call_wrapper(BS->ExitBootServices, 2, image, cookie); + if (EFI_ERROR(status)) + { + ERR_PRT((L"\nExitBootSvcs: failed, memory map has changed.\n")); + if (retries < 2) + { + ERR_PRT((L"Main_Loop: Retrying,... have to rebuild boot params")); + retries++; + free_boot_params(bp); + if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error; + goto retry; + } else { + ERR_PRT((L"\nMain_Loop: tried ExitBootSvcs 3 times... retries exceeded.... giving up\n")); + goto bad_exit; + } + } - /* terminate bootservices */ - status = BS->ExitBootServices(image, cookie); - if (EFI_ERROR(status)) goto bad_exit; start_kernel(kd.kentry, bp); /* NOT REACHED */ @@ -205,6 +300,7 @@ bad_exit: error: free_kmem(); if (imem.start_addr) free(imem.start_addr); + if (mmem.start_addr) free(mmem.start_addr); if (bp) free_boot_params(bp); exit_error: return ELILO_LOAD_ERROR; @@ -221,6 +317,7 @@ elilo_help(VOID) 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"-m file load file as additional boot time vmm module\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"); @@ -252,7 +349,7 @@ fixupargs(EFI_LOADED_IMAGE *info) #define FAKE_ELILONAME L"elilo-forced" - status = BS->HandleProtocol (info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe); + status = uefi_call_wrapper(BS->HandleProtocol, 3, info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe); if (EFI_ERROR(status)) return; default_load_options = info->LoadOptions; @@ -310,7 +407,7 @@ check_edd30(VOID) UINT8 bool = FALSE; INTN ret = -1; - status = RT->GetVariable(L"EDD30", &edd30_guid, NULL, &l, &bool); + status = uefi_call_wrapper(RT->GetVariable, 5, 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; @@ -340,7 +437,7 @@ force_edd30(VOID) UINT8 bool; bool = TRUE; - status = RT->SetVariable(L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool); + status = uefi_call_wrapper(RT->SetVariable, 5, L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool); if (EFI_ERROR(status)) { ERR_PRT((L"can't set EDD30 variable: ignoring it")); return -1; @@ -368,8 +465,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *devpath; - //elilo_opt.verbose=3; - //elilo_opt.debug=1; + elilo_opt.verbose=0; + elilo_opt.debug=0; /* initialize global variable */ systab = system_tab; @@ -384,19 +481,18 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) * mode. * XXX: clean this up ! */ - BS->SetWatchdogTimer(0, 0x0, 0, NULL); + uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); /* initialize memory allocator */ if (alloc_init() == -1) return EFI_LOAD_ERROR; - status = BS->HandleProtocol(image, &LoadedImageProtocol, (VOID **) &info); + status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info); if (EFI_ERROR(status)) { ERR_PRT((L"image handle does not support LOADED_IMAGE protocol")); return EFI_LOAD_ERROR; } - VERB_PRT(5,Print(L"Loaded at 0x%lx size=%d bytes code=%d data=%d\n", info->ImageBase, info->ImageSize, info->ImageCodeType, info->ImageDataType)); - + VERB_PRT(5,Print(L"Loaded at " PTR_FMT " size=%ld bytes code=%d data=%d\n", info->ImageBase, info->ImageSize, info->ImageCodeType, info->ImageDataType)); /* * verify EDD3.0 status. Users may have to reboot */ @@ -491,6 +587,13 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) } StrCpy(elilo_opt.initrd, Optarg); break; + case 'm': + if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { + Print(L"vmm module filename is limited to %d characters\n", FILENAME_MAXLEN); + goto do_exit; + } + StrCpy(elilo_opt.vmcode, Optarg); + break; case 'C': if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { Print(L"config filename is limited to %d characters\n", FILENAME_MAXLEN); @@ -533,7 +636,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) goto do_exit; } } - DBG_PRT((L"Optind=%d optarg=%x argc=%d", Optind, Optarg, argc)); + DBG_PRT((L"Optind=%d optarg=" PTR_FMT " argc=%d", Optind, Optarg, argc)); /* * we can't defer this phase any longer... @@ -548,22 +651,37 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) /* * set per fileops defaults files for configuration and kernel */ - fops_setdefaults(elilo_opt.default_config, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath); + fops_setdefaults(elilo_opt.default_configs, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath); /* * XXX: won't be visible if verbose not required from command line */ VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n", - elilo_opt.default_config,elilo_opt.default_kernel)); + elilo_opt.default_configs[0].fname, elilo_opt.default_kernel)); /* * use default config file if not specified by user */ - ptr = elilo_opt.config[0] == CHAR_NULL ? (retry=1,elilo_opt.default_config) : (retry=0,elilo_opt.config); + ptr = elilo_opt.config[0] == CHAR_NULL ? (retry=1,elilo_opt.default_configs[0].fname) : (retry=0,elilo_opt.config); /* * parse config file (verbose becomes visible if set) */ - ret = read_config(ptr, retry); + ret = read_config(ptr); + VERB_PRT(1,Print(L"read_config=%r\n", ret)); + + /* Only try the default config filenames if user did not specify a + * config filename on the command line */ + if (elilo_opt.config[0] == CHAR_NULL) { + while ((ret != EFI_SUCCESS) && + (retry < MAX_DEFAULT_CONFIGS) && + (elilo_opt.default_configs[retry].fname[0] != CHAR_NULL)) { + + ptr = elilo_opt.default_configs[retry].fname; + ret = read_config(ptr); + VERB_PRT(1,Print(L"read_config=%r\n", ret)); + retry += 1; + } + } /* * when the config file is not found, we fail only if: * - the user did not specified interactive mode @@ -592,11 +710,19 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) * if there was an error when parsing the config file, then * we force interactive mode to give a chance to the user. * We also clear the error. - */ - if (ret && argc == 1) { - Print(L"forcing interactive mode because of errors\n"); + */ + if (ret != EFI_SUCCESS) { + Print(L"forcing interactive mode due to config file error(s)\n"); elilo_opt.prompt = 1; } + /* + * However, if the user specified a kernel on the command line + * then we don't go to interactive mode, even if there was an option in + * the config file telling us to do so. + */ + if (argc > Optind) { + elilo_opt.prompt = 0; + } /* * If EDD30 EFI variable was not set to TRUE (or not defined), we @@ -612,13 +738,6 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) ret = EFI_LOAD_ERROR; - /* - * if the user specified a kernel on the command line - * then we don't go to interactive mode even if it - * was set in the config file or set because of an - * error parsing the config file. - */ - if (argc > Optind) elilo_opt.prompt = 0; /* set default timeout if going interactive */