./elilo/0000755000175000017500000000000011513632716011646 5ustar jasonfjasonf./elilo/devschemes/0000755000175000017500000000000011513632716013774 5ustar jasonfjasonf./elilo/devschemes/Makefile0000644000175000017500000000236507720451700015437 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES=simple.o TARGET=devschemes.o all: $(TARGET) # # XXX: does not trigger recompile when changing filesystem selection # without doing make clean. # $(TARGET): $(FILES) $(LD) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) ./elilo/devschemes/simple.c0000644000175000017500000000731407720451674015445 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. * * Look at the README.devschemes for more explanations on how * to use devschemes. */ #include #include #include "elilo.h" #include "fileops.h" #define NAMING_SCHEME L"simple" typedef struct { INT8 type; INT8 subtype; INTN (*device_func)(device_t *dev, EFI_DEVICE_PATH *dp); } devices_types_t; static UINT32 atapi_count, scsi_count, net_count; static INTN atapi_device(device_t *dev, EFI_DEVICE_PATH *dp) { //ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)dp; dev->name[0] = L'a'; dev->name[1] = L't'; dev->name[2] = L'a'; dev->name[3] = L'p'; dev->name[4] = L'i'; SPrint(dev->name+5,FILEOPS_DEVNAME_MAXLEN-5-1, L"%d", atapi_count); atapi_count++; return 0; } static INTN scsi_device(device_t *dev, EFI_DEVICE_PATH *dp) { //SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)dp; dev->name[0] = L's'; dev->name[1] = L'c'; dev->name[2] = L's'; dev->name[3] = L'i'; SPrint(dev->name+4, FILEOPS_DEVNAME_MAXLEN-4-1, L"%d", scsi_count); scsi_count++; return 0; } static INTN network_device(device_t *dev, EFI_DEVICE_PATH *dp) { //MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)dp; dev->name[0] = L'n'; dev->name[1] = L'e'; dev->name[2] = L't'; SPrint(dev->name+3, FILEOPS_DEVNAME_MAXLEN-3-1, L"%d", net_count); net_count++; return 0; } /* * what we are looking for in the device path */ static devices_types_t dev_types[]={ { MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, atapi_device}, { MESSAGING_DEVICE_PATH, MSG_SCSI_DP, scsi_device}, { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, network_device}, { 0, 0 , NULL} }; static INTN simple_scheme(device_t *tab, UINTN n) { EFI_DEVICE_PATH *dp1, *dp; devices_types_t *p; UINTN i; /* * note that this test is necessary but not sufficient to guarantee that this scheme * will work because, we have no way of detecting that the machine got actually * rebooted if the EDD30 variable was forced. this comes from the fact, that elilo * can be invoked once, aborted and then restarted with no machine reboot. * * XXX: there may be a way to detect this with the another variable which would * be in volatile memory only */ if (elilo_opt.edd30_on == 0) { VERB_PRT(4, Print(L"%s device naming scheme only works with EDD3.0 enabled\n", NAMING_SCHEME)); return -1; } for(i=0; i < n; i++) { dp = DevicePathFromHandle(tab[i].dev); if (dp == NULL) { ERR_PRT((L"cannot get device path for device %d", i)); continue; } dp1 = dp = UnpackDevicePath(dp); while (!IsDevicePathEnd(dp)) { p = dev_types; while (p->type) { if ( p->type == DevicePathType(dp) && p->subtype == DevicePathSubType(dp)) { (*p->device_func)(tab+i, dp); goto done; } p++; } dp = NextDevicePathNode(dp); } done: FreePool(dp1); } return 0; } devname_scheme_t simple_devname_scheme={ NAMING_SCHEME, simple_scheme }; ./elilo/loader.c0000644000175000017500000000344111165216510013253 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #include "loader.h" extern loader_ops_t plain_loader; extern loader_ops_t gzip_loader; static loader_ops_t *ldops_list; loader_ops_t * loader_probe(CHAR16 *kname) { loader_ops_t *ops; UINTN n = 0; for (ops= ldops_list; ops; ops = ops->next) { n++; VERB_PRT(3, Print(L"Probing loader: %s\n", ops->ld_name)); if (ops->ld_probe(kname) == 0) { return ops; } } if (!n) { ERR_PRT((L"No loaders registered")); } return NULL; } INTN loader_register(loader_ops_t *ldops) { if (ldops == NULL) return -1; /* cheap sanity check */ if (ldops->next) { ERR_PRT((L"loader %s is already registered", ldops->ld_name)); return -1; } ldops->next = ldops_list; ldops_list = ldops; VERB_PRT(3, Print(L"New loader registered: %s\n", ldops->ld_name)); return 0; } ./elilo/elilo.h0000644000175000017500000001473111466355452013137 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_H__ #define __ELILO_H__ #define ELILO_VERSION L"3.14" #include #ifdef CONFIG_ia32 #define PTR_FMT L"0x%x" #else #define PTR_FMT L"0x%lx" #endif #include "elilo_debug.h" #include "fileops.h" #include "chooser.h" #include "strops.h" #include "sysdeps.h" #define MB (1024*1024) /* 1 megabyte */ /* Round X up/down to A, which must be an integer power of two. */ #define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1)) #define ROUNDDOWN(x,a) ((x) & ~((a) - 1)) #ifndef UINT32_MAX #define UINT32_MAX ((UINT32)-1) #endif /* * Elilo Boot modes */ #define ELILO_LOAD_SUCCESS 0 #define ELILO_LOAD_ABORTED 1 #define ELILO_LOAD_ERROR 2 #define ELILO_LOAD_RETRY 3 #define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY #define ELILO_TIMEOUT_INFINITY (~0UL) #define CMDLINE_MAXLEN 2048 #define PATHNAME_MAXLEN 512 #define FILENAME_MAXLEN 256 #define MAX_ARGS 256 /* Just pick an arbitrary number that's high enough for now :o) */ #define MAX_DEFAULT_CONFIGS 16 typedef struct { UINT8 nothing_yet; } image_opt_t; typedef struct config_file { CHAR16 fname[FILENAME_MAXLEN]; } config_file_t; typedef struct { /* * list of options controllable from both the command line * and the config file */ UINTN alt_check; /* always check for alternate kernel */ UINTN debug; /* debug print() on */ UINTN delay; /* delay before booting the image */ UINTN verbose; /* verbosity level [1-5] */ CHAR16 initrd[FILENAME_MAXLEN]; /* name of file for initial ramdisk */ CHAR16 vmcode[FILENAME_MAXLEN]; /* name of file for boot time module*/ UINT8 delay_set; /* mark whether or not delay was specified on cmdline */ UINT8 edd30_on; /* true is EDD30 variable is TRUE */ UINT8 edd30_no_force; /* don't force EDD30 variable to true */ /* * list of options controllable from either the command line * or the config file */ UINTN prompt; /* enter interactive mode */ UINTN parse_only; /* only parses the config file */ UINTN timeout; /* timeout before leaving interactive mode*/ image_opt_t img_opt; /* architecture independent per image options*/ sys_img_options_t *sys_img_opts; /* architecture depdendent per image options */ CHAR16 default_kernel[FILENAME_MAXLEN]; /* CHAR16 default_config[FILENAME_MAXLEN]; */ config_file_t default_configs[MAX_DEFAULT_CONFIGS]; CHAR16 config[FILENAME_MAXLEN]; /* name of config file */ CHAR16 chooser[FILENAME_MAXLEN]; /* image chooser to use */ } elilo_config_t; extern elilo_config_t elilo_opt; extern EFI_SYSTEM_TABLE *systab; typedef struct { VOID *start_addr; UINTN pgcnt; UINTN size; } memdesc_t; typedef struct { VOID *kstart; VOID *kend; VOID *kentry; } kdesc_t; typedef struct { EFI_MEMORY_DESCRIPTOR *md; UINTN map_size; UINTN desc_size; UINTN cookie; UINT32 desc_version; } mmap_desc_t; #ifndef MAX #define MAX(a,b) ((a)>(b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) ((a)>(b) ? (b) : (a)) #endif #define VERB_PRT(n,cmd) \ { if (elilo_opt.verbose >= (n)) { cmd; } } /* from alloc.c */ extern INTN alloc_init(VOID); extern VOID *alloc(UINTN, EFI_MEMORY_TYPE); extern VOID free(VOID *); extern VOID *alloc_pages(UINTN, EFI_MEMORY_TYPE, EFI_ALLOCATE_TYPE, VOID *); extern VOID free_pages(VOID *); extern VOID free_all(VOID); extern INTN alloc_kmem(VOID *, UINTN); extern INTN alloc_kmem_anywhere(VOID **, UINTN); extern VOID free_kmem(VOID); extern VOID free_all_memory(VOID); /* from util.c */ extern INTN read_file(UINTN fd, UINTN, CHAR8 *); extern EFI_STATUS check_abort(VOID); extern VOID reset_input(VOID); extern INTN wait_timeout(UINTN); extern INTN argify(CHAR16 *, UINTN, CHAR16 **); extern VOID unargify(CHAR16 **, CHAR16 **); extern void split_args(CHAR16 *, CHAR16 *, CHAR16 *); extern INTN get_memmap(mmap_desc_t *); extern VOID free_memmap(mmap_desc_t *); extern INTN find_kernel_memory(VOID *low_addr, VOID *max_addr, UINTN alignment, VOID ** start); extern VOID print_memmap(mmap_desc_t *); extern VOID ascii2U(CHAR8 *, CHAR16 *, UINTN); extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN); /* from config.c (more in config.h) */ extern EFI_STATUS read_config(CHAR16 *); extern VOID print_config_options(VOID); extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *); extern VOID print_label_list(VOID); extern INTN config_init(VOID); extern CHAR16 *get_message_filename(INTN which); extern CHAR16 *find_description(CHAR16 *label); extern VOID *get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description); extern CHAR16 *get_config_file(VOID); /* from initrd.c */ extern INTN load_file(CHAR16 *, memdesc_t *); /* from alternate.c */ extern INTN alternate_kernel(CHAR16 *, UINTN); /* from bootparams.c */ extern VOID *create_boot_params (CHAR16 *, memdesc_t *, memdesc_t *, UINTN *); extern VOID free_boot_params(VOID *bp); /* * architecture-specific API */ extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, memdesc_t *, UINTN *); extern VOID sysdeps_free_boot_params(boot_params_t *); extern INTN sysdeps_init(EFI_HANDLE dev); extern INTN sysdeps_initrd_get_addr(kdesc_t *, memdesc_t *); extern INTN sysdeps_preloop_actions(EFI_HANDLE, CHAR16 **, INTN, INTN, EFI_HANDLE); extern CHAR16 *sysdeps_get_cmdline_opts(VOID); extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *); extern VOID sysdeps_print_cmdline_opts(VOID); extern INTN sysdeps_register_options(VOID); extern VOID *sysdeps_checkfix_initrd(VOID *, memdesc_t *); #define CHAR_SLASH L'/' #define CHAR_BACKSLASH L'\\' #endif /* __ELILO_H__ */ ./elilo/util.c0000644000175000017500000002754711165216510012777 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 * 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 #include #include "elilo.h" #define TENTH_SEC 1000000 /* 1/10th second in 100ns unit */ #define READ_BLOCK_SIZE (4*EFI_PAGE_SIZE) /* block size for read_file */ #define is_cr(k) (((k)==CHAR_LINEFEED)||((k)==CHAR_CARRIAGE_RETURN)) #define CHAR_SPACE L' ' static INTN read_keypress(EFI_INPUT_KEY *key) { return uefi_call_wrapper(systab->ConIn->ReadKeyStroke, 2, systab->ConIn, key); } EFI_STATUS check_abort(VOID) { EFI_INPUT_KEY key; return read_keypress(&key); } inline VOID reset_input(VOID) { uefi_call_wrapper(systab->ConIn->Reset, 2, systab->ConIn, 1); } #if 0 INTN wait_keypress_abort(VOID) { SIMPLE_INPUT_INTERFACE *conin = systab->ConIn; EFI_INPUT_KEY key; EFI_STATUS status; reset_input(); Print(L"Hit ENTER to continue or ANY other key to cancel"); /* cleanup buffer first */ while (uefi_call_wrapper(conin->ReadKeyStroke, 2, conin, &key) == EFI_SUCCESS); while ((status=uefi_call_wrapper(conin->ReadKeyStroke,2, conin, &key)) == EFI_NOT_READY ); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; Print(L"\n"); return is_cr(key.UnicodeChar) ? ELILO_LOAD_SUCCESS: ELILO_BOOT_ABORTED; } #endif /* * wait for timeout to expire or keypress * Return: * 0 : timeout expired * 1 : a key was pressed (still input stream to process) * -1: an error occured */ INTN wait_timeout(UINTN timeout) { EFI_STATUS status; EFI_EVENT timer; EFI_EVENT list[2]; UINTN idx; if (timeout == 0) return 0; /* Create a timeout timer */ status = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, &timer); if (EFI_ERROR(status)) { ERR_PRT((L" waitkey CreateEvent failed %r", status)); return -1; } /* In 100ns increments */ status = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerPeriodic, TENTH_SEC); if (EFI_ERROR(status)) { ERR_PRT((L"waitkey SetTimer failed %r", status)); return -1; } list[0] = timer; list[1] = systab->ConIn->WaitForKey; do { status = uefi_call_wrapper(BS->WaitForEvent, 3, 2, list, &idx); if (EFI_ERROR(status)) { ERR_PRT((L"waitkey WaitForEvent failed %r", status)); return -1; } if (timeout % 10 == 1) Print(L"."); } while (timeout-- && idx == 0); Print(L"\n"); /* * SetTimer(timer, TimerCancel, 0) is causing problems on IA-32 and gcc3 * I do not know why it dies with EFI12.35. So let's fake a key stroke. */ status = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerCancel, 0); if (EFI_ERROR(status)) { ERR_PRT((L"waitkey SetTimer(TimerCancel) failed %r", status)); return -1; } uefi_call_wrapper(BS->CloseEvent, 1, timer); return idx ? 1 : 0; } INTN argify(CHAR16 *buf, UINTN len, CHAR16 **argv) { UINTN i=0, j=0; CHAR16 *p = buf; if (buf == 0) { argv[0] = NULL; return 0; } /* len represents the number of bytes, not the number of 16 bytes chars */ len = len >> 1; /* * Here we use CHAR_NULL as the terminator rather than the length * because it seems like the EFI shell return rather bogus values for it. * Apparently, we are guaranteed to find the '\0' character in the buffer * where the real input arguments stop, so we use it instead. */ for(;;) { while (buf[i] == CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++; if (buf[i] == CHAR_NULL || i == len) goto end; p = buf+i; i++; while (buf[i] != CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++; argv[j++] = p; if (buf[i] == CHAR_NULL) goto end; buf[i] = CHAR_NULL; if (i == len) goto end; i++; if (j == MAX_ARGS-1) { ERR_PRT((L"too many arguments (%d) truncating", j)); goto end; } } end: #if 0 if (i != len) { ERR_PRT((L"ignoring trailing %d characters on command line", len-i)); } #endif argv[j] = NULL; return j; } VOID unargify(CHAR16 **argv, CHAR16 **args) { if ( *argv == 0 ) { *args = L""; return; } *args = *argv; while ( argv[1] ) { (*argv)[StrLen(*argv)] = CHAR_SPACE; argv++; } } VOID split_args(CHAR16 *buffer, CHAR16 *kname, CHAR16 *args) { CHAR16 *tmp; /* find beginning of kernel name */ while (*buffer && *buffer == CHAR_SPACE) buffer++; tmp = buffer; /* scan through kernel name */ while (*buffer && *buffer != CHAR_SPACE) buffer++; if (*buffer) { *buffer++ = CHAR_NULL; StrCpy(kname, tmp); } /* skip space between kernel and args */ while (*buffer && *buffer == CHAR_SPACE) buffer++; StrCpy(args, buffer); } INTN read_file(UINTN fd, UINTN total_size, CHAR8 *buffer) { UINTN size, j=0; EFI_STATUS status; CHAR16 helicopter[4] = { L'|' , L'/' , L'-' , L'\\' }; INTN ret = ELILO_LOAD_SUCCESS; UINTN sum = 0; /* * We load by chunks rather than a single big read because * early versions of EFI had troubles loading files * from floppies in a single big request. Breaking * the read down into chunks of 4KB fixed that * problem. While this problem has been fixed, we still prefer * this method because it tells us whether or not we're making * forward progress. */ while (total_size > 0) { size = total_size < READ_BLOCK_SIZE? total_size : READ_BLOCK_SIZE; status = fops_read(fd, buffer, &size); if (EFI_ERROR(status)) { ERR_PRT((L"read_file failed %r", status)); return ELILO_LOAD_ERROR; } sum += size; Print(L"%c\b",helicopter[j++%4]); buffer += size; total_size -= size; if (check_abort() == EFI_SUCCESS) { ret = ELILO_LOAD_ABORTED; break; } } return ret; } INTN get_memmap(mmap_desc_t *desc) { #define ELILO_MEMMAP_SIZE_DEFAULT (EFI_PAGE_SIZE*2) #define ELILO_MEMMAP_INC (sizeof(EFI_MEMORY_DESCRIPTOR)<<1) EFI_STATUS status; desc->map_size = ELILO_MEMMAP_SIZE_DEFAULT; for(;;) { desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData); if (desc->md == NULL) { ERR_PRT((L"failed to allocate memory map buffer")); return -1; } status = uefi_call_wrapper(BS->GetMemoryMap, 5, &desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version); if (status == EFI_SUCCESS) break; free(desc->md); if (status != EFI_BUFFER_TOO_SMALL) { ERR_PRT((L"failed to obtain memory map %r")); return -1; } desc->map_size += ELILO_MEMMAP_INC; } DBG_PRT((L"final get_memmap map_size=%d", desc->map_size)); return 0; } #if 0 INTN get_memmap(mmap_desc_t *desc) { EFI_STATUS status; /* will get the right size in return */ desc->map_size = 0; status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version); if (status != EFI_BUFFER_TOO_SMALL) return -1; desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData); if (desc->md == NULL) { ERR_PRT((L"failed to allocate memory map buffer")); return -1; } status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version); if (EFI_ERROR(status)) { ERR_PRT((L"failed to obtain memory map %d: %r", desc->map_size, status)); free(desc->md); return -1; } DBG_PRT((L"final get_memmap map_size=%d", desc->map_size)); return 0; } #endif VOID free_memmap(mmap_desc_t *desc) { if (desc->md) { free(desc->md); desc->md = NULL; } } VOID print_memmap(mmap_desc_t *desc) { EFI_MEMORY_DESCRIPTOR *md; UINTN desc_size; VOID *p; VOID *md_end; INT8 printed; UINTN ntypes; CHAR16* str; static CHAR16 *memtypes[]={ L"ReservedMemoryType", L"LoaderCode", L"LoaderData", L"BootServicesCode", L"BootServicesData", L"RuntimeServicesCode", L"RuntimeServicesData", L"ConventionalMemory", L"UnusableMemory", L"ACPIReclaimMemory", L"ACPIMemoryNVS", L"MemoryMappedIO", L"MemoryMappedIOPortSpace", L"PalCode" }; md_end = ((VOID *)desc->md)+desc->map_size; desc_size = desc->desc_size; ntypes = sizeof(memtypes)/sizeof(CHAR16 *); for(p = desc->md; p < md_end; p += desc_size) { md = p; str = md->Type < ntypes ? memtypes[md->Type] : L"Unknown"; Print(L"%24s %lx-%lx %8lx", str, md->PhysicalStart, md->PhysicalStart+(md->NumberOfPages<NumberOfPages); printed=0; #define P_FLG(f) { \ Print(L" %s %s", printed ? L"|":L"", f); \ printed=1; \ } if (md->Attribute & EFI_MEMORY_UC) { P_FLG(L"UC"); } if (md->Attribute & EFI_MEMORY_WC) { P_FLG(L"WC"); } if (md->Attribute & EFI_MEMORY_WT) { P_FLG(L"WT"); } if (md->Attribute & EFI_MEMORY_WB) { P_FLG(L"WB"); } if (md->Attribute & EFI_MEMORY_UCE) { P_FLG(L"UCE"); } if (md->Attribute & EFI_MEMORY_WP) { P_FLG(L"WP"); } if (md->Attribute & EFI_MEMORY_RP) { P_FLG(L"RP"); } if (md->Attribute & EFI_MEMORY_XP) { P_FLG(L"XP"); } if (md->Attribute & EFI_MEMORY_RUNTIME) { P_FLG(L"RT"); } Print(L"\n"); } } INTN find_kernel_memory(VOID* low_addr, VOID* max_addr, UINTN alignment, VOID** start) { #define HIGHEST_ADDR (VOID*)(~0) mmap_desc_t mdesc; EFI_MEMORY_DESCRIPTOR *md; UINT64 size; VOID *p, *addr; VOID *desc_end, *md_end, *best_addr = HIGHEST_ADDR; /* * first get up-to-date memory map * * XXX: is there a danger of not seeing the latest version if interrupted * during our scan ? * */ if (get_memmap(&mdesc) == -1) { ERR_PRT((L"find_kernel_memory :GetMemoryMap() failed")); return -1; } desc_end = ((VOID *)mdesc.md) + mdesc.map_size; size = max_addr - low_addr; /* * Find memory which covers the desired range */ for(p = mdesc.md; p < desc_end; p += mdesc.desc_size) { md = p; /* * restrict to decent memory types. * * the EFI memory map report where memory is and how it is currently used * using types. * * EfiLoaderData which is used by the AllocatePages() cannot be used * here because it may hold some valid information. Same thing for most * of the memory types with the exception of EfiConventional which * can be assumed as being free to use. */ if (md->Type != EfiConventionalMemory) continue; /* * compute aligned address and upper boundary for range */ md_end = (VOID*)(md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE); addr = (VOID*)ROUNDUP(md->PhysicalStart, alignment); /* * need to check if: * - aligned address still in the range * - the range [addr-addr+size) still fits into memory range * if so we have a match. We do not assume that the memory ranges * are sorted by EFI, therefore we must record the match and only * keep the lowest possible one. */ if (addr < best_addr && addr < md_end && addr+size <= md_end) best_addr = addr; } if (best_addr == HIGHEST_ADDR) { free_memmap(&mdesc); ERR_PRT((L"Could not find memory suitable for loading image")); return -1; } *start = best_addr; free_memmap(&mdesc); return 0; } ./elilo/strops.c0000644000175000017500000000620011466352413013342 0ustar jasonfjasonf/* * Copyright (C) 1999-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include //#define CHAR_NULL (CHAR16)'\0' CHAR16 * StrChr(IN const CHAR16 *s, IN const CHAR16 c) { for(; *s != c; ++s) if (*s == CHAR_NULL) return NULL; return (CHAR16 *)s; } CHAR16 * StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) { CHAR16 *res = dst; while (size && size-- && (*dst++ = *src++) != CHAR_NULL); /* * does the null padding */ while (size && size-- > 0) *dst++ = CHAR_NULL; return res; } CHAR8 * StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size) { CHAR8 *res = dst; while (size && size-- && (*dst++ = (CHAR8)*src++) != '\0'); /* * does the null padding */ while (size && size-- > 0) *dst++ = '\0'; return res; } VOID U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen) { while(maxlen-- > 1 && (*out++ = *in++)); *out = '\0'; } CHAR8 * strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size) { CHAR8 *res = dst; while (size && size-- && (*dst++ = *src++) != '\0'); /* * does the null padding */ while (size && size-- > 0) *dst++ = '\0'; return res; } CHAR8 * strcpya(CHAR8 *dst, const CHAR8 *src) { CHAR8 *tmp = dst; while (*src) { *(dst++) = *(src++); } *dst = 0; return tmp; } CHAR8 * strchra(IN const CHAR8 *s, IN const CHAR8 c) { for(; *s != c; ++s) if (*s == 0) return NULL; return (CHAR8 *)s; } CHAR8 * strcata(IN CHAR8 *dst,IN CHAR8 *src) { return strcpya(dst+strlena(dst), src); } CHAR8 * strrchra(IN const CHAR8 *s, const INTN c) { CHAR8 *found, *p, ch = (CHAR8)c; /* Since strchr is fast, we use it rather than the obvious loop. */ if (ch == '\0') return strchra(s, '\0'); found = NULL; while ((p = strchra(s, ch)) != NULL) { found = p; s = p + 1; } return (CHAR8 *) found; } CHAR8 * strtok_simple(CHAR8 *in, CHAR8 c) { static CHAR8 *last; CHAR8 *tmp; if (in == NULL) in = last; if (in == NULL) return NULL; if (*in == c) in++; tmp = strchra(in, c); if (tmp) { *tmp = '\0'; last = tmp+1; } else { last = NULL; } return in; } VOID ascii2U(CHAR8 *in, CHAR16 *out, UINTN maxlen) { while(maxlen-- > 1 && (*out++ = *in++)); *out = (CHAR16)0; } ./elilo/bootparams.c0000644000175000017500000000666711466354400014176 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" /* * Initialize the generic part of the boot parameters and call the architecture specific * subroutine. * Output: * cookie: the memory map cookie to use with ExitBootServices() * Return: * NULL: if an error occured * bp : the address of the bootparams otherwise (opaque type) */ VOID * create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie) { /* * XXX: need cleanup * See ia32 code for explanation on why it is so big. */ #define BOOT_PARAM_MEMSIZE 16384 UINTN bpsize, cmdline_size; boot_params_t *bp; CHAR8 *cp; CHAR16 ch; /* * Allocate runtime services memory to hold memory descriptor table and * command line arguments and fetch memory map: * * arg_size = number of character in ASCII form */ cmdline_size = StrLen(args) + 1; bpsize = sizeof(boot_params_t) + cmdline_size; if (bpsize > BOOT_PARAM_MEMSIZE) { ERR_PRT((L"BOOT_PARAM_MEMSIZE too small, need at least %d bytes", bpsize)); return NULL; } /* * Allocate memory for boot parameters. * This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel * frees this region when initializing. * FIXME: Is this a bug? (since the memory type *is* EfiLoaderData) */ bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData); if (bp == NULL) { ERR_PRT((L"can't allocate boot params")); return 0; } VERB_PRT(3, Print(L"boot params @ " PTR_FMT "\n", bp)); /* XXX: need to fix this for 3.5 */ #ifdef CONFIG_ia64 cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - cmdline_size; #elif defined CONFIG_ia32 || CONFIG_x86_64 cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - 2048; #endif /* * clear entire buffer. The boot param structure is bigger than * needs be but this allows the kernel bootparam structure to grow * (up to BOOT_PARAM_MEMSIZE) without having to worry about fixing the bootloader. * By convention between the laoder and the kernel, the value 0 means * don't care or not set. */ Memset(bp, 0, BOOT_PARAM_MEMSIZE); U2ascii(args, cp, cmdline_size); if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; /* * Convert kernel command line args from UNICODE to ASCII and put them where * the kernel expects them: */ while (1) { ch = *args++; if (!ch) break; *cp++ = ch; } *cp++ = '\0'; return bp; } VOID free_boot_params(VOID *bp) { boot_params_t *real_bp = (boot_params_t *)bp; sysdeps_free_boot_params(real_bp); free(real_bp); } ./elilo/console.h0000644000175000017500000000211711271404161013452 0ustar jasonfjasonf/* * console.h - Console screen handling functions * * Copyright (C) 2006 Christoph Pfisterer * * 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. */ #ifndef __ELILO_CONSOLE_H__ #define __ELILO_CONSOLE_H__ extern VOID console_textmode(VOID); #endif /* __ELILO_CONSOLE_H__ */ ./elilo/README.gnu-efi0000644000175000017500000000477110650210516014057 0ustar jasonfjasonf IMPORTANT Information related to the gnu-efi package and x86_64 efi support ---------------------------------------------------- August 2003 As of version elilo-3.0, the gnu-efi package is now split in two different packages: -> gnu-efi-X.y: contains the EFI library, header, files, and crt0. -> elilo-X.y : contains the ELILO bootloader. Note that X.y don't need to match for both packages. However elilo-3.x requires at least gnu-efi >= 3.0. When using a version of gcc >3.0 you MUST use at least gnu-efi-3.0a. Note that EFI support for x86_64 has been added as a patch to gnu-efi-3.0c. For x86_64, see the important notes under x86_64. IMPORTANT NOTE FOR IA-32: ------------------------- For IA-32, the Redhat 8.0 toolchain is known to produce working binaries when used with gnu-efi-3.0a + loader script patch which is included in the gnu-efi-3.0a-ia32.patch in this package. The toolchain includes: gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7) as: GNU assembler version 2.13.90.0.2 (i386-redhat-linux) using BFD version 2.13.90.0.2 20020802 ld: GNU ld version 2.13.90.0.2 20020802 The Redhat 9.0 toolchain does not work at the moment. The gnu-efi package can be downloaded from: ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-X.y.tar.gz IMPORTANT NOTE FOR x86_64: ------------------------- EFI x86_64 elilo support requires the following libraries: 1. gnu-efi-3.0c library with x86_64 support. 2. The toolchain known to produce working x86_64 efi binary are: gcc-4.1.1 or above binutils-2.17.50.0.14 with Intel64 EFI support Implementation: -------------- Calls to EFI services in x86_64 require a wrapper to pass the arguments in the appropriate manner. This is implemented with efi wrapper. For IA32 and IA64, the wrapper is a macro that merely calls the EFI services directly. The elilo source has been modified to use the efi wrapper implemented in gnu-efi-3.0c library. elilo for x86_64 and its dependent libraries are built and the final ELF image is converted into PE-COFF image using the objcopy supported by binutils-2.17.50.0.14 or above with Intel64 EFI support. On UEFI 2.0 firmware, only Graphics Output Protocol (GOP) is supported. The x86_64 elilo first queries video information from GOP failing which it queries for text mode support. The video information is passed to Linux kernel via boot parameter. The GOP support requires Linux kernel EFI framebuffer driver (kernel configuration option). ./elilo/examples/0000755000175000017500000000000011513632673013466 5ustar jasonfjasonf./elilo/examples/textmenu_chooser/0000755000175000017500000000000011513632673017061 5ustar jasonfjasonf./elilo/examples/textmenu_chooser/general.msg0000644000175000017500000000417207440772134021213 0ustar jasonfjasonf ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 10 7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74General Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10 7f³70 ³10 7f³70 This is the general screen. You entered by pressing F1 ³10 7f³70 ³10 7f³70 Press any key to return to main screen ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 Help: [71F170-General] [71F270-Params] ³10 7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10 ./elilo/examples/textmenu_chooser/textmenu-message.msg0000644000175000017500000000430607440771746023100 0ustar jasonfjasonf ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 10 7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Install and Recovery Disk7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10 7f³70 This CD demonstrates the elilo textmenu chooser. You can select an entry ³10 7f³70 from the menu with the curosr keys, enter exptra parameters at the propmt, ³10 7f³70 and press to start the process. Help can be made available via ³10 7f³70 the function keys. On a serial console, use Ctrl-F followed by the ³10 7f³70 relevant function key number. ³10 7f³70 ³10 7f³70 7eBeware that this is an install disk, and misuse can result in the loss of 70³10 7f³70 7eany data currently on your disks. 70³10 7f³70 ³10 7f³70 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ7f¿70 ³10 7f³70 ³70 This is where the menu goes 7f³70 ³10 7f³70 ³701e (active colour) 7f³70 ³10 7f³70 ³70 (inactive colour) 7f³70 ³10 7f³70 ³70 1e7f³70 ³10 7f³70 À7fÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 Boot: 35 70 ³10 7f³70 ³10 7f³70 Help: [71F170-General] [71F270-Params] ³10 7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10 ./elilo/examples/textmenu_chooser/params.msg0000644000175000017500000000417207440772143021061 0ustar jasonfjasonf ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 10 7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Params Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10 7f³70 ³10 7f³70 This is the params screen. You entered by pressing F2 ³10 7f³70 ³10 7f³70 Press any key to return to main screen ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 ³10 7f³70 Help: [71F170-General] [71F270-Params] ³10 7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10 ./elilo/examples/textmenu_chooser/elilo-textmenu.conf0000644000175000017500000000133307440772102022677 0ustar jasonfjasonf# # force chooser to textmenu chooser=textmenu delay=20 prompt # # the files containing the text (with attributes) to display # message=textmenu-message.msg # # files to load when the corresponding function key is pressed # f1=general.msg f2=params.msg image=debian/linux label=debian description="Install Debian GNU/Linux" read-only initrd=debian/root.bin root=/dev/ram image=debian/linux label=sda1 description="Boot Debian Linux, root on sda1" read-only root=/dev/sda1 image=debian/linux.old label=old description="Boot Debian Linux, old kernel" read-only root=/dev/sda1 image=debian/linux label=shell description="Execute a shell" read-only initrd=debian/root.bin root=/dev/ram append="init=/bin/sh" ./elilo/examples/netboot/0000755000175000017500000000000011513632673015140 5ustar jasonfjasonf./elilo/examples/netboot/dhcpd.conf0000644000175000017500000000054507440770035017074 0ustar jasonfjasonfsubnet 192.168.2.0 netmask 255.255.255.0 { option domain-name "mydomain.com"; option subnet-mask 255.255.255.0; option routers 15.4.88.1; # here we use a fixed address host test_machine { hardware ethernet 00:D0:B7:C7:FB:F8; fixed-address 192.168.2.10; filename "/tftpboot/elilo.efi"; option host-name "test_machine"; } } ./elilo/examples/netboot/dhcpd-pxe.conf0000644000175000017500000000724207316156505017671 0ustar jasonfjasonf# # Enable proxyDHCP operation. # dhcpd-operation normal; # # BootServer is turned on # bootserver-operation on; ddns-update-style ad-hoc; # # if this dhcpd server is not "master" # not authoritative; #------------------------------------------------------------- # For each of the 3 servers (builtin) define the DHCPD option # tags we are interested in. #------------------------------------------------------------- # # Define DHCPD request option tags # # # This option is used to determine the client boot-time binary runtime # environment. # option client-architecture code 93 = unsigned integer 16; # # Now go to the DHCPD proxy option tags # option space proxy; option proxy.boot-prompt code 10 = { unsigned integer 8, text }; option proxy.boot-menu code 9 = array of { unsigned integer 16, unsigned integer 8, text }; option proxy.boot-servers code 8 = array of { unsigned integer 16, unsigned integer 8, array of ip-address }; option proxy.discovery-control code 6 = unsigned integer 8; # # Now go to the PXE Bootserver options # option space bs; option bs.boot-item code 71 = { unsigned integer 16, unsigned integer 16 }; #------------------------------------------------------------- # Actual configuration #------------------------------------------------------------- subnet 192.168.2.0 netmask 255.255.255.0 { # # In this section define regular DHCPD options # # # Here we show settings with fixed addresses, but dynamic # allocation is possible as well # host test1 { hardware ethernet 00:d0:b7:c7:fb:f8; fixed-address 192.168.2.10; } host test2 { hardware ethernet 00:d0:b7:aa:f0:e3; fixed-address 192.168.2.11; } # # Now we look at options for every possible type of requests # # # # If requets was received by the ProxyDHCPD if proxy { # # Provide proxyDHCP information for Intel ia64 # architecture machines. # if option client-architecture = 00:02 { # # Notify of PXE aware server # option vendor-class-identifier "PXEClient"; # # Force unicast # option proxy.discovery-control 3; # # Print a nice boot menu # # ServerTypes: # 14 -> means Redhat install # 13 -> means Redhat Boot # 23 & 26 are length of string following. # option proxy.boot-menu 14 23 "Remote Redhat/ia64 boot", 13 26 "Remote Redhat/ia64 install"; # # list of possible bootservers for a ServerType # # Currently not possible to define more than one type # option proxy.boot-servers 14 1 192.168.2.32; # # A boot prompt # 30 is timeout in seconds # option proxy.boot-prompt 30 "Press or for menu. Press to local boot."; # # vendor-option-space proxy; } } else if bootserver { if option client-architecture = 00:02 { # # Now analyze bootserver request option tags # # ELILO Layering: # Layer 0: bootloader binary (elilo.efi) # Layer 1: elilo configuration file (elilo.conf) # Layer 2: Linux/ia64 kernel if substring(option bs.boot-item, 2, 2) = 00:00 { filename "/tftpboot/elilo.efi"; # # identify reply layer & server type # option bs.boot-item 14 0; } else if substring(option bs.boot-item, 2, 2) = 00:01 { filename "/tftpboot/elilo.conf"; # # identify reply layer & server type # option bs.boot-item 14 1; } else if substring(option bs.boot-item, 2, 3) = 00:02 { filename "/tftpboot/vmlinux"; # # identify reply layer & server type # option bs.boot-item 14 2; } # # vendor-option-space bs; option vendor-class-identifier "PXEClient"; } } else { # # notify of PXE aware DHCPD server # option vendor-class-identifier "PXEClient"; } } ./elilo/Make.rules0000644000175000017500000000240610650210515013567 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # This file is part of ELILO, the LINUX EFI 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. # %.efi: %.so $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .reloc --target=$(FORMAT) $*.so $@ %.so: %.o $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES) %.o: %.c $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ # a rule for .S %.o: %.S $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ ./elilo/fileops.h0000644000175000017500000001040110015235410013436 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __FILEOPS_H__ #define __FILEOPS_H__ #define FILEOPS_NAME_MAXLEN 32 /* length of filesystem name */ /* * upper-level interface used by the bootloader */ typedef UINTN fops_fd_t; /* Forward declaration: */ struct config_file; extern EFI_STATUS fops_open(CHAR16 *name, fops_fd_t *fd); extern EFI_STATUS fops_read(fops_fd_t fd,VOID *buf, UINTN *size); extern EFI_STATUS fops_close(fops_fd_t fd); extern EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size); extern EFI_STATUS fops_seek(fops_fd_t fd, UINT64 newpos); extern EFI_STATUS fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath); extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen); extern CHAR16 *fops_bootdev_name(VOID); /* * fileops interface used by underlying filesystems layer */ typedef EFI_STATUS (*fops_open_t)(VOID *intf, CHAR16 *name, fops_fd_t *fd); typedef EFI_STATUS (*fops_read_t)(VOID *intf, fops_fd_t fd, VOID *buf, UINTN *size); typedef EFI_STATUS (*fops_close_t)(VOID *intf, fops_fd_t fd); typedef EFI_STATUS (*fops_infosize_t)(VOID *intf, fops_fd_t fd, UINT64 *size); typedef EFI_STATUS (*fops_seek_t)(VOID *intf, fops_fd_t fd, UINT64 newpos); typedef EFI_STATUS (*fops_setdefaults_t)(VOID *intf, struct config_file *defconfs, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath); typedef EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen); typedef struct { VOID *intf; /* pointer to underlying interface */ fops_open_t open; fops_read_t read; fops_close_t close; fops_infosize_t infosize; fops_seek_t seek; fops_setdefaults_t setdefaults; fops_getdefault_path_t getdefault_path; EFI_HANDLE dev; /* handle on device on which proto is installed */ CHAR16 name[FILEOPS_NAME_MAXLEN]; } fileops_t; /* * used to register a new filsystem */ typedef INTN (*fops_fs_glue_t)(fileops_t *this, VOID *intf); typedef EFI_STATUS (*fops_fs_install_t)(VOID); typedef EFI_STATUS (*fops_fs_uninstall_t)(VOID); typedef struct { EFI_GUID proto; /* GUID of filesystem */ fops_fs_glue_t glue; /* glue routine */ fops_fs_install_t install; /* to go away with real EFI drivers */ fops_fs_uninstall_t uninstall; /* to go away with real EFI drivers */ } fileops_fs_t; /* * device description */ #define FILEOPS_DEVNAME_MAXLEN 16 typedef struct { EFI_HANDLE dev; fileops_t *fops; CHAR16 name[FILEOPS_DEVNAME_MAXLEN]; } device_t; extern INTN init_devices(EFI_HANDLE boot_handle); extern INTN close_devices(VOID); extern VOID print_devices(VOID); extern EFI_STATUS fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev); extern INTN fops_split_path(CHAR16 *path, CHAR16 *dev); extern EFI_STATUS fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev); /* * device naming schemes * * Interface: * the scheme() function arguments are: * - the list of detected bootable device * - the number of entries in that table as argument * * There is no expected return value. If the scheme() cannot perform * its tasks, then IT MUST NOT OVERWRITE the generic naming scheme (devXXX) that * is ALWAYS installed by default. Partial modifications are possible, although * not recommended. */ typedef struct { CHAR16 *name; INTN (*install_scheme)(device_t *tab, UINTN ndev); } devname_scheme_t; #endif /* __FILEOPS_H__ */ ./elilo/chooser.h0000644000175000017500000000363407720451637013475 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_CHOOSER_H__ #define __ELILO_CHOOSER_H__ typedef INTN chooser_func_t(CHAR16 **argv, INTN arc, INTN index, CHAR16 *kname, CHAR16 *cmdline); /* * structure to interface to generic chooser selection code. * * XXX: must add support for moer than one choice (rating scheme) * * Interface for probe: * dev: boot device handle * return: -1, if not support, 0 if supported * * Interface for chooser: * argv,argc: command line argument passed to elilo * index : position of first non-option argument (min value=1) * kname : selected kernel name * cmdline : requested kernel command line * return: * -1: if error * 0: if successful */ typedef struct { CHAR16 *chooser_name; INTN (*chooser_probe)(EFI_HANDLE dev); chooser_func_t *chooser_func; } chooser_t; extern INTN init_chooser(EFI_HANDLE); extern INTN exist_chooser(CHAR16 *name); extern chooser_func_t *kernel_chooser; #endif /* __ELILO_CHOOSER_H__ */ ./elilo/chooser.c0000644000175000017500000000567507720451632013472 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #ifdef CONFIG_CHOOSER_SIMPLE #include "choosers/simple.h" #endif #ifdef CONFIG_CHOOSER_TEXTMENU #include "choosers/textmenu.h" #endif static chooser_t *choosers_tab[]={ #ifdef CONFIG_CHOOSER_SIMPLE &simple_chooser, #endif #ifdef CONFIG_CHOOSER_TEXTMENU &textmenu_chooser, #endif NULL }; /* * The intent of this module is to provide a mechanism by which alternate * choosers can be installed. Developers can write new choosers and * add them to the list. They will be probe and the best match * will be started first. It should be possible to switch to another * chooser using a key combination. There is a default simple text-based * chooser that must always be present. * * Currently you can specify a chooser via "-c name" when you invoke elilo, * or via "chooser=name" in the config file. If the specified chooser * probes ok it will be selected, otherwise the first one that probes ok * will be used. * * XXX: at this time, not all chooser functionalities are implemented. * */ chooser_func_t *kernel_chooser; INTN init_chooser(EFI_HANDLE dev) { chooser_t **p; CHAR16 *chooser_name = L"none"; kernel_chooser = NULL; for (p=choosers_tab; *p; p++) { VERB_PRT(4, Print(L"trying chooser %s\n", (*p)->chooser_name)); if ((*p)->chooser_probe(dev) == 0) { /* * if that's the one we asked for, then go for it */ if (!StrCmp(elilo_opt.chooser, (*p)->chooser_name)) { kernel_chooser = (*p)->chooser_func; chooser_name = (*p)->chooser_name; break; } if (kernel_chooser == NULL) { kernel_chooser = (*p)->chooser_func; chooser_name = (*p)->chooser_name; } } } if (kernel_chooser) { VERB_PRT(2, Print(L"selected chooser %s\n", chooser_name)); return 0; } ERR_PRT((L"No chooser selected. Impossible to proceed")); return -1; } INTN exist_chooser(CHAR16 *name) { chooser_t **p; for (p=choosers_tab; *p; p++) { if (!StrCmp(name, (*p)->chooser_name)) return 0; } return -1; } ./elilo/docs/0000755000175000017500000000000011513632673012600 5ustar jasonfjasonf./elilo/docs/edd30.txt0000644000175000017500000001062207433001604014227 0ustar jasonfjasonfInformation related to EDD3.0 and ELILO --------------------------------------- Last updated: 02/02/14 As of elilo-3.0, the filesystem/device naming scheme takes advantage of the EDD3.0 support present in the underlying EFI/BIOS firmware layers. The EDD3.0 support is supposedly turned on by default in all version of the EFI firmware on IA-64 (and possibly IA-32). Support can be enabled or disabled dynamically using an EFI environment variable called "EDD30". The GUID of the variable is as follows: #define EDD30_GUID \ {0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} This is a boolean variable. When true, support is enabled. You can check if support is enabled by typing: Shell> edd30 Usage edd30 [On | Off] Used to support OS Loader debug EDD30 DevicePath Mode is On at this EFI shell prompt. You can enable support by forcing the variable to TRUE. This can be accomplished by typing: Shell> edd30 on EDD30 DevicePath Mode is On Alternatively an EFI application can use RT->SetVariable() to set the value of the EDD30 variable. If the variable was set to false, then to take advantage of EDD3.0 support after switching the variablle to TRUE, the system MUST be rebooted as EDD affects the core of EFI naming scheme. Elilo will check if the variable is defined and valid. If it is set to true, then the device name schemes that rely on it will work properly. That's the case for the 'simple' scheme. If the variable is not set to true or does not exist, elilo will use a generic builtin scheme with names such as dev001, dev002 and so on. The "EDD30" variable is like a system variable therefore it is expected not to be overloaded by users for others purposes. Elilo is fully functional even when EDD30 is off. By default, if EDD30 is off, elilo will try and set the variable to TRUE. However, some controllers do not support EDD30 and forcing the variable may cause problems. Therefore as of elilo-3.2, there is an option to avoid forcing the variable. In the config file, you can use 'noedd30' option and on the command line, you can use the -E option. When the variable is forced back to TRUE, th effect will only be seen after a reboot. Shall you decide not to reboot immediately, elilo will system still operate using the generic naming scheme. When EDD3.0 is enabled the output of the EFI shell 'map' command looks similar to this: Device mapping table fs0 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000) fs1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000) fs2 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1) blk0 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Primary,Master) blk1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0) blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000) blk3 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000) blk4 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part3,Sig00000000) blk5 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0) blk6 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000) blk7 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000) blk8 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000) blk9 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200) blkA : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master) blkB : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1) Shell> The same system with EDD3.0 disabled will look like this: Device mapping table fs0 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000) fs1 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000) fs2 : VenHw(Unknown Device:FF)/CDROM(Entry1) blk0 : VenHw(Unknown Device:00) blk1 : VenHw(Unknown Device:80) blk2 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000) blk3 : VenHw(Unknown Device:80)/HD(Part2,Sig00000000) blk4 : VenHw(Unknown Device:80)/HD(Part3,Sig00000000) blk5 : VenHw(Unknown Device:81) blk6 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000) blk7 : VenHw(Unknown Device:81)/HD(Part2,Sig00000000) blk8 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000) blk9 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200) blkA : VenHw(Unknown Device:FF) blkB : VenHw(Unknown Device:FF)/CDROM(Entry1) Shell> EDD3.0 is an industry standard and the working draft can be downloaded from the following web site: http://www.t13.org/ The document reference is D1386 (Enhanced Disk Drive Services 3.0). ./elilo/docs/eliloalt.txt0000644000175000017500000000512407720451711015145 0ustar jasonfjasonfInformation related to the eliloalt Linux tool --------------------------------------------- (c) 2002-2003 Hewlett Packard Co Contributed by Stephane Eranian Last updated: March 1st, 2002 The elilo alternate image feature uses an EFI variable called EliloAlt. The content of this variable is a UNICODE string containing a kernel image file and its command line options. The variable has a NULL GUID. To create, read, or modify the variable you need to use the EFI variable service and the SetVariable() or GetVariable() interface. The service is available when EFI is in boot service mode, i.e., prior to loading the kernel but it is also available at runtime when the Linux kernel has taken over the control of the machine. In order to modify the variable, you can either write a small EFI applications or use the Linux/ia64 interface to the EFI variables which use the /proc filesystem. The elilalt tool included in this package uses the /proc interface to EFI variables to create, read, or modify the EliloAlt variable. This tool is a Linux/ia64 application and NOT an EFI application. Because modiyfing the EliloAlt can influence how the machine is booted, you must be root to run the program, even when you simply want to read the content of the variable. Eliloalt provides the following options: -h, --help display this help and exit --version output version information and exit -s, --set cmdline set elilo alternate variable to cmdline -p, --print print elilo alternate variable -d, --delete print elilo alternate variable 1/ Creation of the variable To create the variable you can type: # eliloalt -s "vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi" It is VERY important to use quotes to make sure that the entire list of arguments is treated as a single argument to the program. Otherwise only the first element (here vmlinuz-2.4.9) will be used. 2/ Printing the content of the variable To print the content of the variable you need to type: # eliloalt -p EliloAlt="vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi" 3/ Modifying the variable You can simply use the -s option: # eliloalt -s "vmlinuz-2.4.18 root=/dev/sdb2" # eliloalt -p EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2" 3/ Deleting the variable You must use the -d option: # eliloalt -p EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2" # eliloalt -d # eliloalt -p variable not defined Keep in mind that the variable is automatically deleted by elilo if: - the checkalt option is specified in the config file OR - the -a is used on the command line ./elilo/docs/textmenu_chooser.txt0000644000175000017500000000472107720451730016736 0ustar jasonfjasonfInformation about the textmenu chooser -------------------------------------- Copyright (C) 2002-2003 Hewlett-Packard Co. Contributed by Last updated: 02/02/14 Chooser name: textmenu Command line option: -C textmenu Config file option: chooser=textmenu The textmenu chooser provides a facility whereby you can draw a colour boot screen, using line-drawing characters to give the impression of a dialog box, with a scrollable menu from which a boot image can be chosen via cursor up/down keys. A one-line input field is provided for additional parameter input. Menu entries are taken from the description= fields in the config file. The message file format is based on that used for syslinux/isolinux on ia32 platforms, which is copyright H. Peter Anvin. It is basically a text file containing text and graphic characters, along with some control codes to specify colour attributes, menu, and prompt field positions. There are two classes of message files; the main file, specified via message=, which includes menu and prompt field markers, and the additional help files which are invoked via function keys. Graphic characters are taken from the standard IBM VGA character set, and using an appropriate font makes file creation easier. Under Linux you can find a VGA font in the dosemu package. Included in the elilo source is sys2ansi.pl (taken from syslinux), which can be used to translate colour attributes such that they display correctly in an xterm. Valid control codes: 0x01 ^A Mark top left or bottom right of menu area. Current attributes at top left marker are used for inactive menu entries, current attributes when bottom right marker is found are used for the currently active menu attributes. 0x02 ^B Mark left- or right-hand end of the prompt field. Current attributes at the left had end are used to display and parameters entered. 0x0A ^J Linefeed, does implied carriage return. 0x0C ^L Clear screen 0x0D ^M Carriage return; ignored so files can be 'DOS' or 'UNIX' format. 0x0F ^O Attribute specfication; Two hex digits should follow this code, the first being the background colour required, the second the foreground. 0 = black 8 = dark grey 1 = dark blue 9 = bright blue 2 = dark green a = bright green 3 = dark cyan b = bright cyan 4 = dark red c = bright red 5 = dark purple d = bright purple 6 = brown e = yellow 7 = light grey f = white An example of a config file and message file are included in the examples directory. ./elilo/docs/devschemes.txt0000644000175000017500000001354707720451716015503 0ustar jasonfjasonf Some explanations of what the devschemes are for: ------------------------------------------------- Copyright (c) 2001-2003 Hewlett-Packard Co Contributed by Stephane Eranian Whether or not EDD3.0 is enabled, EFI uses a device naming scheme which is somewhat detailed. It tries to follow the hardware path from the System bus down to the actual partition on the media. The following example shows a typical block device path from a SCSI disk: blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000). Elilo allows the user to load files from any device. This means that it must provide a way for the user to specify a file path which include the device name. While it is theoritically possible to specify the path mentioned above, it is far from practical because the names are too long. There is too much details which the user (especially of a boot loader) does not care about. So Elilo, just like the EFI shell, must have a way of assigning logical names to device names (paths). The EFI shell uses the fsX notation wherever it finds a block devices for which it has detected a valid EFI filesystem (i.e. a Fat32+ filesystem). This assignment is done on the fly, and depending on the status of the removable media (like CDROM or floppy) the mapping can change. Those fsX: names are a pure abstraction of the EFI shell and have nothing to do with the EFI specification. Now Elilo could try to emulate then, i.e. try to reproduce the way the EFI shell assigns names. However the problem is that, AT THIS POINT, Elilo recognized more device from which it can load files from than the Shell does. This comes from the fact that it can load files from the network or from an Ext2fs, for instance. We plan on fixing those issues in the next releases of Elilo. Anyway, the problem would still be to make sure that if we follow the same naming scheme, they match at all times, i.e. fs0: maps to the same device in both the EFI shell and Elilo which may be tricky as both EFI and Elilo continue to evolve. Also the Shell naming schemes as some problems which removable devices which would not make it easy from the bootloader. Another possible solution would be to use the Linux kernel naming scheme, i.e., hda, hda1, fd0, sda... Of course, we would drop the /dev prefix in this case. While it would make it very convenient for users and easy to configure from a running system, it is even more difficult that the EFI Shell scheme. Again, to succeed, the loader scheme would have to match EXACTLY what the Linux kernel does for all possible devices. This is a very complicated task as his any naming problem. The recent discussions about the devfs support in the kernel is just yet another proof of the complexity. Another issue here is that this would create a dependency between the loader and the kernel because we would need the way the naming is done in the kernel. Again, this is very complicated, just thinnking about how the PCI buses are scanned looking from devices. So it looks like there is single solutions. Clearly, that is not easy and there are multiple schemes possible. For now, we felt that it was better for Elilo to use its own naming scheme independent from the EFI shell and the Linux kernel. While this introduces yet another scheme, we believe its advantages outweight the software complexity associated with the two schemes described above. However, we recognize the need for flexibilty and that is exactly why, this version of Elilo provide an internal interface which can used to develop custom naming schemes. The way the filepaths are translated by Elilo is very basic and based on a simple string matching algorithm. A full pathname is specified as follows: dev_name:/path/to/my/file. The 'dev_name' is created by Elilo and can be anything relevant to the user. There is an internal binding from the name to the actual EFI device handle and more precisely the filsystem interface associated to it (the device handle is never exposed to the boot loader). By default, Elilo uses an extremely simple scheme which is similar to the EFI shell. if simply builds the device names as follows: devXXX. The XXX is just the number of the device. It is incremented by one each time recognized filesystem is detected on that device. The clear advantage is simplicity. The downside is that is creates a 'flat' namespace where every new device detected (like a floppy is inserted) will show up anywhere in the set of devices and may push some fixed devices up or down. So it hard to rely on devXXX to always mean the same things. Now custom naming schemes can be added on top of this, which would partially or totally replace this default scheme. Elilo is shipped with one such scheme called 'simple'. It provides an example of how one can develop a new scheme. The main characteristic of 'simple' is that it tries to group devices by controller (Messaging Device in EFI terminology). Hence, all the ATAPI devices show up as atapiXXX and the SCSI device show up as SCSIXXX. This implicitely shields the SCSI (fixed most likely) devices from the removable media coming from ATAPI (like floppy or CDROM). So it is slightly better but far from perfect. Here is an example of what it looks like on an actual system: scsi0 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000) scsi1 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000) atapi0 : vfat : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1) scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000) scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000) net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25) The 'simple' scheme is not fully satifactory but developers are strongly encouraged to enhance it or better create new schemes. ./elilo/docs/simple_chooser.txt0000644000175000017500000001350607720451735016364 0ustar jasonfjasonfInformation about the simple chooser -------------------------------------- Copyright (C) 2002-2003 Hewlett-Packard Co. Contributed by Stephane Eranian Last updated: 02/02/14 Chooser name: simple Command line option: -C simple Config file option: chooser=simple, description, message The simple chooser is the default chooser. However it is possible to disable it at compile time, it is highly recommended to keep it in. Elilo must have at least one chooser compiled in. The simple chooser is very basic as its name indicates! It provides a simple one line text mode command prompt similar to what you get with Lilo/x86. Any chooser becomes visible to the user ONLY when the interactive mode is entered. The simple chooser allows the user to select a kernel to boot. The user can use a label as specified in the elilo config file or a kernel file name. File names can be specified with absolute names in the form dev_name:/path/to/my_kernel. 1/ Activation The chooser is activated from: - command line with the -c simple - the config file with the chooser=simple option 2/ Supported options The simple chooser supports the following options in the config file: message=filename : display a message before the prompt. The filename must be an ASCII file description=string: a description of the kernel image (ASCII) All other options have their standard meaning. The chooser does not recognize the fX (X varies from 1-12) options 2/ Builtin commands The simple chooser has some builtin command which the user can get to by typing certain keys as the first character on the command line: TAB: shows the list of defined labels and their descriptions. If the user did not type anything, i.e., the line is empty, pressing TAB will print the list of labels defined in the elilo config file. If the user already typed a name and if the name corresponds to a specified label, the chooser will show how the label is expanded and what the final command line to the kernel will look like. If the line is empty pressing TAB generates something similar to: ELILO boot: linux-up linux nfsroot (or any kernel file name: [dev_name:]/path/file) Note that first label correspond to the default label used if the user hits the enter key with an empty line. This label is not necessarily the first one in the config file. Now pressing TAB with a full label name: ELILO boot: linux-up desc : my default UP kernel cmdline: vmlinuz root=/dev/sdb2 console=ttyS0,115200n8 console=tty0 ro The desc line shows whatever was specified in the "description" option for this particular image in the config file. = : shows the list of accessible devices this key force elilo to print the list of detected devices. Elilo will auto-detect the devices which are accessible to load a config file, the kernel, the initrd from. Those devices typically represent disk partition, CDROM, floppy, or a network path. The list of devices is highly system dependent. It also depends on the filesystem support compiled into elilo. The way the devices are named depends on the device naming scheme selected. It also depends on whether the EDD30 support is activated. For instance, pressing the ? could look as follows: ELILO boot: scsi0 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig72040800) scsi1 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000) scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig72040800) scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000) net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25) 5 devices available for booting boot device net0: netfs Here the vfat (EFI partition type), ext2fs and network filesysten (not to be confused with NFS) were compiled into elilo and were detected on the machine. The left handside of the colon show the logical name associated with the device. For instance, scsi0 corresponds to the first partition of SCSI disk ID 0 and is an EFI partition. The net0 correspond to a network device, here the Ethernet adapter. The last line show the device used to load elilo itself, in the case elilo was downloaded from the network. To get a kernel from scsi0, the user can simply type: ELILO boot: scsi0:/usr/src/linux/vmlinux Note that even though elilo was not downloaded from the network, it is still possible to get the kernel and initrd from a remote machine. % : shows the list of defined variables Elilo has builtin variables which are used to dynamically customized the command line parameters passed to the kernel. The list of variables depends on the support compiled into elilo. Not all elilo subsystems use variables. Typically the network file system does. Pressing '%' only prints the variables that are defined with their current values. Some variables are only defined once the subsystem that creates them has been used. In other words, if the network filesystem was not used to load elilo, then the variables defined by it are not created. If the network was actually used, pressing '%' could generate the following output: ELILO boot: D = "mydomain.com G = "192.168.3.1" H = "test_machine" I = "192.168.3.4" M = "255.255.255.0" & : shows the list default path The path is used as a prefix for all filenames specified as relative. ? : shows the list of supported command keys The simple chooser has also some builtin command line editing commands: ESC : abort (leave elilo) CTRL-D : abort (leave elilo) CTRL-C : kill line empty current line and prompt for new input CTRL-H : erase the previous character CTRL-U : clear current line reset the buffer (does not display correctly if buffer spans more than one line) Backspace: erase character ./elilo/docs/elilovars.txt0000644000175000017500000000432707720451743015351 0ustar jasonfjasonfInformation related to variable support in ELILO ------------------------------------------------ (c) 2002-2003 Hewlett Packard Co Contributed by Stephane Eranian Last updated: 06/13/2002 As of version 3.2, elilo has internal variables which can be programmed by any module inside the bootloader code. These variables are used to parametrize some of the arguments passed on the kernel command line. The value of a variable is a Unicode string. Variables names are composed of a single Unicode character, such as 'I' for instance. Variable names are case sensitive. Elilo has support for 52 variables: A-Z and a-z. The '%' sign is used to name a variable. For instance, '%I' indicates variable 'I'. If '%I' is present on the command line to the kernel, it will be replaced (string replacement) with the value (a string) of 'I'. By default, the Elilo core does not assign any values to any variables. It is up to each module to do so. When a variable is not used, its content is the empty string "", which means that the '%d' notation, for instance, will be replaced with the empty string. Let us look at an example: Supposing that the following variables are defined: 'I' -> "192.168.2.5" 'G' -> "192.168.2.1" 'M' -> "255.255.255.0" 'z' -> "" Then a command line of this form (provided as an append= option in elilo.conf): root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=%I:%z:%G:%N:jung:eth0:on Would pass the following to the kernel: root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=192.168.2.5::192.168.2.1:255.255.255.0:jung:eth0:on Of course, the meaning of each variable is up to each individual module, the names used here are not necessarily representative of the actual names used by elilo. Some choosers, (such as simple) have support to print the list of defined variables. For instance, in simple (the default chooser) you can press '%' to see the list of defined variables. Variables can be useful when netbooting, for instance, to get the dynamically assigned IP, netmask, and gateway addresses. In case the % character needs to be passed to the kernel, it is possible to "despecialize" a character using the & symbol in front of it. See netbooting.txt for more information on this. ./elilo/docs/fpswa.txt0000644000175000017500000000210207720451752014456 0ustar jasonfjasonfInformation related to the FPSWA driver for EFI/ia64 platforms -------------------------------------------------------------- (c) 2002-2003 Hewlett Packard Co Contributed by Stephane Eranian This document is irrelevant for EFI/ia32 platforms. On all EFI/ia64 platforms, the bootloader is responsible for checking for the presence on the EFI system partition of an updated version of the Floating-Point Software Assist (FPSWA) EFI driver (fpswa.efi). For every instance found, elilo will load the driver and let EFI decide if it is newer than the currently installed version. In the end at most one driver is kept in memory. Elilo will look for a file called fpswa.efi in the \EFI\Intel Firmware (there is a space between l and F) directory on ALL accessible EFI system partitions (including on removable media). It will do so even when elilo is downloaded from the network. It does not look for the driver in the ext2fs partitions. The FPSWA reference document is available from the Intel developer's web site at http://developer.intel.com/design/itanium. ./elilo/docs/netbooting.txt0000644000175000017500000004226311267126730015516 0ustar jasonfjasonfHow to netboot using ELILO -------------------------- Copyright (C) 2002-2003 Hewlett-Packard Co. Contributed by Stephane Eranian Updated by Jason Fleischli Last updated: 10/19/2009 x86_64 and uefi support was added @ elilo version 3.8 and linux kernel >= 2.6.24 EFI has full support for the PXE and DHCP protocol. As such it is relatively easy to boot a machine from the network using EFI. The elilo loader has full support for both PXE and DHCP, therefore it is possible to download the elilo config file, the Linux kernel image and the initial ramdisk from a remote server. There are many ways netbooting can be configured but in this document we focus only on two very common cases: - netboot but use local root filesystem. - booting a diskless machine, i.e., use a NFS root filesystem. 1/ How to get EFI to netboot? You do not need any additional software to get EFI to start a netboot session. Any EFI machine can be configured to start a PXE/DHCP session IF it has a network adapter that has support for the UNDI/PXE protocol. Most modern cards do have such support. To enable netbooting, you need to go into the EFI boot manager maintenance menu and 'Add a boot option'. On the screen you see the list of devices to boot from. At least one of them should be of the form: Load File [Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)] which represent Ethernet card (Mac address). If you don't have such option, it means that you either do not have a network adapter in your machine or it does not have the UNDI/PXE support in its option ROM. You need to select this option and give it a logical name such as 'netboot', for instance. Next, you leave the maintenance menu and go back to the main menu. You now have a new boot menu option. If you select 'netboot' then EFI will start the PXE/DCHP discovery request and look for a server to get an IP address. On the server side, you can use a standard DHCP server, such as the one shipped on Redhat7.2 (dhcpd) or a PXE server (not yet available for Linux, probably available for Windows). In this document we show both options. You also need a TFTP server somewhere on the network, it will be used to download the actual files. 2/ Netbooting using DHCP There is nothing specific to EFI that needs to be set in the /etc/dhcpd.conf file. Clearly the filename option must contains the path to the elilo.efi binary. Elilo will auto-detect whether it was downloaded via PXE or DHCP and it will adapt the kind of requests it makes to download the other files that it needs, such as its config file. A simple dhcpd.conf file which uses fixed IP addresses could be as follows: subnet 192.168.2.0 netmask 255.255.255.0 { host test_machine { hardware ethernet 00:D0:B7:A6:FC:25; fixed-address 192.168.2.10; filename "elilo.efi"; option domain-name "mydomain.com"; option host-name "test_machine"; option routers 192.168.2.1; option subnet-mask 255.255.255.0; } } For the tftp server, you need to make sure that it is ACTIVATED by inetd or xinetd depending on your distribution. In most distributions, it is disabled by default for security reasons. On distributions using xinetd, you need to check /etc/xinet.d/tftp. For inetd you need to check /etc/inetd.conf. It is typical to have the root directory for tftp be /tftpboot but it can be anything. In this document we will use /tftpboot as the root directory. The files that we need are as follows: - elilo.efi - the elilo config file - the kernel image - the initial ramdisk (optional) a/ Location of the files in the tftp directory tree For elilo version 3.3b or higher, it is possible to place the files listed above in any subdirectory below the tftp root. Of course the dhcpd.conf file must point to the location of elilo.efi and provide the path from the tftp root directory. Elilo will look for its config file, the kernel image, the initial ramdisk (optional) only from the directory it was loaded from. This is useful when the same tftp server is used to services many different kind of clients. Here is a simple example, suppose the dhcpd.conf file contains the following definition: subnet 192.168.2.0 netmask 255.255.255.0 { host test_machine { hardware ethernet 00:D0:B7:A6:FC:25; fixed-address 192.168.2.10; filename "/rx6000/elilo.efi"; option domain-name "mydomain.com"; option host-name "test_machine"; option routers 192.168.2.1; option subnet-mask 255.255.255.0; } } Elilo will be downloaded from /tftpboot/rx6000. Then elilo will look for all the other files it needs in /tftpboot/rx6000. This rule is applied to all files, including the all the variation of the config file. b/ Getting the config file With DHCP, elilo will first try to download its configuration file. It will try several file names and they are as follows: 1) AABBCCDD.conf where AABBCCDD is the hexadecimal representation of the IP address assigned to the machine by DHCP. The hexadecimal string (AABBCCDD) MUST use upper case characters. This filename is an opportunity to specify a machine specific configuration file. 2) AA[BB[CC]][-ia32|ia64|x86_64].conf As of version 3.5, elilo will also look for IPv4 class A,B,C subnet-specific versions of the config file. This is useful when you want to have a common config file for all machines connected to a particular subnet. For example, if your IP address is 10.0.0.1 (0A000001 in hex), elilo will look first for 0A000001.conf, then 0A0000.conf, then 0A00.conf, and finally 0A.conf. Elilo will also try architecture-specific versions of subnet-specific config files first (So for example, on an Itanium system, "0A0000-ia64.conf" will be tried before "0A0000.conf") 3) elilo-ia32.conf, elilo-x86_64.conf, or elilo-ia64.conf Depending on the machine (client side) architecture elilo will try the matching architecture specific filename. This filename is an opportunity to specify a architecture specific configuration file. This distinction between the architectures is useful when the same TFTP server services the three types of clients : ia32, x86_64, and ia64 machines. 4) elilo.conf All files use the same format. Elilo will stop at the first match. In case no file is found, it will try to download a default kernel file name (vmlinux). c/ Getting the kernel The second request from elilo is typically the kernel image. The filename is based on what is in the elilo config file. The path name depends on how the TFTP server is configured. For security reasons it is customary to have the server do a change root in /tftpboot. Hence filenames are relative to /tftpboot and therefore you don't need to specify it. For instance if elilo.conf contains: image=vmlinuz.249 label=linux-up root=/dev/sdb2 and the user selects linux-up, then elilo will request a filename of 'vmlinux.249' which must therefore be in /tftpboot. Check the configuration of your TFTP server for more on this. d/ Getting the initial ramdisk This step is optional. It follows exactly the same naming rules explained for the kernel image. The initial ramdisk file must therefore be somewhere under /tftpboot. For instance if elilo.conf contains: image=vmlinuz.249 label=linux-up root=/dev/sdb2 initrd=ramdisk/initrd.249 and the user selects linux-up, then elilo will request a filename of 'ramdisk/initrd.249' which must therefore be under /tftpboot. e/ Getting IP address information When elilo is netbooted, the network filesystem module initializes some elilo variables with the information it received from the DHCP server. At a minimum, it received the IP address. The following information is stored in the elilo variables indicated below: - assigned IP address -> %I - assigned netmask -> %M - assigned domainname -> %D - assigned gateway -> %G These variables can be used to dynamically adjust the command line arguments passed to the kernel. See section 5/ below for an example. 3/ Netbooting using PXE EFI has builtin support for PXE. In fact it first tries PXE and then default to DHCP when it does not find a valid PXE server. There is a PXE server package available from Linux/ia32 however this package does not have the necessary extensions to talk to the EFI side, at least on IA-64 platforms. There is no need for special options or compile time flags to get elilo to work with PXE instead of standard DHCP. When netbooted, elilo will automatically detect if it has been downloaded via PXE or DHCP and it will adujst how subsequent files are requested. You need a special version of the DHCPD server developed by the Internet Software Consortium (http://www.isc.org) with a special patch to add the PXE extensions. Unfortunately as of version 3.0xx, the patch has not yet made it into the official tree. It is supposed to show up in version 3.1 of the dhcpd server. In any case, the elilo package contains a simple example of how you can configure the /etc/dhcpd.conf file for a PXE-aware DHCP server using the extensions provided in the patch. You can look in examples/dhcpd-pxe.conf. The syntax is very different from a standard dhcpd server. The key elements to keep in mind are the PXE layers used by elilo to request the different files: Layer 0 : to get the name of the boot loader (elilo.efi) Layer 1 : to get the name of the elilo config file Layer 2 : to get the name of the kernel image There is an IMPORTANT distinction between those layers. The first two (0,1) and requested systematically whereas the last one is used only when the configuration file is not found, i.e., what is the default kernel to boot. The actual files are STILL downloaded via TFTP. Therefore the TFTP server must also be configured (see previous section for more on this). a/ Getting the config file In this mode, elilo use the PXE layer 1 to get the config file to use. Therefore this must be set on the server side. Elilo will use the following sequence when looking for a config file: - use the name provide by the PXE server Layer 1 or - elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or - elilo.conf Elilo stops at the first match. With PXE, elilo does not try to download a config file named after the assigned IP address as it does for DHCP because there is enough flexibility in the PXE server configuration to do this. b/ Getting the kernel image When there is no config file, elilo will use the kernel name returned by PXE layer 2. If it is not specified there, then it default to 'vmlinux'. c/ Getting the initial ramdisk The filename for the ramdisk MUST come from the config file. Elilo does not use a PXE layer to ask for a default name. d/ Getting IP address information When elilo is netbooted, the network filesystem module initializes some elilo variables with the information it received from the DHCP server. At a minimum, it received the IP address. The following information is stored in the variables indicated below: - assigned IP address -> %I - assigned netmask -> %M - assigned domainname -> %D - assigned gateway -> %G These variables can be used to dynamically adjust the command line arguments passed to the kernel. See section 5/ below for an example of how to use the variable. 4/ Netbooting and using a local root filesystem This is the simplest configuration where the boot loader, its config file, the kernel and its optional initial ramdisk are downloaded from the network BUT the kernel uses the local disk for its root filesystem. For such configuration there is no special option necessary in the elilo config file. You simply need to specify which partition is the root partition. A typical elilo.conf would look as follows: image=vmlinuz.249 label=linux-up root=/dev/sdb2 initrd=ramdisk/initrd.249 5/ Netbooting a diskless machine In this configuration we do not use the local machine's disks but instead rely on a remote server to provide the root filesystem via NFS. a/ Prerequisites By default most kernels shipped by distributors do not have the support compiled in for such configuration. This means that you need to recompile your own kernel. For instance, vmlinuz-2.4.9 as shipped in Redhat7.2 on both ia32 and ia64 platforms does not have the support builtin. To get this configuration to work, you need to have a kernel compiled such that it accepts a root filesystem over NFS (CONFIG_ROOT_NFS). This necessitates that the network stack be configured with the, so called, IP plug-and-play support (CONFIG_IP_PNP). b/ On the server side You need to have: - a NFS file server to provide the root filesystem. - a DHCP/PXE server to get the IP address and download the boot loader. Note that both do not need to be on the same machine. There is no special DHCP/PXE configuration option required to get this working. All you need is a kernel compiled with the options mentioned in a/. You also need to make sure that the permission on the NFS server are set appropriately to allow root access from the client machine (no_root_squash), see man 'exports' for more on this. c/ The elilo configuration file To boot successfully, the kernel needs to: - get an IP address and related networking parameters - contact the NFS server to get its root filesystem The 2.4.x kernel series provides several options to get the IP address: - it can do an internal DHCP request (CONFIG_IP_PNP_DHCP) - it can do an internal RARP request (CONFIG_IP_PNP_RARP) - it can do an internal BOOTP request (CONFIG_IP_PNP_BOOTP) - it can get the IP address from the command line The choice is up to you but it is a little bit stupid to go through a DHCP/BOOTP/RARP phase again when this is already done by the EFI firmware. So in this document, we describe how you can pass the information provided by EFI on the command line of the kernel. The syntax used to pass IP information on the command line is described in the kernel source tree in Documentation/nfsroot.txt. The option is called "ip=" and has the following syntax: ip=:::::: To designate the NFS server, you must use the "nfsroot=" option. It has the following syntax: nfsroot=[:][,] Depending on how you want your system configured you can hardcode the values of the parameters in the elilo configuration file. For instance: image=/vmlinuz label=nfsroot description="kernel with NFS root" append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=192.168.2.5::192.168.2.1:255.255.255.0:test_machine:eth0:on" Note the root=/dev/nfs indicates that the root filesystem is over NFS. This example works fine however, it is not very flexible because the IP address, the gateway, netmask and hostname are fixed and do not used the values EFI used to download the boot loader and the kernel. Elilo provides a way to dynamically customize the parameters passed on the command line using substitution variables. We describe those variables in elilovar.txt. The basic idea is to allow the parameters to use the dynamic information obtained by the DHCP/PXE phase. The network support in elilo defines several variables which contained network related information produced by the DHCP/PXE phase. The set of variable is: %I -> the IP address obtained by DHCP/PXE %M -> the netmask obtained by DHCP/PXE %G -> the gateway obtained by DHCP/PXE %H -> the hostname obtained by DHCP/PXE %D -> the domain name obtained by DHCP/PXE So, the configuration file can then be customized as follows: image=/vmlinuz label=nfsroot description="kernel with NFS root" append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=%I::%G:%M:%H:eth0:on" Not all parameters are necessary or even used by the kernel or the user level configuration scripts. There is no variable to substitute the NFS server or the mount point on that server. In the case of a DHCP boot, this type of customization makes sense only for the shared configuration file, elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or elilo.conf. The configuration file based on the IP address (such as C0A80205.conf in this case) would provide another way of customizing parameters for a specific client (IP address). The same thing holds if the name of the config file returned by the PXE server is specific to a client. 6/ References More information on the PXE protocol can be found at the following web site: http://developer.intel.com/ial/wfm/ The source code for the standard and (possibly) PXE-enhanced DHCPD can be downloaded from: http://www.isc.org/ ./elilo/docs/elilo.txt0000644000175000017500000005012310650210516014433 0ustar jasonfjasonf -------------------------------------------------------------------- ELILO.EFI: Linux boot loader for EFI/IA-64,EFI/IA-32 and EFI/x86_64 based systems -------------------------------------------------------------------- Stephane Eranian August 2003 Copyright (C) 2000-2003 Hewlett-Packard Co. Copyright (C) 2006-2010 Intel Co. I/ Introduction ------------ This document describes how to use ELILO on for IA-64, IA-32 and x86_64 EFI-based platforms. This document describes ELILO version 3.7. II/ Command line options -------------------- elilo [-hDpPVvaE] [-d nsec] [-C config] [-i initrd] [-c chooser] [kernel [kernel options...]] -h Display a list of all possible command line options. -V Print the version number and exit. -d nsec Specify the number of 10th of seconds before loading the kernel. -C file Specify the config file to use. The default is elilo.conf in the directory that elilo.efi was loaded from. -P Verify config file syntax only. this option causes ELILO to parse the config file and generate a report on the console. No kernel is loaded. -v Turn on verbose mode. ELILO prints more message about what it is doing. For each occurrence of this option the verbosity level is increased by one. The maximum level is 5. -a Always check for alternate kernel image. The default behavior of ELILO is to NOT look for an alternate image. This option overrides this behavior and ELILO is checking for alternate images no matter what. Alternate images are specified using the EliloAlt EFI variable. -p force interactive prompt mode. Valid when no kernel image is specified on the command line. -D print debug output. -E don't force EDD30 variable to TRUE when FALSE. -i file Use file as the initial ramdisk (initrd). -c name Specify which kernel chooser to use. Default is 'simple', and the only other choice at present is 'textmenu'. In addition, elilo supports platform specific options: For IA-64: ---------- -r the kernel image can be relocated if initial load address is not available. This options requires a special version of the kernel. -F file will try to load the FPSWA driver indicated by 'file'. Only this file will be attempted. When no specific file is given, elilo will try loading \efi\intel firmware\fpswa.efi from all accessible EFI system partitions. For IA-32: ---------- no option defined. All file names (including the kernel file) can include a device name using the following syntax: dev_name:/path/to/my/kernel The 'dev_name' component depends on the naming scheme selected and the detected devices for your system. Some choosers may print the information automatically or on demand, see chooser specific documentation for more on this. See README.devschemes for more information on device naming schemes. The slash character '/' can be used as a directory separator on any file systems including the EFI file system (FAT32). For x86_64: ---------- No new options. III/ Configuration File ------------------ ELILO supports a config file with options similar to the LILO/x86 boot loader. Elilo will use the following sequence (shown in order) when looking for its config file when none is specified on the command line: 1/ AABBCCDD.conf (netbooting with regular DHCP) where AABBCCDD is the hexadecimal representation of the IP address assigned during the DHCP phase. 2/ elilo-ia64.conf or elilo-ia32.conf or elilo-x86_64.conf The choice depends on the client platform. This step allows the same DHCP/PXE server to provide files for both types of clients. 3/ elilo.conf Unless explicitly specified on the command line, elilo looks for its config file in the filesystem and directory it was loaded from. For instance, if elilo.efi is invoked as: fs0:\> \efi\debian\elilo.efi Then elilo will look for its configuration file in fs0:\efi\debian and not in the root directory of fs0:. The prefix fs0:\efi\debian will be used for all other files that elilo needs to download when their paths are specified as being relative. IMPORTANT: This rule also applies when a specific config file is passed via the -C option. For example: fs0:\> \efi\debian\elilo.efi -C elilo.conf This will look for elilo.conf in fs0:\efi\debian and not in fs0:\. To get to the elilo.conf in fs0:\, you need to specify the absolute path: fs0:\> \efi\debian\elilo.efi -C \elilo.conf The configuration file is an ASCII file and not a UNICODE file. The config file contains additional options to change the behavior of the loader. If the same option is specified in the config file AND on the command line, the latter takes precedence. Not all options available in the config file have an equivalent on command line. When elilo is invoked with the -h option, it prints the list of support command line options but also the list of config file options. For each option it also prints the type of data expected. The config file options are divided in 2 groups: - image options which are specific to a particular kernel image. Each kernel image must be identified with a logical name called a label. - global options which affect the behavior of ELILO and apply to all images. The ELILO config file follows the LILO/x86 syntax. First come the global options, then the list of images and options for each of them, if necessary. At least one image MUST be defined and it is possible to have an empty list of global options. Options have types. Three types are defined: - boolean: set or not set - string : a string of characters which can be quoted if necessary - number (in decimal) - filename: a string interpreted as a file name The config file supports the following options: Global Options: --------------- default=value Name the default image to boot. If not defined ELILO will boot the first defined image. timeout=number The number of 10th of seconds to wait while in interactive mode before auto booting default kernel. Default is infinity. delay=number The number of 10th of seconds to wait before auto booting when not in interactive mode. Default is 0. prompt Force interactive mode verbose=number Set level of verbosity [0-5]. Default 0 (no verbose) root=filename Set global root filesystem for Linux/ia64 read-only Force root filesystem to be mounted read-only append=string Append a string of options to kernel command line initrd=filename Name of initrd file image=filename Define a new image chooser=name Specify kernel chooser to use: 'simple' or 'textmenu'. message=filename a message that is printed on the main screen if supported by the chooser. fX=filename Some choosers may take advantage of this option to display the content of a file when a certain function key X is pressed. X can vary from 1-12 to cover function keys F1 to F12. noedd30 do not force the EDD30 EFI variable to TRUE when FALSE. In other words, don't force the EDD30 mode if not set. Image options: -------------- root=filename Set root filesystem for kernel read-only Force root filesystem to be mounted read-only append=string Append a string of options to kernel command line initrd=filename Name of initrd file label=string Logical name of image (used in interactive mode) description=string One line text description of the image. IA-64 specific options: ----------------------- Global options: --------------- fpswa=file Specify the filename for a specific FPSWA to load. If this option is used then no other file will be tried. relocatable In case of memory allocation error at initial load point of kernel, allow attempt to relocate (assume kernels is relocatable) Image options: -------------- relocatable In case of memory allocation error at initial load point of kernel, allow attempt to relocate (assume this kernel is relocatable) IA-32 specific options: ----------------------- legacy-free Indicate that the host machine does not have a legacy BIOS at all. The user can specify a kernel and related kernel options using the image label. Alternatively, the user can also specify a kernel file that is not specified in the config file. In any case, some of the global options (such as append) are always concatenated to whatever the user type. x86_64 specific options: ----------------------- None yet. IV/ Booting from the local system ----------------------------- The elilo.efi binary must be in an EFI system partition (FAT32). The config file, kernel image, and optional initrd ramdisk can be on the same partition or even another EFI partition. In the following discussion we assume that all files are on the same EFI partition which is recognized by the EFI shell (nshell) as fs0. The kernel and initrd can be copied from the any linux filesystems to the EFI partition using either the mtools (mcopy) or by mounting the EFI partition as a vfat partition. However you do not really need this because most linux distributions install both files in the EFI partition and mount this partition in /boot/efi. To boot a kernel, simply power cycle the machine. Once you get to the EFI shell prompt, change to the filesystem that maps to the partition where elilo is. Shell> fs0: fs0:\> You might need to make sure that the Shell Path is set such that it will load ELILO from fs0:. You can verify this by typing: fs0:\> set path : fs0:\ At this point you can invoke ELILO: fs0:\> elilo If there is no config file, then it will: - pick up the kernel image named vmlinux if it exists, otherwise it will abort. - pass no argument to the kernel. You can specify the kernel image and its options on the command line. For instance you can do: fs0:\> elilo vmlinux root=/dev/sda5 You can specify as many parameters as you want. The syntax follows the kernel rule, i.e., list of value pairs (or even single values) separated by space. A more complicated example would be: fs0:\> elilo -i initrd-2.4.9 vmlinuz-2.4.9 root=/dev/sda2 console=tty0 console="ttyS0,115200n8" In this example, notice the double quotes. They are required because the comma is a control character for nshell. In the case a config file is found, then elilo will behave according to the options in that file. However if elilo is invoked with command line options, they will be combined or they will override (if conflicting) what is defined in the config file. As of version 3.3, elilo is fully compliant with the EFI specification (1.10) with regards to where the bootloader (elilo.efi) must be located in the EFI system partition. In section 11.2.1.3 of the EFI1.10 specification, it is said that in order to avoid conflicts between various loaders for various OSes or distributions of the same OS, every vendor MUST use a dedicated directory: \EFI\vendor\. The bootloader must be placed in this directory. This has always been possible as this is a matter of creating the directory and copying the elilo.efi file in it. However up until version 3.3, elilo would look for its config file and kernel/initrd in the root (/) of the partition it was loaded from. As of version 3.3, elilo will now ONLY look for its configuration file FROM THE DIRECTORY IT WAS LOADED FROM. The same applies to the kernel and initrd files unless absolute paths are specified. Let us look at a simple example: - suppose elilo.efi is in \EFI\DIST if fs0: (for the EFI Shell) - if you invoke elilo as follows: fs0:\> \efi\dist\elilo -v -p default file path: \efi\dist\ config file : \efi\dist\elilo.conf ELILO boot: Note that this is the same if you invoke elilo directly from \efi or \efi\dist. File references in the configuration file are treated as relative to the directory elilo was loaded from except if they use an absolute path. As of version 3.4 a similar rule applies to the network boot sequence, see netbooting.txt for details. V/ Interactive mode ---------------- Elilo can be forced into interactive mode using the "prompt" option in the config file or with the -p option. In this mode, the user can select a kernel to load. The interface depends on the chooser, it may be a simple command line prompt as provided by the simple chooser or a more sophisticated screen with scroll menus as provided by textmenu. Most choosers depends on the elilo config file to get the information they display. The simple chooser can operated without the elilo config file. However it is always better to have this file, to create handy logical names for each possible boot choices. The logical names are specified with the "label" option in the config file. They represent a specific kernel "image" and its specific options. In elilo, the user can select a particular kernel image using the corresponding label name. A simple example is as follows: If we suppose that the following is defined in elilo.conf: image=vmlinuz-2.4.9 label=linux-up initrd=initrd-2.4.9 root=/dev/sda2 append="console=tty0 console=ttyS0,115200n8" then the user can specify linux-up at the prompt and elilo will load the vmlinuz-2.4.9 kernel file and the initrd-2.4.9 ramdisk and will pass "root=/dev/sda2 console=tty0 console=ttyS0,115200n8" as command line arguments to the kernel. This behavior is identical to Lilo/x86. However, elilo further allows the user to specify actual kernel files names as well, i.e., kernels that are not defined in the configuration file. If we reuse the above example and the simple chooser, the user can type: ELILO boot: vmlinux-2.4.18 root=/dev/sda2 and elilo will boot the vmlinuz-2.4.18 kernel if it exists. VI/ The alternate kernel image -------------------------- Oftentimes when debugging kernels you want to reboot the machine once with your test kernel and, if something goes wrong, you want to fall back to a more stable kernel. In addition you want to be able to do this from a remote machine. Many things can go wrong when doing kernel debugging. It could be that you don't even reach user-mode. In this case however, you still want to fall back to a stable kernel. The feature you'd like from a boot loader is 'boot once and then fall back to safe kernel'. Elilo offers this feature and it's called 'alternate kernel image'. You can configure elilo to load a kernel only once and then whatever happens the next reboot falls back to a different kernel hopefully more stable. To do this, elilo relies on an EFI variable called 'EliloAlt' with a NULL GUID. The content of this variable is a UNICODE string containing the kernel file name and its command line options. When the -a option is specified on the command line or if the "checkalt" option is present in the config file, elilo will check for the presence of this variable. If found and the content is a valid UNICODE string, elilo will use it as the kernel to boot. There is no verification made on the validity of the kernel name or options. Then the variable is deleted. If the variable is rejected because it does not look sane, it is also deleted. The variable can be set from a running Linux system using the /proc/efi/vars interface. In the tools directory of this package, there is a Linux tool called elilovar which can be used to create, modify, print, and delete the EliloAlt variable. Refer to eliloalt.txt for more information on this tool. VII/ Auto booting the machine ----------------------- Once you're satisfied with your machine setup, it is good to install an auto boot procedure. You have two options to do this: - from the EFI boot manager menu - from the EFI shell The first option is preferred and is used by most Linux distributions. Elilo can be invoked directly from the boot manager. You need to get into the 'boot maintenance' menu and use load file a file. This can be tedious so instead it is recommended that you use a Linux tool called efibootmgr which is also shipped in most distributions. With this tool, you can create your own boot option and change the boot order. The second approach use the EFI shell and a shell script with a special name: 'startup.nsh'. When the system boots, it looks for EFI partitions and if it finds a 'startup.nsh' file in ANY of these it will jumpstart execution from it. So the typical way of auto booting your Linux/ia64 system is to simply create such a file with the following content: # cat /boot/startup.nsh elilo vmlinuz root=/dev/sda2 Of course, this can be simplified if there is a configuration file. VII/ Netbooting ---------- Please refer to netbooting.txt for a complete description of how to boot from the network. XII/ Booting on EFI/ia32 platforms ----------------------------- Until PC comes with the EFI firmware built in, you need to boot from a floppy that has the EFI firmware on it. Such floppy can be constructed from the EFI sample implementation and toolkit that is available from the Intel Developer Web site at: http://developer.intel.com/technology/efi/ To use elilo on IA-32, you can put it on a floppy and on a FAT32 partition (msdos partition). You can also netbooting if you network adapter has support for UNDI/PXE. Elilo/ia32 is capable of booting unmodified 2.2.x. and 2.4.x kernels as they are shipped by distributors today (such as Redhat7.2). You don't need to recompile the kernel with special options. Elilo ONLY takes compressed kernel image which are typically obtained via a 'make bzImage'. Plain elf/32 kernel can't be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can be used without modifications. XIII/ Booting on EFI/x86_64 platforms ----------------------------- To use elilo on x86_64, you can put it on a floppy and on a FAT32 partition (msdos partition). You can also netboot if your network adapter has support for UNDI/PXE. Elilo/x86_64 requires efi64 enabled linux kernel (> 2.6.21). You need to compile the kernel with CONFIG_EFI option. x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol and therefore only the Graphics Output Protocol (GOP) is supported. For such platforms, the kernel must be configured with EFI_FB option. This will enable early boot messages on the console. The elilo for x86_64 attempts to query the firmware for GOP and if it fails it defaults to text mode. Elilo ONLY takes compressed kernel image which are typically obtained via a 'make bzImage'. Plain elf/x86_64 kernel can't be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can be used without modifications. The x86_64 implementation converts the EFI memory map into E820 map and passes it in the bootparameter supplied to the OS. For details on bootparameter, see x86_64/sysdeps.h. IX/ Credits ------- Intel Corp. Stephane Eranian David Mosberger Johannes Erdfelt Richard Hirst Chris Ahna Mike Johnston Fenghua Yu Bibo Mao Chandramouli Narayanan X/ Bug reports ----------- You can submit bugs to or to the Linux/ia64 mailing list at linux-ia64@linuxia64.org. Visit http://www.linuxia64.org to subscribe to this list. XIII/ Reference --------- UEFI 2.0 specifications are available from the following web site: http://www.uefi.org/home EFI v1.02 specifications are available from the following web site: http://developer.intel.com/technology/efi/ The latest sources of ELILO can be downloaded at: ftp://ftp.hpl.hp.com/pub/linux-ia64 ./elilo/initrd.c0000644000175000017500000000626011466353731013313 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" /* * This function allocates memory for file image and loads it to memory * OUTPUTS: * - ELILO_LOAD_SUCCESS: if everything works * - ELILO_LOAD_ABORTED: in case the user decided to abort loading * - ELILO_LOAD_ERROR: there was an error during alloc/read * * Adapted from Bill Nottingham patch for ELI. */ INTN load_file(CHAR16 *filename, memdesc_t *image) { EFI_STATUS status; /* * Actually using the value from sysdeps_initrd_get_addr() * instead of NULL is no change for ia64! */ VOID *start_addr = image->start_addr; UINTN pgcnt; UINT64 size = 0; fops_fd_t fd; INTN ret = ELILO_LOAD_ERROR; if (filename == NULL || filename[0] == 0) return -1; /* Open the file */ status = fops_open(filename, &fd); if (EFI_ERROR(status)) { ERR_PRT((L"Open file %s failed: %r", filename, status)); return -1; } DBG_PRT((L"open %s worked", filename)); /* warning: this function allocates memory */ status = fops_infosize(fd, &size); if (EFI_ERROR(status)) { ERR_PRT((L"Couldn't read file %s info %r", filename, status)); goto error; } image->size = size; /* round up to get required number of pages (4KB) */ image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size); start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr); start_addr = sysdeps_checkfix_initrd(start_addr, image); if (start_addr == NULL) { ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt, filename)); goto error; } VERB_PRT(2, Print(L"%s image: total_size: %d bytes base: " PTR_FMT " " "pages %d\n", filename, image->size, start_addr, pgcnt)); Print(L"Loading file %s...", filename); ret = read_file(fd, image->size, start_addr); fops_close(fd); if (ret != ELILO_LOAD_SUCCESS) { ERR_PRT((L"read image(%s) failed: %d", filename, ret)); goto error; } Print(L"done\n"); image->start_addr = start_addr; return ELILO_LOAD_SUCCESS; error: if (start_addr) free(start_addr); /* * make sure nothing is passed to kernel * in case of error. */ image->start_addr = 0; image->pgcnt = 0; image->size = 0; return ret; } ./elilo/Makefile0000644000175000017500000000503611466353142013312 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # Contributed by Fenghua Yu # Contributed by Chandramouli Narayanan # # This file is part of ELILO, the LINUX EFI 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 Make.defaults TOPDIR=. CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) FORMAT = efi-app-$(ARCH) FILESYSTEM = ifeq ($(CONFIG_localfs),y) FILESYSTEMS += glue_localfs.o endif ifeq ($(CONFIG_ext2fs),y) FILESYSTEMS += glue_ext2fs.o endif ifeq ($(CONFIG_netfs),y) FILESYSTEMS += glue_netfs.o endif SUBDIRS = fs choosers devschemes tools ifeq ($(ARCH),ia64) SUBDIRS += ia64 endif ifeq ($(ARCH),ia32) SUBDIRS += ia32 endif ifeq ($(ARCH),x86_64) SUBDIRS += x86_64 endif FILES = elilo.o getopt.o strops.o loader.o \ fileops.o util.o vars.o alloc.o chooser.o \ config.o initrd.o alternate.o bootparams.o \ gunzip.o console.o fs/fs.o \ choosers/choosers.o \ devschemes/devschemes.o \ $(ARCH)/sysdeps.o \ $(FILESYSTEMS) TARGETS = elilo.efi all: check_gcc $(SUBDIRS) $(TARGETS) elilo.efi: elilo.so elilo.so: $(FILES) elilo.o : elilo.c $(ARCH)/sysdeps.h fileops.o : Make.defaults chooser.o : Make.defaults $(SUBDIRS): dummy $(MAKE) -C $@ dummy: clean: @set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done rm -f $(TARGETS) *~ *.so $(FILES) .PRECIOUS: elilo.so # # on both platforms you must use gcc 3.0 or higher # check_gcc: ifeq ($(GCC_VERSION),2) @echo "you need to use a version of gcc >= 3.0, you are using `$(CC) --version`" @exit 1 endif include Make.rules ./elilo/Make.defaults0000644000175000017500000000656511512672232014264 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # Contributed by Chandramouli Narayanan # # This file is part of ELILO, the LINUX EFI 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. # # # File system selection. At least one filesystem must be enabled # CONFIG_localfs=y CONFIG_netfs=y # # WARNING WARNING WARNING # # Use this option with caution. This filesystem module does not # support ext3 formatted partitions, i.e., it does not know how # to recover from failures (ignores the log). # CONFIG_ext2fs=n # # Chooser selection(at least one must be defined) # CONFIG_chooser_simple=y CONFIG_chooser_textmenu=y # # Enable IP-address based config file (elilo.conf) when netbooted # CONFIG_machspec_netconfig=y # # Indicate where the EFI include and libaries are. # They are installed as part of the GNU-EFI package installation # EFIINC = /usr/include/efi GNUEFILIB = /usr/lib EFILIB = /usr/lib EFICRT0 = /usr/lib CDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) TOPDIR = ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I$(TOPDIR)/efi110 CPPFLAGS = -DCONFIG_$(ARCH) OPTIMFLAGS = -O2 DEBUGFLAGS = -Wall CFLAGS = $(OPTIMFLAGS) -fno-stack-protector -fno-strict-aliasing -fpic -fshort-wchar $(DEBUGFLAGS) LDFLAGS = -nostdlib -znocombreloc INSTALL = install ifeq ($(CONFIG_machspec_netconfig),y) CFLAGS += -DENABLE_MACHINE_SPECIFIC_NETCONFIG endif ifeq ($(CONFIG_localfs),y) CFLAGS += -DCONFIG_LOCALFS endif ifeq ($(CONFIG_netfs),y) CFLAGS += -DCONFIG_NETFS endif ifeq ($(CONFIG_ext2fs),y) CFLAGS += -DCONFIG_EXT2FS endif ifeq ($(CONFIG_chooser_simple),y) CFLAGS += -DCONFIG_CHOOSER_SIMPLE endif ifeq ($(CONFIG_chooser_textmenu),y) CFLAGS += -DCONFIG_CHOOSER_TEXTMENU endif prefix = /usr/bin/ # Redhat 8.0 ia32 gcc-3.x version is reported to produce working EFI binaries. # Redhat 9.0 ia32 gcc-3.x version is reported to produce BAD binaries. CC = $(prefix)gcc AS = $(prefix)as LD = $(prefix)ld AR = $(prefix)ar RANLIB = $(prefix)ranlib OBJCOPY = $(prefix)objcopy # Use Modified binutils that supports x86_64 using UEFI ABI ifeq ($(ARCH), x86_64) CFLAGS += -DEFI_FUNCTION_WRAPPER OBJCOPY = /usr/bin/objcopy endif ifeq ($(ARCH),ia64) GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') ifneq ($(GCC_VERSION),2) CFLAGS += -frename-registers endif # EFI specs allows only lower floating point partition to be used CFLAGS += -mfixed-range=f32-f127 endif ./elilo/alloc.c0000644000175000017500000001412211466353731013110 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #define NALLOC 512 typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t; typedef struct _alloc_entry { struct _alloc_entry *next; struct _alloc_entry *prev; VOID *addr; UINTN size; /* bytes for pool, page count for pages */ alloc_types_t type; } alloc_entry_t; static alloc_entry_t allocs[NALLOC]; static alloc_entry_t *free_allocs, *used_allocs; static VOID *kmem_addr; static UINTN kmem_pgcnt; /* * initializes the free list which is singly linked */ INTN alloc_init(VOID) { UINTN i; for(i=0; i < NALLOC-1; i++) { allocs[i].next = allocs+i+1; } allocs[i].next = NULL; free_allocs = allocs; used_allocs = NULL; return 0; } static VOID alloc_add(VOID * addr, UINTN size, alloc_types_t type) { alloc_entry_t *alloc; /* remove from freelist */ alloc = free_allocs; free_allocs = free_allocs->next; alloc->prev = NULL; alloc->next = used_allocs; alloc->addr = addr; alloc->type = type; alloc->size = size; /* add to used list */ if (used_allocs) used_allocs->prev = alloc; used_allocs = alloc; } VOID * alloc(UINTN size, EFI_MEMORY_TYPE type) { EFI_STATUS status; VOID *tmp = 0; /* no more free slots */ if (free_allocs == NULL) { ERR_PRT((L"allocator: no more slots\n")); return NULL; } if (type == 0) type = EfiLoaderData; status = uefi_call_wrapper(BS->AllocatePool, 3, type, size, &tmp); if (EFI_ERROR(status)) { ERR_PRT((L"allocator: AllocatePool(%d, %d) failed (%r)\n", type, size, status)); return NULL; } alloc_add(tmp, size, ALLOC_POOL); #ifdef DEBUG_MEM DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]", size, tmp, tmp+size)); #endif return tmp; } /* * no possibility to partially free an allocated group of pages */ VOID * alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr) { EFI_STATUS status; EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr; /* no more free slots */ if (free_allocs == NULL) { ERR_PRT((L"allocator: no more slots\n")); return NULL; } status = uefi_call_wrapper(BS->AllocatePages, 4, where, type , pgcnt, &tmp); if (EFI_ERROR(status)) { VERB_PRT(1, Print(L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status)); return NULL; } /* XXX: will cause warning on IA-32 */ addr = (VOID *)tmp; alloc_add(addr, pgcnt, ALLOC_PAGES); DBG_PRT((L"allocator: allocated %d pages @" PTR_FMT, pgcnt, tmp)); return addr; } /* * free previously allocated slot */ VOID free(VOID *addr) { alloc_entry_t *p; /* find allocation record */ for(p=used_allocs; p ; p = p->next) { if (p->addr == addr) goto found; } /* not found */ VERB_PRT(1, Print(L"allocator: invalid free @ " PTR_FMT "\n", addr)); return; found: #ifdef DEBUG_MEM DBG_PRT((L"free: %s @" PTR_FMT " size=%d", p->type == ALLOC_POOL ? L"Pool": L"Page", addr, p->size)); #endif if (p->type == ALLOC_POOL) uefi_call_wrapper(BS->FreePool, 1, addr); else uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)addr, p->size); /* remove from used list */ if (p->next) p->next->prev = p->prev; if (p->prev) p->prev->next = p->next; else used_allocs = p->next; /* put back on free list */ p->next = free_allocs; free_allocs = p; } /* * garbage collect all used allocations. * will put the allocator in initial state */ VOID free_all(VOID) { alloc_entry_t *tmp; while(used_allocs) { #ifdef DEBUG_MEM DBG_PRT((L"free_all %a @ " PTR_FMT, used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr)); #endif if (used_allocs->type == ALLOC_POOL) uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr); else uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size); tmp = used_allocs->next; /* put back on free list */ used_allocs->next = free_allocs; free_allocs = used_allocs; used_allocs = tmp; } } INTN alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt) { void * tmp; /* * During "AllocateAnyPages" *start_addr will be ignored. * Therefore we can safely subvert it to reuse this function with * an alloc_kmem_anyhwere_below() semantic... */ tmp = alloc_pages(pgcnt, EfiLoaderData, (*start_addr) ? AllocateMaxAddress : AllocateAnyPages, *start_addr); if (tmp == NULL) return -1; kmem_addr = tmp; kmem_pgcnt = pgcnt; *start_addr = tmp; return 0; } INTN alloc_kmem(VOID *start_addr, UINTN pgcnt) { if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1; kmem_addr = start_addr; kmem_pgcnt = pgcnt; return 0; } VOID free_kmem(VOID) { #ifdef DEBUG_MEM DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); #endif if (kmem_addr && kmem_pgcnt != 0) { free(kmem_addr); kmem_addr = NULL; kmem_pgcnt = 0; } #ifdef DEBUG_MEM DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); #endif } VOID free_all_memory(VOID) { free_all(); free_kmem(); } ./elilo/glue_localfs.h0000644000175000017500000000215107720452050014451 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __GLUE_LOCALFS_H__ #define __GLUE_LOCALFS_H__ #include "fileops.h" extern fileops_fs_t localfs_glue; #endif /* __GLUE_LOCALFS_H__ */ ./elilo/choosers/0000755000175000017500000000000011513632716013473 5ustar jasonfjasonf./elilo/choosers/simple.h0000644000175000017500000000214707720451647015150 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_CHOOSER_SIMPLE_H__ #define __ELILO_CHOOSER_SIMPLE_H__ #include "fileops.h" extern chooser_t simple_chooser; #endif ./elilo/choosers/Makefile0000644000175000017500000000260511466353142015136 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES= ifeq ($(CONFIG_chooser_simple),y) FILES +=simple.o endif ifeq ($(CONFIG_chooser_textmenu),y) FILES +=textmenu.o endif TARGET=choosers.o all: $(TARGET) $(TARGET): $(TOPDIR)/Make.defaults $(FILES) @if [ -z "$(FILES)" ]; then \ echo "You need to define at least one chooser in Make.defaults"; \ exit 1; \ fi $(LD) -o $@ -r $(FILES) clean: $(RM) -f $(TARGET) $(FILES) ./elilo/choosers/textmenu.c0000644000175000017500000003405711466353221015517 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Richard Hirst * 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 * 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 #include #include "elilo.h" #include "console.h" #define MAX_LABELS 64 #define MSGBUFLEN 4096 static UINT8 msgbuf[MSGBUFLEN]; static CHAR16 *labels[MAX_LABELS]; static CHAR16 *descriptions[MAX_LABELS]; static INTN nlabels; static INTN CursorRow, CursorCol, PromptRow, PromptCol; static INTN MenuRow, MenuCol, MenuWidth, MenuHeight; static INTN DisplayParsed, CurrentAttr, PromptAttr; static INTN PromptWidth, MenuHiAttr, MenuLoAttr; static INTN PromptLen, MenuActive, MenuFirst; static CHAR16 PromptBuf[CMDLINE_MAXLEN]; #define DEF_ATTR EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK) #define ClearScreen() uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut) #define SetTextAttr(a) uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, a) static INTN tohex(INTN c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'A' && c <= 'F') return c = c - 'A' + 10; else if (c >= 'a' && c <= 'f') return c = c - 'a' + 10; else return 16; } static VOID paint_msg(UINT8 *msg) { INTN c; CursorCol = CursorRow = 0; CurrentAttr = DEF_ATTR; SetTextAttr(CurrentAttr); ClearScreen(); while ((c = *msg++)) { /* First map VGA to EFI line drawing chars */ if (c == 0xda) c = BOXDRAW_DOWN_RIGHT; else if (c == 0xc4) c = BOXDRAW_HORIZONTAL; else if (c == 0xbf) c = BOXDRAW_DOWN_LEFT; else if (c == 0xb3) c = BOXDRAW_VERTICAL; else if (c == 0xd9) c = BOXDRAW_UP_LEFT; else if (c == 0xc0) c = BOXDRAW_UP_RIGHT; else if (c == 0xb4) c = BOXDRAW_VERTICAL_LEFT; else if (c == 0xc3) c = BOXDRAW_VERTICAL_RIGHT; else if (c == 0x1e) c = GEOMETRICSHAPE_UP_TRIANGLE; else if (c == 0x1f) c = GEOMETRICSHAPE_DOWN_TRIANGLE; else if (c > 0x7f) c = '?'; /* Now print the printable chars, then process controls */ if (c >= ' ') { Print(L"%c", c); CursorCol++; } else { switch (c) { case '\r': /* Ignore CR */ break; case '\n': /* LF treated as cr/lf */ CursorRow++; CursorCol = 0; Print(L"\n"); break; case 0x0c: /* FF - Clear screen */ CursorCol = CursorRow = 0; ClearScreen(); break; case 0x0f: /* ^O - Attributes */ if (msg[0] && msg[1]) { INTN bg = tohex(*msg++); INTN fg = tohex(*msg++); if (bg < 16 || fg < 16) { CurrentAttr = EFI_TEXT_ATTR(fg, bg); SetTextAttr(CurrentAttr); } } break; case 0x01: /* ^A - Prompt */ if (!DisplayParsed) { if (!PromptRow) { PromptRow = CursorRow; PromptCol = CursorCol; PromptAttr = CurrentAttr; } else if (!PromptWidth) PromptWidth = CursorCol - PromptCol; /* else bad syntax */ } break; case 0x02: /* ^B - Menu */ if (!DisplayParsed) { if (!MenuRow) { MenuRow = CursorRow; MenuCol = CursorCol; MenuLoAttr = CurrentAttr; } else if (!MenuWidth) { MenuWidth = CursorCol - MenuCol; MenuHeight = CursorRow - MenuRow + 1; MenuHiAttr = CurrentAttr; } /* else bad syntax */ } break; default: Print(L"?"); CursorCol++; } } } } static VOID paint_prompt(VOID) { INTN offset = PromptLen > PromptWidth - 1 ? PromptLen - PromptWidth + 1: 0; SetTextAttr(PromptAttr); PrintAt(PromptCol, PromptRow, L"%s%s", PromptBuf + offset, L" \b"); SetTextAttr(CurrentAttr); } static VOID paint_menu(VOID) { INTN i, j; for (i = 0; i < MenuHeight; i++) { INTN attr = (i + MenuFirst == MenuActive) ? MenuHiAttr: MenuLoAttr; CHAR16 description[80]; for (j = 0; j < MenuWidth; j++) description[j] = ' '; description[MenuWidth] = '\0'; if (i + MenuFirst < nlabels) { for (j = 0; descriptions[i + MenuFirst][j] && j < MenuWidth; j++) description[j+1] = descriptions[i + MenuFirst][j]; } SetTextAttr(attr); PrintAt(MenuCol, MenuRow + i, L"%-.*s", MenuWidth, description); SetTextAttr(CurrentAttr); } paint_prompt(); } static INTN read_message_file(INTN msg, UINT8 *buf, UINTN max) { CHAR16 *filename; fops_fd_t message_fd; EFI_STATUS status; UINTN len = max; if (msg > 10) return 0; if ((filename = get_message_filename(msg)) == NULL) { VERB_PRT(3, Print(L"no message file specified\n")); return 0; } VERB_PRT(3, Print(L"opening message file %s\n", filename)); status = fops_open(filename, &message_fd); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"message file %s not found\n", filename)); return 0; } status = fops_read(message_fd, buf, &len); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"Error reading message file\n")); len = 0; } fops_close(message_fd); VERB_PRT(3, Print(L"done reading message file %s\n", filename)); return len; } /* * interactively select a kernel image and options. * The kernel can be an actual filename or a label in the config file * Return: * -1: if unsucessful * 0: otherwise */ static INTN select_kernel(CHAR16 *label, INTN lsize) { #define CHAR_CTRL_C (L'\003') /* Unicode CTRL-C */ #define CHAR_CTRL_D (L'\004') /* Unicode CTRL-D */ #define CHAR_CTRL_F (L'\006') /* Unicode CTRL-F */ #define CHAR_DEL (L'\177') /* Unicode DEL */ SIMPLE_INPUT_INTERFACE *ip = systab->ConIn; EFI_INPUT_KEY key; EFI_STATUS status; INT8 first_time = 1; INTN i; INT8 fn = 0; reprint: i = read_message_file(0, msgbuf, MSGBUFLEN-1); msgbuf[i] = 0; paint_msg(msgbuf); DisplayParsed = 1; paint_menu(); CurrentAttr = PromptAttr; SetTextAttr(CurrentAttr); for (;;) { while ((status = uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key)) == EFI_NOT_READY); if (EFI_ERROR(status)) { SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)); ClearScreen(); ERR_PRT((L"select_kernel readkey: %r", status)); return -1; } if (key.UnicodeChar == CHAR_CTRL_F) { fn = 1; continue; } if (fn) { if (key.UnicodeChar >= '0' && key.UnicodeChar <= '9') { if (key.UnicodeChar == '0') key.ScanCode = SCAN_F10; else key.ScanCode = SCAN_F1 + key.UnicodeChar - '1'; key.UnicodeChar = 0; } fn = 0; } if (key.ScanCode == SCAN_UP) { if (MenuActive) MenuActive--; else continue; if (MenuActive < MenuFirst) MenuFirst = MenuActive; paint_menu(); continue; } else if (key.ScanCode == SCAN_DOWN) { if (MenuActive < nlabels - 1) MenuActive++; else continue; if (MenuActive >= MenuFirst + MenuHeight) MenuFirst = MenuActive - MenuHeight + 1; paint_menu(); continue; } else if (key.ScanCode >= SCAN_F1 && key.ScanCode <= SCAN_F10) { i = read_message_file(key.ScanCode - SCAN_F1 + 1, msgbuf, MSGBUFLEN-1); if (i) { msgbuf[i] = 0; paint_msg(msgbuf); while ((status= uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key)) == EFI_NOT_READY); goto reprint; } } switch (key.UnicodeChar) { /* XXX Do we really want this in textmenual mode? */ case L'?': Print(L"\n"); print_devices(); first_time = 0; goto reprint; case CHAR_BACKSPACE: case CHAR_DEL: if (PromptLen == 0) break; PromptLen--; PromptBuf[PromptLen] = 0; if (PromptLen >= PromptWidth-2) paint_prompt(); else Print(L"\b \b"); break; case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: StrCpy(label, labels[MenuActive]); SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)); ClearScreen(); return 0; default: if ( key.UnicodeChar == CHAR_CTRL_D || key.UnicodeChar == CHAR_CTRL_C) { SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)); ClearScreen(); Print(L"\nGiving up then...\n"); return -1; } if (key.UnicodeChar == CHAR_NULL) break; if (PromptLen > CMDLINE_MAXLEN-1) break; if (key.UnicodeChar < ' ' || key.UnicodeChar > 0x7e) key.UnicodeChar = '?'; PromptBuf[PromptLen++] = key.UnicodeChar; PromptBuf[PromptLen] = 0; /* Write the character out */ if (PromptLen >= PromptWidth-1) paint_prompt(); else Print(L"%c", key.UnicodeChar); } } return 0; } INTN textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline) { # define BOOT_IMG_STR L"BOOT_IMAGE=" CHAR16 label[CMDLINE_MAXLEN]; CHAR16 initrd_name[PATHNAME_MAXLEN]; CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; CHAR16 devname[PATHNAME_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *slash_pos, *colon_pos, *backslash_pos; UINTN len; INTN ret; VOID *handle = NULL; /* Clear all static variables, as we might be called more than once */ CursorRow = CursorCol = PromptRow = PromptCol = 0; MenuRow = MenuCol = MenuWidth = MenuHeight = 0; DisplayParsed = CurrentAttr = PromptAttr = 0; PromptWidth = MenuHiAttr = MenuLoAttr = 0; PromptLen = MenuActive = MenuFirst = 0; PromptBuf[0] = CHAR_NULL; nlabels = 0; while (nlabels < MAX_LABELS && (handle = get_next_description(handle, labels + nlabels, descriptions + nlabels))) { if (descriptions[nlabels][0] == 0) descriptions[nlabels] = labels[nlabels]; nlabels++; } restart: vmcode_name[0] = initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL; /* reset per image loader options */ Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt)); if (elilo_opt.prompt) { console_textmode(); ret = select_kernel(label, sizeof(label)); if (ret == -1) return -1; argc = argify(PromptBuf,sizeof(PromptBuf), argv); index = 0; } /* * check for alternate kernel image and params in EFI variable */ if (elilo_opt.alt_check && alternate_kernel(PromptBuf, sizeof(PromptBuf)) == 0) { argc = argify(PromptBuf,sizeof(PromptBuf), argv); index = 0; label[0] = args[0] = initrd_name[0] = vmcode_name[0] = 0; } /* * First search for matching label in the config file * if options were specified on command line, they take * precedence over the ones in the config file * * if no match is found, the args and initrd arguments may * still be modified by global options in the config file. */ if (label[0]) ret = find_label(label, kname, args, initrd_name, vmcode_name); else ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name); /* * not found, so assume first argument is kernel name and * not label name */ if (ret == -1) { if ((index < argc) && argv[index]) StrCpy(kname, argv[index]); else StrCpy(kname, elilo_opt.default_kernel); } /* * no matter what happened for kname, if user specified * additional options, they override the ones in the * config file */ if (label[0]) index--; if (argc > 1+index) { /*StrCpy(args, argv[++index]);*/ while (++index < argc) { StrCat(args, L" "); StrCat(args, argv[index]); } } /* * if initrd specified on command line, it overrides * the one defined in config file, if any */ if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) { StrCpy(elilo_opt.initrd, initrd_name); } if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) { StrCpy(elilo_opt.vmcode, vmcode_name); } VERB_PRT(1, { Print(L"kernel is '%s'\n", kname); Print(L"arguments are '%s'\n", args); if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd); if (elilo_opt.vmcode[0]) Print(L"vmm is '%s'\n", elilo_opt.vmcode); }); if (elilo_opt.prompt == 0) { /* minimal printing */ Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH); ret = wait_timeout(elilo_opt.delay); if (ret != 0) { elilo_opt.prompt = 1; elilo_opt.initrd[0] = elilo_opt.vmcode[0] = CHAR_NULL; elilo_opt.timeout = ELILO_TIMEOUT_INFINITY; goto restart; } } /* * add the device name, if not already specified, * so that we know where we came from */ slash_pos = StrChr(kname, L'/'); backslash_pos = StrChr(kname, L'\\'); colon_pos = StrChr(kname, L':'); if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos; if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) { StrCpy(devname, fops_bootdev_name()); StrCat(devname, L":"); /* the default path is always terminated with a separator */ if (kname[0] != L'/' && kname[0] != L'\\') { fops_getdefault_path(dpath,FILENAME_MAXLEN); StrCat(devname, dpath); } } else { devname[0] = CHAR_NULL; } /* * create final argument list to the kernel */ len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */ +StrLen(devname) /* device name */ +StrLen(kname) /* kernel name */ +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname) +1 /* space */ +StrLen(args); /* args length */ if (len >= CMDLINE_MAXLEN-1) { SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)); ClearScreen(); ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n")); return -1; } StrCpy(cmdline, L"BOOT_IMAGE="); StrCat(cmdline, devname); if (elilo_opt.vmcode[0]) StrCat(cmdline, elilo_opt.vmcode); else StrCat(cmdline, kname); StrCat(cmdline, L" "); StrCat(cmdline, args); VERB_PRT(3, Print(L"final command line is '%s'\n", cmdline)); return 0; } static INTN textmenu_probe(EFI_HANDLE dev) { /* this chooser always works */ return 0; } chooser_t textmenu_chooser={ L"textmenu", textmenu_probe, textmenu_choose }; ./elilo/choosers/textmenu.h0000644000175000017500000000215407720451656015526 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Richard Hirst * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_CHOOSER_TEXTMENU_H__ #define __ELILO_CHOOSER_TEXTMENU_H__ #include "fileops.h" extern chooser_t textmenu_chooser; #endif ./elilo/choosers/simple.c0000644000175000017500000002557411466353221015143 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #include "vars.h" #include "console.h" /* static is ugly but does the job here! */ static CHAR16 **alt_argv; static VOID display_label_info(CHAR16 *name) { CHAR16 *desc; CHAR16 initrd_name[PATHNAME_MAXLEN]; CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 options_tmp[CMDLINE_MAXLEN]; CHAR16 options[CMDLINE_MAXLEN]; CHAR16 kname[FILENAME_MAXLEN]; desc = find_description(name); if (desc) { Print(L"desc : %s\n", desc); } initrd_name[0] = vmcode_name[0] = options_tmp[0] = kname[0] = CHAR_NULL; if (find_label(name, kname, options_tmp, initrd_name, vmcode_name) == -1) { StrCpy(kname, name); Print(L"\n"); } subst_vars(options_tmp, options, CMDLINE_MAXLEN); Print(L"cmdline: %s %s\n", kname, options); if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name); if (vmcode_name[0]) Print(L"vmcode : %s\n", vmcode_name); } static VOID print_infos(int force) { CHAR16 *config_file; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *boot_dev_name; UINT8 is_abs; boot_dev_name = fops_bootdev_name(); config_file = get_config_file(); fops_getdefault_path(dpath, FILENAME_MAXLEN); if (force || elilo_opt.verbose > 0) Print(L"default file path: %s:%s\n", boot_dev_name, dpath); is_abs = config_file && (config_file[0] == CHAR_BACKSLASH || config_file[0] == CHAR_SLASH) ? 1 : 0; if (force || elilo_opt.verbose > 0) Print(L"config file : %s%s\n", config_file && is_abs == 0 ? dpath : L"", config_file ? config_file : L"none used"); if (alt_argv) { CHAR16 **p = alt_argv; Print(L"found alternate default choice :"); while (*p) Print(L" %s", *p++); Print(L"\n"); } } static VOID print_help(int force) { if (force || elilo_opt.verbose > 0) Print(L"command list (must be first character):\n=:print device list, %%:print variable list, &:print paths, ?:help\nTAB:print label information\n"); } /* * interactively select a kernel image and options. * The kernel can be an actual filename or a label in the config file * Return: * -1: if unsucessful * 0: otherwise */ static INTN select_kernel(CHAR16 *buffer, INTN size) { #define CHAR_CTRL_C L'\003' /* Unicode CTRL-C */ #define CHAR_CTRL_D L'\004' /* Unicode CTRL-D */ #define CHAR_CTRL_U L'\025' /* Unicode CTRL-U */ //#define CHAR_TAB L'\t' SIMPLE_INPUT_INTERFACE *ip = systab->ConIn; EFI_INPUT_KEY key; EFI_STATUS status; INTN pos = 0, ret; INT8 first_time = 1; /* * let's give some help first */ print_help(0); print_infos(0); reprint: buffer[pos] = CHAR_NULL; Print(L"\nELILO boot: %s", buffer); /* * autoboot with default choice after timeout expires */ if (first_time && (ret=wait_timeout(elilo_opt.timeout)) != 1) { return ret == -1 ? -1: 0; } first_time = 0; for (;;) { while ((status = uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key)) == EFI_NOT_READY); if (EFI_ERROR(status)) { ERR_PRT((L"select_kernel readkey: %r", status)); return -1; } switch (key.UnicodeChar) { case CHAR_TAB: Print(L"\n"); if (pos == 0) { print_label_list(); Print(L"(or a kernel file name: [[dev_name:/]path/]kernel_image cmdline options)\n"); } else { buffer[pos] = CHAR_NULL; display_label_info(buffer); } goto reprint; case L'%': if (pos>0) goto normal_char; Print(L"\n"); print_vars(); goto reprint; case L'?': if (pos>0) goto normal_char; Print(L"\n"); print_help(1); goto reprint; case L'&': if (pos>0) goto normal_char; Print(L"\n"); print_infos(1); goto reprint; case L'=': if (pos>0) goto normal_char; Print(L"\n"); print_devices(); goto reprint; case CHAR_BACKSPACE: if (pos == 0) break; pos--; Print(L"\b \b"); break; case CHAR_CTRL_U: /* clear line */ while (pos) { Print(L"\b \b"); pos--; } break; case CHAR_CTRL_C: /* kill line */ pos = 0; goto reprint; case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: buffer[pos] = CHAR_NULL; Print(L"\n"); return 0; default: normal_char: if (key.UnicodeChar == CHAR_CTRL_D || key.ScanCode == 0x17 ) { Print(L"\nGiving up then...\n"); return -1; } if (key.UnicodeChar == CHAR_NULL) break; if (pos > size-1) break; buffer[pos++] = key.UnicodeChar; /* Write the character out */ Print(L"%c", key.UnicodeChar); } } return 0; } static VOID display_message(VOID) { fops_fd_t fd; EFI_STATUS status; UINTN len, i; CHAR16 *filename; CHAR8 buf[256]; if ((filename = get_message_filename(0)) == NULL) return; if (*filename == CHAR_NULL) return; VERB_PRT(3, Print(L"opening message file %s\n", filename)); status = fops_open(filename, &fd); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"message file %s not found\n", filename)); return; } len = 256; Print(L"\n"); while ((status = fops_read(fd, buf, &len)) == EFI_SUCCESS) { /* XXX: ugly ! */ for (i=0; i < len; i++) { Print(L"%c", (CHAR16)buf[i]); } if (len < 256) break; } fops_close(fd); } static INTN simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline) { # define BOOT_IMG_STR L"BOOT_IMAGE=" CHAR16 buffer[CMDLINE_MAXLEN]; CHAR16 alt_buffer[CMDLINE_MAXLEN]; CHAR16 initrd_name[PATHNAME_MAXLEN]; CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; CHAR16 devname[PATHNAME_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *slash_pos, *colon_pos, *backslash_pos; UINTN len; INTN ret; buffer[0] = alt_buffer[0] = CHAR_NULL; display_message(); restart: initrd_name[0] = vmcode_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL; /* reset per image loader options */ Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt)); /* * check for alternate kernel image and params in EFI variable */ if (elilo_opt.alt_check && alternate_kernel(alt_buffer, sizeof(alt_buffer)) == 0) { argc = argify(alt_buffer,sizeof(alt_buffer), argv); alt_argv = argv; index = 0; args[0] = initrd_name[0] = vmcode_name[0] = 0; /* * don't check twice because the variable is deleted after * first access */ elilo_opt.alt_check = 0; } if (elilo_opt.prompt) { console_textmode(); ret = select_kernel(buffer, CMDLINE_MAXLEN); if (ret == -1) return -1; /* this function takes really the number of bytes ... */ argc = argify(buffer,sizeof(buffer), argv); index = 0; } /* * if we found an alternate choice and the user * did not force it manually, then use the alternate * option. */ if (alt_buffer[0] && buffer[0] == CHAR_NULL) { StrCpy(buffer, alt_buffer); } /* * First search for matching label in the config file * if options were specified on command line, they take * precedence over the ones in the config file * * if no match is found, the args and initrd arguments may * still be modified by global options in the config file. */ ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name); /* * not found, so assume first argument is kernel name and * not label name */ if (ret == -1) { if ((index < argc) && argv[index]) StrCpy(kname, argv[index]); else StrCpy(kname, elilo_opt.default_kernel); } /* * no matter what happened for kname, if user specified * additional options, they override the ones in the * config file */ if (argc > 1+index) { /*StrCpy(args, argv[++index]);*/ while (++index < argc) { StrCat(args, L" "); StrCat(args, argv[index]); } } /* * if initrd specified on command line, it overrides * the one defined in config file, if any */ if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) { StrCpy(elilo_opt.initrd, initrd_name); } if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) { StrCpy(elilo_opt.vmcode, vmcode_name); } VERB_PRT(1, { Print(L"kernel is '%s'\n", kname); Print(L"arguments are '%s'\n", args); if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd); if (elilo_opt.vmcode[0]) Print(L"vmm is '%s'\n", elilo_opt.vmcode); }); if (elilo_opt.prompt == 0) { /* minimal printing */ Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH); ret = wait_timeout(elilo_opt.delay); if (ret != 0) { elilo_opt.prompt = 1; elilo_opt.initrd[0] = elilo_opt.vmcode[0] = CHAR_NULL; elilo_opt.timeout = ELILO_TIMEOUT_INFINITY; goto restart; } } /* * add the device name, if not already specified, * so that we know where we came from */ slash_pos = StrChr(kname, L'/'); backslash_pos = StrChr(kname, L'\\'); colon_pos = StrChr(kname, L':'); if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos; if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) { StrCpy(devname, fops_bootdev_name()); StrCat(devname, L":"); /* the default path is always terminated with a separator */ if (kname[0] != L'/' && kname[0] != L'\\') { fops_getdefault_path(dpath,FILENAME_MAXLEN); StrCat(devname, dpath); } } else { devname[0] = CHAR_NULL; } /* * create final argument list to the kernel */ len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */ +StrLen(devname) /* device name */ /* kernel name */ +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname) +1 /* space */ +StrLen(args); /* args length */ if (len >= CMDLINE_MAXLEN-1) { ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n")); return -1; } StrCpy(cmdline, L"BOOT_IMAGE="); StrCat(cmdline, devname); if (elilo_opt.vmcode[0]) StrCat(cmdline, elilo_opt.vmcode); else StrCat(cmdline, kname); StrCat(cmdline, L" "); StrCat(cmdline, args); return 0; } static INTN simple_probe(EFI_HANDLE dev) { /* this chooser always work */ return 0; } chooser_t simple_chooser={ L"simple", simple_probe, simple_choose }; ./elilo/getopt.c0000644000175000017500000000501310650210516013302 0ustar jasonfjasonf/* * Simplistic getopt() function for EFI * * This function provides the basic functionality of the POSIX getopt() function. * No long options are supported. * * This code is meant for EFI programs and therefore deals with Unicode characters. * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian * * 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. */ #include #include #define DASH (CHAR16)'-' #define COLON (CHAR16)':' #define EOS (CHAR16)'\0' #define BADCH (INTN)'?' #define BADARG (INTN)':' extern CHAR16 * StrChr(IN const CHAR16 *s, CHAR16 c); CHAR16 *Optarg; INTN Optind = 1; INTN Optopt; /* * This simple version of getopt supports: * - option with no argument (no :) * - option with REQUIRED argument (single :) * it does not support: * - long options * - optional arguments to options * - optreset */ INTN Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring) { static CHAR16 *cur_chr = NULL; CHAR16 *opt; if (Optind >= argc) { /* no option or end of argument list */ cur_chr = NULL; return -1; } if (cur_chr == NULL || *cur_chr == EOS) { cur_chr = argv[Optind]; if (*cur_chr++ != DASH) { /* missing DASH */ cur_chr = NULL; return -1; } if (*cur_chr == DASH) { cur_chr = NULL; Optind++; return -1; /* -- case, we're done */ } } Optopt = *cur_chr++; opt = StrChr(optstring, Optopt); if (!opt) { Print(L"%s: illegal option -- %c\n", argv[0], Optopt); if (*cur_chr == EOS) Optind++; return BADCH; } if (*(opt+1) != COLON) { Optarg = NULL; if (*cur_chr == EOS) Optind++; } else { if (*cur_chr) { Optarg = cur_chr; } else if ( ++Optind >= argc ) { Print(L"%s: option `%s' requires an argument\n", argv[0], argv[Optind-1]), cur_chr = NULL; return BADARG; } else { Optarg = argv[Optind]; } Optind++; } return Optopt; } ./elilo/vars.c0000644000175000017500000000557307720452311012773 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include /* * A variable name is 1 character long and case sensitive. So * we actually have 52 (26*2) possible variables. */ #define MAX_VARIABLES (26<<1) #define MAX_VARIABLE_LENGTH 128 #define VAR_IDX(a) (((a) >= 'a' && (a) <= 'z') ? 26-'a'+(a) : (a)-'A') #define IDX_VAR(i) ((i) < 26 ? 'A'+(i) : 'a'+ ((i)-26)) typedef struct { CHAR16 value[MAX_VARIABLE_LENGTH]; } elilo_var_t; static elilo_var_t vars[MAX_VARIABLES]; /* set of variables */ INTN set_var(CHAR16 v, CHAR16 *value) { /* invalid variable name */ if (v < 'A' || (v > 'Z' && v < 'a') || v > 'z') return -1; StrCpy(vars[VAR_IDX(v)].value, value); return 0; } CHAR16 * get_var(CHAR16 v) { /* invalid variable name */ if (v < L'A' || (v > L'Z' && v < L'a') || v > L'z') return NULL; return vars[VAR_IDX(v)].value; } VOID print_vars(VOID) { INTN i; UINTN cnt = 0; for(i=0; i < MAX_VARIABLES; i++) { if (vars[i].value[0]) { cnt++; Print(L"%c = \"%s\"\n", IDX_VAR(i), vars[i].value); } } if (cnt == 0) Print(L"no variable defined\n"); } INTN subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen) { /* * we cannot use \\ for the despecialization character because * it is also used as a path separator in EFI. */ #define DSPEC_CHAR L'&' INTN i, l, j, cnt; INTN m = 0, d = 0; CHAR16 *val; if (in == NULL || out == NULL || maxlen <= 1) return -1; l = StrLen(in); maxlen--; for (i=0, j=0;i < l; i++) { cnt = 1; val = in+i; if (*val == DSPEC_CHAR && d == 0) { d = 1; continue; } if(m == 1) { m = 0; val = get_var(*val); if (val == NULL) continue; cnt = StrLen(val); } else if (*val == L'%' && d == 0) { m = 1; continue; } d = 0; while (j < maxlen && cnt) { out[j++] = *val++; cnt--; } if (j == maxlen) break; } out[j] = CHAR_NULL; return 0; } ./elilo/glue_ext2fs.c0000644000175000017500000000416007720452032014236 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "glue_ext2fs.h" #include "fs/ext2fs.h" #include "strops.h" static INTN glue(fileops_t *this, VOID *intf); /* object exported to fileops */ fileops_fs_t ext2fs_glue = { EXT2FS_PROTOCOL , glue, ext2fs_install, ext2fs_uninstall}; static EFI_STATUS ext2fs_infosize(ext2fs_interface_t *this, fops_fd_t fd, UINT64 *sz) { ext2fs_stat_t st; EFI_STATUS status; if (this == NULL || sz == NULL) return EFI_INVALID_PARAMETER; status = this->ext2fs_fstat(this, fd, &st); if (status != EFI_SUCCESS) return status; *sz = (UINT64)st.st_size; return EFI_SUCCESS; } static INTN glue(fileops_t *fp, VOID *intf) { ext2fs_interface_t *ext2fs = (ext2fs_interface_t *)intf; /* record underlying interface */ fp->intf = intf; fp->open = (fops_open_t)ext2fs->ext2fs_open; fp->read = (fops_read_t)ext2fs->ext2fs_read; fp->close = (fops_close_t)ext2fs->ext2fs_close; fp->infosize = (fops_infosize_t)ext2fs_infosize; /* local override */ fp->seek = (fops_seek_t)ext2fs->ext2fs_seek; /* fill out the name of the underlying file system */ ext2fs->ext2fs_name(ext2fs, fp->name, FILEOPS_NAME_MAXLEN); return 0; } ./elilo/ChangeLog0000644000175000017500000006644111512674432013433 0ustar jasonfjasonf2011-1-10 signed off by Jason Fleischli * Uptake of SUSE patches - add sysfs support for efi vars (formerly /proc/efi/vars) - fix strncpy overflow - fix bzimage alloc - cleanups - support longer command line - yet some more mac fixes - align elilo with latest kernel boot protocol format. - new memory management strategy for initrd and kernel image loading. * add force text mode command line option. * replace error output on GOP handle failed, downgraded to normal print status with more informative output. 2009-10-22 signed off by Jason Fleischli * elilo 3.12 release commit * Added additional #defines for debug levels to reduce the output * Added Mac console patch rework from Julien Blache @ debian this fixes the invisible console output from elilo on Macs * Moved static ELILO_VERSION variable from elilo.c to elilo.h so that elilo will print its version string and arch on startup. * Fixed bug 2825044 ExitBootServices error handling, correctly deal with changed memory map key if memory map changes from under elilo. * Added memory map key to map debug output. * Fixed bug 2874380 netbooting just flat broken. fixed ia64, x86_64 ia32, fixed handling of server side support of tfpt options (get file size) elilo now attempts to get file size before attempting read of file to set the buffers up correctly and deal with tftp servers that dont support options extensions a little better. * netboot, fixed bad blocksize handling * netboot, fixed filename length for elilo-x86_64.conf type on tftp server. * increased bzimage kernel max length sizes to 4mb on i386 and 8mb on x86_64... this is a legacy design hold over from original design and needs to be re-written to do dynamic size memory management based on the size of the actual vmlinuz image, as ia64/gzip does. 2008-04-02 signed off by Jason Fleischli * elilo 3.10 release commit * Bumped version string to 3.10 * added PTR_FMT 32bit & 64bit pointer translation for correct output * elilo hang bugfix x86_64 non-standard kernels with non-traditional start address elilo will pull the start address from the kernel elf header for 2.6 or newer kernels, map memory and use that start address, else use standard 1MB default start address. And handle case of overlapping kernels and initrds in memory. Patch contributor Stuart Hayes @ Dell, thanks Stuart! * ported kernel start adress fix to ia32 * eliminated all possible compiler warnings except those actually caused by gnu-efi that cant be fixed here. * Debug output improvement, added pauses with visual feedback when user sets debug & verbose options. * bugfix added missing find_bits function definition back into ia32 subtree * bugfix loader_probe now correctly errors out if no loaders registered. 2008-01-11 signed off by Jason Fleischli * Various compile warning cleanups. 2008-01-03 signed off by Jason Fleischli * Patch contribution from Scott Davilla when x is zero for the first call to add_memory_region, e820_map[-1] will access memory outside the bounds of e820_map. While this does not result in any problems as there is a UINT32 unused_8[41] block above the e820_map[0] location that should have been zeroed by the bootloader, the code should not access outside the bounds of structures. 2008-01-03 Jason Fleischli * initrd.c -- Let the allocator decide where to grab the memory from the efi memory map. Current start_addr=image->start_addr forces the same efi region everytime, and has a 7mb limit. ramdisk (initrd.img) files larger than 7MB wouldnt fit into the memory region assumed by the image->start_addr resulting in an elilo hang. Leaving start_addr NULL at initialization forces alloc_pages to get a memory region sufficient for the size of the initrd image. 2007-12-19 Jason Fleischli * bumping version string to 3.8 2007-12-19 Jason Fleischli * MORE PATCHES FROM INTEL FOR IA32 X86_64. * Fix compile warning for cmdline_addr assignment. * Fix an issue caused by uninitialized e820_nr_map in fill_e820map. * On some machines, there are too many EFI memory map entries, so that, the number of E820 map entries converted from EFI memory map exceeds the limit (128). This patch fixes this bug by merging consecutive memory map entries with the same type. * CL_MAGIC is not supported by 32-bit boot protocol. So, the kernel command line passing code is changed accordingly. * EFI-2.0 boot support patches have been accepted into Linux kernel 2.6.24-rc4 and EFI runtime service patches have been accepted by Linux kernel 2.6.24-rc4-mm1. There are some changes during the merging, so there are some updates for elilo ia32/x86_64 too. * The x86_64 boot parameters of Linux kernel is rearranged to line up with ia32 boot parameters. * The boot loader signature of IA32 and x86_64 is redefined to make it possible for Linux kernel to distinguish whether the underlying firmware is EFI 32 or EFI 64. * The EFI framebuffer type ID is changed in Linux kernel to conform to Linux kernel framebuffer type ID grouping rules. So the EFI framebuffer type ID setting code in ELILO is changed accordingly. * E820 memory map is added to IA32 to make it possible for Linux kernel not to depend on EFI memory map on EFI 32. 2007-09-27 Jason Fleischli * updating changelog for last commit that was omitted * incorporating AGriffis patches to enhance parsing passes root= option to kernel options and accounts for -- option designation. 2007-07-19 Jason Fleischli * Integrated x86_64 support patches from Chandramouli Narayanan changes summarized in following bullets. * alloc.c -- adds patch contributors credit to copyright * alloc.c -- adds uefi_call_wrapper around BS->function calls * alloc.c -- adds call to Print on VERB_PRT * alternate.c -- adds patch contributors credit around copyright * alternate.c -- adds uefi_call_wrapper around RT->function calls * simple.c -- adds patch contributors credit to copyright * simple.c -- adds uefi_call_wrapper around ip->ReadKeyStroke * textmenu.c -- adds patch contributors credit to copyright * textmenu.c -- adds uefi_call_wrapper around ClearScreen & SetTextAttr * textmenu.c -- adds uefi_call_wrapper around ip->ReadKeyStroke * elilo.c -- adds patch contributors credit to copyright * elilo.c -- fixes version number for ELILO_VERSION macro to current * elilo.c -- adds uefi_call_wrapper around BS->function calls * elilo.c -- adds uefi_call_wrapper around RT->function calls * fileops.c -- adds patch contributors credit to copyright * fileops.c -- adds uefi_call_wrapper around BS->function calls * fileops.c -- adds uefi_call_wrapper around RT->function calls * fileops.c -- adds uefi_call_wrapper around blkio->function calls * localfs.c -- adds patch contributors credit to copyright * localfs.c -- changed EFI_HANDLE *dev declaration to non-pointer type * localfs.c -- adds uefi_call_wrapper around lfs->volume->functions * localfs.c -- adds uefi_call_wrapper around BS->function calls * netfs.c -- adds patch contributors credit to copyright * netfs.c -- adds uefi_call_wrapper around nfs->pxe->function calls * netfs.c -- adds uefi_call_wrapper around BS->function calls * getopt.c -- changed int to char in StrChr() function * Make.defaults -- adds patch contributors credit to copyright * Make.defaults -- adds cflag for efi function wrapper * Makefile -- adds patch contributors credit to copyright * Makefile -- x86_64 subdir and a new rule for .S * util.c -- adds patch contributors credit to copyright * util.c -- adds uefi_call_wrapper to systab->functions * util.c -- adds uefi_call_wrapper to conin->functions * util.c -- adds uefi_call_wrapper to BS->functions * util.c -- doubles ELILO_MEMMAP_SIZE_DEFAULT in get_memmap() function * bootparams.c -- uses ia32 params for x86_64 addition.. hmmmm? * config.c -- adds patch contributors credit to copyright * config.c -- adds define reference for x86_64.conf * config.c -- in config_error() removes use of va_list which maps to the gnu C-lib iface __gnuc_va_list. Replaces the use of _IPrint on the va_list with direct use of IPrint(systab->ConOut, msg); *maintainer note, this probably introduces a bug, in light of this note from the patch submitter --> "On some x86_64 systems with EFI1.10 firmware I tested, early boot messages did not appear on console. However, I didn't encounter this behavior on x86_64 systems with UEFI2.0 firmware" * elf.h -- adds #def for x86_64 * glue_netfs.c -- adds patch contributors credit to copyright * glue_netfs.c -- adds define for x86_64.conf * sysdeps.h -- adds patch contributors credit to copyright * sysdeps.h -- add include reference for new x86_64 subdir * x86_64/ -- new subdir - all based on elilo/ia32 subdir * x86_64/bin_to_h.c -- new file, stream fed binary to hex converter * x86_64/bzimage.c -- new file, binary compressed kernel support * x86_64/gzip.c -- new file, embedded gzip * x86_64/gzip_loader.c -- new file, embedded gzip * x86_64/gzip.h -- new file, embedded gzip * x86_64/inflate.c -- new file, a pkzip method 8 embedded decompressor * x86_64/Makefile -- new file * x86_64/plain_loader.c -- new file, for loading non-compressed kernels * x86_64/private.h -- new file * x86_64/rmswitch.S -- new file, RealMode assembly module * x86_64/sysdeps.h -- new file, system stuff for x86_64, e820 mapping added. * x86_64/sysdeps.c -- new file, system stuff for x86_64 * elilo.txt -- documentation update, add Intel to copyright * README.gnu-efi -- documentation update for x86_64 2006-01-27 Alex Williamson * Found a couple more places where vmcode isn't zeroed, causing the option to get carried over to labels it shouldn't. 2006-01-09 Brett Johnson * Released 3.6 2005-12-22 Alex Williamson * Fixed vmcode_name initialization in textmenu chooser 2005-12-01 Alex Williamson * Applied patch from Fred Yang to support the vmm= boot option. This option specifies the kernel image for a virtual machine monitor (aka hypervisor). The vmm= and image= options are used together to load both the hypervisor kernel and the guest domain kernel into memory. If a vmm= option is not specified, elilo defaults to the old behavior of loading and booting to the image= kernel. * Added support for compressed image= files when used with the vmm= option. If the image= file is detected to be gzip compressed, the image will be uncompressed into memory before it is provided to the hypervisor. Any combination of compressed and uncompressed images can be used for the image and vmm options. 2005-09-15 Brett Johnson * Applied patch from Tristan Gingold to add dcache flush and sync with icache to gzip and plain loaders. This ommision was just noticed now due to the much larger caches in Montecito, and the smaller size of Xen (as compared to the linux kernel). 2004-09-27 Brett Johnson * Increase the hardcoded size of the texmenu chooser menu from 16 to 64 2004-09-23 Brett Johnson * Fix for 924147. Thanks to Stephanie Schaaf for a patch that the fix is based on. 2004-02-19 Brett Johnson * Fixed bug where default image initrd would carry over to another image that was selected interactively (iff the newly selected image did not have an initrd). * Added support for subnet-specific config files in netfs. 2004-02-17 Brett Johnson * integrated ia32 compressed kernel support from Matt Tolentino 2003-08-20 Stephane Eranian * released 3.4 2003-08-19 Stephane Eranian * integrated ia32 updates from Matt Tolentino 2003-08-13 Stephane Eranian * updated elilo.txt and netbooting.txt * fix a bug in choosers/simple.c:print_infos(). it needs to check if config file path is absolute when printing filename. * move definitions of CHAR_SLASH CHAR_BACKSLASH to elilo.h * fix a bug in read_config() where it would try other filename even when the user explicitely specified one via -C, now it fails it that file cannot be opened. * updated simple chooser set of builtin command keys * command keys are only valid if first on the line * increase default buffer size and increment when netbooting 2003-06-04 Stephane Eranian * fix fs/netfs.c to work with recent version of EFI (14.61 or higher) which do not have the TFTP problem anymore. fix submitted by Guy Laborde 2003-04-21 Stephane Eranian * ext2fs support is turned off by default to avoid problems with ext3-formatted partitions. * added gcc version check. MUST use 3.0 or higher 2003-03-03 Stephane Eranian * added check on dev_tab in fs/*fs.c:*_uninstall() 2003-02-07 Stephane Eranian * clean up in glue_localfs.c w.r.t. CHAR16 in set_default_path() * added support for extracting basename of bootloader path when using BOOTP (DHCP) only. The prefix is then used for all files open via netfs. Suggestion and initial patch by Guy Laborde from HP. 2003-01-28 Stephane Eranian * fix the set_default_path() routine in glue_localfs.c. It would not correctly get the basename of the devpath. This caused the elilo.conf not to be found sometimes. 2003-01-21 Stephane Eranian * fix bug in glue_netfs.c convert_ip2decstr() which caused some IP addresses to be incorrectly converted to strings. 2002-11-01 Stephane Eranian * fix bug in -r option for IA64. There is no argument to this option. 2002-10-15 Stephane Eranian * fixed a double free bug for the kernel memory in case of abort. (bug spotted by Levent Akyl from Intel) * released 3.3a 2002-09-14 Stephane Eranian * applied patch from Andreas Schwab to eliloalt.c. eliloalt dynamically selects a variable in /proc/efi/vars. 2002-09-12 Stephane Eranian * removed extra free() from fs/ext2fs.c:ext2fs_init_state(). Bug report and fix by NOMURA Jun'ichi * rewrote fs/ext2fs.c:read_bytes() to large memory stack buffer which was bigger than the 128KB limit of EFI causing some weird fimrware errors. bug reported by OMURA Jun'ichi * on IA-64 forbid the use of f32-f127 by the compiler (EFI spec) 2002-09-10 Stephane Eranian * fix a bug in argify() that was causing an EFI assertion when aborting at the elilo prompt when netbooted. 2002-08-26 Stephane Eranian * fixed devschemes/simple.c to use SPrint() instead of its own buggy conversion code (spotted by Richard Hirst). * fix bug in argify() when there was no NULL character in the string. * released 3.3 2002-08-19 Stephane Eranian * added fpswa.txt in the docs directory * updated elilo.txt 2002-08-15 Stephane Eranian * added -F file option for IA-64 to allow a specific fpswa driver to be loaded * fixed fpswa.c to try and load the driver from all accessible partitions * added support to load (plain or gzipped) big-endian ELF/ia64 binaries using p_paddr. * fixed problem in fs/netfs.c causing large (>4MB) binaries to fail the Mftp() call 2002-06-13 Stephane Eranian * Changed the despecialization character for the variables from \\ to & to avoid conflicts with \\ as a path separator 2002-06-11 Stephane Eranian * fixed the return value in efi_main(). elilo was always returning success even in case of failure. Bug reported by Egan Ford * applied patch from Richard Hirst to fix an initialization bug in choosers/textmenu.c * applied patch from Richard Hirst to make elilo compliant with EFI spec with regards to where it looks for files. With this patch, elilo will look in the directory it was loaded from, not on the root of the partition anymore. 2002-03-04 Stephane Eranian * released version 3.2 * cleanup some GNU extension in fs/ext2fs.c (variable size array) * updated all documentation. Added netbooting.txt, simple_chooser.txt, eliloalt.txt, elilovar.txt 2002-02-21 Stephane Eranian * added a Linux utility program (elilovar in tools) to set/read/delete the EliloAlt EFI variable used to specify an alternate kernel to boot. * rename DBG_PRINT() to DBG_PRT, PRINT_ERR() to ERR_PRT() * added support for hostname,domain name extraction in fs/netfs.c * fixed all known bugs in alternate.c * integrated patch from SGI to fix load offset for relocatable kernels (Jack Steiner, Brent Casavant) 2002-02-21 Michael Johnston and Chris Ahna * major update to ia32 support: can now boot 2.4.x, and 2.2.x kernels 2002-02-20 Stephane Eranian * fixed missing netfs_fd_free() in case of file not found in netfs.c 2002-02-19 Stephane Eranian * added support for substitution variables (vars.c) * changed the bootparam structure size back to 4kB * added support to simple to print final command line option with tab key * got rid of all the \r characters in strings use only \n (adjust emulator) * added EFICRT0 variable in Makefile to indicate location of loader script+crt0 2002-02-14 Stephane Eranian * added support for message= option to simple chooser * added support for description= option to simple chooser 2002-02-13 Stephane Eranian * choosers/textmenu.c: new textmenu chooser (by rhirst@linuxcare.com) used by Debian * config.c: added support for dynamic global/per-image option management * ia64/plain_loader.c,ia64/gzip.c: fix load_offset () * added cmd line (-E) and config option (noedd30) to not set EDD30 EFI variable to true if not already TRUE (request by Matt_Domsch@dell.com) * added support for multiple devname schemes and probing 2002-01-31 Stephane Eranian * cleaned up alternate.c * added support for ctrl-U (clear line) in chooser/simple.c 2002-01-25 Stephane Eranian * added support for architecture specific config file (elilo-ia64.conf, elilo-ia32.conf). 2002-01-13 Stephane Eranian * removed call to Reset() in ext2fs.c 2001-08-17 Stephane Eranian * released 3.1 * added support for command line architecture specific options: sysdeps_get_cmdline_opts(), sysdeps_print_cmdline_opts(), syspdeps_getopt() * added IA-64 command line option (-r) for relocation * fix behavior when kernel specified on command line but prompt mode was specified in config file. In this case, we now autoboot and ignore the prompt directive. * updated elilo.txt 2001-08-15 Brent Casavant * fix a bug in config.c:find_option() where it would do a strXcmp() on a NULL string. 2001-08-01 Stephane Eranian * fixed bug in fs/netfs.c where it would not handle the small buffer error correctly. The retry path was not allocating a bigger buffer. * Global config options are now used if the user specifies a non-label load target, i.e. a kernel image file. * added support for architecture dependent config file image options (sys_img_options_t). * added support for setjmp/longjmp. * added support for aborting during a compressed load * added support for user to abort a load of a compressed file. * added 2 new ia-64 only config file options allowing kernel relocation: 'relocatable' as a global or per image option. * added support for kernel relocation on memory error. Based on code from Brent Casavant . * added slash/backslash conversion for filenames on vfat filesystems. 2001-07-23 Stephane Eranian * fixed error in netfs.c where the kernel name was not correctly set in netfs_query_layer() * fixed to wait_timeout() to correct the problem with the interactive prompt when return is hit directly when no text * fixed command line argument destruction problem, now we make a copy of them. This was affecting elilo when called directly from bootmanager with NVRAM options. 2001-06-28 Stephane Eranian * removed W2U() hack to get from wide-char to unicode. Use -fshort-wchar option instead. * split gnu-efi package in two different packages: the libary+include+crt and the bootloader. * restructured the fileops module. Now use direct function calls. * added support for accessing files on different devices. * fixed a buffer leak in simple_chooser.c. Renamed simple_chooser.c to simple.c. * created a strops.c file to incorporate all string operations functions. * added support for ext2fs filesystem. * restructured code to allow additional filesystems to be added easily. * cleaned up add-on chooser interface. * restructured code to use the EFI protocol interface to install filesystems. * added compile-time options to turn on and off specific filesystems. * added support for architecture specific configuration options (elilo.conf). * added fpswa option to IA-64 to designate a fpswa driver file. * incoporated IA-32 support from Mike Johnston * incorporated rewritten gzip.c:flush_window() from Tony Luck * added interface for custom device naming schemes (devnames directory). * added support for 2 possible config file (now just on netboot). The first (primary) choice uses a host specific filename based on the IP address. Suggestion from Egan Ford . 2001-04-06 Stephane Eranian * incorporated patches from David and Michael Johnston at Intel to get the package to compile for IA-32 linux target. * Fixed ELILO to compile for Ia-32 (does not execute yet, though): Makefile and start_kernel() function. 2001-04-06 Andreas Schwab * Fixed config.c to get the timeout directive to do something. implemented the global root= directive. * Fix the efi_main() to deal with the -C option properly 2001-04-05 Stephane Eranian * update efi library to latest EFI toolkit 1.02 as distributed by Intel. Fixed header + library files to compile with GCC * merged ELI and LILO (as of gnu-efi-1.1) together, mostly taking the config file feature of ELI. * renamed LILO to ELILO to make the distinction * restructured code to make it easier to understand and maintain * fixed FPSWA driver checking and loading: we try all possible files and let the driver itself figure out if it is the most recent. * added support for compression (gzip) but keep support for plain ELF image. ELILO autodetects the format * change the way the kernel is invoked. Now we call it in physical memory mode. This breaks the dependency between the kernel code and the loader. No more lilo_start.c madness. * changed the way the boot_params are passed. We don't use the ZERO_PAGE_ADDR trick anymore. Instead we use EFI runtime memory. The address of the structure is passed to the kernel in r28 by our convention. * released as gnu-efi-2.0 2001-04-03 David Mosberger * gnuefi/reloc_ia32.c (_relocate): Change return type from "void" to "int". Return error status if relocation fails for some reason. * gnuefi/elf_ia32_efi.lds: Drop unneeded ".rel.reloc" section. * gnuefi/crt0-efi-ia32.S (_start): Exit if _relocate() returns with non-zero exit status. * inc/ia32/efibind.h [__GNUC__]: Force 8-byte alignment for 64-bit types as that is what EFI appears to be expecting, despite the "#pragma pack()" at the beginning of the file! 2001-03-29 David Mosberger * gnuefi/reloc_ia32.c: Add a couple of defines to work around libc/efilib collision on uint64_t et al. (_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)(). * gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry. 2001-03-29 David Mosberger * gnuefi/reloc_ia32.c: Add a couple of defines to work around libc/efilib collision on uint64_t et al. (_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)(). * gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry. 2000-10-26 David Mosberger * gnuefi/elf_ia64_efi.lds: Mention .rela.sdata. * Make.defaults (CFLAGS): Remove -nostdinc flags so we can pick up the C compiler's stdarg.h. * inc/stdarg.h: Remove this file. It's not correct for gcc (nor most other optimizing compilers). 2000-10-10 Stephane Eranian * cleaned up the error message and printing of those. * added support to load the FPSWA from a file in case support is not present in the firmware already * fixed split_args() to do the right thing when you have leading spaces before kernel name * changed the argify() function to rely on \0 instead of LoadOptionSize as the field seems to be broken with current firmware * bumped version to 1.0 2000-10-04 David Mosberger * gnuefi/reloc_ia64.S: Reserve space for up to 750 function descriptors. * gnuefi/elf_ia64_efi.lds: Add .sdata section for small data and put __gp in the "middle" of it. * gnuefi/crt0-efi-ia64.S (_start): Use movl/add to load gp-relative addresses that could be out of the range of the addl offset. * gnuefi/reloc_ia64.S (_relocate): Ditto. * apps/Makefile: Remove standard rules and include Make.rules instead. * lilo/Makefile: Ditto. * Make.rules: New file. 2000-08-04 Stephane Eranian * released version 0.9 * incorporated ACPI changes for Asuza by NEC < kouchi@hpc.bs1.fc.nec.co.jp> * added support for initrd (-i option) original ELI code from Bill Nottingham ) * lots of cleanups * got rid of #ifdef LILO_DEBUG and uses macro instead * fix a few extra memory leaks in create_boot_params() * added exit capability just before starting the kernel 2000-06-22 David Mosberger * gnuefi/elf_ia64_efi.lds: Add .srodata, .ctors, .IA64.unwind, .IA64.unwind_info to .data section and .rela.ctors to .rela section. 2000-04-03 David Mosberger * lilo/lilo.c (LILO_VERSION): Up version number to 0.9. * gnuefi/elf_ia64_efi.lds: Include .IA_64.unwind and .IA_64.unwind_info in .data segment to avoid EFI load error "ImageAddress: pointer outside of image" error due to the .dynsym relocations against these sections. * ChangeLog: Moved from lilo/ChangeLogs. * gnuefi/reloc_ia64.S: fixed typo: .space directive had constant 100 hardcoded instead of using MAX_FUNCTION_DESCRIPTORS macro. Duh. Fri Mar 17 15:19:18 PST 2000 Stephane Eranian * Released 0.8 * replace the getopt.c with new version free with better license * created a documentation file * fix a couple of memory leaks * code cleanups * created a separate directory for lilo in the gnu-efi package. * added support for the BOOT_IMAGE argument to kernel * default is to build natively now ./elilo/strops.h0000644000175000017500000000321107720452262013347 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __STROPS_H__ #define __STROPS_H__ extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c); extern CHAR16 *StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); extern CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count); extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c); extern CHAR8 *strrchra(IN const CHAR8 *s, const INTN c); extern CHAR8 *strcata(IN CHAR8 *dst,IN CHAR8 *src); extern CHAR8 *strchra(IN const CHAR8 *s, IN const CHAR8 c); extern CHAR8 *strcpya(CHAR8 *dst, const CHAR8 *src); extern CHAR8 *strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size); extern VOID U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen); #endif /* __LOADER_H__ */ ./elilo/elilo_debug.h0000644000175000017500000000266211271404161014267 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_DEBUG__ #define __ELILO_DEBUG__ //#define DEBUG_MEM //#define DEBUG_GZIP //#define DEBUG_BZ #define ELILO_DEBUG 1 #define ERR_PRT(a) do { Print(L"%a(line %d):", __FILE__, __LINE__); Print a; Print(L"\n"); } while (0); #ifdef ELILO_DEBUG #define DBG_PRT(a) do { \ if (elilo_opt.debug) { \ Print(L"%a(line %d):", __FILE__, __LINE__); \ Print a; \ Print(L"\n"); \ } } while (0); #else #define DBG_PRT(a) #endif #endif /* __ELILO_DEBUG_H__ */ ./elilo/elilo.c0000644000175000017500000005436211466353221013126 0ustar jasonfjasonf/* * elilo.c - IA-64/IA-32/x86_64 EFI Linux loader * * Copyright (C) 1999-2003 Hewlett-Packard Co. * Contributed by David Mosberger . * Contributed by Stephane Eranian * * 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 * 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 #include #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_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: * 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 INTN do_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); } INTN kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem) { CHAR16 kernel[FILENAME_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(kernel, 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; elilo_opt.vmcode[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 [" 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_file(elilo_opt.initrd, imem)) { case ELILO_LOAD_SUCCESS: break; case ELILO_LOAD_ERROR: goto exit_error; case ELILO_LOAD_ABORTED: 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; } static INTN main_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, mmem; INTN r, retries=0; /* * 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; 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, &mmem)) { 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)); /* 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, &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; } } 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 (mmem.start_addr) free(mmem.start_addr); if (bp) free_boot_params(bp); exit_error: return ELILO_LOAD_ERROR; } static VOID elilo_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"-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"); 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 VOID fixupargs(EFI_LOADED_IMAGE *info) { EFI_STATUS status; EFI_PXE_BASE_CODE *pxe; #define FAKE_ELILONAME L"elilo-forced" status = uefi_call_wrapper(BS->HandleProtocol, 3, 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 VOID unfixupargs(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 INTN check_edd30(VOID) { EFI_STATUS status; UINTN l = sizeof(BOOLEAN); UINT8 bool = FALSE; INTN ret = -1; 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; } 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 force_edd30(VOID) { EFI_STATUS status; UINTN l = sizeof(BOOLEAN); UINT8 bool; bool = TRUE; 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; } VERB_PRT(3, Print(L"EDD30 variable forced to TRUE. You should reboot to take advantage of EDD3.0.\n")); return 0; } /* * That's equivalent of main(): main entry point */ EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) { CHAR16 *argv[MAX_ARGS]; CHAR16 optstring[MAX_ARGS]; EFI_LOADED_IMAGE *info; EFI_STATUS status, ret = EFI_LOAD_ERROR; INTN argc = 0, c; INTN edd30_status, retry; CHAR16 *ptr, *arglist = NULL; BOOLEAN devices_initialized = FALSE; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *devpath; elilo_opt.verbose=0; elilo_opt.debug=0; /* initialize global variable */ systab = system_tab; /* initialize EFI library */ InitializeLib(image, systab); /* * disable the platform watchdog timer if we go interactive * XXX: we should reinstate it once we're done * It seems like with PXE, the timer is set to a few minutes * and sometimes triggers if we stay too long in interactive * mode. * XXX: clean this up ! */ uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); /* initialize memory allocator */ if (alloc_init() == -1) return EFI_LOAD_ERROR; 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 " 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 */ edd30_status = check_edd30(); /* * initialize configuration empire */ if (config_init() == -1) goto do_exit; /* * architecture-specific initializations */ if (sysdeps_init(info->DeviceHandle) == -1) goto do_exit; if (sysdeps_register_options() == -1) goto do_exit; /* * This may be required in case Elilo was booted with absolutely no arguments * Elilo's logic is that just like normal Linux programs at least one argument * (argv[0]) exists at all times and that it usually gives the name of the program * (the command used to start it). ERR_PRT((L"LoadOptions=%x OpenSize=%d", info->LoadOptions, info->LoadOptionsSize)); */ /* * in case there is something wrong with the default boot_device * we default to basic fixups and we need to force interactive * mode to make sure the user has a chance of specifying a kernel */ fixupargs(info); #if 0 Print(L"LoadOptions=%x OpenSize=%d\n", info->LoadOptions, info->LoadOptionsSize); { INTN i; for (i=0; i< info->LoadOptionsSize>>1; i++) Print(L"options[%d]=%d (%c)\n", i, ((CHAR16 *)info->LoadOptions)[i], ((CHAR16 *)info->LoadOptions)[i]); } #endif /* * we must copy argument because argify modifies the string. * This caused problems when arguments are coming from NVRAM * as passed by the EFI boot manager * * We add an extra character to the buffer in case the LoadOptions is not * NULL terminated. The extra space will be used to ADD the extra terminator. */ arglist = alloc(info->LoadOptionsSize+sizeof(CHAR16), EfiLoaderData); if (arglist == NULL) { ERR_PRT((L"cannot copy argument list")); return EFI_OUT_OF_RESOURCES; } Memcpy(arglist, info->LoadOptions, info->LoadOptionsSize); argc = argify(arglist,info->LoadOptionsSize, argv); StrCpy(optstring, ELILO_SHARED_CMDLINE_OPTS); StrCat(optstring, sysdeps_get_cmdline_opts()); while ((c=Getopt(argc, argv, optstring)) != -1 ) { switch(c) { case 'a': elilo_opt.alt_check = 1; break; case 'D': elilo_opt.debug = 1; break; case 'p': elilo_opt.prompt = 1; break; case 'v': elilo_opt.verbose++; if (elilo_opt.verbose > 5) elilo_opt.verbose = 5; break; case 'h': elilo_help(); ret = EFI_SUCCESS; goto do_exit; case 'd': /* * zero is a valid value here, so we use the delay-set to mark the * fact that the user specified a value on cmdline. See config.c */ elilo_opt.delay = Atoi(Optarg); elilo_opt.delay_set = 1; break; case 'E': /* don't force EDD30 EFI variable if not already set */ elilo_opt.edd30_no_force = 1; break; case 'i': if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { Print(L"initrd filename is limited to %d characters\n", FILENAME_MAXLEN); goto do_exit; } 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); goto do_exit; } StrCpy(elilo_opt.config, Optarg); break; case 'M': /* builtin debug tool */ { mmap_desc_t mdesc; if (get_memmap(&mdesc) == -1) { Print(L"Cannot get memory map\n"); return EFI_LOAD_ERROR; } print_memmap(&mdesc); ret = EFI_SUCCESS; goto do_exit; } case 'V': Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH); ret = EFI_SUCCESS; goto do_exit; case 'P': /* cmdline only option */ elilo_opt.parse_only = 1; break; case 'c': if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { Print(L"chooser name is limited to %d characters\n", FILENAME_MAXLEN); goto do_exit; } StrCpy(elilo_opt.chooser, Optarg); break; default: /* * try system dependent options before declaring error */ if (sysdeps_getopt(c, Optind, Optarg) == 0) continue; Print(L"Unknown option -%c\n", (CHAR16)c); goto do_exit; } } DBG_PRT((L"Optind=%d optarg=" PTR_FMT " argc=%d", Optind, Optarg, argc)); /* * we can't defer this phase any longer... * Must be done after the elilo_opt are initialized (at least partially) */ if (init_devices(info->DeviceHandle) == -1) goto do_exit; devices_initialized = TRUE; devpath = DevicePathToStr(info->FilePath); /* * set per fileops defaults files for configuration and kernel */ 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_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_configs[0].fname) : (retry=0,elilo_opt.config); /* * parse config file (verbose becomes visible if set) */ 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 * - the user did not explicitely specify the config file */ if (ret == EFI_NOT_FOUND || ret == EFI_TFTP_ERROR) { if (elilo_opt.prompt == 0 && elilo_opt.config[0] != CHAR_NULL) { Print(L"config file %s not found\n", ptr); goto do_exit; } fops_getdefault_path(dpath, FILENAME_MAXLEN); if (ret == EFI_TFTP_ERROR) Print(L"no config file found on TFTP server in %s\n", dpath); else Print(L"no config file found in %s\n", dpath); } /* * stop if just doing parsing */ if (elilo_opt.parse_only) { if (ret == EFI_SUCCESS) Print(L"Config file %s parsed successfully\n", ptr); goto do_exit; } /* * 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 != 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 * we try to force it. This will take effect at the next reboot. * * Some controllers don't have EDD30 support, in this case forcing it * may cause problems, therefore we check the edd_no_force option * before making the call. */ if (edd30_status == -1 && elilo_opt.edd30_no_force == 0) { force_edd30(); } ret = EFI_LOAD_ERROR; /* set default timeout if going interactive */ if ((elilo_opt.prompt && elilo_opt.timeout == 0)) { elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; } /* * which chooser we will use */ if (init_chooser(info->DeviceHandle) == -1) { ERR_PRT((L"Cannot find a decent chooser\n")); goto do_exit; } //if (elilo_opt.prompt == 0) VERB_PRT(1, print_devices()); main_loop(info->DeviceHandle, argv, argc, Optind, image); /* should not return */ do_exit: unfixupargs(info); //if (arglist) free(arglist); /* free all resources assiocated with file accesses */ if (devices_initialized) close_devices(); /* garbage collect all remaining allocations */ free_all_memory(); return ret; } ./elilo/glue_netfs.c0000644000175000017500000002005211466353321014143 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "glue_netfs.h" #include "fs/netfs.h" #include "strops.h" #include "elilo.h" #include "vars.h" /* * disable this if you only want the default config file (elilo.conf) * and not the ip-address based first file attempt */ static INTN glue(fileops_t *this, VOID *intf); /* object exported to fileops */ fileops_fs_t netfs_glue = { NETFS_PROTOCOL , glue, netfs_install, netfs_uninstall}; #define NETFS_DEFAULT_KERNEL L"vmlinux" #define NETFS_DEFAULT_CONFIG L"elilo.conf" #define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT static CHAR16 netfs_default_path[FILENAME_MAXLEN]; /* * Pxe Discovery protocol layers * Layer 0 is used to download the boot loader */ #define NETFS_CONFIG_LAYER 1 #define NETFS_KERNEL_LAYER 2 static CHAR16 *hexa=L"0123456789ABCDEF"; static VOID convert_mac2hex(UINT8 *hw_addr,INTN l, CHAR16 *str) { UINTN i; for (i=0 ; i < l; i++) { str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4]; str[3*i+1] = hexa[hw_addr[i] & 0x0f]; str[3*i+2] = ':'; } str[3*l-1]='\0'; } static VOID convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str) { UINTN i; for(i=0; i < l; i++) { str[2*i] = hexa[(ip[i] & 0xf0)>>4]; str[2*i+1] = hexa[ip[i] & 0x0f]; } } static VOID convert_ip2decstr(UINT8 *ip, INTN l, CHAR16 *str) { UINTN i, j; UINTN v, val; for(i=0, j=0; i < l; i++) { val = ip[i]; v = val / 100; if (v) { str[j++] = L'0'+v; } val = val % 100; v = val / 10; if (v || ip[i] >= 100) { str[j++] = L'0'+v; } v = val % 10; str[j++] = L'0'+v; if (i < l-1) str[j++] = L'.'; } str[j] = CHAR_NULL; } static int netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info) { INTN len; StrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN); len = StrLen(netfs_default_path) - 1; while (len >= 0) { if (netfs_default_path[len] == CHAR_SLASH || netfs_default_path[len] == CHAR_BACKSLASH) break; len--; } netfs_default_path[len+1] = CHAR_NULL; DBG_PRT((L"netfs_default_path=%s\n", netfs_default_path)); return EFI_SUCCESS; } static EFI_STATUS netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) { netfs_interface_t *netfs = (netfs_interface_t *)intf; netfs_info_t info; EFI_STATUS status; UINT8 *ipaddr; UINTN m; CHAR16 ip_var[64], str[64]; UINT8 *ip; if (config == NULL || kname == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; netfs->netfs_getinfo(netfs, &info); m = info.using_ipv6 ? 16 : 4; ipaddr = info.using_ipv6 ? info.cln_ipaddr.v6.Addr: info.cln_ipaddr.v4.Addr; convert_ip2decstr(ipaddr, m, ip_var); set_var(VAR_NETFS_IPADDR, ip_var); ip = info.using_ipv6 ? info.netmask.v6.Addr: info.netmask.v4.Addr; convert_ip2decstr(ip, m, str); set_var(VAR_NETFS_NETMASK, str); ip = info.using_ipv6 ? info.gw_ipaddr.v6.Addr: info.gw_ipaddr.v4.Addr; convert_ip2decstr(ip, m, str); set_var(VAR_NETFS_GATEWAY, str); set_var(VAR_NETFS_HOSTNAME, info.hostname); set_var(VAR_NETFS_DOMAINAME, info.domainame); if (info.using_pxe) { DBG_PRT((L"netfs_setdefaults: using_pxe")); status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname); if (EFI_ERROR(status)) { StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); config[0].fname[maxlen-1] = CHAR_NULL; } status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname); if (EFI_ERROR(status)) { StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); kname[maxlen-1] = CHAR_NULL; } } else { #ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG # if defined(CONFIG_ia64) # define CONFIG_ARCH_EXTENSION L"-ia64.conf\0" # define EXTENSION_LENGTH 11 # elif defined (CONFIG_ia32) # define CONFIG_ARCH_EXTENSION L"-ia32.conf\0" # define EXTENSION_LENGTH 11 # elif defined (CONFIG_x86_64) # define CONFIG_ARCH_EXTENSION L"-x86_64.conf\0" # define EXTENSION_LENGTH 13 # else # error "You need to specfy your default arch config file" # endif # define CONFIG_EXTENSION L".conf\0" DBG_PRT((L"netfs_setdefaults: machine specific (!using_pxe)")); /* * will try machine/subnet specific files first. * the filenames are constructed based on the IP(v4) address */ convert_ip2hex(ipaddr, m, str); StrnCpy(config[0].fname, str, maxlen-1); StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); StrnCpy(config[1].fname, str, maxlen-1); StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); StrnCpy(config[2].fname, str, maxlen-1); StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6); StrnCpy(config[3].fname, str, maxlen-1); StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); StrnCpy(config[4].fname, str, maxlen-1); StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6); StrnCpy(config[5].fname, str, maxlen-1); StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); StrnCpy(config[6].fname, str, maxlen-1); StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); /* use the MAC address as a possible file name as well */ convert_mac2hex(info.hw_addr,6,str); StrnCpy(config[7].fname, str, maxlen-1); StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); #else StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); config[0].fname[maxlen-1] = CHAR_NULL; #endif StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); kname[maxlen-1] = CHAR_NULL; /* * extract bootloader path prefix to be used for * the config file (and possibly the other files we * need to download) */ netfs_set_default_path(netfs, &info); } return EFI_SUCCESS; } static EFI_STATUS netfs_getdefault_path(CHAR16 *path, UINTN maxlen) { if (maxlen <= StrLen(netfs_default_path)) return EFI_BUFFER_TOO_SMALL; StrCpy(path, netfs_default_path); return EFI_SUCCESS; } static EFI_STATUS glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd) { netfs_interface_t *netfs = (netfs_interface_t *)intf; CHAR16 fullname[FILENAME_MAXLEN]; if (name[0] != CHAR_SLASH && name[0] != CHAR_BACKSLASH && netfs_default_path[0] != CHAR_NULL) { if (StrLen(netfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN) return EFI_INVALID_PARAMETER; StrCpy(fullname, netfs_default_path); StrCat(fullname, name); name = fullname; } return netfs->netfs_open(intf, name, fd); } static INTN glue(fileops_t *fp, VOID *intf) { netfs_interface_t *netfs = (netfs_interface_t *)intf; /* record underlying interface */ fp->intf = intf; fp->open = glue_open; fp->read = (fops_read_t)netfs->netfs_read; fp->close = (fops_close_t)netfs->netfs_close; fp->infosize = (fops_infosize_t)netfs->netfs_infosize; fp->seek = (fops_seek_t)netfs->netfs_seek; fp->setdefaults = (fops_setdefaults_t)netfs_setdefaults; fp->getdefault_path = (fops_getdefault_path_t)netfs_getdefault_path; fp->intf = intf; /* fill out the name of the underlying file system */ netfs->netfs_name(netfs, fp->name, FILEOPS_NAME_MAXLEN); return 0; } ./elilo/ia32/0000755000175000017500000000000011513632673012406 5ustar jasonfjasonf./elilo/ia32/bzimage.c0000644000175000017500000001477711466353731014212 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * * 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 #include #include "elilo.h" #include "loader.h" boot_params_t *param_start = NULL; UINTN param_size = 0; UINTN kernel_size = 0x400000; /* 4M (default x86 bzImage size limit) */ static INTN bzImage_probe(CHAR16 *kname) { EFI_STATUS efi_status; UINTN size; fops_fd_t fd; UINT8 bootsect[512]; DBG_PRT((L"probe_bzImage_boot()\n")); if (!kname) { ERR_PRT((L"kname == " PTR_FMT, kname)); free_kmem(); return -1; } /* * Open kernel image. */ DBG_PRT((L"opening %s...\n", kname)); efi_status = fops_open(kname, &fd); if (EFI_ERROR(efi_status)) { ERR_PRT((L"Could not open %s.", kname)); free_kmem(); return -1; } /* * Read boot sector. */ DBG_PRT((L"\nreading boot sector...\n")); size = sizeof bootsect; efi_status = fops_read(fd, bootsect, &size); if (EFI_ERROR(efi_status) || size != sizeof bootsect) { ERR_PRT((L"Could not read boot sector from %s.", kname)); fops_close(fd); free_kmem(); return -1; } /* * Verify boot sector signature. */ if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) { ERR_PRT((L"%s is not a bzImage kernel image.\n", kname)); fops_close(fd); free_kmem(); return -1; } /* * Check for out of range setup data size. * Will almost always be 7, but we will accept 1 to 64. */ DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1])); if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) { ERR_PRT((L"%s is not a valid bzImage kernel image.", kname)); fops_close(fd); free_kmem(); return -1; } /* * Allocate and read setup data. */ DBG_PRT((L"reading setup data...\n")); param_size = (bootsect[0x1F1] + 1) * 512; param_start = alloc(param_size, EfiLoaderData); DBG_PRT((L"param_size=%d param_start=" PTR_FMT, param_size, param_start)); if (!param_start) { ERR_PRT((L"Could not allocate %d bytes of setup data.", param_size)); fops_close(fd); free_kmem(); return -1; } CopyMem(param_start, bootsect, sizeof bootsect); size = param_size - 512; efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size); if (EFI_ERROR(efi_status) || size != param_size - 512) { ERR_PRT((L"Could not read %d bytes of setup data.", param_size - 512)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } /* * Check for setup data signature. */ { UINT8 *c = ((UINT8 *)param_start)+514; DBG_PRT((L"param_start(c=" PTR_FMT "): %c-%c-%c-%c", c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3])); } if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) { ERR_PRT((L"%s does not have a setup signature.", kname)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } /* * Allocate memory for kernel. */ /* * Get correct address for kernel from header, if applicable & available. */ if ((param_start->s.hdr_major == 2) && (param_start->s.hdr_minor >= 6) && (param_start->s.kernel_start >= DEFAULT_KERNEL_START)) { kernel_start = (void *)param_start->s.kernel_start; VERB_PRT(3, Print(L"kernel header suggests kernel start at address "PTR_FMT"\n", kernel_start)); } kernel_load_address = NULL; /* allocate anywhere! */ if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { /* * Couldn't get desired address--just load it anywhere and move it later. * (Easier than relocating kernel, and also works with non-relocatable kernels.) */ if (alloc_kmem_anywhere(&kernel_load_address, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { ERR_PRT((L"Could not allocate memory for kernel.")); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); return -1; } } VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d loading at: "PTR_FMT"\n", kernel_start, kernel_size, kernel_load_address)); /* * Now read the rest of the kernel image into memory. */ DBG_PRT((L"reading kernel image...\n")); size = kernel_size; efi_status = fops_read(fd, kernel_load_address, &size); if (EFI_ERROR(efi_status) || size < 0x10000) { ERR_PRT((L"Error reading kernel image %s.", kname)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024)); /* * Boot sector, setup data and kernel image loaded. */ fops_close(fd); return 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static INTN bzImage_load(CHAR16 *kname, kdesc_t *kd) { DBG_PRT((L"load_bzImage_boot()\n")); if (!kname || !kd) { ERR_PRT((L"kname=" PTR_FMT " kd=" PTR_FMT, kname, kd)); free(param_start); param_start = NULL; param_size = 0; free_kmem(); return -1; } kd->kstart = kd->kentry = kernel_start; kd->kend = ((UINT8 *)kd->kstart) + kernel_size; DBG_PRT((L"kstart=" PTR_FMT " kentry=" PTR_FMT " kend=" PTR_FMT "\n", kd->kstart, kd->kentry, kd->kend)); return 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ loader_ops_t bzimage_loader = { NULL, L"bzImage_loader", &bzImage_probe, &bzImage_load }; ./elilo/ia32/plain_loader.c0000644000175000017500000001634311165216511015202 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include #include "elilo.h" #include "loader.h" #include "elf.h" #include "private.h" #define LD_NAME L"plain_elf32" static INTN is_valid_header(Elf32_Ehdr *ehdr) { UINT16 type, machine; type = ehdr->e_type; machine = ehdr->e_machine; DBG_PRT((L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS32 && type == ET_EXEC /* must be executable */ && machine == EM_386 ? 0 : -1; } static INTN plain_probe(CHAR16 *kname) { Elf32_Ehdr ehdr; EFI_STATUS status; INTN ret = -1; fops_fd_t fd; UINTN size = sizeof(ehdr); status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error; ret = is_valid_header(&ehdr); error: fops_close(fd); return ret; } static INTN load_elf(fops_fd_t fd, kdesc_t *kd) { Elf32_Ehdr ehdr; Elf32_Phdr *phdrs; EFI_STATUS status; INTN ret = ELILO_LOAD_ERROR; UINTN i, total_size = 0; UINTN pages, size, bss_sz, osize; VOID *low_addr = (VOID *)~0; VOID *max_addr = (VOID *)0; UINTN paddr, memsz, filesz; UINT16 phnum; Print(L"Loading Linux... "); size = sizeof(ehdr); status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) || size < sizeof(ehdr)) return ELILO_LOAD_ERROR; if (is_valid_header(&ehdr) == -1) { ERR_PRT((L"%s : not a 32-bit ELF image\n", LD_NAME)); return ELILO_LOAD_ERROR; } VERB_PRT(3, { Print(L"ELF Header information: \n"); Print(L"\tEntry point "PTR_FMT"\n", (ehdr.e_entry & PADDR_MASK)); Print(L"\t%d program headers\n", ehdr.e_phnum); Print(L"\t%d segment headers\n", ehdr.e_shnum); }); phnum = ehdr.e_phnum; if (fops_seek(fd, ehdr.e_phoff) < 0) { ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff)); return ELILO_LOAD_ERROR; } size = osize = (phnum * sizeof(Elf32_Phdr)); DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n", LD_NAME, size, phnum, sizeof(Elf32_Phdr), ehdr.e_phentsize)); phdrs = (Elf32_Phdr *)alloc(size, 0); if (phdrs == NULL) { ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME)); return ELILO_LOAD_ERROR; } status = fops_read(fd, phdrs, &size); if (EFI_ERROR(status) || size != osize) { ERR_PRT((L"%s : phdr load failed", LD_NAME, status)); goto out; } /* * First pass to figure out total memory footprint */ for (i = 0; i < phnum; i++) { paddr = (phdrs[i].p_paddr & PADDR_MASK); memsz = phdrs[i].p_memsz; DBG_PRT((L"Phdr %d paddr ["PTR_FMT"-"PTR_FMT"] offset "PTR_FMT"" " filesz "PTR_FMT" memsz="PTR_FMT" bss_sz="PTR_FMT" p_type="PTR_FMT"\n", 1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset, phdrs[i].p_filesz, memsz, (memsz - phdrs[i].p_filesz), phdrs[i].p_type)); if (phdrs[i].p_type != PT_LOAD) continue; if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr; if (paddr + memsz > (UINTN)max_addr) max_addr = (VOID *)paddr + memsz; } if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : kernel low address "PTR_FMT" not page aligned\n", LD_NAME, low_addr)); goto out; } /* how many bytes are needed to hold the kernel? */ total_size = (UINTN)max_addr - (UINTN)low_addr; /* round up to get required number of pages */ pages = EFI_SIZE_TO_PAGES(total_size); /* keep track of location where kernel starts and ends */ kd->kstart = low_addr; kd->kend = (low_addr + (pages << EFI_PAGE_SHIFT)); kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK); VERB_PRT(3, { Print(L"Lowest PhysAddr: "PTR_FMT"\nTotalMemSize:%d bytes (%d pages)\n", low_addr, total_size, pages); Print(L"Kernel entry @ "PTR_FMT"\n", kd->kentry); }); /* now allocate memory for the kernel at the exact requested spot */ if (alloc_kmem(low_addr, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, "PTR_FMT") for kernel failed\n", LD_NAME, pages, low_addr)); ERR_PRT((L"%s : Could not alloc %d pages for the kernel at "PTR_FMT"" " and relocation is not not been implemented!\n", LD_NAME, pages, low_addr)); goto load_abort; } /* Pure paranoia. Clear the memory first. Just in case... */ Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT)); VERB_PRT(1, Print(L"Press any key to interrupt\n")); /* * Walk through the program headers * and actually load data into physical memory */ for (i = 0; i < phnum; i++) { /* Check for pure loadable segment; ignore if not loadable */ if (phdrs[i].p_type != PT_LOAD) continue; VERB_PRT(3, Print(L"poffs: "PTR_FMT" (phdrs[%d].p_offset)\n", phdrs[i].p_offset, i)); filesz = phdrs[i].p_filesz; low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK); /* Move to the right position */ if (fops_seek(fd, phdrs[i].p_offset) < 0) goto out_kernel; /* How many BSS bytes to clear */ bss_sz = phdrs[i].p_memsz - filesz; VERB_PRT(4, { Print(L"\nHeader #%d\n", i); Print(L"Offset in file "PTR_FMT"\n", phdrs[i].p_offset); Print(L"Physical addr "PTR_FMT"\n", low_addr); Print(L"BSS size %d bytes\n", bss_sz); }); /* * Read actual segment into memory */ ret = fops_read(fd, low_addr, &filesz); if (ret == ELILO_LOAD_ABORTED) goto load_abort; if (ret == ELILO_LOAD_ERROR) goto out; /* * Clear bss section */ if (bss_sz) Memset((VOID *)low_addr+filesz, 0, bss_sz); } free(phdrs); Print(L"..Done\n"); return ELILO_LOAD_SUCCESS; load_abort: Print(L"..Aborted\n"); ret = ELILO_LOAD_ABORTED; out_kernel: /* free kernel memory */ free_kmem(); out: free(phdrs); return ret; } static INTN plain_load_kernel(CHAR16 *kname, kdesc_t *kd) { INTN ret; fops_fd_t fd; EFI_STATUS status; /* * Moving the open here simplifies the load_elf() error handling */ status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; Print(L"Loading %s...", kname); ret = load_elf(fd, kd); fops_close(fd); return ret; } loader_ops_t plain_loader={ NULL, LD_NAME, plain_probe, plain_load_kernel }; ./elilo/ia32/bin_to_h.c0000644000175000017500000000053707434573353014346 0ustar jasonfjasonf#include #include int main(void) { unsigned n = 0; int c; printf("UINT8 rmswitch_image[] = {\n"); while ((c = getchar()) != EOF) { printf("0x%02x,%s", c & 0xFF, (++n & 0x07) ? " " : "\n"); } if (n & 0x07) { printf("\n"); } printf( "};\n" "UINTN rmswitch_size = sizeof rmswitch_image;\n"); return 0; } ./elilo/ia32/rmswitch.S0000644000175000017500000000335007434573353014401 0ustar jasonfjasonf# # Switch from protected mode to real mode and jump to setup.S # image located at %cx:0. # # This module must be placed into physical memory at 0:7C00h. # EFI has some real mode thunking code at 2000:0h. # # Processor and non-maskable interrupts should be disabled # before control is passed to this module. # .global _start .code32 .text _start: # # Load identity mapped GDT & real mode IDT. # Add 7C00h to the addresses since this is linked to start # at 0h and it is being placed at 7C00h. # lgdt %cs:gdt_48 + 0x7C00 lidt %cs:idt_48 + 0x7C00 # # Turn off PG bit in CR0 and set CR3 to zero. # movl %cr0, %eax andl $0x7FFFFFFF, %eax movl %eax, %cr0 xorl %eax, %eax movl %eax, %cr3 # # Reload CS. # Now we add 7B00h because we need to force the segment # address and selector to be the same. # .byte 0xEA .long pm_reload + 0x7B00 .word 0x10 pm_reload: .code16 # # Reload DS, ES, FS, GS & SS. # movw $0x18, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss # # Switch to real mode. Clear PE bit in CR0. # movl %cr0, %eax andl $0xFFFFFFFE, %eax movl %eax, %cr0 # # Reload CS. # .byte 0xEA .word rm_reload + 0x7C00 .word 0 rm_reload: # # Reload SS & SP. # xorw %ax, %ax movw %ax, %ss movw $0x7BFE, %sp # # Start running setup.S # .byte 0xEA .word 0 .word 0x9020 # # GDT & IDT stuff for switching into real mode. # gdt: .word 0, 0, 0, 0 # unused (00h) .word 0, 0, 0, 0 # dummy (08h) .word 0xFFFF, 0x100 # code (10h) .word 0x9A00, 0 .word 0xFFFF, 0x180 # data (18h) .word 0x9200, 0 gdt_48: .word 0x08 * 0x400 .long gdt + 0x7C00 idt_48: .word 0x400 .long 0 # # Be careful not to exceed 1F0h or the the bootsect.S # parameters will be lost! # .end ./elilo/ia32/private.h0000644000175000017500000000210307720452103014216 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __ELILO_PRIVATE_IA32_H__ #define __ELILO_PRIVATE_IA32_H__ #endif /* __ELILO_PRIVATE_IA32_H__ */ ./elilo/ia32/Makefile0000644000175000017500000000273310014523360014036 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o TARGET=sysdeps.o all: $(TARGET) system.o: rmswitch.h rmswitch.h: bin_to_h.c rmswitch.S $(CC) -o bin_to_h bin_to_h.c $(AS) -o rmswitch.o rmswitch.S $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o ./bin_to_h rmswitch.h $(TARGET): $(FILES) $(LD) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) $(RM) -f bin_to_h.o bin_to_h $(RM) -f rmswitch.h rmswitch.o rmswitch ./elilo/ia32/system.c0000644000175000017500000005325411511435355014103 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * * 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. */ /* * This file contains all the IA-32 specific code expected by generic loader */ #include #include #include "elilo.h" #include "loader.h" #include "rmswitch.h" extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; /* * Descriptor table base addresses & limits for Linux startup. */ dt_addr_t gdt_addr = { 0x800, 0x94000 }; dt_addr_t idt_addr = { 0, 0 }; /* * Initial GDT layout for Linux startup. */ UINT16 init_gdt[] = { /* gdt[0]: dummy */ 0, 0, 0, 0, /* gdt[1]: unused */ 0, 0, 0, 0, /* gdt[2]: code */ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */ 0x0000, /* base address=0 */ 0x9A00, /* code read/exec */ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */ /* gdt[3]: data */ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */ 0x0000, /* base address=0 */ 0x9200, /* data read/write */ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */ }; UINTN sizeof_init_gdt = sizeof init_gdt; /* * Highest available base memory address. * * For traditional kernels and loaders this is always at 0x90000. * For updated kernels and loaders this is computed by taking the * highest available base memory address and rounding down to the * nearest 64 kB boundary and then subtracting 64 kB. * * A non-compressed kernel is automatically assumed to be an updated * kernel. A compressed kernel that has bit 6 (0x40) set in the * loader_flags field is also assumed to be an updated kernel. */ UINTN high_base_mem = 0x90000; /* * Highest available extended memory address. * * This is computed by taking the highest available extended memory * address and rounding down to the nearest EFI_PAGE_SIZE (usually * 4 kB) boundary. * This is only used for backward compatibility. */ UINTN high_ext_mem = 32 * 1024 * 1024; /* This starting address will hold true for all of the loader types for now */ VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START; /* The kernel may load elsewhere if EFI firmware reserves kernel_start */ VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START; VOID *initrd_start = NULL; UINTN initrd_size = 0; INTN sysdeps_init(EFI_HANDLE dev) { DBG_PRT((L"sysdeps_init()\n")); /* * Register our loader(s)... */ loader_register(&bzimage_loader); loader_register(&plain_loader); loader_register(&gzip_loader); return 0; } /* * initrd_get_addr() * Compute a starting address for the initial RAMdisk image. * For now, this image is placed immediately after the end of * the kernel memory. Inside the start_kernel() code, the * RAMdisk image will be relocated to the top of available * extended memory. */ INTN sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) { DBG_PRT((L"initrd_get_addr()\n")); if (!kd || !imem) { ERR_PRT((L"kd=" PTR_FMT " imem=" PTR_FMT, kd, imem)); return -1; } VERB_PRT(3, Print(L"kstart=" PTR_FMT " kentry=" PTR_FMT " kend=" PTR_FMT "\n", kd->kstart, kd->kentry, kd->kend)); imem->start_addr = kd->kend; VERB_PRT(3, Print(L"initrd start_addr=" PTR_FMT " pgcnt=%d\n", imem->start_addr, imem->pgcnt)); return 0; } VOID * sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) { return start_addr; } VOID sysdeps_free_boot_params(boot_params_t *bp) { mmap_desc_t md; ZeroMem(&md, sizeof md); md.md = (VOID *)bp->s.efi_mem_map; free_memmap(&md); } static VOID find_bits(unsigned long mask, UINT8 *first, UINT8* len) { unsigned char bit_pos = 0, bit_len = 0; *first =0; *len = 0; if (mask == 0) return; while (!(mask & 0x1)) { mask = mask >> 1; bit_pos++; } while (mask & 0x1) { mask = mask >> 1; bit_len++; } *first = bit_pos; *len = bit_len; } /* * Get video information. */ static INTN get_video_info(boot_params_t * bp) { EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info; EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Gop_mode = NULL; EFI_HANDLE *Gop_handle = NULL; EFI_STATUS efi_status; UINTN size = 0; UINTN size1; UINT8 i; efi_status = uefi_call_wrapper( BS->LocateHandle, 5, ByProtocol, &GopProtocol, NULL, &size, (VOID **)Gop_handle); if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { Print(L"LocateHandle GopProtocol failed.\n"); Print(L"--Either no graphics head is installed,\n" \ "--efi console is set to serial, or,\n" \ "--the EFI firmware version of this machine is\n" \ "--older than UEFI 2.0. and does not support GOP"); Print(L"you can SAFELY IGNORE this error. elilo will\n" \ "default to text-mode.\n Alternatively you can " \ "now force text mode by setting config variable\n" \ "text_mode=1 for x86 in elilo.conf or via cmdline.\n\n"); Print(L"However if this is the last text output you see\n" \ "ensure that your kernel console command line\n " \ "variable matches up with the actual efi boot menu\n" \ "console output settings. for example efi console\n\n"); return -1; } Gop_handle = alloc(size, 0); efi_status = uefi_call_wrapper( BS->LocateHandle, 5, ByProtocol, &GopProtocol, NULL, &size, (VOID **)Gop_handle); if (EFI_ERROR(efi_status)) { ERR_PRT((L"LocateHandle GopProtocol failed.")); free(Gop_handle); return -1; } for (i=0; i < size/sizeof(EFI_HANDLE); i++) { Gop_handle += i; efi_status = uefi_call_wrapper( BS->HandleProtocol, 3, *Gop_handle, &GopProtocol, (VOID **) &Gop_interface); if (EFI_ERROR(efi_status)) { continue; } Gop_mode = Gop_interface->Mode; efi_status = uefi_call_wrapper( Gop_interface->QueryMode, 4, Gop_interface, Gop_mode->Mode, &size1, &Gop_info); if (!EFI_ERROR(efi_status)) break; if (EFI_ERROR(efi_status)) { continue; } } if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) { ERR_PRT((L"HandleProtocol GopProtocol failed.")); free(Gop_handle); return -1; } bp->s.is_vga = 0x70; bp->s.orig_cursor_col = 0; bp->s.orig_cursor_row = 0; bp->s.orig_video_page = 0; bp->s.orig_video_mode = 0; bp->s.orig_video_cols = 0; bp->s.orig_video_rows = 0; bp->s.orig_ega_bx = 0; bp->s.orig_video_points = 0; bp->s.lfb_width = Gop_info->HorizontalResolution; bp->s.lfb_height = Gop_info->VerticalResolution; bp->s.lfb_base = Gop_mode->FrameBufferBase; bp->s.lfb_size = Gop_mode->FrameBufferSize; bp->s.lfb_pages = 1; bp->s.vesa_seg = 0; bp->s.vesa_off = 0; if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { bp->s.lfb_depth = 32; bp->s.lfb_red_size = 8; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 8; bp->s.lfb_green_pos = 8; bp->s.lfb_blue_size = 8; bp->s.lfb_blue_pos = 16; bp->s.lfb_rsvd_size = 8; bp->s.lfb_rsvd_pos = 24; bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4; } else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { bp->s.lfb_depth = 32; bp->s.lfb_red_size = 8; bp->s.lfb_red_pos = 16; bp->s.lfb_green_size = 8; bp->s.lfb_green_pos = 8; bp->s.lfb_blue_size = 8; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 8; bp->s.lfb_rsvd_pos = 24; bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4; } else if (Gop_info->PixelFormat == PixelBitMask) { find_bits(Gop_info->PixelInformation.RedMask, &bp->s.lfb_red_pos, &bp->s.lfb_red_size); find_bits(Gop_info->PixelInformation.GreenMask, &bp->s.lfb_green_pos, &bp->s.lfb_green_size); find_bits(Gop_info->PixelInformation.BlueMask, &bp->s.lfb_blue_pos, &bp->s.lfb_blue_size); find_bits(Gop_info->PixelInformation.ReservedMask, &bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size); bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size + bp->s.lfb_blue_size + bp->s.lfb_rsvd_size; bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8; } else { bp->s.lfb_depth = 4; bp->s.lfb_red_size = 0; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 0; bp->s.lfb_green_pos = 0; bp->s.lfb_blue_size = 0; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 0; bp->s.lfb_rsvd_pos = 0; bp->s.lfb_line_len = bp->s.lfb_width / 2; } return 0; } /* Convert EFI memory map to E820 map for the operating system * This code is based on a Linux kernel patch submitted by Edgar Hucek */ /* Add a memory region to the e820 map */ static void add_memory_region (struct e820entry *e820_map, int *e820_nr_map, UINT64 start, UINT64 size, UINT32 type) { int x = *e820_nr_map; if (x == E820_MAX) { Print(L"Too many entries in the memory map!\n"); return; } if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start && e820_map[x-1].type == type) e820_map[x-1].size += size; else { e820_map[x].addr = start; e820_map[x].size = size; e820_map[x].type = type; (*e820_nr_map)++; } } void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) { int nr_map, e820_nr_map = 0, i; UINT64 start, end, size; EFI_MEMORY_DESCRIPTOR *md, *p; struct e820entry *e820_map; nr_map = mdesc->map_size/mdesc->desc_size; e820_map = (struct e820entry *)bp->s.e820_map; for (i = 0, p = mdesc->md; i < nr_map; i++) { md = p; switch (md->Type) { case EfiACPIReclaimMemory: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_ACPI); break; case EfiRuntimeServicesCode: case EfiRuntimeServicesData: case EfiReservedMemoryType: case EfiMemoryMappedIO: case EfiMemoryMappedIOPortSpace: case EfiUnusableMemory: case EfiPalCode: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_RESERVED); break; case EfiLoaderCode: case EfiLoaderData: case EfiBootServicesCode: case EfiBootServicesData: case EfiConventionalMemory: start = md->PhysicalStart; size = md->NumberOfPages << EFI_PAGE_SHIFT; end = start + size; /* Fix up for BIOS that claims RAM in 640K-1MB region */ if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) { /* start < 640K * set memory map from start to 640K */ add_memory_region(e820_map, &e820_nr_map, start, 0xA0000ULL-start, E820_RAM); } if (end <= 0x100000ULL) continue; /* end > 1MB * set memory map avoiding 640K to 1MB hole */ start = 0x100000ULL; size = end - start; } add_memory_region(e820_map, &e820_nr_map, start, size, E820_RAM); break; case EfiACPIMemoryNVS: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_NVS); break; default: /* We should not hit this case */ add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_RESERVED); break; } p = NextMemoryDescriptor(p, mdesc->desc_size); } bp->s.e820_nrmap = e820_nr_map; } /* * IA-32 specific boot parameters initialization routine */ INTN sysdeps_create_boot_params( boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, memdesc_t *vmcode, /* no use for ia32 now*/ UINTN *cookie) { mmap_desc_t mdesc; EFI_STATUS efi_status; UINTN rows, cols; UINT8 row, col; UINT8 mode; UINT16 hdr_version; DBG_PRT((L"fill_boot_params()\n")); if (!bp || !cmdline || !initrd || !cookie) { ERR_PRT((L"bp=" PTR_FMT " cmdline=" PTR_FMT " initrd=" PTR_FMT " cookie=" PTR_FMT, bp, cmdline, initrd, cookie)); if (param_start != NULL) { free(param_start); param_start = NULL; param_size = 0; } free_kmem(); return -1; } /* * Copy temporary boot sector and setup data storage to * elilo allocated boot parameter storage. We only need * the first two sectors (1K). The rest of the storage * can be used by the command line. */ if (param_start != NULL) { CopyMem(bp, param_start, 0x2000); free(param_start); param_start = NULL; param_size = 0; } /* * Save off our header revision information. */ hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor; /* * Clear out unused memory in boot sector image. */ bp->s.unused_1 = 0; bp->s.unused_2 = 0; ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3); ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4); ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51); ZeroMem(bp->s.unused_52, sizeof bp->s.unused_52); bp->s.unused_6 = 0; bp->s.unused_7 = 0; ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8); /* * Tell kernel this was loaded by an advanced loader type. * If this field is zero, the initrd_start and initrd_size * fields are ignored by the kernel. */ bp->s.loader_type = LDRTYPE_ELILO; /* * Setup command line information. */ bp->s.cmdline_magik = CMDLINE_MAGIK; bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp; /* * Clear out the cmdline_addr field so the kernel can find * the cmdline. */ bp->s.cmdline_addr = 0x0; /* * Setup hard drive parameters. * %%TBD - It should be okay to zero fill the hard drive * info buffers. The kernel should do its own detection. */ ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info); ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info); /* * Memory info. */ bp->s.alt_mem_k = high_ext_mem / 1024; if (bp->s.alt_mem_k <= 65535) bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k; else bp->s.ext_mem_k = 65535; /* * Initial RAMdisk and root device stuff. */ DBG_PRT((L"initrd->start_addr=" PTR_FMT " initrd->pgcnt=%d\n", initrd->start_addr, initrd->pgcnt)); /* These RAMdisk flags are not needed, just zero them. */ bp->s.ramdisk_flags = 0; if (initrd->start_addr && initrd->pgcnt) { /* %%TBD - This will probably have to be changed. */ bp->s.initrd_start = (UINT32)initrd->start_addr; bp->s.initrd_size = (UINT32)(initrd->size); /* * This is the RAMdisk root device for RedHat 2.2.x * kernels (major 0x01, minor 0x00). */ bp->s.orig_root_dev = 0x0100; } else { bp->s.initrd_start = 0; bp->s.initrd_size = 0; } /* * APM BIOS info. */ bp->s.apm_bios_ver = NO_APM_BIOS; bp->s.bios_code_seg = 0; bp->s.bios_entry_point = 0; bp->s.bios_code_seg16 = 0; bp->s.bios_data_seg = 0; bp->s.apm_bios_flags = 0; bp->s.bios_code_len = 0; bp->s.bios_data_len = 0; /* * MCA BIOS info (misnomer). */ bp->s.mca_info_len = 0; ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf); /* * Pointing device presence. The kernel will detect this. */ bp->s.aux_dev_info = NO_MOUSE; /* * EFI loader signature */ CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_IA32, 4); /* * Kernel entry point. */ bp->s.kernel_start = (UINT32)kernel_start; /* * When changing stuff in the parameter structure compare * the offsets of the fields with the offsets used in the * boot sector and setup source files. * arch/i386/boot/bootsect.S * arch/i386/boot/setup.S * arch/i386/kernel/setup.c * include/asm-i386/setup.h (2.5/2.6) */ #define CHECK_OFFSET(n, o, f) \ { \ UINTN p = (UINT8 *)&bp->s.n - (UINT8 *)bp; \ UINTN q = (UINTN)(o); \ if (p != q) { \ test |= 1; \ Print(L"%20a: %3xh %3xh ", #n, p, q); \ if (*f) { \ Print(f, bp->s.n); \ } \ Print(L"\n"); \ } \ } #define WAIT_FOR_KEY() \ { \ EFI_INPUT_KEY key; \ while (uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key) != EFI_SUCCESS) { \ ; \ } \ } { UINTN test = 0; CHECK_OFFSET(orig_cursor_col, 0x00, L"%xh"); CHECK_OFFSET(orig_cursor_row, 0x01, L"%xh"); CHECK_OFFSET(ext_mem_k, 0x02, L"%xh"); CHECK_OFFSET(orig_video_page, 0x04, L"%xh"); CHECK_OFFSET(orig_video_mode, 0x06, L"%xh"); CHECK_OFFSET(orig_video_cols, 0x07, L"%xh"); CHECK_OFFSET(orig_ega_bx, 0x0A, L"%xh"); CHECK_OFFSET(orig_video_rows, 0x0E, L"%xh"); CHECK_OFFSET(is_vga, 0x0F, L"%xh"); CHECK_OFFSET(orig_video_points, 0x10, L"%xh"); CHECK_OFFSET(lfb_width, 0x12, L"%xh"); CHECK_OFFSET(lfb_height, 0x14, L"%xh"); CHECK_OFFSET(lfb_depth, 0x16, L"%xh"); CHECK_OFFSET(lfb_base, 0x18, L"%xh"); CHECK_OFFSET(lfb_size, 0x1C, L"%xh"); CHECK_OFFSET(cmdline_magik, 0x20, L"%xh"); CHECK_OFFSET(cmdline_offset, 0x22, L"%xh"); CHECK_OFFSET(lfb_line_len, 0x24, L"%xh"); CHECK_OFFSET(lfb_red_size, 0x26, L"%xh"); CHECK_OFFSET(lfb_red_pos, 0x27, L"%xh"); CHECK_OFFSET(lfb_green_size, 0x28, L"%xh"); CHECK_OFFSET(lfb_green_pos, 0x29, L"%xh"); CHECK_OFFSET(lfb_blue_size, 0x2A, L"%xh"); CHECK_OFFSET(lfb_blue_pos, 0x2B, L"%xh"); CHECK_OFFSET(lfb_rsvd_size, 0x2C, L"%xh"); CHECK_OFFSET(lfb_rsvd_pos, 0x2D, L"%xh"); CHECK_OFFSET(vesa_seg, 0x2E, L"%xh"); CHECK_OFFSET(vesa_off, 0x30, L"%xh"); CHECK_OFFSET(lfb_pages, 0x32, L"%xh"); CHECK_OFFSET(lfb_reserved, 0x34, L""); CHECK_OFFSET(apm_bios_ver, 0x40, L"%xh"); CHECK_OFFSET(bios_code_seg, 0x42, L"%xh"); CHECK_OFFSET(bios_entry_point, 0x44, L"%xh"); CHECK_OFFSET(bios_code_seg16, 0x48, L"%xh"); CHECK_OFFSET(bios_data_seg, 0x4A, L"%xh"); CHECK_OFFSET(apm_bios_flags, 0x4C, L"%xh"); CHECK_OFFSET(bios_code_len, 0x4E, L"%xh"); CHECK_OFFSET(bios_data_len, 0x52, L"%xh"); CHECK_OFFSET(hd0_info, 0x80, L""); CHECK_OFFSET(hd1_info, 0x90, L""); CHECK_OFFSET(mca_info_len, 0xA0, L"%xh"); CHECK_OFFSET(mca_info_buf, 0xA2, L""); CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'"); CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh"); CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh"); CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh"); CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh"); CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh"); CHECK_OFFSET(loader_start, 0x1D8, L"%xh"); CHECK_OFFSET(loader_size, 0x1DC, L"%xh"); CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh"); CHECK_OFFSET(e820_nrmap, 0x1E8, L"%xh"); CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh"); CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh"); CHECK_OFFSET(sys_size, 0x1F4, L"%xh"); CHECK_OFFSET(swap_dev, 0x1F6, L"%xh"); CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh"); CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh"); CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh"); CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh"); CHECK_OFFSET(jump, 0x200, L"%xh"); CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'"); CHECK_OFFSET(hdr_minor, 0x206, L"%xh"); CHECK_OFFSET(hdr_major, 0x207, L"%xh"); CHECK_OFFSET(rm_switch, 0x208, L"%xh"); CHECK_OFFSET(start_sys_seg, 0x20C, L"%xh"); CHECK_OFFSET(kernel_verstr_offset, 0x20E, L"%xh"); CHECK_OFFSET(loader_type, 0x210, L"%xh"); CHECK_OFFSET(loader_flags, 0x211, L"%xh"); CHECK_OFFSET(setup_move_size, 0x212, L"%xh"); CHECK_OFFSET(kernel_start, 0x214, L"%xh"); CHECK_OFFSET(initrd_start, 0x218, L"%xh"); CHECK_OFFSET(initrd_size, 0x21C, L"%xh"); CHECK_OFFSET(bootsect_helper, 0x220, L"%xh"); CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh"); CHECK_OFFSET(cmdline_addr, 0x228, L"%xh"); CHECK_OFFSET(e820_map, 0x2D0, L"'%-2560.2560a'"); if (test) { ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); free_kmem(); return -1; } } /* * Get video information. * Do this last so that any other cursor positioning done * in the fill routine gets accounted for. */ if (!get_video_info(bp)) goto do_memmap; efi_status = uefi_call_wrapper( ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &cols, &rows); if (EFI_ERROR(efi_status)) { ERR_PRT((L"QueryMode failed. Fake it.")); mode = 3; rows = 25; cols = 80; row = 24; col = 0; } else { mode = (UINT8)ST->ConOut->Mode->Mode; col = (UINT8)ST->ConOut->Mode->CursorColumn; row = (UINT8)ST->ConOut->Mode->CursorRow; } bp->s.orig_cursor_col = col; bp->s.orig_cursor_row = row; bp->s.orig_video_page = 0; bp->s.orig_video_mode = mode; bp->s.orig_video_cols = (UINT8)cols; bp->s.orig_video_rows = (UINT8)rows; bp->s.orig_ega_bx = 0; bp->s.is_vga = 0; bp->s.orig_video_points = 16; bp->s.lfb_width = 0; bp->s.lfb_height = 0; bp->s.lfb_depth = 0; bp->s.lfb_base = 0; bp->s.lfb_size = 0; bp->s.lfb_line_len = 0; bp->s.lfb_red_size = 0; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 0; bp->s.lfb_green_pos = 0; bp->s.lfb_blue_size = 0; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 0; bp->s.lfb_rsvd_pos = 0; bp->s.lfb_pages = 0; bp->s.vesa_seg = 0; bp->s.vesa_off = 0; do_memmap: /* * Get memory map description and cookie for ExitBootServices() */ if (get_memmap(&mdesc)) { ERR_PRT((L"Could not get memory map.")); free_kmem(); return -1; } *cookie = mdesc.cookie; bp->s.efi_mem_map = (UINTN)mdesc.md; bp->s.efi_mem_map_size = mdesc.map_size; bp->s.efi_mem_desc_size = mdesc.desc_size; bp->s.efi_mem_desc_ver = mdesc.desc_version; bp->s.efi_sys_tbl = (UINTN)systab; /* Now that we have EFI memory map, convert it to E820 map * and update the bootparam accordingly */ fill_e820map(bp, &mdesc); return 0; } ./elilo/ia32/config.c0000644000175000017500000000463007720452067014024 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Chris Ahna * * 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 #include #include "elilo.h" #include "config.h" #include "private.h" typedef struct { UINTN legacy_free_boot; } ia32_global_config_t; static ia32_global_config_t ia32_gconf; static config_option_t sysdeps_global_options[]={ {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &ia32_gconf.legacy_free_boot} }; /* * IA-32 operations that need to be done only once and just before * entering the main loop of the loader * Return: * 0 if sucessful * -1 otherwise (will abort execution) */ INTN sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image) { return 0; } #define IA32_CMDLINE_OPTIONS L"" CHAR16 * sysdeps_get_cmdline_opts(VOID) { return IA32_CMDLINE_OPTIONS; } INTN sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg) { return -1; } VOID sysdeps_print_cmdline_opts(VOID) { } INTN ia32_use_legacy_free_boot(VOID) { return ia32_gconf.legacy_free_boot ? 1 : 0; } INTN sysdeps_register_options(VOID) { INTN ret; ret = register_config_options(sysdeps_global_options, sizeof(sysdeps_global_options)/sizeof(config_option_t), OPTIONS_GROUP_GLOBAL); #if 0 /* no per image options yet */ if (ret == -1 ) return ret; ret = register_config_options(sysdeps_image_options, sizeof(sysdeps_image_options)/sizeof(config_option_t), OPTIONS_GROUP_IMAGE); #endif return ret; } ./elilo/ia32/gzip.c0000644000175000017500000003251211271404161013514 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include #include "elf.h" #include "elilo.h" #include "gzip.h" #include "private.h" #define LD_NAME L"gzip_ia32" #define memzero(s, n) Memset((VOID *)(s), 0, (n)) #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) /* size of output buffer */ #define WSIZE 0x8000 /* Window size must be at least 32k, */ /* and a power of two */ /* size of input buffer */ #define INBUFSIZE 0x8000 /* * gzip declarations */ #define OF(args) args #define FUNC_STATIC static typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; typedef struct segment { unsigned long addr; /* start address */ unsigned long offset; /* file offset */ unsigned long size; /* file size */ unsigned long bss_sz; /* BSS size */ UINT8 flags; /* indicates whether to load or not */ } segment_t; #define CHUNK_FL_VALID 0x1 #define CHUNK_FL_LOAD 0x2 #define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD #define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD #define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD) #define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID #define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0 #define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID) /* * static parameters to gzip helper functions * we cannot use paramters because API was not * designed that way */ static segment_t *chunks; /* holds the list of segments */ static segment_t *cur_chunk; static UINTN nchunks; static UINTN chunk; /* current segment */ static UINTN input_fd; static VOID *kernel_entry, *kernel_base, *kernel_end; static uch *inbuf; /* input buffer (compressed data) */ static uch *window; /* output buffer (uncompressed data) */ static unsigned long file_offset; /* position in the file */ static unsigned insize = 0; /* valid bytes in inbuf */ static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) /* Diagnostic functions */ #ifdef INFLATE_DEBUG # define Assert(cond,msg) {if(!(cond)) error(msg);} int stderr; # define Trace(x) Print(L"line %d:\n", __LINE__); # define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;} # define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;} # define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;} # define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif static int fill_inbuf(void); static void flush_window(void); static void error(char *m); static long bytes_out; static void error(char *m); static int error_return; static void * gzip_malloc(int size) { return (void *)alloc(size, 0); } static void gzip_free(void *where) { return free(where); } #include "inflate.c" /* * Fill the input buffer and return the first byte in it. This is called * only when the buffer is empty and at least one byte is really needed. */ int fill_inbuf(void) { UINTN expected, nread; EFI_STATUS status; expected = nread = INBUFSIZE; status = fops_read(input_fd, inbuf, &nread); if (EFI_ERROR(status)) { error("elilo: Read failed"); } #ifdef DEBUG_GZIP DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected)); #endif insize = nread; inptr = 1; return inbuf[0]; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ /* * Run a set of bytes through the crc shift register. If s is a NULL * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. * * Input: * S pointer to bytes to pump through. * N number of bytes in S[]. */ unsigned long updcrc(unsigned char *s, unsigned n) { register unsigned long c; /* crc is defined in inflate.c */ if (!s) { c = 0xffffffffL; } else { c = crc; while (n--) { c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } } crc = c; return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */ } /* * Clear input and output buffers */ void clear_bufs(void) { outcnt = 0; inptr = 0; chunk = 0; cur_chunk = NULL; file_offset = 0; } static INTN is_valid_header(Elf32_Ehdr *ehdr) { UINT16 type, machine; type = ehdr->e_type; machine = ehdr->e_machine; VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS32 && type == ET_EXEC /* must be executable */ && machine == EM_386 ? 0 : -1; } /* * will invalidate loadble segments which overlap with others */ void check_overlap(int i) { int j; unsigned long iend = chunks[i].addr + chunks[i].size; for(j=0; j < nchunks; j++) { if (j ==i) continue; if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) { DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j)); CHUNK_INVALIDATE(i); /* nullyify segment */ break; } } } void analyze_chunks(void) { INTN i; for (i=0; i < nchunks; i++) { if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i); } } /* * The decompression code calls this function after decompressing the * first block of the object file. The first block must contain all * the relevant header information. */ int first_block (const unsigned char *buf, long blocksize) { Elf32_Ehdr *elf; Elf32_Phdr *phdrs; UINTN total_size, pages; UINTN low_addr, max_addr; UINTN offs = 0; UINT16 phnum; UINTN paddr, memsz; INTN i; elf = (Elf32_Ehdr *)buf; if (is_valid_header(elf) == -1) return -1; offs = elf->e_phoff; phnum = elf->e_phnum; VERB_PRT(3, { Print(L"Entry point "PTR_FMT"\n", elf->e_entry); Print(L"%d program headers\n", phnum); Print(L"%d segment headers\n", elf->e_shnum); }); if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) { ERR_PRT((L"%s : ELF program headers not in first block (%d)\n", LD_NAME, offs)); return -1; } kernel_entry = (VOID *)(elf->e_entry & PADDR_MASK); phdrs = (Elf32_Phdr *) (buf + offs); low_addr = ~0; max_addr = 0; /* * allocate chunk table * Convention: a segment that does not need loading will * have chunk[].addr = 0. */ chunks = (void *)alloc(sizeof(struct segment)*phnum, 0); if (chunks == NULL) { ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME)); return -1; } nchunks = phnum; /* * find lowest and higest virtual addresses * don't assume FULLY sorted ! */ for (i = 0; i < phnum; ++i) { /* * record chunk no matter what because no load may happen * anywhere in archive, not just as the last segment */ paddr = (phdrs[i].p_paddr & PADDR_MASK); memsz = phdrs[i].p_memsz, chunks[i].addr = paddr; chunks[i].offset = phdrs[i].p_offset; chunks[i].size = phdrs[i].p_filesz; chunks[i].bss_sz = phdrs[i].p_memsz - phdrs[i].p_filesz; CHUNK_VALIDATE(i); if (phdrs[i].p_type != PT_LOAD) { CHUNK_NO_LOAD(i); /* mark no load chunk */ DBG_PRT((L"%s : skipping segment %d\n", LD_NAME, i)); continue; } CHUNK_CAN_LOAD(i); /* mark no load chunk */ VERB_PRT(3, Print(L"\n%s : segment %d vaddr ["PTR_FMT"-"PTR_FMT"] offset %d filesz %d " "memsz=%d bss_sz=%d\n", LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+phdrs[i].p_filesz, chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz)); if (paddr < low_addr) low_addr = paddr; if (paddr + memsz > max_addr) max_addr = paddr + memsz; } if (low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : low_addr not page aligned "PTR_FMT"\n", LD_NAME, low_addr)); goto error; } analyze_chunks(); DBG_PRT((L"%s : %d program headers entry=" PTR_FMT "\nlowest_addr="PTR_FMT" highest_addr="PTR_FMT"\n", LD_NAME, phnum, kernel_entry, low_addr, max_addr)); total_size = (UINTN)max_addr - (UINTN)low_addr; pages = EFI_SIZE_TO_PAGES(total_size); /* * Record end of kernel for initrd */ kernel_base = (void *)low_addr; kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT)); /* allocate memory for the kernel */ if (alloc_kmem((void *)low_addr, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, "PTR_FMT") for kernel failed\n", LD_NAME, pages, low_addr)); ERR_PRT((L"%s : Could not load kernel at "PTR_FMT"\n", LD_NAME, low_addr)); ERR_PRT((L"%s : Bailing\n", LD_NAME)); goto error; } return 0; error: if (chunks) free(chunks); return -1; } /* * Determine which chunk in the Elf file will be coming out of the expand * code next. */ static void nextchunk(void) { int i; segment_t *cp; cp = NULL; for(i=0; i < nchunks; i++) { if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue; if (file_offset > chunks[i].offset) continue; if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i]; } cur_chunk = cp; } /* * Write the output window window[0..outcnt-1] holding uncompressed * data and update crc. */ void flush_window(void) { static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' }; static UINTN heli_count; struct segment *cp; unsigned char *src, *dst; long cnt; if (!outcnt) return; #ifdef DEBUG_GZIP DBG_PRT((L"%s : flush_window outnct=%d file_offset=%d\n", LD_NAME, outcnt, file_offset)); #endif Print(L"%c\b",helicopter[heli_count++%4]); updcrc(window, outcnt); /* first time, we extract the headers */ if (!bytes_out) { if (first_block(window, outcnt) < 0) error("invalid exec header"); nextchunk(); } bytes_out += outcnt; src = window; tail: /* check if user wants to abort */ if (check_abort() == EFI_SUCCESS) goto load_abort; cp = cur_chunk; if (cp == NULL || file_offset + outcnt <= cp->offset) { file_offset += outcnt; return; } /* Does this window begin before the current chunk? */ if (file_offset < cp->offset) { unsigned long skip = cp->offset - file_offset; src += skip; file_offset += skip; outcnt -= skip; } dst = (unsigned char *)cp->addr + (file_offset - cp->offset); cnt = cp->offset + cp->size - file_offset; if (cnt > outcnt) cnt = outcnt; Memcpy(dst, src, cnt); file_offset += cnt; outcnt -= cnt; src += cnt; /* See if we are at the end of this chunk */ if (file_offset == cp->offset + cp->size) { if (cp->bss_sz) { dst = (unsigned char *)cp->addr + cp->size; Memset(dst, 0, cp->bss_sz); } nextchunk(); /* handle remaining bytes */ if (outcnt) goto tail; } return; load_abort: free_kmem(); error_return = ELILO_LOAD_ABORTED; } static void error(char *x) { ERR_PRT((L"%s : %a", LD_NAME, x)); /* will eventually exit with error from gunzip() */ } INT32 decompress_kernel(VOID) { INT32 ret; clear_bufs(); makecrc(); Print(L"Uncompressing Linux... "); ret = gunzip(); if (ret == 0) Print(L"done\n"); return ret == 0 ? 0 : -1; } int gunzip_kernel(fops_fd_t fd, kdesc_t *kd) { int ret = -1; error_return = ELILO_LOAD_ERROR; window = (void *)alloc(WSIZE, 0); if (window == NULL) { ERR_PRT((L"%s : allocate output window failed\n", LD_NAME)); return -1; } inbuf = (void *)alloc(INBUFSIZE, 0); if (inbuf == NULL) { ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME)); goto error; } input_fd = fd; insize = 0; bytes_out = 0; ret = decompress_kernel(); error: if (window) free(window); if (inbuf) free(inbuf); if (ret == 0) { kd->kentry = kernel_entry; kd->kend = kernel_end; kd->kstart = kernel_base; error_return = ELILO_LOAD_SUCCESS; } return error_return; } ./elilo/ia32/sysdeps.h0000644000175000017500000002710311165216511014244 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * * 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. */ /* * This file is used to define all the IA32-specific data structures * and constant used by the generic ELILO */ #ifndef __ELILO_SYSDEPS_IA32_H__ #define __ELILO_SYSDEPS_IA32_H__ #define ELILO_ARCH "IA-32" /* ASCII string */ #define PADDR_MASK 0xfffffff #define INITRD_START (15*1024*1024) #define DEFAULT_KERNEL_START 0x100000 /* for now use library versions */ #define Memset(a,v,n) SetMem((a),(n),(v)) #define Memcpy(a,b,n) CopyMem((a),(b),(n)) /* * This version must match the one in the kernel. * * This table was put together using information from the * following Linux kernel source files: * linux/include/tty.h * linux/arch/i386/kernel/setup.c * linux/arch/i386/boot/bootsect.S * linux/arch/i386/boot/setup.S * linux/arch/i386/boot/video.S * * New fields in this structure for EFI and ELILO are: * efi_loader_sig * efi_st_addr * * A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags * field is also defined in this file. */ #pragma pack(1) /* Definitions for converting EFI memory map to E820 map for Linux * These definitions are from include/linux/asm-x86/e820.h * The structure ia32_boot_params below is updated to accommodate E820 map * EFI memory map is converted to E820 map in this structure and passed * to Linux. This way the OS does not need to do the conversion. */ #define E820_RAM 1 #define E820_RESERVED 2 #define E820_ACPI 3 #define E820_NVS 4 #define E820_MAX 128 struct e820entry { UINT64 addr; /* start of memory segment */ UINT64 size; /* size of memory segment */ UINT32 type; /* type of memory segment */ } __attribute__((packed)); typedef union ia32_boot_params { UINT8 raw[0x2000]; struct { /* Cursor position before passing control to kernel. */ /* 0x00 */ UINT8 orig_cursor_col; /* LDR */ /* 0x01 */ UINT8 orig_cursor_row; /* LDR */ /* Available contiguous extended memory in KB. */ /* 0x02 */ UINT16 ext_mem_k; /* LDR */ /* Video page, mode and screen width before passing control to kernel. */ /* 0x04 */ UINT16 orig_video_page; /* LDR */ /* 0x06 */ UINT8 orig_video_mode; /* LDR */ /* 0x07 */ UINT8 orig_video_cols; /* LDR */ /* 0x08 */ UINT16 unused_1; /* unused */ /* %%TBD */ /* 0x0A */ UINT16 orig_ega_bx; /* LDR */ /* 0x0C */ UINT16 unused_2; /* unused */ /* Screen height before passing control to kernel. */ /* 0x0E */ UINT8 orig_video_rows; /* LDR */ /* %%TBD */ /* 0x0F */ UINT8 is_vga; /* LDR */ /* 0x10 */ UINT16 orig_video_points; /* LDR */ /* %%TBD */ /* 0x12 */ UINT16 lfb_width; /* LDR */ /* 0x14 */ UINT16 lfb_height; /* LDR */ /* 0x16 */ UINT16 lfb_depth; /* LDR */ /* 0x18 */ UINT32 lfb_base; /* LDR */ /* 0x1C */ UINT32 lfb_size; /* LDR */ /* Offset of command line (from start of ia32_boot_param struct). */ /* The command line magik number must be set for the kernel setup */ /* code to use the command line offset. */ /* 0x20 */ UINT16 cmdline_magik; /* LDR */ #define CMDLINE_MAGIK 0xA33F /* 0x22 */ UINT16 cmdline_offset; /* LDR */ /* %%TBD */ /* 0x24 */ UINT16 lfb_line_len; /* LDR */ /* %%TBD */ /* 0x26 */ UINT8 lfb_red_size; /* LDR */ /* 0x27 */ UINT8 lfb_red_pos; /* LDR */ /* 0x28 */ UINT8 lfb_green_size; /* LDR */ /* 0x29 */ UINT8 lfb_green_pos; /* LDR */ /* 0x2A */ UINT8 lfb_blue_size; /* LDR */ /* 0x2B */ UINT8 lfb_blue_pos; /* LDR */ /* 0x2C */ UINT8 lfb_rsvd_size; /* LDR */ /* 0x2D */ UINT8 lfb_rsvd_pos; /* LDR */ /* %%TBD */ /* 0x2E */ UINT16 vesa_seg; /* LDR */ /* 0x30 */ UINT16 vesa_off; /* LDR */ /* %%TBD */ /* 0x32 */ UINT16 lfb_pages; /* LDR */ /* 0x34 */ UINT8 lfb_reserved[0x0C]; /* reserved */ /* %%TBD */ /* 0x40 */ UINT16 apm_bios_ver; /* LDR */ #define NO_APM_BIOS 0x0000 /* %%TBD */ /* 0x42 */ UINT16 bios_code_seg; /* LDR */ /* 0x44 */ UINT32 bios_entry_point; /* LDR */ /* 0x48 */ UINT16 bios_code_seg16; /* LDR */ /* 0x4A */ UINT16 bios_data_seg; /* LDR */ /* %%TBD */ /* 0x4C */ UINT16 apm_bios_flags; /* LDR */ #define NO_32BIT_APM_MASK 0xFFFD /* %%TBD */ /* 0x4E */ UINT32 bios_code_len; /* LDR */ /* 0x52 */ UINT16 bios_data_len; /* LDR */ /* 0x54 */ UINT8 unused_3[0x2C]; /* unused */ /* %%TBD */ /* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */ /* 0x90 */ UINT8 hd1_info[0x10]; /* LDR */ /* %%TBD */ /* 0xA0 */ UINT16 mca_info_len; /* LDR */ /* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */ /* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */ /* EFI boot loader signature. */ /* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */ #define EFI_LOADER_SIG_IA32 "EL32" /* Address of the EFI system table. */ /* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */ /* EFI memory descriptor size. */ /* 0x1C8 */ UINT32 efi_mem_desc_size; /* LDR */ /* EFI memory descriptor version. */ /* 0x1CC */ UINT32 efi_mem_desc_ver; /* LDR */ /* Address & size of EFI memory map. */ /* 0x1D0 */ UINT32 efi_mem_map; /* LDR */ /* 0x1D4 */ UINT32 efi_mem_map_size; /* LDR */ /* Address & size of loader. */ /* 0x1D8 */ UINT32 loader_start; /* LDR */ /* 0x1DC */ UINT32 loader_size; /* LDR */ /* Available contiguous extended memory in KB. */ /* 0x1E0 */ UINT32 alt_mem_k; /* LDR */ /* 0x1E4 */ UINT32 unused_51; /* unused */ /* 0x1E8 */ UINT8 e820_nrmap; /* 0x1E9 */ UINT32 unused_52[2]; /* unused */ /* Size of setup code in sectors (1 sector == 512 bytes). */ /* 0x1F1 */ UINT8 setup_sectors; /* BLD */ /* %%TBD */ /* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */ /* %%TBD */ /* 0x1F4 */ UINT16 sys_size; /* BLD */ /* %%TBD */ /* 0x1F6 */ UINT16 swap_dev; /* BLD */ /* %%TBD */ /* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */ #define RAMDISK_PROMPT 0x8000 #define RAMDISK_LOAD 0x4000 /* %%TBD */ /* 0x1FA */ UINT16 video_mode_flag; /* BLD */ /* %%TBD */ /* 0x1FC */ UINT16 orig_root_dev; /* BLD */ /* 0x1FE */ UINT8 unused_6; /* unused */ /* %%TBD */ /* 0x1FF */ UINT8 aux_dev_info; /* LDR */ #define NO_MOUSE 0x00 #define FOUND_MOUSE 0xAA /* Jump past setup data (not used in EFI). */ /* 0x200 */ UINT16 jump; /* BLD */ /* Setup data signature. */ /* 0x202 */ UINT8 setup_sig[4]; /* BLD */ #define SETUP_SIG "HdrS" /* %%TBD */ /* 0x206 */ UINT8 hdr_minor; /* BLD */ /* 0x207 */ UINT8 hdr_major; /* BLD */ /* %%TBD */ /* 0x208 */ UINT32 rm_switch; /* LDD */ /* %%TBD */ /* 0x20C */ UINT16 start_sys_seg; /* BLD */ /* %%TBD */ /* 0x20E */ UINT16 kernel_verstr_offset; /* BLD */ /* Loader type & version. */ /* 0x210 */ UINT8 loader_type; /* LDR */ #define LDRTYPE_ELILO 0x50 /* 5?h == elilo */ /* ?0h == revision */ /* 0x211 */ UINT8 loader_flags; /* BLD and LDR */ #define LDRFLAG_CAN_USE_HEAP 0x80 #define LDRFLAG_BOOT_PARAM_RELOC 0x40 /* %%TBD */ /* 0x212 */ UINT16 setup_move_size; /* BLD */ /* %%TBD */ /* 0x214 */ UINT32 kernel_start; /* LDR */ /* %%TBD */ /* 0x218 */ UINT32 initrd_start; /* LDR */ /* 0x21C */ UINT32 initrd_size; /* LDR */ /* %%TBD */ /* 0x220 */ UINT32 bootsect_helper; /* BLD */ /* %%TBD */ /* 0x224 */ UINT16 heap_end_ptr; /* LDR */ /* %%TBD */ /* 0x226 */ UINT16 unused_7; /* LDR */ /* 0x228 */ UINT32 cmdline_addr; /* LDR */ /* 0x22C */ UINT32 unused_8[41]; /* 0x2D0 */ UINT8 e820_map[2560]; } s; } boot_params_t; #pragma pack() /* * The stuff below here is for jumping to the kernel. */ /* * Some macros to copy and set memory after EFI has been * stopped. */ #define MEMCPY(to, from, cnt) { \ UINT8 *t = (UINT8 *)(to); \ UINT8 *f = (UINT8 *)(from); \ UINTN n = cnt; \ if (t && f && n && (tf)) { \ t += n; \ f += n; \ while (n--) { \ *t-- = *f--; \ } \ } \ } #define MEMSET(ptr, size, val) { \ UINT8 *p = (UINT8 *)(ptr); \ UINTN n = (UINTN)(size); \ UINT8 v = (UINT8)(val); \ if (p && n) { \ while (n--) { \ *p++ = v; \ } \ } \ } /* * Descriptor table pointer format. */ #pragma pack(1) typedef struct { UINT16 limit; UINT32 base; } dt_addr_t; #pragma pack() extern UINTN high_base_mem; extern UINTN high_ext_mem; extern boot_params_t *param_start; extern UINTN param_size; extern VOID *kernel_start; extern UINTN kernel_size; extern VOID *initrd_start; extern UINTN initrd_size; extern VOID *kernel_load_address; extern dt_addr_t gdt_addr; extern dt_addr_t idt_addr; extern UINT16 init_gdt[]; extern UINTN sizeof_init_gdt; extern UINT8 rmswitch_image[]; extern UINTN rmswitch_size; extern INTN ia32_use_legacy_free_boot(); /* * How to jump to kernel code */ static inline void start_kernel(VOID *kentry, boot_params_t *bp) { UINT32 temp; /* * Disable interrupts. */ asm volatile ( "cli" : : ); /* * Relocate kernel (if needed), and initrd (if present). * Copy kernel first, in case kernel was loaded overlapping where we're * planning to copy the initrd. This assumes that the initrd didn't * get loaded overlapping where we're planning to copy the kernel, but * that's pretty unlikely since we couldn't alloc that space for the * kernel (or the kernel would already be there). */ if (kernel_start != kernel_load_address) { MEMCPY(kernel_start, kernel_load_address, kernel_size); } if (bp->s.initrd_start) { temp = bp->s.initrd_start; MEMCPY(INITRD_START, temp , bp->s.initrd_size); bp->s.initrd_start = INITRD_START; } /* * Copy boot sector, setup data and command line * to final resting place. We need to copy * BOOT_PARAM_MEMSIZE bytes. */ MEMCPY(high_base_mem, bp, 0x4000); bp = (boot_params_t *)high_base_mem; bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset; /* * Initialize Linux GDT. */ MEMSET(gdt_addr.base, gdt_addr.limit, 0); MEMCPY(gdt_addr.base, init_gdt, sizeof_init_gdt); if (! ia32_use_legacy_free_boot()) { /* * Copy our real mode transition code to 0x7C00. */ MEMCPY(0x7C00, rmswitch_image, rmswitch_size); asm volatile ( "movl $0x7C00, %%ebx" : : ); asm volatile ( "jmp *%%ebx" : : ); } /* * Load descriptor table pointers. */ asm volatile ( "lidt %0" : : "m" (idt_addr) ); asm volatile ( "lgdt %0" : : "m" (gdt_addr) ); /* * ebx := 0 (%%TBD - do not know why, yet) * ecx := kernel entry point * esi := address of boot sector and setup data */ asm volatile ( "movl %0, %%esi" : : "m" (high_base_mem) ); asm volatile ( "movl %0, %%ecx" : : "m" (kentry) ); asm volatile ( "xorl %%ebx, %%ebx" : : ); /* * Jump to kernel entry point. */ asm volatile ( "jmp *%%ecx" : : ); } typedef struct sys_img_options { UINT8 nothing_yet; } sys_img_options_t; #endif /* __ELILO_SYSDEPS_IA32_H__ */ ./elilo/ia32/gzip_loader.c0000644000175000017500000000354310343667143015056 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #include "loader.h" #include "gzip.h" #define LD_NAME L"gzip_ia32" static INTN gzip_probe_format(CHAR16 *kname) { UINT8 buf[4]; EFI_STATUS status; INTN ret = -1; UINTN size; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; size = sizeof(buf); status = fops_read(fd, buf, &size); if (EFI_ERROR(status) || size != sizeof(buf)) goto error; ret = gzip_probe(buf, sizeof(buf)); error: fops_close(fd); return ret; } static INTN gzip_load_kernel(CHAR16 *kname, kdesc_t *kd) { EFI_STATUS status; INT32 ret; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; ret = gunzip_kernel(fd, kd); fops_close(fd); return ret; /* could be success, error, or abort */ } loader_ops_t gzip_loader={ NULL, LD_NAME, gzip_probe_format, gzip_load_kernel }; ./elilo/config.c0000644000175000017500000006677011466353221013275 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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. * * Portions of this file are derived from the LILO/x86 * Copyright 1992-1997 Werner Almesberger. */ #include #include #include #include "elilo.h" #include "config.h" /* * The first default config file is architecture dependent. This is useful * in case of network booting where the server is used for both types of * architectures. */ #if defined(CONFIG_ia64) #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf" #elif defined (CONFIG_ia32) #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf" #elif defined (CONFIG_x86_64) #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-x86_64.conf" #else #error "You need to specfy your default arch config file" #endif /* * last resort config file. Common to all architectures */ #define ELILO_DEFAULT_CONFIG L"elilo.conf" #define MAX_STRING 512 #define CONFIG_BUFSIZE 512 /* input buffer size */ /* * maximum number of message files. * * main message= goes at entry 0, entries [1-12] are used for function keys * */ #define MAX_MESSAGES 13 typedef struct boot_image { struct boot_image *next; CHAR16 label[MAX_STRING]; CHAR16 kname[FILENAME_MAXLEN]; CHAR16 options[CMDLINE_MAXLEN]; CHAR16 initrd[FILENAME_MAXLEN]; CHAR16 vmcode[FILENAME_MAXLEN]; CHAR16 root[FILENAME_MAXLEN]; CHAR16 fallback[MAX_STRING]; CHAR16 description[MAX_STRING]; UINTN ramdisk; UINTN readonly; UINTN literal; sys_img_options_t sys_img_opts; /* architecture specific image options */ } boot_image_t; typedef enum { TOK_ERR, TOK_EQUAL, TOK_STR, TOK_EOF } token_t; /* * global shared options * architecture specific global options are private to each architecture */ typedef struct { CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */ CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */ CHAR16 vmcode[FILENAME_MAXLEN];/* globally defined boot-time module */ CHAR16 options[CMDLINE_MAXLEN]; CHAR16 default_image_name[MAX_STRING]; CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN]; CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */ CHAR16 config_file[FILENAME_MAXLEN]; boot_image_t *default_image; UINTN readonly; /* * options that may affect global elilo options */ UINTN alt_check; UINTN debug; UINTN delay; UINTN prompt; UINTN timeout; UINTN verbose; UINTN edd30_no_force; /* don't force EDD30 if not set */ } global_config_t; /* * structure used to point to a group of options. * Several group for the same category are supported via a linked list. */ typedef struct _config_option_group { struct _config_option_group *next; /* pointer to next group */ config_option_t *options; /* the table of options for this group */ UINTN nentries; /* number of entries for this group */ } config_option_group_t; static option_action_t do_image, do_literal, do_options; static INTN check_verbosity(VOID *), check_chooser(VOID *); static global_config_t global_config; /* options shared by all images */ /* * Core global options: shared by all architectures, all modules */ static config_option_t global_common_options[]={ {OPT_STR, OPT_GLOBAL, L"default", NULL, NULL, global_config.default_image_name}, {OPT_NUM, OPT_GLOBAL, L"timeout", NULL, NULL, &global_config.timeout}, {OPT_NUM, OPT_GLOBAL, L"delay", NULL, NULL, &global_config.delay}, {OPT_BOOL, OPT_GLOBAL, L"debug", NULL, NULL, &global_config.debug}, {OPT_BOOL, OPT_GLOBAL, L"prompt", NULL, NULL, &global_config.prompt}, {OPT_NUM, OPT_GLOBAL, L"verbose", NULL, check_verbosity, &global_config.verbose}, {OPT_FILE, OPT_GLOBAL, L"root", NULL, NULL, global_config.root}, {OPT_BOOL, OPT_GLOBAL, L"read-only", NULL, NULL, &global_config.readonly}, {OPT_BOOL, OPT_GLOBAL, L"noedd30", NULL, NULL, &global_config.edd30_no_force}, {OPT_CMD, OPT_GLOBAL, L"append", NULL, NULL, global_config.options}, {OPT_FILE, OPT_GLOBAL, L"initrd", NULL, NULL, global_config.initrd}, {OPT_FILE, OPT_GLOBAL, L"vmm", NULL, NULL, global_config.vmcode}, {OPT_FILE, OPT_GLOBAL, L"image", do_image, NULL, opt_offsetof(kname)}, {OPT_BOOL, OPT_GLOBAL, L"checkalt", NULL, NULL, &global_config.alt_check}, {OPT_STR, OPT_GLOBAL, L"chooser", NULL, check_chooser, global_config.chooser}, {OPT_FILE, OPT_GLOBAL, L"message", NULL, NULL, global_config.message_file[0]}, {OPT_FILE, OPT_GLOBAL, L"f1", NULL, NULL, global_config.message_file[1]}, {OPT_FILE, OPT_GLOBAL, L"f2", NULL, NULL, global_config.message_file[2]}, {OPT_FILE, OPT_GLOBAL, L"f3", NULL, NULL, global_config.message_file[3]}, {OPT_FILE, OPT_GLOBAL, L"f4", NULL, NULL, global_config.message_file[4]}, {OPT_FILE, OPT_GLOBAL, L"f5", NULL, NULL, global_config.message_file[5]}, {OPT_FILE, OPT_GLOBAL, L"f6", NULL, NULL, global_config.message_file[6]}, {OPT_FILE, OPT_GLOBAL, L"f7", NULL, NULL, global_config.message_file[7]}, {OPT_FILE, OPT_GLOBAL, L"f8", NULL, NULL, global_config.message_file[8]}, {OPT_FILE, OPT_GLOBAL, L"f9", NULL, NULL, global_config.message_file[9]}, {OPT_FILE, OPT_GLOBAL, L"f10", NULL, NULL, global_config.message_file[10]}, {OPT_FILE, OPT_GLOBAL, L"f11", NULL, NULL, global_config.message_file[11]}, {OPT_FILE, OPT_GLOBAL, L"f12", NULL, NULL, global_config.message_file[12]} }; static config_option_t image_common_options[]={ {OPT_FILE, OPT_IMAGE, L"root", NULL, NULL, opt_offsetof(root)}, {OPT_BOOL, OPT_IMAGE, L"read-only", NULL, NULL, opt_offsetof(readonly)}, {OPT_CMD, OPT_IMAGE, L"append", do_options, NULL, opt_offsetof(options)}, {OPT_CMD, OPT_IMAGE, L"literal", do_literal, NULL, NULL}, {OPT_FILE, OPT_IMAGE, L"initrd", NULL, NULL, opt_offsetof(initrd)}, {OPT_FILE, OPT_IMAGE, L"vmm", NULL, NULL, opt_offsetof(vmcode)}, {OPT_STR, OPT_IMAGE, L"label", NULL, NULL, opt_offsetof(label)}, {OPT_FILE, OPT_IMAGE, L"image", do_image, NULL, opt_offsetof(kname)}, {OPT_STR, OPT_IMAGE, L"description", NULL, NULL, opt_offsetof(description)}, }; #define OPTION_IS_GLOBAL(p) ((p)->scope == OPT_GLOBAL) #define OPTION_IS_IMG_SYS(p) ((p)->scope == OPT_IMAGE_SYS) #define CHAR_EOF (CHAR16)-1 /* Unicode version of EOF */ #define CHAR_NUM0 L'0' #define CHAR_NUM9 L'9' static UINTN line_num; static INTN back; /* can go back by one char */ static config_option_group_t *global_option_list; static config_option_group_t *image_option_list; static config_option_group_t *current_options; static boot_image_t *image_list, *first_image; static boot_image_t *current_img; static INT8 config_buf[CONFIG_BUFSIZE]; /* input buffer: file must be in ASCII! */ static UINTN buf_max, buf_pos; static fops_fd_t config_fd; static VOID config_error(CHAR16 *msg,...) { Print(L"near line %d: ",line_num); IPrint(systab->ConOut, msg); Print(L"\n"); } /* * low level read routine * Return: * * Success: * - the next available unicode character * Error: * - CHAR_EOF : indicating error or EOF * * XXX: we suppose that the file is in ASCII format! */ static CHAR16 getc(VOID) { EFI_STATUS status; if (buf_pos == 0 || buf_pos == buf_max) { buf_max = CONFIG_BUFSIZE; status = fops_read(config_fd, config_buf, &buf_max); if (EFI_ERROR(status) || buf_max == 0) return CHAR_EOF; buf_pos = 0; } return (CHAR16)config_buf[buf_pos++]; } /* * get the next unicode character with a one character * rewind buffer. */ static CHAR16 next(VOID) { CHAR16 ch; if (back) { ch = back; back = 0; return ch; } /* * config files served from pxe/tftpboot windows servers can contain * extraneous '\r' characters, often the first char in the file, and * we need to simply skip over those and continue on */ ch = getc(); if(ch == '\r') ch = getc(); return ch; } /* * rewind by one character */ static VOID again(CHAR16 ch) { if (back) { config_error(L"config: again invoked twice"); } back = ch; } /* * Look for matching option in the current group * * Return: * - pointer to option if found * - NULL if not found */ static config_option_t * find_option(config_option_group_t *grp, CHAR16 *str) { config_option_t *p = NULL; config_option_t *end; while(grp) { p = grp->options; end = grp->options+grp->nentries; while (p != end) { if (!StrCmp(str, p->name)) return p; p++; } grp = grp->next; } return NULL; } /* * main parser function * Return: * - a token code representing the kind of element found * - TOK_EOF: end-of-file (or error) detected * - TOK_STR: if string is found * - TOK_EQUAL: for the '=' sign * - TOK_ERR: in case of (parsing) error */ static token_t get_token_core(CHAR16 *str, UINTN maxlen, BOOLEAN rhs) { INTN ch, escaped; CHAR16 *here; for (;;) { while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n' ) line_num++; if (ch == CHAR_EOF) return TOK_EOF; /* skip comment line */ if (ch != '#') break; while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF; line_num++; } if (ch == '=' && !rhs) return TOK_EQUAL; if (ch == '"') { here = str; while (here-str < maxlen) { if ((ch = next()) == CHAR_EOF) { config_error(L"EOF in quoted string"); return TOK_ERR; } if (ch == '"') { *here = 0; return TOK_STR; } if (ch == '\\') { ch = next(); if (ch != '"' && ch != '\\' && ch != '\n') { config_error(L"Bad use of \\ in quoted string"); return TOK_ERR; } if (ch == '\n') continue; #if 0 while ((ch = next()), ch == ' ' || ch == '\t'); if (!ch) continue; again(ch); ch = ' '; } #endif } if (ch == '\n' || ch == '\t') { config_error(L"\\n and \\t are not allowed in quoted strings"); return TOK_ERR; } *here++ = ch; } config_error(L"Quoted string is too long"); return TOK_ERR; } here = str; escaped = 0; while (here-str < maxlen) { if (escaped) { if (ch == CHAR_EOF) { config_error(L"\\ precedes EOF"); return TOK_ERR; } if (ch == '\n') line_num++; else *here++ = ch == '\t' ? ' ' : ch; escaped = 0; } else { if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' || ch == CHAR_EOF || (ch == '=' && !rhs)) { again(ch); *here = 0; return TOK_STR; } if (!(escaped = (ch == '\\'))) *here++ = ch; } ch = next(); } config_error(L"Token is too long"); return TOK_ERR; } static token_t get_token(CHAR16 *str, UINTN maxlen) { return get_token_core(str, maxlen, FALSE); } static token_t get_token_rhs(CHAR16 *str, UINTN maxlen) { return get_token_core(str, maxlen, TRUE); } static INTN image_check(boot_image_t *img) { boot_image_t *b; if (img == NULL) return -1; /* do the obvious first */ if (img->label[0] == '\0') { config_error(L"image has no label"); return -1; } /* image_list points to the */ for(b=image_list; b; b = b->next) { if (img == b) continue; if (!StrCmp(img->label, b->label)) { config_error(L"image with label %s already defined", img->label); return -1; } } return 0; } static INTN global_check(VOID) { return 0; } static INTN final_check(VOID) { boot_image_t *b; if (global_config.default_image_name[0]) { for(b=image_list; b; b = b->next) { if (!StrCmp(b->label, global_config.default_image_name)) goto found; } config_error(L"default image '%s' not defined ", global_config.default_image_name); return -1; } global_config.default_image = first_image; return 0; found: global_config.default_image = b; return 0; } /* * depending on the active set of options * adjust the option data pointer to: * if global option set: * - just the straight value from p->data * if image option set: * - adjust as offset to image * Return: * - the adjusted pointer */ static inline VOID * adjust_pointer(config_option_t *p) { /* * adjust pointer */ if (OPTION_IS_GLOBAL(p)) return p->data; if (OPTION_IS_IMG_SYS(p)) return (VOID *)((UINTN)¤t_img->sys_img_opts + p->data); return (VOID *)((UINTN)current_img + p->data); } /* * create a new image entry */ static INTN do_image(config_option_t *p, VOID *str) { boot_image_t *img; /* * if we move to a new image from the current one * then we need to check for validity of current. * * if this is the first image, then check the global * options. */ if (current_img) { if (image_check(current_img) == -1) return -1; } else if (global_check() == -1) return -1; img = (boot_image_t *)alloc(sizeof(boot_image_t), EfiLoaderData); if (img == NULL) return -1; Memset(img, 0, sizeof(boot_image_t)); DBG_PRT((L"must do image on %s", (CHAR16 *)str)); /* copy kernel file name */ StrCpy(img->kname, str); /* switch to image mode */ current_options = image_option_list; /* keep track of first image in case no default is defined */ if (image_list == NULL) first_image = img; /* append to end of image list, so when a chooser asks for the list * it gets them in the order they were in in the config file */ if (image_list == NULL) image_list = img; else { boot_image_t * p = image_list; while (p->next) p = p->next; p->next = img; } /* update current image */ current_img = img; return 0; } /* * by default all boolean options are defined * as false. This function sets the boolean * to true */ static INTN do_boolean(config_option_t *p) { INT8 *buf; buf = adjust_pointer(p); if (p->action) return p->action(p, NULL); /* set the field to true, overwrite if already defined */ *buf = 1; return 0; } /* * the image option 'literal' requires special handling * because it overrides any defined option be it global or * local. so we use the option field and record the fact that * it should be interpreted as literal */ static INTN do_literal(config_option_t *p, VOID *str) { /* * we know we have a valid current image at this point */ StrCpy(current_img->options, str); current_img->literal = 1; return 0; } static INTN do_options(config_option_t *p, VOID *str) { /* we ignore append if literal is already defined */ if (current_img->literal) return 0; /* * we know we have a valid current image at this point */ StrCpy(current_img->options, str); return 0; } static INTN do_numeric(config_option_t *p) { CHAR16 numstr[MAX_STRING]; CHAR16 *str; token_t tok; UINTN *buf; UINTN tmp; /* * match the '=' sign */ tok = get_token(numstr, MAX_STRING); if (tok != TOK_EQUAL) { config_error(L"Option %s expects an equal signal + value", p->name); return -1; } /* * now get the value * XXX: = lexer should return TOK_NUM (and we'd be done) */ tok = get_token(numstr, MAX_STRING); if (tok != TOK_STR) { config_error(L"Option %s expects a value", p->name); return -1; } str = numstr; /* * if there is a customized way of doing the operation * do it and bypass generic */ if (p->action) return p->action(p, str); /* * no field to update */ if (p->data == NULL) return 0; buf = (UINTN *)adjust_pointer(p); while (*str && *str >= CHAR_NUM0 && *str <= CHAR_NUM9) str++; if (*str) { config_error(L"%s is expecting a numeric decimal value", p->name); return -1; } tmp = Atoi(numstr); if (p->check && p->check(&tmp) == -1) return -1; /* * check for multiple definitions in the same context * XXX: zero must not be a valid number ! */ if (*buf) { config_error(L"option %s is already defined in this context", p->name); return -1; } *buf = tmp; return 0; } static INTN check_verbosity(VOID *data) { UINTN *val = (UINTN *)data; if (*val > 5) { config_error(L"Verbosity level must be in [0-5] and not %d", *val); return -1; } return 0; } /* * here we simply check if chooser is compiled in. At this point, the chooser * initialization is not done, so we don't know if that chooser will even be * useable. */ static INTN check_chooser(VOID *data) { CHAR16 *chooser = (CHAR16 *)data; if (exist_chooser(chooser) == -1) { config_error(L"chooser %s is unknown\n", chooser); return -1; } return 0; } static INTN do_string_core(config_option_t *p, CHAR16 *str, UINTN maxlen, CHAR16 *msg) { token_t tok; CHAR16 *buf; /* * match the '=' sign */ tok = get_token(str, maxlen); if (tok != TOK_EQUAL) { config_error(L"Option %s expects an equal signal + %s", p->name, msg); return -1; } /* * now get the value */ tok = get_token_rhs(str, maxlen); if (tok != TOK_STR) { config_error(L"Option %s expects %s", p->name, msg); return -1; } /* * if there is a customized way of doing the operation * do it and bypass generic */ if (p->action) return p->action(p, str); /* * no field to update */ if (p->data == NULL) return 0; buf = adjust_pointer(p); if (*buf != CHAR_NULL) { config_error(L"'%s' already defined", p->name); return -1; } if (p->check && p->check(str) == -1) return -1; /* * initialize field */ StrCpy(buf, str); return 0; } static INTN do_string(config_option_t *p) { CHAR16 str[MAX_STRING]; return do_string_core(p, str, MAX_STRING, L"string"); } static INTN do_file(config_option_t *p) { CHAR16 str[FILENAME_MAXLEN]; return do_string_core(p, str, FILENAME_MAXLEN, L"filename"); } static INTN do_cmd(config_option_t *p) { CHAR16 str[CMDLINE_MAXLEN]; return do_string_core(p, str, CMDLINE_MAXLEN, L"kernel options"); } INTN config_parse(VOID) { CHAR16 str[MAX_STRING]; INTN ret = -1; token_t tok; config_option_t *p; for (;;) { tok = get_token(str, MAX_STRING); if (tok == TOK_EOF) break; if (tok == TOK_ERR) { Print(L"Bad Token from elilo config file, parser read: %s\n elilo exiting\n", str); return -1; } if ( (p = find_option(current_options, str)) == NULL) { config_error(L"Unkown option %s", str); return -1; } /* make sure we trap in case of error */ ret = -1; switch(p->type) { case OPT_BOOL: ret = do_boolean(p); break; case OPT_STR: ret = do_string(p); break; case OPT_NUM: ret = do_numeric(p); break; case OPT_FILE: ret = do_file(p); break; case OPT_CMD: ret = do_cmd(p); break; default: config_error(L"Unkown option type %d", p->type); } if (ret == -1) goto error; } if (current_img) { ret = image_check(current_img); } else { config_error(L"No image defined !"); } if (ret == 0) ret = final_check(); error: return ret; } static VOID update_elilo_opt(VOID) { /* * update boolean options first * Rule: by default not set unless explcitely requested on command line * therefore we can just update from global_config is set there. */ if (global_config.alt_check) elilo_opt.alt_check = 1; if (global_config.debug) elilo_opt.debug = 1; if (global_config.prompt) elilo_opt.prompt = 1; /* * update only if not set on command line * XXX: rely on the existence of a non-valid value as a marker than * the option was not specified on the command line */ if (global_config.verbose && elilo_opt.verbose == 0) elilo_opt.verbose = global_config.verbose; if (global_config.chooser[0] && elilo_opt.chooser[0] == 0) StrCpy(elilo_opt.chooser, global_config.chooser); /* * if edd30_no_force not set by command line option but via config * file, then propagate */ if (global_config.edd30_no_force && elilo_opt.edd30_no_force == 0) elilo_opt.edd30_no_force = 1; /* * Difficult case of numeric where 0 can be a valid value * XXX: find a better way of handling these options! */ if (global_config.delay && elilo_opt.delay_set == 0) elilo_opt.delay = global_config.delay; /* readjusted by caller if necessary. 0 not a valid value here */ elilo_opt.timeout = global_config.timeout; /* initrd is updated later when we have an image match */ } /* * When called after read_config(), this function returns the config file * used by the loader, or NULL if no file was found. */ CHAR16 * get_config_file(VOID) { return global_config.config_file[0] ? global_config.config_file : NULL; } EFI_STATUS read_config(CHAR16 *filename) { EFI_STATUS status; INTN ret; if (filename == NULL) return EFI_INVALID_PARAMETER; VERB_PRT(3, Print(L"trying config file %s\n", filename)); StrCpy(global_config.config_file, filename); status = fops_open(filename, &config_fd); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"cannot open config file %s\n", filename)); return status; } /* * start numbering at line 1 */ line_num = 1; ret = config_parse(); fops_close(config_fd); DBG_PRT((L"done parsing config file\n")); if (ret != 0) return EFI_INVALID_PARAMETER; update_elilo_opt(); return EFI_SUCCESS; } VOID print_label_list(VOID) { boot_image_t *img, *dfl = global_config.default_image; if (dfl) Print(L" %s\n", dfl->label); for (img = image_list; img; img = img->next) { if (img != dfl) Print(L" %s\n", img->label); } } /* Make labels and corresponding descriptions available to choosers. The * idea is that the caller passes NULL for 'prev'; the first time, and * passes the previously returned value on subsequent calls. The caller * repeats until this fn returns NULL. */ VOID * get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description) { boot_image_t *img = (boot_image_t *)prev; if (img == NULL) img = image_list; else img = img->next; if (img) { *label = img->label; *description = img->description; return (void *)img; } else return NULL; } /* * find a description using the label name * return NULL if label not found or no description defined */ CHAR16 * find_description(CHAR16 *label) { boot_image_t *img; /* Attempt to find the image name now */ for (img = image_list; img; img = img->next) { if (StriCmp(img->label, label) == 0) { return img->description; } } return NULL; } static void add_root_to_options(CHAR16 *options, CHAR16 *root, CHAR16 *vmcode) { CHAR16 *o, ko[CMDLINE_MAXLEN]; if (vmcode[0]) { for (o = options; *o; o++) { if (*o == '-' && *(o+1) == '-') break; } if (! *o) { /* no separator found, add one */ StrCpy(o, L" -- "); o++; } /* advance past separator and whitespace */ o += 2; while (*o == ' ') o++; } else { o = options; } /* insert root param at this point */ StrCpy(ko, o); StrCpy(o, L"root="); StrCat(o, root); StrCat(o, L" "); StrCat(o, ko); } INTN find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode) { boot_image_t *img; if (label == NULL) { if (global_config.default_image == NULL) return -1; img = global_config.default_image; goto found; } options[0] = 0; /* Attempt to find the image name now */ for (img = image_list; img; img = img->next) { if (StriCmp(img->label, label) == 0) { goto found; } } /* * when the label does not exist, we still propagate the global options */ if (global_config.options[0]) { StrCat(options, L" "); StrCat(options, global_config.options); } if (global_config.root[0]) add_root_to_options(options, global_config.root, global_config.vmcode); if (global_config.readonly) StrCat(options, L" ro"); if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd); if (global_config.vmcode[0]) StrCpy(vmcode, global_config.vmcode); /* make sure we don't get garbage here */ elilo_opt.sys_img_opts = NULL; return -1; found: StrCpy(kname, img->kname); /* per image initrd has precedence over global initrd */ if (img->initrd[0]) StrCpy(initrd, img->initrd); else StrCpy(initrd, global_config.initrd); /* per image vmcode has precedence over global vmcode */ if (img->vmcode[0]) StrCpy(vmcode, img->vmcode); else StrCpy(vmcode, global_config.vmcode); /* * literal option overrides any other image-based or global option * * In any case, the image option has priority over the global option */ if (img->literal == 0) { /* XXX: check max length */ if (img->options[0] || global_config.options[0]) { StrCat(options, L" "); StrCat(options, img->options[0] ? img->options: global_config.options); } if (img->root[0] || global_config.root[0]) { add_root_to_options(options, img->root[0] ? img->root : global_config.root, vmcode); } if (img->readonly || global_config.readonly) { StrCat(options, L" ro"); } } else { /* literal options replace everything */ StrCpy(options, img->options); } /* * point to architecture dependent options for this image */ elilo_opt.sys_img_opts = &img->sys_img_opts; DBG_PRT((L"label %s: kname=%s options=%s initrd=%s vmcode=%s", img->label, kname, options, initrd, vmcode)); return 0; } static VOID print_options(config_option_group_t *grp, BOOLEAN first) { config_option_t *end, *p; CHAR16 *str; while (grp) { p = grp->options; end = grp->options+grp->nentries; while (p != end) { str = NULL; switch(p->type) { case OPT_BOOL: str = L"%s"; break; case OPT_STR : str = L"%s=string"; break; case OPT_FILE : str = L"%s=filename"; break; case OPT_CMD : str = L"%s=kernel_options"; break; case OPT_NUM : str = L"%s=number"; break; default: break; } if (str && first == FALSE) Print(L", "); if (str) Print(str, p->name); first = FALSE; p++; } grp = grp->next; } } VOID print_config_options(VOID) { Print(L"Global options supported:\n"); print_options(global_option_list, TRUE); Print(L"\n\n"); Print(L"Image options supported:\n"); print_options(image_option_list, TRUE); Print(L"\n"); } /* * returns a pointer to filename used for message N (which). NULL if it does * not exist. */ CHAR16 * get_message_filename(INTN which) { if (which < 0 || which >= MAX_MESSAGES) return NULL; return global_config.message_file[which]; } INTN register_config_options(config_option_t *opt, UINTN n, config_option_group_scope_t group) { config_option_group_t *newgrp, **grp; if (opt == NULL || n == 0 || (group != OPTIONS_GROUP_GLOBAL && group != OPTIONS_GROUP_IMAGE)) return -1; VERB_PRT(3, Print(L"registering %d options for group %s\n", n, group == OPTIONS_GROUP_GLOBAL ? L"global" : L"image")); newgrp = alloc(sizeof(config_option_group_t), EfiLoaderData); if (newgrp == NULL) return -1; grp = group == OPTIONS_GROUP_GLOBAL ? &global_option_list : &image_option_list; if (*grp) while ((*grp)->next) grp = &(*grp)->next; newgrp->options = opt; newgrp->next = NULL; newgrp->nentries = n; if (*grp) { (*grp)->next = newgrp; } else { *grp = newgrp; } return 0; } /* * initialize config options: register global and per image options */ INTN config_init(VOID) { INTN ret; ret = register_config_options(global_common_options, sizeof(global_common_options)/sizeof(config_option_t), OPTIONS_GROUP_GLOBAL); if (ret == -1) return -1; ret = register_config_options(image_common_options, sizeof(image_common_options)/sizeof(config_option_t), OPTIONS_GROUP_IMAGE); current_options = global_option_list; return ret; } ./elilo/glue_ext2fs.h0000644000175000017500000000214507720452036014250 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __GLUE_EXT2FS_H__ #define __GLUE_EXT2FS_H__ #include "fileops.h" extern fileops_fs_t ext2fs_glue; #endif /* __GLUE_EXT2FS_H__ */ ./elilo/LIMITATIONS0000644000175000017500000000012107316473501013360 0ustar jasonfjasonf See the TODO file, for more on the known limitations of this version of elilo. ./elilo/ia64/0000755000175000017500000000000011513632673012413 5ustar jasonfjasonf./elilo/ia64/plain_loader.c0000644000175000017500000002665710742000575015221 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include #include "elilo.h" #include "loader.h" #include "elf.h" #include "private.h" #define LD_NAME L"plain_elf64" #define PLAIN_MIN_BLOCK_SIZE sizeof(Elf64_Ehdr) /* see load_elf() for details */ #define SKIPBUFSIZE 2048 /* minimal default size of the skip buffer */ static CHAR8 *skip_buffer; /* used to skip over unneeded data */ static UINTN skip_bufsize; static UINTN elf_is_big_endian; /* true if ELF file is big endian */ static inline UINT64 bswap64(UINT64 v) { if(elf_is_big_endian) v = __ia64_swab64(v); return v; } static inline UINT32 bswap32(UINT32 v) { if(elf_is_big_endian) v = __ia64_swab32(v); return v; } static inline UINT16 bswap16(UINT16 v) { if(elf_is_big_endian) v = __ia64_swab16(v); return v; } static INTN is_valid_header(Elf64_Ehdr *ehdr) { UINT16 type, machine; if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) { type = __ia64_swab16(ehdr->e_type); machine = __ia64_swab16(ehdr->e_machine); } else { type = ehdr->e_type; machine = ehdr->e_machine; } DBG_PRT((L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS64 && type == ET_EXEC /* must be executable */ && machine == EM_IA_64 ? 0 : -1; } static INTN plain_probe(CHAR16 *kname) { Elf64_Ehdr ehdr; EFI_STATUS status; INTN ret = -1; fops_fd_t fd; UINTN size = sizeof(ehdr); status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error; ret = is_valid_header(&ehdr); error: fops_close(fd); return ret; } /* * move skip bytes forward in the file * this is required because we cannot assume fileops has * seek() capabilities. */ static INTN skip_bytes(fops_fd_t fd, UINTN curpos, UINTN newpos) { EFI_STATUS status; UINTN n, skip; skip = newpos - curpos; /* check if seek capability exists */ status = fops_seek(fd, newpos); if (status == EFI_SUCCESS) return 0; if (status != EFI_UNSUPPORTED) goto error; /* unsupported case */ if (skip_buffer == NULL) { skip_bufsize = MAX(skip, SKIPBUFSIZE); skip_buffer= (CHAR8 *)alloc(skip_bufsize, EfiLoaderData); if (skip_buffer == NULL) return -1; } while (skip) { n = skip > skip_bufsize? skip_bufsize : skip; status = fops_read(fd, skip_buffer, &n); if (EFI_ERROR(status)) goto error; skip -=n; } return 0; error: ERR_PRT((L"%s : cannot skip %d bytes\n", LD_NAME, n)); return -1; } static INTN load_elf(fops_fd_t fd, kdesc_t *kd) { Elf64_Ehdr ehdr; Elf64_Phdr *phdrs; EFI_STATUS status; INTN ret = ELILO_LOAD_ERROR; UINTN i, total_size = 0; UINTN pages, size, bss_sz, osize; UINTN offs = 0; VOID *low_addr = (VOID *)~0; VOID *max_addr = (VOID *)0; UINTN load_offset = 0; UINTN paddr, memsz, filesz, poffs; UINT16 phnum; Print(L"Loading Linux... "); size = sizeof(ehdr); status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) ||size < sizeof(ehdr)) return ELILO_LOAD_ERROR; offs += size; /* * do some sanity checking on the file */ if (is_valid_header(&ehdr) == -1) { ERR_PRT((L"%s : not an elf 64-bit file\n", LD_NAME)); return ELILO_LOAD_ERROR; } /* determine file endianess */ elf_is_big_endian = ehdr.e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0; VERB_PRT(3, { Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian"); Print(L"Entry point 0x%lx\n", bswap64(ehdr.e_entry)); Print(L"%d program headers\n", bswap16(ehdr.e_phnum)); Print(L"%d segment headers\n", bswap16(ehdr.e_shnum)); }); phnum = bswap16(ehdr.e_phnum); if (skip_bytes(fd, offs, bswap64(ehdr.e_phoff)) != 0) { ERR_PRT((L"%s : skip tp %ld for phdrs failed", LD_NAME, offs)); return ELILO_LOAD_ERROR; } offs = bswap64(ehdr.e_phoff); size = osize = phnum*sizeof(Elf64_Phdr); DBG_PRT((L"%s : phdrs allocate %d bytes sizeof=%d entsize=%d\n", LD_NAME, size,sizeof(Elf64_Phdr), bswap16(ehdr.e_phentsize))); phdrs = (Elf64_Phdr *)alloc(size, 0); if (phdrs == NULL) { ERR_PRT((L"%s : allocate phdrs failed", LD_NAME)); return ELILO_LOAD_ERROR; } status = fops_read(fd, phdrs, &size); if (EFI_ERROR(status) || size != osize) { ERR_PRT((L"%s : load phdrs failed", LD_NAME, status)); goto out; } offs += size; /* * First pass to figure out: * - lowest physical address * - total memory footprint */ for (i = 0; i < phnum; i++) { paddr = bswap64(phdrs[i].p_paddr); memsz = bswap64(phdrs[i].p_memsz); DBG_PRT((L"Phdr %d paddr [0x%lx-0x%lx] offset %ld" " filesz %ld memsz=%ld bss_sz=%ld p_type=%d\n", 1+i, paddr, paddr+bswap64(phdrs[i].p_filesz), bswap64(phdrs[i].p_offset), bswap64(phdrs[i].p_filesz), memsz, memsz - bswap64(phdrs[i].p_filesz), bswap32(phdrs[i].p_type))); if (bswap32(phdrs[i].p_type) != PT_LOAD) continue; if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr; if (paddr + memsz > (UINTN)max_addr) max_addr = (VOID *)paddr + memsz; } if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : kernel low address 0x%lx not page aligned\n", LD_NAME, low_addr)); goto out; } /* how many bytes are needed to hold the kernel */ total_size = (UINTN)max_addr - (UINTN)low_addr; /* round up to get required number of pages */ pages = EFI_SIZE_TO_PAGES(total_size); /* keep track of location where kernel ends for * the initrd ramdisk (it will be put right after the kernel) */ kd->kstart = low_addr; kd->kend = low_addr+ (pages << EFI_PAGE_SHIFT); /* * that's the kernel entry point (virtual address) */ kd->kentry = (VOID *)bswap64(ehdr.e_entry); if (((UINTN)kd->kentry >> 61) != 0) { ERR_PRT((L"%s: <> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kd->kentry)); } VERB_PRT(3, { Print(L"Lowest PhysAddr: 0x%lx\nTotalMemSize:%d bytes (%d pages)\n", low_addr, total_size, pages); Print(L"Kernel entry @ 0x%lx\n", kd->kentry); }); /* * now allocate memory for the kernel at the exact requested spot */ if (alloc_kmem(low_addr, pages) == -1) { VOID *new_addr; VERB_PRT(1, Print(L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); if (ia64_can_relocate() == 0) { ERR_PRT((L"relocation is disabled, cannot load kernel")); goto out; } /* * could not allocate at requested spot, try to find a * suitable location to relocate the kernel * * The maximum sized Itanium TLB translation entry is 256 MB. * If we relocate the kernel by this amount we know for sure * that alignment constraints will be satisified, regardless * of the kernel used. */ Print(L"Attempting to relocate kernel.\n"); if (find_kernel_memory(low_addr, max_addr, 256*MB, &new_addr) == -1) { ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset)); goto out; } /* unsigned arithmetic */ load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB)); VERB_PRT(3, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset)); /* * correct various addesses for non-zero load_offset */ low_addr = (VOID*) ((UINTN) low_addr + load_offset); max_addr = (VOID*) ((UINTN) max_addr + load_offset); kd->kstart = (VOID *) ((UINTN) kd->kstart + load_offset); kd->kend = (VOID *) ((UINTN) kd->kend + load_offset); kd->kentry = (VOID *) ((UINTN) kd->kentry + load_offset); /* * try one last time to get memory for the kernel */ if (alloc_kmem(low_addr, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset)); goto out; } } VERB_PRT(1, Print(L"Press any key to interrupt\n")); /* Second pass: * Walk through the program headers * and actually load data into physical memory */ for (i = 0; i < phnum; i++) { /* * Check for pure loadable segment; ignore if not loadable */ if (bswap32(phdrs[i].p_type) != PT_LOAD) continue; poffs = bswap64(phdrs[i].p_offset); size = poffs - offs; VERB_PRT(3, Print(L"\noff=%ld poffs=%ld size=%ld\n", offs, poffs, size)); filesz = bswap64(phdrs[i].p_filesz); /* * correct p_paddr for non-zero load offset */ phdrs[i].p_paddr = (Elf64_Addr) ((UINTN) bswap64(phdrs[i].p_paddr) + load_offset); /* * Move to the right position */ if (size && skip_bytes(fd, offs, poffs) != 0) goto out_kernel; /* * Keep track of current position in file */ offs += size; /* * How many BSS bytes to clear */ bss_sz = bswap64(phdrs[i].p_memsz) - filesz; VERB_PRT(4, { Print(L"\nHeader #%d\n", i); Print(L"offset %ld\n", poffs); Print(L"Phys addr 0x%lx\n", phdrs[i].p_paddr); /* already endian adjusted */ Print(L"BSS size %ld bytes\n", bss_sz); Print(L"skip=%ld offs=%ld\n", size, offs); }); /* * Read actual segment into memory */ ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr); if (ret == ELILO_LOAD_ABORTED) goto load_abort; if (ret == ELILO_LOAD_ERROR) goto out; if (bswap32(phdrs[i].p_flags) & PF_X) flush_dcache ((CHAR8 *)phdrs[i].p_paddr, filesz); /* * update file position */ offs += filesz; /* * Clear bss section */ if (bss_sz) Memset((VOID *) phdrs[i].p_paddr+filesz, 0, bss_sz); } free(phdrs); Print(L"..done\n"); return ELILO_LOAD_SUCCESS; load_abort: Print(L"..Aborted\n"); ret = ELILO_LOAD_ABORTED; out_kernel: /* free kernel memory */ free_kmem(); out: free(phdrs); return ret; } static INTN plain_load_kernel(CHAR16 *kname, kdesc_t *kd) { INTN ret; fops_fd_t fd; EFI_STATUS status; /* * Moving the open here simplifies the load_elf() error handling */ status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; Print(L"Loading %s...", kname); ret = load_elf(fd, kd); fops_close(fd); /* * if the skip buffer was ever used, free it */ if (skip_buffer) { free(skip_buffer); /* in case we come back */ skip_buffer = NULL; } return ret; } loader_ops_t plain_loader={ NULL, LD_NAME, plain_probe, plain_load_kernel }; ./elilo/ia64/memcpy.S0000644000175000017500000001777607720452134014050 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. * * This file is derived from the Linux/ia64 kernel source code */ /* * * Optimized version of the standard memcpy() function * * Inputs: * in0: destination address * in1: source address * in2: number of bytes to copy * Output: * no return value * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian * Copyright (C) 2000 David Mosberger-Tang */ /* be pessimistic for now... */ #define CONFIG_ITANIUM_B0_SPECIFIC 1 #if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) # define BRP(args...) nop.b 0 #else # define BRP(args...) brp.loop.imp args #endif .text // FALL THROUGH .global Memcpy .proc Memcpy Memcpy: # define MEM_LAT 21 /* latency to memory */ # define dst r2 # define src r3 # define retval r8 # define saved_pfs r9 # define saved_lc r10 # define saved_pr r11 # define cnt r16 # define src2 r17 # define t0 r18 # define t1 r19 # define t2 r20 # define t3 r21 # define t4 r22 # define src_end r23 # define N (MEM_LAT + 4) # define Nrot ((N + 7) & ~7) /* * First, check if everything (src, dst, len) is a multiple of eight. If * so, we handle everything with no taken branches (other than the loop * itself) and a small icache footprint. Otherwise, we jump off to * the more general copy routine handling arbitrary * sizes/alignment etc. */ .prologue .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot .save ar.lc, saved_lc mov saved_lc=ar.lc or t0=in0,in1 ;; or t0=t0,in2 .save pr, saved_pr mov saved_pr=pr .body cmp.eq p6,p0=in2,r0 // zero length? mov retval=in0 // return dst (p6) br.ret.spnt.many rp // zero length, return immediately ;; mov dst=in0 // copy because of rotation shr.u cnt=in2,3 // number of 8-byte words to copy mov pr.rot=1<<16 ;; adds cnt=-1,cnt // br.ctop is repeat/until cmp.gtu p7,p0=16,in2 // copying less than 16 bytes? mov ar.ec=N ;; and t0=0x7,t0 mov ar.lc=cnt ;; cmp.ne p6,p0=t0,r0 mov src=in1 // copy because of rotation (p7) br.cond.spnt.few memcpy_short (p6) br.cond.spnt.few memcpy_long ;; nop.m 0 ;; nop.m 0 nop.i 0 ;; nop.m 0 ;; .rotr val[N] .rotp p[N] .align 32 1: { .mib (p[0]) ld8 val[0]=[src],8 nop.i 0 BRP(1b, 2f) } 2: { .mfb (p[N-1])st8 [dst]=val[N-1],8 nop.f 0 br.ctop.dptk.few 1b } ;; mov ar.lc=saved_lc mov pr=saved_pr,-1 mov ar.pfs=saved_pfs br.ret.sptk.many rp /* * Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time * copy loop. This performs relatively poorly on Itanium, but it doesn't * get used very often (gcc inlines small copies) and due to atomicity * issues, we want to avoid read-modify-write of entire words. */ .align 32 memcpy_short: adds cnt=-1,in2 // br.ctop is repeat/until mov ar.ec=MEM_LAT BRP(1f, 2f) ;; mov ar.lc=cnt ;; nop.m 0 ;; nop.m 0 nop.i 0 ;; nop.m 0 ;; nop.m 0 ;; /* * It is faster to put a stop bit in the loop here because it makes * the pipeline shorter (and latency is what matters on short copies). */ .align 32 1: { .mib (p[0]) ld1 val[0]=[src],1 nop.i 0 BRP(1b, 2f) } ;; 2: { .mfb (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1 nop.f 0 br.ctop.dptk.few 1b } ;; mov ar.lc=saved_lc mov pr=saved_pr,-1 mov ar.pfs=saved_pfs br.ret.sptk.many rp /* * Large (>= 16 bytes) copying is done in a fancy way. Latency isn't * an overriding concern here, but throughput is. We first do * sub-word copying until the destination is aligned, then we check * if the source is also aligned. If so, we do a simple load/store-loop * until there are less than 8 bytes left over and then we do the tail, * by storing the last few bytes using sub-word copying. If the source * is not aligned, we branch off to the non-congruent loop. * * stage: op: * 0 ld * : * MEM_LAT+3 shrp * MEM_LAT+4 st * * On Itanium, the pipeline itself runs without stalls. However, br.ctop * seems to introduce an unavoidable bubble in the pipeline so the overall * latency is 2 cycles/iteration. This gives us a _copy_ throughput * of 4 byte/cycle. Still not bad. */ # undef N # undef Nrot # define N (MEM_LAT + 5) /* number of stages */ # define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */ #define LOG_LOOP_SIZE 6 memcpy_long: alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame and t0=-8,src // t0 = src & ~7 and t2=7,src // t2 = src & 7 ;; ld8 t0=[t0] // t0 = 1st source word adds src2=7,src // src2 = (src + 7) sub t4=r0,dst // t4 = -dst ;; and src2=-8,src2 // src2 = (src + 7) & ~7 shl t2=t2,3 // t2 = 8*(src & 7) shl t4=t4,3 // t4 = 8*(dst & 7) ;; ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise sub t3=64,t2 // t3 = 64-8*(src & 7) shr.u t0=t0,t2 ;; add src_end=src,in2 shl t1=t1,t3 mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7) ;; or t0=t0,t1 mov cnt=r0 adds src_end=-1,src_end ;; (p3) st1 [dst]=t0,1 (p3) shr.u t0=t0,8 (p3) adds cnt=1,cnt ;; (p4) st2 [dst]=t0,2 (p4) shr.u t0=t0,16 (p4) adds cnt=2,cnt ;; (p5) st4 [dst]=t0,4 (p5) adds cnt=4,cnt and src_end=-8,src_end // src_end = last word of source buffer ;; // At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy: 1:{ add src=cnt,src // make src point to remainder of source buffer sub cnt=in2,cnt // cnt = number of bytes left to copy mov t4=ip } ;; and src2=-8,src // align source pointer adds t4=memcpy_loops-1b,t4 mov ar.ec=N and t0=7,src // t0 = src & 7 shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy shl cnt=cnt,3 // move bits 0-2 to 3-5 ;; .rotr val[N+1], w[2] .rotp p[N] cmp.ne p6,p0=t0,r0 // is src aligned, too? shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7) adds t2=-1,t2 // br.ctop is repeat/until ;; add t4=t0,t4 mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy mov ar.lc=t2 ;; nop.m 0 ;; nop.m 0 nop.i 0 ;; nop.m 0 ;; (p6) ld8 val[1]=[src2],8 // prime the pump... mov b6=t4 br.sptk.few b6 ;; memcpy_tail: // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is // less than 8) and t0 contains the last few bytes of the src buffer: (p5) st4 [dst]=t0,4 (p5) shr.u t0=t0,32 mov ar.lc=saved_lc ;; (p4) st2 [dst]=t0,2 (p4) shr.u t0=t0,16 mov ar.pfs=saved_pfs ;; (p3) st1 [dst]=t0 mov pr=saved_pr,-1 br.ret.sptk.many rp /////////////////////////////////////////////////////// .align 64 #define COPY(shift,index) \ 1: { .mib \ (p[0]) ld8 val[0]=[src2],8; \ (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \ BRP(1b, 2f) \ }; \ 2: { .mfb \ (p[MEM_LAT+4]) st8 [dst]=w[1],8; \ nop.f 0; \ br.ctop.dptk.few 1b; \ }; \ ;; \ ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \ ;; \ shrp t0=val[N-1],val[N-index],shift; \ br memcpy_tail memcpy_loops: COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */ COPY(8, 0) COPY(16, 0) COPY(24, 0) COPY(32, 0) COPY(40, 0) COPY(48, 0) COPY(56, 0) .endp Memcpy ./elilo/ia64/setjmp.S0000644000175000017500000000724210746751560014052 0ustar jasonfjasonf/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by David Mosberger-Tang . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. The layout of the jmp_buf is as follows. This is subject to change and user-code should never depend on the particular layout of jmp_buf! offset: description: ------- ------------ 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS) 0x008 r1 (gp) 0x010 caller's unat 0x018 fpsr 0x020 r4 0x028 r5 0x030 r6 0x038 r7 0x040 rp (b0) 0x048 b1 0x050 b2 0x058 b3 0x060 b4 0x068 b5 0x070 ar.pfs 0x078 ar.lc 0x080 pr 0x088 ar.bsp ; unchangeable (see __longjmp.S) 0x090 ar.unat 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat) 0x0a0 f2 0x0b0 f3 0x0c0 f4 0x0d0 f5 0x0e0 f16 0x0f0 f17 0x100 f18 0x110 f19 0x120 f20 0x130 f21 0x130 f22 0x140 f23 0x150 f24 0x160 f25 0x170 f26 0x180 f27 0x190 f28 0x1a0 f29 0x1b0 f30 0x1c0 f31 */ /* The following two entry points are the traditional entry points: */ .text .global setjmp .proc setjmp setjmp: alloc r8=ar.pfs,2,0,0,0 mov in1=1 br.cond.sptk.many __sigsetjmp .endp setjmp /* __sigsetjmp(__jmp_buf buf, int savemask) */ .proc __sigsetjmp __sigsetjmp: //.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) .body alloc loc1=ar.pfs,2,2,2,0 mov r16=ar.unat ;; mov r17=ar.fpsr mov r2=in0 add r3=8,in0 ;; st8.spill.nta [r2]=sp,16 // r12 (sp) ;; st8.spill.nta [r3]=gp,16 // r1 (gp) ;; st8.nta [r2]=r16,16 // save caller's unat st8.nta [r3]=r17,16 // save fpsr add r8=0xa0,in0 ;; st8.spill.nta [r2]=r4,16 // r4 ;; st8.spill.nta [r3]=r5,16 // r5 add r9=0xb0,in0 ;; stf.spill.nta [r8]=f2,32 stf.spill.nta [r9]=f3,32 mov loc0=rp ;; stf.spill.nta [r8]=f4,32 stf.spill.nta [r9]=f5,32 mov r17=b1 ;; stf.spill.nta [r8]=f16,32 stf.spill.nta [r9]=f17,32 mov r18=b2 ;; stf.spill.nta [r8]=f18,32 stf.spill.nta [r9]=f19,32 mov r19=b3 ;; stf.spill.nta [r8]=f20,32 stf.spill.nta [r9]=f21,32 mov r20=b4 ;; stf.spill.nta [r8]=f22,32 stf.spill.nta [r9]=f23,32 mov r21=b5 ;; stf.spill.nta [r8]=f24,32 stf.spill.nta [r9]=f25,32 mov r22=ar.lc ;; stf.spill.nta [r8]=f26,32 stf.spill.nta [r9]=f27,32 mov r24=pr ;; stf.spill.nta [r8]=f28,32 stf.spill.nta [r9]=f29,32 ;; stf.spill.nta [r8]=f30 stf.spill.nta [r9]=f31 st8.spill.nta [r2]=r6,16 // r6 ;; st8.spill.nta [r3]=r7,16 // r7 ;; mov r23=ar.bsp mov r25=ar.unat mov out0=in0 st8.nta [r2]=loc0,16 // b0 st8.nta [r3]=r17,16 // b1 mov out1=in1 ;; st8.nta [r2]=r18,16 // b2 st8.nta [r3]=r19,16 // b3 ;; st8.nta [r2]=r20,16 // b4 st8.nta [r3]=r21,16 // b5 ;; st8.nta [r2]=loc1,16 // ar.pfs st8.nta [r3]=r22,16 // ar.lc ;; st8.nta [r2]=r24,16 // pr st8.nta [r3]=r23,16 // ar.bsp ;; st8.nta [r2]=r25 // ar.unat st8.nta [r3]=in0 // &__jmp_buf mov r8=0 mov rp=loc0 mov ar.pfs=loc1 br.ret.sptk.many rp .endp __sigsetjmp ./elilo/ia64/setjmp.h0000644000175000017500000000244207331740635014071 0ustar jasonfjasonf/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version. Copyright (C) 1999, 2000 Free Software Foundation, Inc. Contributed by David Mosberger-Tang . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* User code must not depend on the internal representation of jmp_buf. */ #define _JBLEN 70 /* the __jmp_buf element type should be __float80 per ABI... */ typedef long jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */ extern int setjmp (jmp_buf __env); extern void longjmp (jmp_buf __env, int __val); ./elilo/ia64/private.h0000644000175000017500000000237010312571020014220 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __ELILO_PRIVATE_IA64_H__ #define __ELILO_PRIVATE_IA64_H__ extern INTN check_fpswa(EFI_HANDLE, EFI_HANDLE, CHAR16 *); extern INTN query_fpswa(VOID **); extern INTN ia64_can_relocate(); extern void flush_dcache (CHAR8 *addr, UINT64 len); #endif /* __ELILO_PRIVATE_IA64_H__ */ ./elilo/ia64/fpswa.c0000644000175000017500000001104510742000575013671 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #include "fileops.h" typedef struct { UINT32 revision; UINT32 reserved; VOID *fpswa; } fpswa_interface_t; INTN query_fpswa(VOID **fpswa) { EFI_HANDLE fpswa_image; UINTN size; EFI_STATUS status; EFI_GUID FpswaProtocol = FPSWA_PROTOCOL; DBG_PRT((L"Querying FpswaProtocol")); size = sizeof(EFI_HANDLE); status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image); if (EFI_ERROR(status)) { ERR_PRT((L"boot_params could not locate FPSWA driver", status)); return -1; } status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa); if (EFI_ERROR(status)) { ERR_PRT((L"boot_params FpswaProtocol not able find the interface")); return -1; } VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa, ((fpswa_interface_t *)*fpswa)->revision)); return 0; } static INTN do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file) { EFI_STATUS status; EFI_HANDLE handle; EFI_DEVICE_PATH *dp; dp = FileDevicePath(dev, fpswa_file); if (dp == NULL) { ERR_PRT((L"Cannot create FilePath for %s", fpswa_file)); return -1; } status = BS->LoadImage(0, image, dp, NULL, 0, &handle); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"..not found\n")); FreePool(dp); return -1; } VERB_PRT(3, Print(L"..starting..")); status = BS->StartImage(handle, 0, 0); if (EFI_ERROR(status)) { VERB_PRT(3, Print(L"failed (%r)\n", status)); /* * StartImage() automatically unloads if error * FPSWA init code will automatically abort if newer revision * is already installed */ } else { VERB_PRT(3, Print(L"..ok\n")); } FreePool(dp); return 0; } /* * If the caller specifies a fpswa filename, then it used instead of the * defaults. * Return: * 0 : indicates that one fpswa driver was loaded, i.e. an update could be done * -1: no update was found that would have a more recent version of the driver. This is * not a fatal return value. */ INTN check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file) { /* * we must use \\ here as this is given to LoadImage() directly * * The FPSWA driver MUST be called fpswa.efi and the FPSWA document * (see developer.intel.com/design/itanium) stipulates that the * file must be placed in \EFI\Intel Firmware\ (no mention of which * EFI system partition). So elilo will check on all accessible * Fat32+ partition for the existence of this directory and file. */ static CHAR16 *fpswa_filenames[] ={ L"\\efi\\intel firmware\\fpswa.efi", #if 0 L"\\fpswa.efi", L"\\fw\\fpswa.efi", L"\\efi\\fpswa.efi", L"\\efi\\tools\\fpswa.efi", L"\\fpswa.efi", L"fpswa.efi", #endif }; UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *); UINTN cookie; CHAR16 devname[FILENAME_MAXLEN]; if (fpswa_file) { INTN r; devname[0] = CHAR_NULL; r = fops_split_path(fpswa_file, devname); if (r == -1) { ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file)); return -1; } if (devname[0] != CHAR_NULL) { if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) { ERR_PRT((L"cannot find device %s for FPSWA driver", devname)); return -1; } } return do_check_fpswa(image, dev, fpswa_file); } cookie = 0; while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) { for (j = 0; j < count; j++) { VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j])); /* * we need to do all choices to make sure we pickup * the latest version. */ do_check_fpswa(image, dev, fpswa_filenames[j]); } } return -1; } ./elilo/ia64/memset.S0000644000175000017500000000644107720452125014033 0ustar jasonfjasonf/* * Copyright (C) 1999-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. * * This code is derived from the Linux/ia64 source code. */ /* * * Optimized version of the standard memset() function * * Return: none * * Inputs: * in0: address of buffer * in1: byte value to use for storing * in2: length of the buffer * */ // arguments // #define buf r32 #define val r33 #define len r34 // // local registers // #define saved_pfs r14 #define cnt r18 #define buf2 r19 #define saved_lc r20 #define tmp r21 .text .global Memset .proc Memset Memset: .prologue .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here cmp.eq p8,p0=r0,len // check for zero length .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) ;; .body adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment (p8) br.ret.spnt.few rp cmp.lt p7,p0=16,len // if len > 16 then long memset mux1 val=val,@brcst // prepare value (p7) br.cond.dptk.few long_memset ;; mov ar.lc=tmp // initialize lc for small count ;; // avoid RAW and WAW on ar.lc 1: // worst case 15 cyles, avg 8 cycles st1 [buf]=val,1 br.cloop.dptk.few 1b ;; // avoid RAW on ar.lc mov ar.lc=saved_lc mov ar.pfs=saved_pfs br.ret.sptk.few rp // end of short memset // at this point we know we have more than 16 bytes to copy // so we focus on alignment long_memset: (p6) st1 [buf]=val,1 // 1-byte aligned (p6) adds len=-1,len;; // sync because buf is modified tbit.nz p6,p0=buf,1 ;; (p6) st2 [buf]=val,2 // 2-byte aligned (p6) adds len=-2,len;; tbit.nz p6,p0=buf,2 ;; (p6) st4 [buf]=val,4 // 4-byte aligned (p6) adds len=-4,len;; tbit.nz p6,p0=buf,3 ;; (p6) st8 [buf]=val,8 // 8-byte aligned (p6) adds len=-8,len;; shr.u cnt=len,4 // number of 128-bit (2x64bit) words ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt (p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp ;; 2: // 16bytes/iteration st8 [buf]=val,16 st8 [buf2]=val,16 br.cloop.dptk.few 2b ;; .dotail: // tail correction based on len only tbit.nz p6,p0=len,3 ;; (p6) st8 [buf]=val,8 // at least 8 bytes tbit.nz p6,p0=len,2 ;; (p6) st4 [buf]=val,4 // at least 4 bytes tbit.nz p6,p0=len,1 ;; (p6) st2 [buf]=val,2 // at least 2 bytes tbit.nz p6,p0=len,0 mov ar.lc=saved_lc ;; (p6) st1 [buf]=val // only 1 byte left br.ret.dptk.few rp .endp Memset ./elilo/ia64/Makefile0000644000175000017500000000235107720452175014056 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES=system.o config.o fpswa.o plain_loader.o gzip_loader.o \ gzip.o memset.o memcpy.o setjmp.o longjmp.o TARGET=sysdeps.o all: $(TARGET) $(TARGET): $(FILES) $(LD) -o $@ -r $(FILES) clean: $(RM) -f $(TARGET) $(FILES) ./elilo/ia64/longjmp.S0000644000175000017500000001045110746751560014212 0ustar jasonfjasonf/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by David Mosberger-Tang . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. Note that __sigsetjmp() did NOT flush the register stack. Instead, we do it here since __longjmp() is usually much less frequently invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp() didn't (and wouldn't be able to) save ar.rnat either. This is a problem because if we're not careful, we could end up loading random NaT bits. There are two cases: (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp) ar.rnat contains the desired bits---preserve ar.rnat across loadrs and write to ar.bspstore (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp) The desired ar.rnat is stored in ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those bits into ar.rnat after setting ar.bspstore. */ # define pPos p6 /* is rotate count positive? */ # define pNeg p7 /* is rotate count negative? */ /* __longjmp(__jmp_buf buf, int val) */ .text .global longjmp .proc longjmp longjmp: alloc r8=ar.pfs,2,1,0,0 mov r27=ar.rsc add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr ;; ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr mov r10=ar.bsp and r11=~0x3,r27 // clear ar.rsc.mode ;; flushrs // flush dirty regs to backing store (must be first in insn grp) ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf ;; ld8 r25=[r2] // r25 <- jmpbuf.ar_unat extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f ;; cmp.lt pNeg,pPos=r8,r0 mov r2=in0 ;; (pPos) mov r16=r8 (pNeg) add r16=64,r8 (pPos) sub r17=64,r8 (pNeg) sub r17=r0,r8 ;; mov ar.rsc=r11 // put RSE in enforced lazy mode shr.u r8=r25,r16 add r3=8,in0 // r3 <- &jmpbuf.r1 shl r9=r25,r17 ;; or r25=r8,r9 ;; mov r26=ar.rnat mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12) ;; ld8.fill.nta sp=[r2],16 // r12 (sp) ld8.fill.nta gp=[r3],16 // r1 (gp) dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp) ;; ld8.nta r16=[r2],16 // caller's unat ld8.nta r17=[r3],16 // fpsr ;; ld8.fill.nta r4=[r2],16 // r4 ld8.fill.nta r5=[r3],16 // r5 (gp) cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp) ;; ld8.fill.nta r6=[r2],16 // r6 ld8.fill.nta r7=[r3],16 // r7 ;; mov ar.unat=r16 // restore caller's unat mov ar.fpsr=r17 // restore fpsr ;; ld8.nta r16=[r2],16 // b0 ld8.nta r17=[r3],16 // b1 ;; (p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp) mov ar.bspstore=r23 // restore ar.bspstore ;; ld8.nta r18=[r2],16 // b2 ld8.nta r19=[r3],16 // b3 ;; ld8.nta r20=[r2],16 // b4 ld8.nta r21=[r3],16 // b5 ;; ld8.nta r11=[r2],16 // ar.pfs ld8.nta r22=[r3],56 // ar.lc ;; ld8.nta r24=[r2],32 // pr mov b0=r16 ;; ldf.fill.nta f2=[r2],32 ldf.fill.nta f3=[r3],32 mov b1=r17 ;; ldf.fill.nta f4=[r2],32 ldf.fill.nta f5=[r3],32 mov b2=r18 ;; ldf.fill.nta f16=[r2],32 ldf.fill.nta f17=[r3],32 mov b3=r19 ;; ldf.fill.nta f18=[r2],32 ldf.fill.nta f19=[r3],32 mov b4=r20 ;; ldf.fill.nta f20=[r2],32 ldf.fill.nta f21=[r3],32 mov b5=r21 ;; ldf.fill.nta f22=[r2],32 ldf.fill.nta f23=[r3],32 mov ar.lc=r22 ;; ldf.fill.nta f24=[r2],32 ldf.fill.nta f25=[r3],32 cmp.eq p8,p9=0,in1 ;; ldf.fill.nta f26=[r2],32 ldf.fill.nta f27=[r3],32 mov ar.pfs=r11 ;; ldf.fill.nta f28=[r2],32 ldf.fill.nta f29=[r3],32 ;; ldf.fill.nta f30=[r2] ldf.fill.nta f31=[r3] (p8) mov r8=1 mov ar.rnat=r26 // restore ar.rnat ;; mov ar.rsc=r27 // restore ar.rsc (p9) mov r8=in1 invala // virt. -> phys. regnum mapping may change mov pr=r24,-1 br.ret.dptk.few rp .endp longjmp ./elilo/ia64/system.c0000644000175000017500000001047711466353731014116 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ /* * this file contains all the IA-64 specific code expected by generic loader */ #include #include #include "elilo.h" #include "loader.h" #include "private.h" extern loader_ops_t plain_loader, gzip_loader; /* * IA-64 specific boot paramters initialization routine */ INTN sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie) { UINTN cols, rows; SIMPLE_TEXT_OUTPUT_INTERFACE *conout; EFI_STATUS status; mmap_desc_t mdesc; /* * retrieve address of FPSWA interface * if not found, argument is not touched * will be 0 because of Memset() */ query_fpswa((VOID **)&bp->fpswa); if (get_memmap(&mdesc) == -1) return -1; DBG_PRT((L"Got memory map @ 0x%lx (%d bytes) with key %d", mdesc.md, mdesc.map_size, mdesc.cookie)); bp->efi_systab = (UINTN)systab; bp->efi_memmap = (UINTN)mdesc.md; bp->efi_memmap_size = mdesc.map_size; bp->efi_memdesc_size = mdesc.desc_size; bp->efi_memdesc_version = mdesc.desc_version; bp->command_line = (UINTN)cmdline; bp->initrd_start = (UINTN) initrd->start_addr; bp->initrd_size = initrd->size; DBG_PRT((L"Got initrd @ 0x%lx (%d bytes)", initrd->start_addr, initrd->size)); bp->vmcode_start = (UINTN) vmcode->start_addr; bp->vmcode_size = vmcode->size; DBG_PRT((L"Got vmcode @ 0x%lx (%d bytes)", vmcode->start_addr, vmcode->size)); /* fetch console parameters: */ conout = systab->ConOut; status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); if (EFI_ERROR(status)) { ERR_PRT((L"boot_params QueryMode failed %r", status)); goto error; } DBG_PRT((L"Got console info: cols=%d rows=%d x=%d y=%d", cols, rows, conout->Mode->CursorColumn, conout->Mode->CursorRow)); bp->console_info.num_cols = cols; bp->console_info.num_rows = rows; bp->console_info.orig_x = conout->Mode->CursorColumn; bp->console_info.orig_y = conout->Mode->CursorRow; *cookie = mdesc.cookie; return 0; error: /* free descriptors' memory */ free_memmap(&mdesc); return -1; } VOID sysdeps_free_boot_params(boot_params_t *bp) { mmap_desc_t md; Memset(&md, 0, sizeof(md)); md.md = (VOID *)bp->efi_memmap; free_memmap(&md); } INTN sysdeps_init(EFI_HANDLE dev) { loader_register(&plain_loader); loader_register(&gzip_loader); return 0; } INTN sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) { /* * We currently place the initrd at the next page aligned boundary * after the kernel. * * Current kernel implementation requires this (see arch/ia64/kernel/setup.c). * * IMPORTANT: EFI & kernel page sizes may differ. We have no way * of guessing what size the kernel uses. It is the responsibility * of the kernel to adjust. * */ #if 0 imem->start_addr = (VOID *)ROUNDUP((UINTN)kd->kend, EFI_PAGE_SIZE); #else imem->start_addr = 0; /* let the allocator decide */ #endif return 0; } VOID * sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) { return start_addr; } /* Flush data cache [addr; addr + len], and sync with icache. */ void flush_dcache (CHAR8 *addr, UINT64 len) { /* Cache line length is at least 32. */ UINT64 a = (UINT64)addr & ~0x1f; DBG_PRT((L"Flush 0x%lx-", a)); /* Flush data. */ for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20) asm volatile ("fc %0" : : "r" (a)); /* Sync and serialize. Maybe extra. */ asm volatile (";; sync.i;; srlz.i;;"); DBG_PRT((L"0x%lx\n", a)); } ./elilo/ia64/config.c0000644000175000017500000000777207720452202014032 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #include "config.h" #include "private.h" #include "sysdeps.h" #include "getopt.h" typedef struct { CHAR16 fpswa[FILENAME_MAXLEN]; CHAR16 cmd_fpswa[FILENAME_MAXLEN]; UINTN allow_relocation; } ia64_global_config_t; #define ia64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option) static ia64_global_config_t ia64_gconf; /* * No IA-64 specific options at this point * The last entry in each table MUST be use the OPT_NULL type to terminate * the chain. */ config_option_t sysdeps_global_options[]={ {OPT_FILE, OPT_GLOBAL, L"fpswa", NULL, NULL, ia64_gconf.fpswa}, {OPT_BOOL, OPT_GLOBAL, L"relocatable", NULL, NULL, &ia64_gconf.allow_relocation}, }; config_option_t sysdeps_image_options[]={ {OPT_BOOL, OPT_IMAGE_SYS, L"relocatable", NULL, NULL, ia64_opt_offsetof(allow_relocation)}, }; /* * IA-64 operations that need to be done only once and just before * entering the main loop of the loader * Return: * 0 if sucessful * -1 otherwise (will abort execution) */ INTN sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image) { /* * we have separate string to make sure that the command line take precedence over * the config file */ if (ia64_gconf.cmd_fpswa[0] != CHAR_NULL) { check_fpswa(image, dev, ia64_gconf.cmd_fpswa); } else if (ia64_gconf.fpswa[0] != CHAR_NULL) check_fpswa(image, dev, ia64_gconf.fpswa); else check_fpswa(image, dev, NULL); return 0; } /* * Return: * 1: if image or global configuration allows relocation * 0: otherwise * * It is written has a function rather than a macro to avoid * exposing config data structure to the rest of the code in ia64 */ INTN ia64_can_relocate(VOID) { return ia64_gconf.allow_relocation == TRUE || (elilo_opt.sys_img_opts && elilo_opt.sys_img_opts->allow_relocation ==TRUE) ? 1 : 0; } #define IA64_CMDLINE_OPTIONS L"rF:" CHAR16 * sysdeps_get_cmdline_opts(VOID) { return IA64_CMDLINE_OPTIONS; } INTN sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg) { INTN ret = 0; /* let's be optimistic ! */ /* * XXX: for now these command line options have to be global */ switch(c) { case L'r': ia64_gconf.allow_relocation = 1; break; case L'F': if (StrLen(Optarg) >= FILENAME_MAXLEN) { Print(L"FPSWA filename is limited to %d characters\n", FILENAME_MAXLEN); return -1; } StrCpy(ia64_gconf.cmd_fpswa, Optarg); break; default: ret = -1; } return ret; } VOID sysdeps_print_cmdline_opts(VOID) { Print(L"-r kernel image can be relocated if load address inexistent\n"); Print(L"-F file name of a specific FPSWA EFI driver to load\n"); } INTN sysdeps_register_options(VOID) { INTN ret; ret = register_config_options(sysdeps_global_options, sizeof(sysdeps_global_options)/sizeof(config_option_t), OPTIONS_GROUP_GLOBAL); if (ret == -1 ) return ret; ret = register_config_options(sysdeps_image_options, sizeof(sysdeps_image_options)/sizeof(config_option_t), OPTIONS_GROUP_IMAGE); return ret; } ./elilo/ia64/gzip.c0000644000175000017500000004024411271404161013522 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include #include "elf.h" #include "elilo.h" #include "gzip.h" #include "private.h" #include "setjmp.h" #define LD_NAME L"gzip_ia64" #define memzero(s, n) Memset((VOID *)(s), 0, (n)) #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) /* size of output buffer */ #define WSIZE 0x8000 /* Window size must be at least 32k, */ /* and a power of two */ /* size of input buffer */ #define INBUFSIZE 0x8000 /* * gzip declarations */ #define OF(args) args #define FUNC_STATIC static typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; typedef struct segment { unsigned long addr; /* start address */ unsigned long offset; /* file offset */ unsigned long size; /* file size */ unsigned long bss_sz; /* BSS size */ UINT8 flags; /* indicates whether to load or not */ } segment_t; #define CHUNK_FL_VALID 0x1 #define CHUNK_FL_LOAD 0x2 #define CHUNK_FL_X 0x4 #define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD #define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD #define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD) #define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID #define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0 #define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID) /* * static parameters to gzip helper functions * we cannot use paramters because API was not * designed that way */ static segment_t *chunks; /* holds the list of segments */ static segment_t *cur_chunk; static UINTN nchunks; static UINTN chunk; /* current segment */ static UINTN input_fd; static VOID *kernel_entry, *kernel_base, *kernel_end; static uch *inbuf; /* input buffer (compressed data) */ static uch *window; /* output buffer (uncompressed data) */ static unsigned long file_offset; /* position in the file */ static unsigned insize = 0; /* valid bytes in inbuf */ static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) /* Diagnostic functions */ #ifdef INFLATE_DEBUG # define Assert(cond,msg) {if(!(cond)) error(msg);} int stderr; # define Trace(x) Print(L"line %d:\n", __LINE__); # define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;} # define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;} # define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;} # define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif static int fill_inbuf(void); static void flush_window(void); static void error(char *m); static long bytes_out; static void error(char *m); static jmp_buf jbuf; static int error_return; static UINTN elf_is_big_endian; /* true if ELF file is big endian */ static void * gzip_malloc(int size) { return (void *)alloc(size, 0); } static void gzip_free(void *where) { return free(where); } #include "inflate.c" /* * Fill the input buffer and return the first byte in it. This is called * only when the buffer is empty and at least one byte is really needed. */ int fill_inbuf(void) { UINTN expected, nread; EFI_STATUS status; expected = nread = INBUFSIZE; status = fops_read(input_fd, inbuf, &nread); if (EFI_ERROR(status)) { error("elilo: Read failed"); } #ifdef DEBUG_GZIP DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected)); #endif insize = nread; inptr = 1; return inbuf[0]; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ /* * Run a set of bytes through the crc shift register. If s is a NULL * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. * * Input: * S pointer to bytes to pump through. * N number of bytes in S[]. */ unsigned long updcrc(unsigned char *s, unsigned n) { register unsigned long c; /* crc is defined in inflate.c */ if (!s) { c = 0xffffffffL; } else { c = crc; while (n--) { c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } } crc = c; return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */ } /* * Clear input and output buffers */ void clear_bufs(void) { outcnt = 0; inptr = 0; chunk = 0; cur_chunk = NULL; file_offset = 0; } static inline UINT64 bswap64(UINT64 v) { if(elf_is_big_endian) v = __ia64_swab64(v); return v; } static inline UINT32 bswap32(UINT32 v) { if(elf_is_big_endian) v = __ia64_swab32(v); return v; } static inline UINT16 bswap16(UINT16 v) { if(elf_is_big_endian) v = __ia64_swab16(v); return v; } static INTN is_valid_header(Elf64_Ehdr *ehdr) { UINT16 type, machine; if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) { type = __ia64_swab16(ehdr->e_type); machine = __ia64_swab16(ehdr->e_machine); } else { type = ehdr->e_type; machine = ehdr->e_machine; } VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS64 && type == ET_EXEC /* must be executable */ && machine == EM_IA_64 ? 0 : -1; } /* * will invalidate loadble segments which overlap with others */ void check_overlap(int i) { int j; unsigned long iend = chunks[i].addr + chunks[i].size; for(j=0; j < nchunks; j++) { if (j ==i) continue; if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) { DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j)); CHUNK_INVALIDATE(i); /* nullyify segment */ break; } } } void analyze_chunks(void) { INTN i; for(i=0; i < nchunks; i++) { if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i); } } /* * The decompression code calls this function after decompressing the * first block of the object file. The first block must contain all * the relevant header information. */ int first_block (const unsigned char *buf, long blocksize) { Elf64_Ehdr *elf; Elf64_Phdr *phdrs; UINTN total_size, pages; UINTN low_addr, max_addr; UINTN load_offset = 0; UINTN offs = 0; UINT16 phnum; UINTN paddr, memsz; INTN i; elf = (Elf64_Ehdr *)buf; if (is_valid_header(elf) == -1) return -1; /* determine file endianess */ elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0; offs = bswap64(elf->e_phoff); phnum = bswap16(elf->e_phnum); VERB_PRT(3, { Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian"); Print(L"Entry point 0x%lx\n", bswap64(elf->e_entry)); Print(L"%d program headers\n", phnum); Print(L"%d segment headers\n", bswap16(elf->e_shnum)); }); /* XXX: need to check on this */ if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) { ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs)); return -1; } kernel_entry = (void *)bswap64(elf->e_entry); if (((UINTN)kernel_entry >> 61) != 0) { ERR_PRT((L"%s: <> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kernel_entry)); } phdrs = (Elf64_Phdr *) (buf + offs); low_addr = ~0; max_addr = 0; /* * allocate chunk table * Convention: a segment that does not need loading will * have chunk[].addr = 0. */ chunks = (void *)alloc(sizeof(struct segment)*phnum, 0); if (chunks == NULL) { ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME)); return -1; } nchunks = phnum; /* * find lowest and higest virtual addresses * don't assume FULLY sorted ! */ for (i = 0; i < phnum; ++i) { /* * record chunk no matter what because no load may happen * anywhere in archive, not just as the last segment */ paddr = bswap64(phdrs[i].p_paddr); memsz = bswap64(phdrs[i].p_memsz), chunks[i].addr = paddr; chunks[i].offset = bswap64(phdrs[i].p_offset); chunks[i].size = bswap64(phdrs[i].p_filesz); chunks[i].bss_sz = bswap64(phdrs[i].p_memsz) - bswap64(phdrs[i].p_filesz); CHUNK_VALIDATE(i); if (bswap32(phdrs[i].p_type) != PT_LOAD) { CHUNK_NO_LOAD(i); /* mark no load chunk */ DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i)); continue; } if (bswap32(phdrs[i].p_flags) & PF_X) chunks[i].flags |= CHUNK_FL_X; CHUNK_CAN_LOAD(i); /* mark no load chunk */ VERB_PRT(3, Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld memsz=%ld bss_sz=%ld\n", LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+bswap64(phdrs[i].p_filesz), chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz)); if (paddr < low_addr) low_addr = paddr; if (paddr + memsz > max_addr) max_addr = paddr + memsz; } if (low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr)); goto error; } analyze_chunks(); DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n", LD_NAME, phnum, kernel_entry, low_addr, max_addr)); total_size = (UINTN)max_addr - (UINTN)low_addr; pages = EFI_SIZE_TO_PAGES(total_size); /* * Record end of kernel for initrd */ kernel_base = (void *)low_addr; kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT)); /* allocate memory for the kernel */ if (alloc_kmem((void *)low_addr, pages) == -1) { VOID *new_addr; VERB_PRT(1, Print(L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); if (ia64_can_relocate() == 0) { ERR_PRT((L"relocation is disabled, cannot load kernel")); goto error; } /* * could not allocate at requested spot, try to find a * suitable location to relocate the kernel * * The maximum sized Itanium TLB translation entry is 256 MB. * If we relocate the kernel by this amount we know for sure * that alignment constraints will be satisified, regardless * of the kernel used. */ VERB_PRT(1, Print(L"Attempting to relocate kernel.\n")); if (find_kernel_memory((VOID*) low_addr, (VOID*) max_addr, 256*MB, &new_addr) == -1) { ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset)); goto error; } /* unsigned arithmetic */ load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB)); VERB_PRT(1, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset)); /* * correct various addresses for non-zero load_offset */ kernel_base = (void *) ((UINTN) kernel_base + load_offset); kernel_end = (void *) ((UINTN) kernel_end + load_offset); kernel_entry = (void*) ((UINTN) kernel_entry + load_offset); for (i = 0; i < phnum; ++i) { chunks[i].addr += load_offset; phdrs[i].p_paddr = (Elf64_Addr) ((UINT64) phdrs[i].p_paddr + load_offset); } /* * try one last time to get memory for the kernel */ if (alloc_kmem((void *)low_addr+load_offset, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr+load_offset)); ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset)); goto error; } } return 0; error: if (chunks) free(chunks); return -1; } /* * Determine which chunk in the Elf file will be coming out of the expand * code next. */ static void nextchunk(void) { int i; segment_t *cp; cp = NULL; for(i=0; i < nchunks; i++) { if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue; if (file_offset > chunks[i].offset) continue; if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i]; } cur_chunk = cp; } /* * Write the output window window[0..outcnt-1] holding uncompressed * data and update crc. */ void flush_window(void) { static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' }; static UINTN heli_count; struct segment *cp; unsigned char *src, *dst; long cnt; if (!outcnt) return; #ifdef DEBUG_GZIP DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset)); #endif Print(L"%c\b",helicopter[heli_count++%4]); updcrc(window, outcnt); /* * first time, we extract the headers */ if (!bytes_out) { if (first_block(window, outcnt) < 0) error("invalid exec header"); nextchunk(); } bytes_out += outcnt; src = window; tail: /* check if user wants to abort */ if (check_abort() == EFI_SUCCESS) goto load_abort; cp = cur_chunk; if (cp == NULL || file_offset + outcnt <= cp->offset) { file_offset += outcnt; return; } // Does this window begin before the current chunk? if (file_offset < cp->offset) { unsigned long skip = cp->offset - file_offset; src += skip; file_offset += skip; outcnt -= skip; } dst = (unsigned char *)cp->addr + (file_offset - cp->offset); cnt = cp->offset + cp->size - file_offset; if (cnt > outcnt) cnt = outcnt; Memcpy(dst, src, cnt); if (cp->flags & CHUNK_FL_X) flush_dcache (dst, cnt); file_offset += cnt; outcnt -= cnt; src += cnt; /* See if we are at the end of this chunk */ if (file_offset == cp->offset + cp->size) { if (cp->bss_sz) { dst = (unsigned char *)cp->addr + cp->size; Memset(dst, 0, cp->bss_sz); } nextchunk(); /* handle remaining bytes */ if (outcnt) goto tail; } return; load_abort: free_kmem(); error_return = ELILO_LOAD_ABORTED; longjmp(jbuf, 1); } static void error(char *x) { ERR_PRT((L"%s : %a", LD_NAME, x)); /* will eventually exit with error from gunzip() */ longjmp(jbuf,1); } INT32 decompress_kernel(VOID) { INT32 ret; clear_bufs(); makecrc(); Print(L"Uncompressing Linux... "); ret = gunzip(); if (ret == 0) Print(L"done\n"); return ret == 0 ? 0 : -1; } int gunzip_kernel(fops_fd_t fd, kdesc_t *kd) { int ret = -1; error_return = ELILO_LOAD_ERROR; window = (void *)alloc(WSIZE, 0); if (window == NULL) { ERR_PRT((L"%s : allocate output window failed\n", LD_NAME)); return -1; } inbuf = (void *)alloc(INBUFSIZE, 0); if (inbuf == NULL) { ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME)); goto error; } input_fd = fd; insize = 0; bytes_out = 0; if (setjmp(jbuf) == 1) goto error; ret = decompress_kernel(); error: if (window) free(window); if (inbuf) free(inbuf); if (ret == 0) { kd->kentry = kernel_entry; kd->kend = kernel_end; kd->kstart = kernel_base; error_return = ELILO_LOAD_SUCCESS; } return error_return; } ./elilo/ia64/sysdeps.h0000644000175000017500000000667710742000576014270 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ /* * This file is used to define all the IA64-specific data structures, functions, * and constants used by the generic ELILO. * * For things specific to this platform use private.h instead */ #ifndef __ELILO_SYSDEPS_IA64_H__ #define __ELILO_SYSDEPS_IA64_H__ #define ELILO_ARCH "IA-64" /* ASCII string ! */ /* in respective assembly files */ extern VOID Memset(VOID *, INTN, UINTN); extern VOID Memcpy(VOID *, VOID *, UINTN); extern VOID sysdep_register_options(VOID); /* * This version must match the one in the kernel */ typedef struct ia64_boot_params { /* * The following three pointers MUST point to memory that is marked * as EfiRuntimeServicesData so that the kernel doesn't think the * underlying memory is free. */ UINTN command_line; /* physical address of command line arguments */ UINTN efi_systab; /* physical address of EFI system table */ UINTN efi_memmap; /* physical address of EFI memory map */ UINTN efi_memmap_size; /* size of EFI memory map */ UINTN efi_memdesc_size; /* size of an EFI memory map descriptor */ UINT32 efi_memdesc_version; /* descriptor version */ struct { UINT16 num_cols; /* number of columns on console output device */ UINT16 num_rows; /* number of rows on console output device */ UINT16 orig_x; /* cursor's x position */ UINT16 orig_y; /* cursor's y position */ } console_info; UINTN fpswa; /* physical address of fpswa interface */ UINTN initrd_start; /* virtual address where the initial ramdisk begins */ UINTN initrd_size; /* how big is the initial ramdisk */ UINTN vmcode_start; /* virtual address where the boot time vmcode begins */ UINTN vmcode_size; /* how big is the boot module */ UINTN loader_addr; /* start address of boot loader */ UINTN loader_size; /* size of loader code & data */ } boot_params_t; typedef struct sys_img_options { UINT8 dummy; /* forces non-zero offset for first field */ UINT8 allow_relocation; /* allow kernel relocation on allocation error */ } sys_img_options_t; /* * How to jump to kernel code */ static inline void start_kernel(VOID *kentry, VOID *bp) { asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(kentry),"r"(bp)); } static inline UINT64 __ia64_swab64 (UINT64 x) { UINT64 result; asm volatile ("mux1 %0=%1,@rev" : "=r" (result) : "r" (x)); return result; } static inline UINT32 __ia64_swab32 (UINT32 x) { return __ia64_swab64(x) >> 32; } static inline UINT16 __ia64_swab16(UINT16 x) { return __ia64_swab64(x) >> 48; } #endif /* __ELILO_SYSDEPS_IA64_H__ */ ./elilo/ia64/gzip_loader.c0000644000175000017500000000354410343667143015064 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "elilo.h" #include "loader.h" #include "gzip.h" #define LD_NAME L"gzip_ia64" static INTN gzip_probe_format(CHAR16 *kname) { UINT8 buf[4]; EFI_STATUS status; INTN ret = -1; UINTN size; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; size = sizeof(buf); status = fops_read(fd, buf, &size); if (EFI_ERROR(status) || size != sizeof(buf)) goto error; ret = gzip_probe(buf, sizeof(buf)); error: fops_close(fd); return ret; } static INTN gzip_load_kernel(CHAR16 *kname, kdesc_t *kd) { EFI_STATUS status; INT32 ret; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; ret = gunzip_kernel(fd, kd); fops_close(fd); return ret; /* could be success, error, or abort */ } loader_ops_t gzip_loader={ NULL, LD_NAME, gzip_probe_format, gzip_load_kernel }; ./elilo/efi110/0000755000175000017500000000000011513632673012635 5ustar jasonfjasonf./elilo/efi110/efiConsoleControl.h0000644000175000017500000000726111271404161016431 0ustar jasonfjasonf/*++ Copyright (c) 2004, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: ConsoleControl.h Abstract: Abstraction of a Text mode or UGA screen --*/ #ifndef __CONSOLE_CONTROL_H__ #define __CONSOLE_CONTROL_H__ #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } } /* typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; */ struct _EFI_CONSOLE_CONTROL_PROTOCOL; typedef enum { EfiConsoleControlScreenText, EfiConsoleControlScreenGraphics, EfiConsoleControlScreenMaxValue } EFI_CONSOLE_CONTROL_SCREEN_MODE; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, OUT BOOLEAN *UgaExists, OPTIONAL OUT BOOLEAN *StdInLocked OPTIONAL ) /*++ Routine Description: Return the current video mode information. Also returns info about existence of UGA Draw devices in system, and if the Std In device is locked. All the arguments are optional and only returned if a non NULL pointer is passed in. Arguments: This - Protocol instance pointer. Mode - Are we in text of grahics mode. UgaExists - TRUE if UGA Spliter has found a UGA device StdInLocked - TRUE if StdIn device is keyboard locked Returns: EFI_SUCCESS - Mode information returned. --*/ ; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode ) /*++ Routine Description: Set the current mode to either text or graphics. Graphics is for Quiet Boot. Arguments: This - Protocol instance pointer. Mode - Mode to set the Returns: EFI_SUCCESS - Mode information returned. --*/ ; typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, IN CHAR16 *Password ) /*++ Routine Description: Lock Std In devices until Password is typed. Arguments: This - Protocol instance pointer. Password - Password needed to unlock screen. NULL means unlock keyboard Returns: EFI_SUCCESS - Mode information returned. EFI_DEVICE_ERROR - Std In not locked --*/ ; typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL { EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; } EFI_CONSOLE_CONTROL_PROTOCOL; extern EFI_GUID gEfiConsoleControlProtocolGuid; #endif ./elilo/fs/0000755000175000017500000000000011513632716012256 5ustar jasonfjasonf./elilo/fs/localfs.h0000644000175000017500000000354307720452005014053 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __LOCALFS_H__ #define __LOCALFS_H__ INTERFACE_DECL(_localfs_interface_t); typedef struct _localfs_interface_t { EFI_STATUS (*localfs_name)(struct _localfs_interface_t *this, CHAR16 *name, UINTN maxlen); EFI_STATUS (*localfs_open)(struct _localfs_interface_t *this, CHAR16 *name, UINTN *fd); EFI_STATUS (*localfs_read)(struct _localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size); EFI_STATUS (*localfs_close)(struct _localfs_interface_t *this, UINTN fd); EFI_STATUS (*localfs_infosize)(struct _localfs_interface_t *this, UINTN fd, UINT64 *size); EFI_STATUS (*localfs_seek)(struct _localfs_interface_t *this, UINTN fd, UINT64 newpos); } localfs_interface_t; #define LOCALFS_PROTOCOL \ { 0x3a42ff5d, 0x43c9, 0x4db8, {0x82, 0x4e, 0xb8, 0x5b, 0xab, 0x97, 0x63, 0xcc} } extern EFI_STATUS localfs_install(VOID); extern EFI_STATUS localfs_uninstall(VOID); #endif /* __LOCALFS_H__ */ ./elilo/fs/localfs.c0000644000175000017500000001722011466352715014054 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #include "fs/localfs.h" /* * LocalFS is just a shim layer on top of the * FileSystem Protocol which gives access to FAT32,16,12 */ #define FS_NAME L"vfat" typedef struct { EFI_HANDLE dev; /* device we're attached to */ EFI_FILE_HANDLE volume; /* root of volume */ } localfs_priv_state_t; #define LOCALFS_F2FD(f) ((UINTN)(f)) #define LOCALFS_FD2F(fd) ((EFI_FILE_HANDLE)(fd)) typedef union { localfs_interface_t pub_intf; struct { localfs_interface_t pub_intf; localfs_priv_state_t priv_data; } localfs_priv; } localfs_t; #define FS_PRIVATE(n) (&(((localfs_t *)n)->localfs_priv.priv_data)) static EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL; /* * let's be clean here */ typedef union { EFI_HANDLE dev; localfs_t *intf; } dev_tab_t; static dev_tab_t *dev_tab; /* holds all devices we found */ static UINTN ndev; /* how many entries in dev_tab */ static EFI_STATUS localfs_name(localfs_interface_t *this, CHAR16 *name, UINTN maxlen) { if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; StrnCpy(name, FS_NAME, maxlen-1); name[maxlen-1] = CHAR_NULL; return EFI_SUCCESS; } static EFI_STATUS localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd) { localfs_priv_state_t *lfs; EFI_STATUS status; EFI_FILE_HANDLE fh; if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER; lfs = FS_PRIVATE(this); DBG_PRT((L"localfs_open on %s\n", name)); status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, (UINT64)0); if (status == EFI_SUCCESS) { *fd = LOCALFS_F2FD(fh); } return status; } static EFI_STATUS localfs_read(localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size) { localfs_priv_state_t *lfs; if (this == NULL || fd == 0 || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER; lfs = FS_PRIVATE(this); return uefi_call_wrapper(lfs->volume->Read, 3, LOCALFS_FD2F(fd), size, buf); } static EFI_STATUS localfs_close(localfs_interface_t *this, UINTN fd) { localfs_priv_state_t *lfs; if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER; lfs = FS_PRIVATE(this); return uefi_call_wrapper(lfs->volume->Close, 1, LOCALFS_FD2F(fd)); } static EFI_STATUS localfs_infosize(localfs_interface_t *this, UINTN fd, UINT64 *sz) { localfs_priv_state_t *lfs; EFI_FILE_INFO *info; if (this == NULL || fd == 0 || sz == NULL) return EFI_INVALID_PARAMETER; lfs = FS_PRIVATE(this); info = LibFileInfo(LOCALFS_FD2F(fd)); if (info == NULL) return EFI_UNSUPPORTED; *sz = info->FileSize; uefi_call_wrapper(BS->FreePool, 1, info); return EFI_SUCCESS; } static EFI_STATUS localfs_seek(localfs_interface_t *this, UINTN fd, UINT64 newpos) { localfs_priv_state_t *lfs; if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER; lfs = FS_PRIVATE(this); return uefi_call_wrapper(lfs->volume->SetPosition, 2, LOCALFS_FD2F(fd), newpos); } static VOID localfs_init_state(localfs_t *localfs, EFI_HANDLE dev, EFI_FILE_HANDLE volume) { localfs_priv_state_t *lfs = FS_PRIVATE(localfs); /* need to do some init here on localfs_intf */ Memset(localfs, 0, sizeof(*localfs)); localfs->pub_intf.localfs_name = localfs_name; localfs->pub_intf.localfs_open = localfs_open; localfs->pub_intf.localfs_read = localfs_read; localfs->pub_intf.localfs_close = localfs_close; localfs->pub_intf.localfs_infosize = localfs_infosize; localfs->pub_intf.localfs_seek = localfs_seek; lfs->dev = dev; lfs->volume = volume; } static EFI_STATUS localfs_install_one(EFI_HANDLE dev, VOID **intf) { EFI_STATUS status; localfs_t *localfs; EFI_FILE_IO_INTERFACE *volume; EFI_FILE_HANDLE volume_fh; status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &LocalFsProtocol, (VOID **)&localfs); if (status == EFI_SUCCESS) { ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME)); goto found; } status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &FileSystemProtocol, (VOID **)&volume); if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER; status = uefi_call_wrapper(volume->OpenVolume, 2, volume, &volume_fh); if (EFI_ERROR(status)) { ERR_PRT((L"cannot open volume")); return status; } localfs = (localfs_t *)alloc(sizeof(*localfs), EfiLoaderData); if (localfs == NULL) { ERR_PRT((L"failed to allocate %s", FS_NAME)); return EFI_OUT_OF_RESOURCES; } localfs_init_state(localfs, dev, volume_fh); status = LibInstallProtocolInterfaces(&dev, &LocalFsProtocol, localfs, NULL); if (EFI_ERROR(status)) { ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status)); free(localfs); return status; } found: if (intf) *intf = (VOID *)localfs; VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(dev); str = DevicePathToStr(dp); Print(L"attached %s to %s\n", FS_NAME, str); uefi_call_wrapper(BS->FreePool, 1, str); }); return EFI_SUCCESS; } EFI_STATUS localfs_install(VOID) { UINTN size = 0; UINTN i; EFI_STATUS status; VOID *intf; uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, NULL); if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */ DBG_PRT((L"size=%d", size)); dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData); if (dev_tab == NULL) { ERR_PRT((L"failed to allocate handle table")); return EFI_OUT_OF_RESOURCES; } status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab); if (status != EFI_SUCCESS) { ERR_PRT((L"failed to get handles: %r", status)); free(dev_tab); return status; } ndev = size / sizeof(EFI_HANDLE); for(i=0; i < ndev; i++) { intf = NULL; localfs_install_one(dev_tab[i].dev, &intf); /* override device handle with interface pointer */ dev_tab[i].intf = intf; } return EFI_SUCCESS; } EFI_STATUS localfs_uninstall(VOID) { localfs_priv_state_t *lfs; EFI_STATUS status; UINTN i; for(i=0; i < ndev; i++) { if (dev_tab[i].intf == NULL) continue; lfs = FS_PRIVATE(dev_tab[i].intf); status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, lfs->dev, &LocalFsProtocol, dev_tab[i].intf); if (EFI_ERROR(status)) { ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status)); continue; } VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(lfs->dev); str = DevicePathToStr(dp); Print(L"uninstalled %s on %s\n", FS_NAME, str); uefi_call_wrapper(BS->FreePool, 1, str); }); free(dev_tab[i].intf); } if (dev_tab) free(dev_tab); return EFI_SUCCESS; } ./elilo/fs/ext2fs.c0000644000175000017500000006326711165216511013645 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. * * The ext2 code in this file is derived from aboot-0.7 (the Linux/Alpha * bootloader) and credits are attributed to: * * This file has been ported from the DEC 32-bit Linux version * by David Mosberger (davidm@cs.arizona.edu). */ #include #include #include "elilo.h" #define FS_NAME L"ext2fs" #ifdef PATH_MAX #error You must have included some Linux header file by error #endif #define PATH_MAX 4095 #define EXT2FS_PATH_MAXLEN PATH_MAX #include "fs/ext2fs.h" #include "fs/ext2_private.h" /* * should we decide to spin off ext2, let's say to a boottime driver * we would have to change this */ #define EXT2FS_MEMTYPE EfiLoaderData /* ext2 file size is __u32 */ #define EXT2_FILESIZE_MAX (0x100000000UL) /* * Number of simultaneous open files. This needs to be high because * directories are kept open while traversing long path names. */ #define MAX_OPEN_FILES 32 typedef struct inode_table_entry { struct ext2_inode inode; int inumber; int free; unsigned short old_mode; UINT32 pos; /* current position in file ext2 uses __u32 !*/ } inode_entry_t; typedef struct { struct ext2_super_block sb; struct ext2_group_desc *gds; struct ext2_inode *root_inode; int ngroups; int directlim; /* Maximum direct blkno */ int ind1lim; /* Maximum single-indir blkno */ int ind2lim; /* Maximum double-indir blkno */ int ptrs_per_blk; /* ptrs/indirect block */ CHAR8 blkbuf[EXT2_MAX_BLOCK_SIZE]; int cached_iblkno; CHAR8 iblkbuf[EXT2_MAX_BLOCK_SIZE]; int cached_diblkno; CHAR8 diblkbuf[EXT2_MAX_BLOCK_SIZE]; long blocksize; inode_entry_t inode_table[MAX_OPEN_FILES]; /* fields added to fit the protocol construct */ EFI_BLOCK_IO *blkio; UINT32 mediaid; EFI_HANDLE dev; } ext2fs_priv_state_t; typedef union { ext2fs_interface_t pub_intf; struct { ext2fs_interface_t pub_intf; ext2fs_priv_state_t priv_data; } ext2fs_priv; } ext2fs_t; #define FS_PRIVATE(n) (&(((ext2fs_t *)n)->ext2fs_priv.priv_data)) typedef union { EFI_HANDLE *dev; ext2fs_t *intf; } dev_tab_t; static dev_tab_t *dev_tab; /* holds all devices we found */ static UINTN ndev; /* how many entries in dev_tab */ static EFI_GUID Ext2FsProtocol = EXT2FS_PROTOCOL; static INTN read_bytes(EFI_BLOCK_IO *blkio, UINT32 mediaid, UINTN offset, VOID *addr, UINTN size) { EFI_STATUS status; UINT8 *buffer; UINTN count, buffer_size; EFI_LBA base; INTN ret = EFI_INVALID_PARAMETER; base = offset / blkio->Media->BlockSize; count = (size + blkio->Media->BlockSize -1) / blkio->Media->BlockSize; buffer_size = count * blkio->Media->BlockSize; DBG_PRT((L"readblock(%x, %d,%d) base=%d count=%d", blkio, offset, size, base, count)); /* * slow but avoid large buffer on the stack */ buffer = (UINT8 *)alloc(buffer_size, EfiLoaderData); if (buffer == NULL) { ERR_PRT((L"cannot allocate ext2fs buffer size=%d", buffer_size)); return ret; } DBG_PRT((L"readblock(PTR_FMT ", %d, %ld, %d, " PTR_FMT ")", blkio, mediaid, base, buffer_size, buffer)); status = uefi_call_wrapper(blkio->ReadBlocks, 5, blkio, mediaid, base, buffer_size, buffer); if (EFI_ERROR(status)) { ERR_PRT((L"readblock(%d,%d)=%r", base, buffer_size, status)); goto error; } DBG_PRT((L"readblock(%d,%d)->%r", offset, buffer_size, status)); Memcpy(addr, buffer+(offset-(base*blkio->Media->BlockSize)), size); ret = 0; error: free(buffer); return ret; } /* * Read the specified inode from the disk and return it to the user. * Returns NULL if the inode can't be read... */ static struct ext2_inode * ext2_iget(ext2fs_priv_state_t *e2fs, int ino) { int i; struct ext2_inode *ip; struct inode_table_entry *itp = 0; int group; long offset; ip = 0; for (i = 0; i < MAX_OPEN_FILES; i++) { DBG_PRT((L"ext2_iget: looping, entry %d inode %d free %d", i, e2fs->inode_table[i].inumber, e2fs->inode_table[i].free)); if (e2fs->inode_table[i].free) { itp = &e2fs->inode_table[i]; ip = &itp->inode; break; } } if (!ip) { ERR_PRT((L"ext2_iget: no free inodes")); return NULL; } group = (ino-1) / e2fs->sb.s_inodes_per_group; DBG_PRT((L" itp-inode_table=%d bg_inode_table=%d group=%d ino=%d\n", (UINTN)(itp-e2fs->inode_table), (UINTN)(e2fs->gds[group].bg_inode_table), (UINTN)group, (UINTN)ino)); offset = ((long) e2fs->gds[group].bg_inode_table * e2fs->blocksize) + (((ino - 1) % EXT2_INODES_PER_GROUP(&e2fs->sb)) * EXT2_INODE_SIZE(&e2fs->sb)); DBG_PRT((L"ext2_iget: reading %d bytes at offset %d" " ((%d * %d) + ((%d) %% %d) * %d) " "(inode %d -> table %d)", sizeof(struct ext2_inode), (UINTN)offset, (UINTN)e2fs->gds[group].bg_inode_table, (UINTN)e2fs->blocksize, (UINTN)(ino - 1), (UINTN)EXT2_INODES_PER_GROUP(&e2fs->sb), EXT2_INODE_SIZE(&e2fs->sb), (UINTN)ino, (UINTN) (itp - e2fs->inode_table))); if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, ip, sizeof(struct ext2_inode))) { ERR_PRT((L"ext2_iget: read error")); return NULL; } DBG_PRT((L"mode=%x uid=%d size=%d gid=%d links=%d flags=%d", (UINTN)ip->i_mode, (UINTN)ip->i_uid, (UINTN)ip->i_size, (UINTN)ip->i_gid, (UINTN)ip->i_flags)); itp->free = 0; itp->inumber = ino; itp->old_mode = ip->i_mode; return ip; } /* * Release our hold on an inode. Since this is a read-only application, * don't worry about putting back any changes... */ static void ext2_iput(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip) { struct inode_table_entry *itp; /* Find and free the inode table slot we used... */ itp = (struct inode_table_entry *)ip; DBG_PRT((L"ext2_iput: inode %d table %d", itp->inumber, (int) (itp - e2fs->inode_table))); itp->inumber = 0; itp->free = 1; } /* * Map a block offset into a file into an absolute block number. * (traverse the indirect blocks if necessary). Note: Double-indirect * blocks allow us to map over 64Mb on a 1k file system. Therefore, for * our purposes, we will NOT bother with triple indirect blocks. * * The "allocate" argument is set if we want to *allocate* a block * and we don't already have one allocated. */ static int ext2_blkno(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, int blkoff) { unsigned int *lp; unsigned int *ilp; unsigned int *dlp; int blkno; int iblkno; int diblkno; long offset; ilp = (unsigned int *)e2fs->iblkbuf; dlp = (unsigned int *)e2fs->diblkbuf; lp = (unsigned int *)e2fs->blkbuf; /* If it's a direct block, it's easy! */ if (blkoff <= e2fs->directlim) { return ip->i_block[blkoff]; } /* Is it a single-indirect? */ if (blkoff <= e2fs->ind1lim) { iblkno = ip->i_block[EXT2_IND_BLOCK]; if (iblkno == 0) { return 0; } /* Read the indirect block */ if (e2fs->cached_iblkno != iblkno) { offset = iblkno * e2fs->blocksize; if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) { ERR_PRT((L"ext2_blkno: error on iblk read")); return 0; } e2fs->cached_iblkno = iblkno; } blkno = ilp[blkoff-(e2fs->directlim+1)]; return blkno; } /* Is it a double-indirect? */ if (blkoff <= e2fs->ind2lim) { /* Find the double-indirect block */ diblkno = ip->i_block[EXT2_DIND_BLOCK]; if (diblkno == 0) { return 0; } /* Read in the double-indirect block */ if (e2fs->cached_diblkno != diblkno) { offset = diblkno * e2fs->blocksize; if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->diblkbuf, e2fs->blocksize)) { ERR_PRT((L"ext2_blkno: err reading dindr blk")); return 0; } e2fs->cached_diblkno = diblkno; } /* Find the single-indirect block pointer ... */ iblkno = dlp[(blkoff - (e2fs->ind1lim+1)) / e2fs->ptrs_per_blk]; if (iblkno == 0) { return 0; } /* Read the indirect block */ if (e2fs->cached_iblkno != iblkno) { offset = iblkno * e2fs->blocksize; if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) { ERR_PRT((L"ext2_blkno: err on iblk read")); return 0; } e2fs->cached_iblkno = iblkno; } /* Find the block itself. */ blkno = ilp[(blkoff-(e2fs->ind1lim+1)) % e2fs->ptrs_per_blk]; return blkno; } if (blkoff > e2fs->ind2lim) { ERR_PRT((L"ext2_blkno: block number too large: %d", blkoff)); return 0; } return -1; } static int ext2_breadi(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, long blkno, long nblks, CHAR8 *buffer) { long dev_blkno, ncontig, offset, nbytes, tot_bytes; tot_bytes = 0; if ((blkno+nblks)*e2fs->blocksize > ip->i_size) nblks = (ip->i_size + e2fs->blocksize) / e2fs->blocksize - blkno; while (nblks) { /* * Contiguous reads are a lot faster, so we try to group * as many blocks as possible: */ ncontig = 0; nbytes = 0; dev_blkno = ext2_blkno(e2fs,ip, blkno); do { ++blkno; ++ncontig; --nblks; nbytes += e2fs->blocksize; } while (nblks && ext2_blkno(e2fs, ip, blkno) == dev_blkno + ncontig); if (dev_blkno == 0) { /* This is a "hole" */ Memset(buffer, 0, nbytes); } else { /* Read it for real */ offset = dev_blkno*e2fs->blocksize; DBG_PRT((L"ext2_bread: reading %d bytes at offset %d", nbytes, offset)); if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, buffer, nbytes)) { ERR_PRT((L"ext2_bread: read error")); return -1; } } buffer += nbytes; tot_bytes += nbytes; } return tot_bytes; } static struct ext2_dir_entry_2 * ext2_readdiri(ext2fs_priv_state_t *e2fs, struct ext2_inode *dir_inode, int rewind) { struct ext2_dir_entry_2 *dp; static int diroffset = 0, blockoffset = 0; /* Reading a different directory, invalidate previous state */ if (rewind) { diroffset = 0; blockoffset = 0; /* read first block */ if (ext2_breadi(e2fs, dir_inode, 0, 1, e2fs->blkbuf) < 0) return NULL; } DBG_PRT((L"ext2_readdiri: blkoffset %d diroffset %d len %d", blockoffset, diroffset, dir_inode->i_size)); if (blockoffset >= e2fs->blocksize) { diroffset += e2fs->blocksize; if (diroffset >= dir_inode->i_size) return NULL; ERR_PRT((L"ext2_readdiri: reading block at %d", diroffset)); /* assume that this will read the whole block */ if (ext2_breadi(e2fs, dir_inode, diroffset / e2fs->blocksize, 1, e2fs->blkbuf) < 0) return NULL; blockoffset = 0; } dp = (struct ext2_dir_entry_2 *) (e2fs->blkbuf + blockoffset); blockoffset += dp->rec_len; #if 0 Print(L"ext2_readdiri: returning %x = "); { INTN i; for(i=0; i < dp->name_len; i++) Print(L"%c", (CHAR16)dp->name[i]); Print(L"\n");} #endif return dp; } /* * the string 'name' is modified by this call as per the parsing that * is done in strtok_simple() */ static struct ext2_inode * ext2_namei(ext2fs_priv_state_t *e2fs, CHAR8 *name) { CHAR8 *component; struct ext2_inode *dir_inode; struct ext2_dir_entry_2 *dp; int next_ino; /* start at the root: */ if (!e2fs->root_inode) e2fs->root_inode = ext2_iget(e2fs, EXT2_ROOT_INO); dir_inode = e2fs->root_inode; if (!dir_inode) return NULL; component = strtok_simple(name, '/'); while (component) { int component_length; int rewind = 0; /* * Search for the specified component in the current * directory inode. */ next_ino = -1; component_length = strlena(component); DBG_PRT((L"ext2_namei: component = %a", component)); /* rewind the first time through */ while ((dp = ext2_readdiri(e2fs, dir_inode, !rewind++))) { if ((dp->name_len == component_length) && (strncmpa(component, dp->name, component_length) == 0)) { /* Found it! */ DBG_PRT((L"ext2_namei: found entry %a", component)); next_ino = dp->inode; break; } DBG_PRT((L"ext2_namei: looping")); } DBG_PRT((L"ext2_namei: next_ino = %d", next_ino)); /* * At this point, we're done with this directory whether * we've succeeded or failed... */ if (dir_inode != e2fs->root_inode) ext2_iput(e2fs, dir_inode); /* * If next_ino is negative, then we've failed (gone * all the way through without finding anything) */ if (next_ino < 0) { return NULL; } /* * Otherwise, we can get this inode and find the next * component string... */ dir_inode = ext2_iget(e2fs, next_ino); if (!dir_inode) return NULL; component = strtok_simple(NULL, '/'); } /* * If we get here, then we got through all the components. * Whatever we got must match up with the last one. */ return dir_inode; } /* * Read block number "blkno" from the specified file. */ static int ext2_bread(ext2fs_priv_state_t *e2fs, int fd, long blkno, long nblks, char *buffer) { struct ext2_inode * ip; ip = &e2fs->inode_table[fd].inode; return ext2_breadi(e2fs, ip, blkno, nblks, buffer); } #if 0 /* * Note: don't mix any kind of file lookup or other I/O with this or * you will lose horribly (as it reuses blkbuf) */ static const char * ext2_readdir(ext2fs_priv_state_t *e2fs, int fd, int rewind) { struct ext2_inode * ip = &e2fs->inode_table[fd].inode; struct ext2_dir_entry_2 * ent; if (!S_ISDIR(ip->i_mode)) { ERR_PRT((L"fd %d (inode %d) is not a directory (mode %x)", fd, e2fs->inode_table[fd].inumber, ip->i_mode)); return NULL; } ent = ext2_readdiri(e2fs, ip, rewind); if (ent) { ent->name[ent->name_len] = '\0'; return ent->name; } else { return NULL; } } #endif static int ext2_fstat(ext2fs_priv_state_t *e2fs, int fd, ext2fs_stat_t *buf) { struct ext2_inode * ip = &e2fs->inode_table[fd].inode; Memset(buf, 0, sizeof(*buf)); /* fill in relevant fields */ buf->st_ino = e2fs->inode_table[fd].inumber; buf->st_mode = ip->i_mode; buf->st_nlink = ip->i_links_count; buf->st_uid = ip->i_uid; buf->st_gid = ip->i_gid; buf->st_size = ip->i_size; buf->st_atime = ip->i_atime; buf->st_mtime = ip->i_mtime; buf->st_ctime = ip->i_ctime; return 0; /* NOTHING CAN GO WROGN! */ } static EFI_STATUS ext2fs_fstat(ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st) { ext2fs_priv_state_t *e2fs; if (this == NULL || fd > MAX_OPEN_FILES || st == NULL) return EFI_INVALID_PARAMETER; e2fs = FS_PRIVATE(this); ext2_fstat(e2fs, fd, st); return EFI_SUCCESS; } static EFI_STATUS ext2fs_seek(ext2fs_interface_t *this, UINTN fd, UINT64 newpos) { ext2fs_priv_state_t *e2fs; if (this == NULL || fd > MAX_OPEN_FILES || newpos >= EXT2_FILESIZE_MAX) return EFI_INVALID_PARAMETER; e2fs = FS_PRIVATE(this); if (newpos > (UINT64)e2fs->inode_table[fd].inode.i_size) return EFI_INVALID_PARAMETER; e2fs->inode_table[fd].pos = newpos; return EFI_SUCCESS; } static EFI_STATUS ext2fs_read(ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size) { ext2fs_priv_state_t *e2fs; UINTN count, nc, bofs, bnum, pos; EFI_STATUS ret = EFI_INVALID_PARAMETER; CHAR8 *block; if (this == NULL || size == NULL || buf == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER; e2fs = FS_PRIVATE(this); count = MIN(*size, e2fs->inode_table[fd].inode.i_size - e2fs->inode_table[fd].pos); if (count == 0) { *size = 0; return EFI_SUCCESS; } block = e2fs->blkbuf; *size = 0; pos = e2fs->inode_table[fd].pos; DBG_PRT((L"size=%d i_size=%d count=%d pos=%ld", *size,e2fs->inode_table[fd].inode.i_size, count, pos)); while (count) { bnum = pos / e2fs->blocksize; bofs = pos % e2fs->blocksize; nc = MIN(count, e2fs->blocksize - bofs); DBG_PRT((L"bnum =%d bofs=%d nc=%d *size=%d", bnum, bofs, nc, *size)); if (ext2_bread(e2fs, fd, bnum, 1, block) == -1) goto error; #if 0 { int i; char *p = block+bofs; for(i=MIN(nc, 64); i>=0 ; i--, p++) { if (i % 16 == 0) Print(L"\n"); Print(L"%02x ", (UINTN)*p & 0xff); } } #endif Memcpy(buf, block+bofs, nc); count -= nc; pos += nc; buf += nc; *size += nc; } e2fs->inode_table[fd].pos += *size; ret = EFI_SUCCESS; error: DBG_PRT((L"*size=%d ret=%r", *size, ret)); return ret; } static struct ext2_inode * ext2_follow_link(ext2fs_priv_state_t *e2fs, struct ext2_inode * from, const char * base) { char *linkto; if (from->i_blocks) { linkto = e2fs->blkbuf; if (ext2_breadi(e2fs, from, 0, 1, e2fs->blkbuf) == -1) return NULL; DBG_PRT((L"long link!")); } else { linkto = (char*)from->i_block; } DBG_PRT((L"symlink to %s", linkto)); /* Resolve relative links */ if (linkto[0] != '/') { char *end = strrchra(base, '/'); if (end) { //char fullname[(end - base + 1) + strlena(linkto) + 1]; char fullname[EXT2FS_PATH_MAXLEN]; if (((end - base + 1) + strlena(linkto) + 1) >= EXT2FS_PATH_MAXLEN) { Print(L"%s: filename too long, can't resolve\n", __FUNCTION__); return NULL; } strncpya(fullname, base, end - base + 1); fullname[end - base + 1] = '\0'; strcata(fullname, linkto); DBG_PRT((L"resolved to %s", fullname)); return ext2_namei(e2fs, fullname); } else { /* Assume it's in the root */ return ext2_namei(e2fs, linkto); } } else { return ext2_namei(e2fs, linkto); } } static int ext2_open(ext2fs_priv_state_t *e2fs, char *filename) { /* * Unix-like open routine. Returns a small integer (actually * an index into the inode table... */ struct ext2_inode * ip; ip = ext2_namei(e2fs, filename); if (ip) { struct inode_table_entry *itp; while (S_ISLNK(ip->i_mode)) { ip = ext2_follow_link(e2fs, ip, filename); if (!ip) return -1; } itp = (struct inode_table_entry *)ip; return itp - e2fs->inode_table; } else return -1; } static void ext2_close(ext2fs_priv_state_t *e2fs, int fd) { /* blah, hack, don't close the root inode ever */ if (&e2fs->inode_table[fd].inode != e2fs->root_inode) ext2_iput(e2fs, &e2fs->inode_table[fd].inode); } static EFI_STATUS ext2fs_close(ext2fs_interface_t *this, UINTN fd) { ext2fs_priv_state_t *e2fs; if (this == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER; e2fs = FS_PRIVATE(this); ext2_close(e2fs, fd); return EFI_SUCCESS; } static EFI_STATUS ext2fs_open(ext2fs_interface_t *this, CHAR16 *name, UINTN *fd) { ext2fs_priv_state_t *e2fs; CHAR8 filename[EXT2FS_PATH_MAXLEN]; /* XXX: kind of big for a stack object */ INTN tmp; DBG_PRT((L"name:%s fd=%x", name, fd)); if (this == NULL || name == NULL || fd == NULL || StrLen(name) >=EXT2FS_PATH_MAXLEN) return EFI_INVALID_PARAMETER; e2fs = FS_PRIVATE(this); /* * XXX: for security reasons, we may have to force a prefix like /boot to all filenames */ StrnXCpy(filename, name, EXT2FS_PATH_MAXLEN); DBG_PRT((L"ASCII name:%a UTF-name:%s", filename, name)); tmp = ext2_open(e2fs, filename); if (tmp != -1) { *fd = (UINTN)tmp; e2fs->inode_table[tmp].pos = 0; /* reset file position */ } DBG_PRT((L"name: %s fd=%d tmp=%d", name, *fd, tmp)); return tmp == -1 ? EFI_NOT_FOUND : EFI_SUCCESS; } static EFI_STATUS ext2fs_name(ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen) { if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; StrnCpy(name, FS_NAME, maxlen-1); name[maxlen-1] = CHAR_NULL; return EFI_SUCCESS; } static INTN ext2fs_init_state(ext2fs_t *ext2fs, EFI_HANDLE dev, EFI_BLOCK_IO *blkio, struct ext2_super_block *sb) { ext2fs_priv_state_t *e2fs = FS_PRIVATE(ext2fs); UINTN i; EFI_STATUS status; Memset(ext2fs, 0, sizeof(*ext2fs)); e2fs->dev = dev; e2fs->blkio = blkio; e2fs->mediaid = blkio->Media->MediaId; /* fools gcc builtin memcpy */ Memcpy(&e2fs->sb, sb, sizeof(*sb)); e2fs->ngroups = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb); e2fs->gds = (struct ext2_group_desc *)alloc(e2fs->ngroups * sizeof(struct ext2_group_desc), EXT2FS_MEMTYPE); if (e2fs->gds == NULL) { ERR_PRT((L"failed to allocate gds")); return EFI_OUT_OF_RESOURCES; } e2fs->blocksize = EXT2_BLOCK_SIZE(sb); DBG_PRT((L"gds_size=%d gds_offset=%d ngroups=%d blocksize=%d", e2fs->ngroups * sizeof(struct ext2_group_desc), e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1), e2fs->ngroups, (UINTN)e2fs->blocksize)); /* read in the group descriptors (immediately follows superblock) */ status = read_bytes(blkio, e2fs->mediaid, e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1), e2fs->gds, e2fs->ngroups * sizeof(struct ext2_group_desc)); if (EFI_ERROR(status)) { ERR_PRT((L"cannot read gds: %r", status)); free(e2fs->gds); return EFI_INVALID_PARAMETER; } #if 0 { int i; char *p = (char *)e2fs->gds; for(i=e2fs->ngroups*sizeof(*e2fs->gds); i ; i--, p++) { if (i % 16 == 0) Print(L"\n"); Print(L"%02x ", (UINTN)*p & 0xff); } } #endif e2fs->cached_diblkno = -1; e2fs->cached_iblkno = -1; /* initialize the inode table */ for (i = 0; i < MAX_OPEN_FILES; i++) { e2fs->inode_table[i].free = 1; e2fs->inode_table[i].inumber = 0; } /* clear the root inode pointer (very important!) */ e2fs->root_inode = NULL; /* * Calculate direct/indirect block limits for this file system * (blocksize dependent): ext2_blocksize = EXT2_BLOCK_SIZE(&sb); */ e2fs->directlim = EXT2_NDIR_BLOCKS - 1; e2fs->ptrs_per_blk = e2fs->blocksize/sizeof(unsigned int); e2fs->ind1lim = e2fs->ptrs_per_blk + e2fs->directlim; e2fs->ind2lim = (e2fs->ptrs_per_blk * e2fs->ptrs_per_blk) + e2fs->directlim; ext2fs->pub_intf.ext2fs_name = ext2fs_name; ext2fs->pub_intf.ext2fs_open = ext2fs_open; ext2fs->pub_intf.ext2fs_read = ext2fs_read; ext2fs->pub_intf.ext2fs_close = ext2fs_close; ext2fs->pub_intf.ext2fs_seek = ext2fs_seek; ext2fs->pub_intf.ext2fs_fstat = ext2fs_fstat; return EFI_SUCCESS; } static EFI_STATUS ext2fs_install_one(EFI_HANDLE dev, VOID **intf) { struct ext2_super_block sb; long sb_block = 1; EFI_STATUS status; EFI_BLOCK_IO *blkio; ext2fs_t *ext2fs; status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &Ext2FsProtocol, (VOID **)&ext2fs); if (status == EFI_SUCCESS) { ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME)); goto found; } status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &BlockIoProtocol, (VOID **)&blkio); if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER; VERB_PRT(5, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(dev); str = DevicePathToStr(dp); Print(L"dev:%s\nLogical partition: %s BlockSize: %d WriteCaching: %s \n", str, blkio->Media->LogicalPartition ? L"Yes": L"No", blkio->Media->BlockSize, blkio->Media->WriteCaching ? L"Yes":L"No"); FreePool(str); }); if (blkio->Media->LogicalPartition == FALSE) return EFI_INVALID_PARAMETER; #if 0 /* * Used to be necessary on some older versions of EFI to avoid getting * stuck. Now can cause problems with some SCSI controllers when enabled. * Does not seem necessary with EFI 12.38 */ blkio->Reset(blkio, FALSE); #endif status = read_bytes(blkio, blkio->Media->MediaId, sb_block * EXT2_MIN_BLOCK_SIZE, &sb, sizeof(sb)); if (EFI_ERROR(status)) { DBG_PRT((L"cannot read superblock: %r", status)); return EFI_INVALID_PARAMETER; } if (sb.s_magic != EXT2_SUPER_MAGIC) { DBG_PRT((L"bad magic "PTR_FMT"\n", sb.s_magic)); return EFI_INVALID_PARAMETER; } ext2fs = (ext2fs_t *)alloc(sizeof(*ext2fs), EXT2FS_MEMTYPE); if (ext2fs == NULL) return EFI_OUT_OF_RESOURCES; status = ext2fs_init_state(ext2fs, dev, blkio, &sb); if (status != EFI_SUCCESS) { free(ext2fs); return status; } status = LibInstallProtocolInterfaces(&dev, &Ext2FsProtocol, ext2fs, NULL); if (EFI_ERROR(status)) { ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status)); free(ext2fs); return status; } found: if (intf) *intf = (VOID *)ext2fs; VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(dev); str = DevicePathToStr(dp); Print(L"dev:%s %s detected\n", str, FS_NAME); FreePool(str); }); return EFI_SUCCESS; } EFI_STATUS ext2fs_install(VOID) { UINTN size = 0; UINTN i; EFI_STATUS status; VOID *intf; uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL, &size, NULL); if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */ DBG_PRT((L"size=%d", size)); dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData); if (dev_tab == NULL) { ERR_PRT((L"failed to allocate handle table")); return EFI_OUT_OF_RESOURCES; } status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL, &size, (VOID **)dev_tab); if (status != EFI_SUCCESS) { ERR_PRT((L"failed to get handles: %r", status)); free(dev_tab); return status; } ndev = size / sizeof(EFI_HANDLE); for(i=0; i < ndev; i++) { intf = NULL; ext2fs_install_one(dev_tab[i].dev, &intf); /* override device handle with interface pointer */ dev_tab[i].intf = intf; } return EFI_SUCCESS; } EFI_STATUS ext2fs_uninstall(VOID) { ext2fs_priv_state_t *e2fs; EFI_STATUS status; UINTN i; for(i=0; i < ndev; i++) { if (dev_tab[i].intf == NULL) continue; e2fs = FS_PRIVATE(dev_tab[i].intf); status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf); if (EFI_ERROR(status)) { ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status)); continue; } VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(e2fs->dev); str = DevicePathToStr(dp); Print(L"uninstalled %s on %s\n", FS_NAME, str); FreePool(str); }); free(dev_tab[i].intf); } if (dev_tab) free(dev_tab); return EFI_SUCCESS; } ./elilo/fs/ext2_fs_sb.h0000644000175000017500000000403107316156505014466 0ustar jasonfjasonf/* * linux/include/linux/ext2_fs_sb.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/include/linux/minix_fs_sb.h * * Copyright (C) 1991, 1992 Linus Torvalds */ #ifndef _LINUX_EXT2_FS_SB #define _LINUX_EXT2_FS_SB /* * The following is not needed anymore since the descriptors buffer * heads are now dynamically allocated */ /* #define EXT2_MAX_GROUP_DESC 8 */ #define EXT2_MAX_GROUP_LOADED 8 /* * second extended-fs super-block data in memory */ struct ext2_sb_info { unsigned long s_frag_size; /* Size of a fragment in bytes */ unsigned long s_frags_per_block;/* Number of fragments per block */ unsigned long s_inodes_per_block;/* Number of inodes per block */ unsigned long s_frags_per_group;/* Number of fragments in a group */ unsigned long s_blocks_per_group;/* Number of blocks in a group */ unsigned long s_inodes_per_group;/* Number of inodes in a group */ unsigned long s_itb_per_group; /* Number of inode table blocks per group */ unsigned long s_gdb_count; /* Number of group descriptor blocks */ unsigned long s_desc_per_block; /* Number of group descriptors per block */ unsigned long s_groups_count; /* Number of groups in the fs */ struct buffer_head * s_sbh; /* Buffer containing the super block */ struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */ struct buffer_head ** s_group_desc; unsigned short s_loaded_inode_bitmaps; unsigned short s_loaded_block_bitmaps; unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED]; struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED]; unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED]; struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED]; unsigned long s_mount_opt; uid_t s_resuid; gid_t s_resgid; unsigned short s_mount_state; unsigned short s_pad; int s_addr_per_block_bits; int s_desc_per_block_bits; int s_inode_size; int s_first_ino; }; #endif /* _LINUX_EXT2_FS_SB */ ./elilo/fs/Makefile0000644000175000017500000000313111466353142013714 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES= ifeq ($(CONFIG_localfs),y) FILES += localfs.o endif # # Ext2 is now disabled by default. See top level Makefile # for details # ifeq ($(CONFIG_ext2fs),y) FILES += ext2fs.o endif ifeq ($(CONFIG_netfs),y) FILES += netfs.o endif TARGET=fs.o all: $(TARGET) # # XXX: does not trigger recompile when changing filesystem selection # without doing make clean. # $(TARGET): $(TOPDIR)/Make.defaults $(FILES) @if [ -z "$(FILES)" ]; then \ echo "You need to define at least one filesystem in Make.defaults"; \ exit 1; \ fi $(LD) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) ./elilo/fs/ext2_private.h0000644000175000017500000000403107720452021015033 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __FS_EXT2FS_PRIVATE_H__ #define __FS_EXT2FS_PRIVATE_H__ /* * Implement the Linux kernel internal data types * used by ext2 */ typedef UINT32 __u32; typedef INT32 __s32; typedef UINT16 __u16; typedef INT16 __s16; typedef UINT8 __u8; typedef INT8 __s8; typedef UINT32 uid_t; typedef UINT32 gid_t; /* * Get some constant from linux/stat.h */ #define S_IFMT 00170000 #define S_IFSOCK 0140000 #define S_IFLNK 0120000 #define S_IFREG 0100000 #define S_IFBLK 0060000 #define S_IFDIR 0040000 #define S_IFCHR 0020000 #define S_IFIFO 0010000 #define S_ISUID 0004000 #define S_ISGID 0002000 #define S_ISVTX 0001000 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) #include "fs/ext2_fs.h" #include "fs/ext2_fs_sb.h" #include "fs/ext2_fs_i.h" #endif /* __FS_EXT2FS_PRIVATE_H__*/ ./elilo/fs/fs.h0000644000175000017500000013740207316156505013051 0ustar jasonfjasonf#ifndef _LINUX_FS_H #define _LINUX_FS_H /* * This file has definitions for some important file table * structures etc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct poll_table_struct; /* * It's silly to have NR_OPEN bigger than NR_FILE, but you can change * the file limit at runtime and only root can increase the per-process * nr_file rlimit, so it's safe to set up a ridiculously high absolute * upper limit on files-per-process. * * Some programs (notably those using select()) may have to be * recompiled to take full advantage of the new limits.. */ /* Fixed constants first: */ #undef NR_OPEN #define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ #define INR_OPEN 1024 /* Initial setting for nfile rlimits */ #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1<kern_mnt by * kern_mount() which must be called _after_ * register_filesystem(). */ #define FS_NOMOUNT 16 /* Never mount from userland */ #define FS_LITTER 32 /* Keeps the tree in dcache */ #define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon * as nfs_rename() will be cleaned up */ /* * These are the fs-independent mount-flags: up to 32 flags are supported */ #define MS_RDONLY 1 /* Mount read-only */ #define MS_NOSUID 2 /* Ignore suid and sgid bits */ #define MS_NODEV 4 /* Disallow access to device special files */ #define MS_NOEXEC 8 /* Disallow program execution */ #define MS_SYNCHRONOUS 16 /* Writes are synced at once */ #define MS_REMOUNT 32 /* Alter flags of a mounted FS */ #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ #define MS_BIND 4096 /* * Flags that can be altered by MS_REMOUNT */ #define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\ MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME) /* * Old magic mount flag and mask */ #define MS_MGC_VAL 0xC0ED0000 #define MS_MGC_MSK 0xffff0000 /* Inode flags - they have nothing to superblock flags now */ #define S_SYNC 1 /* Writes are synced at once */ #define S_NOATIME 2 /* Do not update access times */ #define S_QUOTA 4 /* Quota initialized for file */ #define S_APPEND 8 /* Append-only file */ #define S_IMMUTABLE 16 /* Immutable file */ #define S_DEAD 32 /* removed, but still open directory */ /* * Note that nosuid etc flags are inode-specific: setting some file-system * flags just means all the inodes inherit those flags by default. It might be * possible to override it selectively if you really wanted to with some * ioctl() that is not currently implemented. * * Exception: MS_RDONLY is always applied to the entire file system. * * Unfortunately, it is possible to change a filesystems flags with it mounted * with files in use. This means that all of the inodes will not have their * i_flags updated. Hence, i_flags no longer inherit the superblock mount * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org */ #define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg)) #define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY) #define IS_NOSUID(inode) __IS_FLG(inode, MS_NOSUID) #define IS_NODEV(inode) __IS_FLG(inode, MS_NODEV) #define IS_NOEXEC(inode) __IS_FLG(inode, MS_NOEXEC) #define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC)) #define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK) #define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA) #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) #define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME)) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ #define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */ #define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */ #define BLKRRPART _IO(0x12,95) /* re-read partition table */ #define BLKGETSIZE _IO(0x12,96) /* return device size */ #define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ #define BLKRASET _IO(0x12,98) /* Set read ahead for block device */ #define BLKRAGET _IO(0x12,99) /* get current read ahead setting */ #define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */ #define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */ #define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */ #define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ #if 0 #define BLKPG _IO(0x12,105)/* See blkpg.h */ #define BLKELVGET _IOR(0x12,106,sizeof(blkelv_ioctl_arg_t))/* elevator get */ #define BLKELVSET _IOW(0x12,107,sizeof(blkelv_ioctl_arg_t))/* elevator set */ /* This was here just to show that the number is taken - probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ #endif #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ #ifdef __KERNEL__ #include #include extern void update_atime (struct inode *); #define UPDATE_ATIME(inode) update_atime (inode) extern void buffer_init(unsigned long); extern void inode_init(unsigned long); /* bh state bits */ #define BH_Uptodate 0 /* 1 if the buffer contains valid data */ #define BH_Dirty 1 /* 1 if the buffer is dirty */ #define BH_Lock 2 /* 1 if the buffer is locked */ #define BH_Req 3 /* 0 if the buffer has been invalidated */ #define BH_Mapped 4 /* 1 if the buffer has a disk mapping */ #define BH_New 5 /* 1 if the buffer is new and not yet written out */ #define BH_Protected 6 /* 1 if the buffer is protected */ /* * Try to keep the most commonly used fields in single cache lines (16 * bytes) to improve performance. This ordering should be * particularly beneficial on 32-bit processors. * * We use the first 16 bytes for the data which is used in searches * over the block hash lists (ie. getblk() and friends). * * The second 16 bytes we use for lru buffer scans, as used by * sync_buffers() and refill_freelist(). -- sct */ struct buffer_head { /* First cache line: */ struct buffer_head *b_next; /* Hash queue list */ unsigned long b_blocknr; /* block number */ unsigned short b_size; /* block size */ unsigned short b_list; /* List that this buffer appears */ kdev_t b_dev; /* device (B_FREE = free) */ atomic_t b_count; /* users using this block */ kdev_t b_rdev; /* Real device */ unsigned long b_state; /* buffer state bitmap (see above) */ unsigned long b_flushtime; /* Time when (dirty) buffer should be written */ struct buffer_head *b_next_free;/* lru/free list linkage */ struct buffer_head *b_prev_free;/* doubly linked list of buffers */ struct buffer_head *b_this_page;/* circular list of buffers in one page */ struct buffer_head *b_reqnext; /* request queue */ struct buffer_head **b_pprev; /* doubly linked list of hash-queue */ char * b_data; /* pointer to data block */ struct page *b_page; /* the page this bh is mapped to */ void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */ void *b_private; /* reserved for b_end_io */ unsigned long b_rsector; /* Real buffer location on disk */ wait_queue_head_t b_wait; struct inode * b_inode; struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */ }; typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate); void init_buffer(struct buffer_head *, bh_end_io_t *, void *); #define __buffer_state(bh, state) (((bh)->b_state & (1UL << BH_##state)) != 0) #define buffer_uptodate(bh) __buffer_state(bh,Uptodate) #define buffer_dirty(bh) __buffer_state(bh,Dirty) #define buffer_locked(bh) __buffer_state(bh,Lock) #define buffer_req(bh) __buffer_state(bh,Req) #define buffer_mapped(bh) __buffer_state(bh,Mapped) #define buffer_new(bh) __buffer_state(bh,New) #define buffer_protected(bh) __buffer_state(bh,Protected) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset); #define touch_buffer(bh) SetPageReferenced(bh->b_page) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Attribute flags. These should be or-ed together to figure out what * has been changed! */ #define ATTR_MODE 1 #define ATTR_UID 2 #define ATTR_GID 4 #define ATTR_SIZE 8 #define ATTR_ATIME 16 #define ATTR_MTIME 32 #define ATTR_CTIME 64 #define ATTR_ATIME_SET 128 #define ATTR_MTIME_SET 256 #define ATTR_FORCE 512 /* Not a change, but a change it */ #define ATTR_ATTR_FLAG 1024 /* * This is the Inode Attributes structure, used for notify_change(). It * uses the above definitions as flags, to know which values have changed. * Also, in this manner, a Filesystem can look at only the values it cares * about. Basically, these are the attributes that the VFS layer can * request to change from the FS layer. * * Derek Atkins 94-10-20 */ struct iattr { unsigned int ia_valid; umode_t ia_mode; uid_t ia_uid; gid_t ia_gid; loff_t ia_size; time_t ia_atime; time_t ia_mtime; time_t ia_ctime; unsigned int ia_attr_flags; }; /* * This is the inode attributes flag definitions */ #define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */ #define ATTR_FLAG_NOATIME 2 /* Don't update atime */ #define ATTR_FLAG_APPEND 4 /* Append-only file */ #define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */ #define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */ /* * Includes for diskquotas and mount structures. */ #include #include /* * oh the beauties of C type declarations. */ struct page; struct address_space; struct address_space_operations { int (*writepage)(struct page *); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ int (*bmap)(struct address_space *, long); }; struct address_space { struct list_head clean_pages; /* list of clean pages */ struct list_head dirty_pages; /* list of dirty pages */ struct list_head locked_pages; /* list of locked pages */ unsigned long nrpages; /* number of total pages */ struct address_space_operations *a_ops; /* methods */ struct inode *host; /* owner: inode, block_device */ struct vm_area_struct *i_mmap; /* list of private mappings */ struct vm_area_struct *i_mmap_shared; /* list of shared mappings */ spinlock_t i_shared_lock; /* and spinlock protecting it */ int gfp_mask; /* how to allocate the pages */ }; struct char_device { struct list_head hash; atomic_t count; dev_t dev; atomic_t openers; struct semaphore sem; }; struct block_device { struct list_head bd_hash; atomic_t bd_count; /* struct address_space bd_data; */ dev_t bd_dev; /* not a kdev_t - it's a search key */ atomic_t bd_openers; const struct block_device_operations *bd_op; struct semaphore bd_sem; /* open/close mutex */ }; struct inode { struct list_head i_hash; struct list_head i_list; struct list_head i_dentry; struct list_head i_dirty_buffers; unsigned long i_ino; atomic_t i_count; kdev_t i_dev; umode_t i_mode; nlink_t i_nlink; uid_t i_uid; gid_t i_gid; kdev_t i_rdev; loff_t i_size; time_t i_atime; time_t i_mtime; time_t i_ctime; unsigned long i_blksize; unsigned long i_blocks; unsigned long i_version; struct semaphore i_sem; struct semaphore i_zombie; struct inode_operations *i_op; struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct super_block *i_sb; wait_queue_head_t i_wait; struct file_lock *i_flock; struct address_space *i_mapping; struct address_space i_data; struct dquot *i_dquot[MAXQUOTAS]; /* These three should probably be a union */ struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct char_device *i_cdev; unsigned long i_dnotify_mask; /* Directory notify events */ struct dnotify_struct *i_dnotify; /* for directory notifications */ unsigned long i_state; unsigned int i_flags; unsigned char i_sock; atomic_t i_writecount; unsigned int i_attr_flags; __u32 i_generation; union { struct minix_inode_info minix_i; struct ext2_inode_info ext2_i; struct hpfs_inode_info hpfs_i; struct ntfs_inode_info ntfs_i; struct msdos_inode_info msdos_i; struct umsdos_inode_info umsdos_i; struct iso_inode_info isofs_i; struct nfs_inode_info nfs_i; struct sysv_inode_info sysv_i; struct affs_inode_info affs_i; struct ufs_inode_info ufs_i; struct efs_inode_info efs_i; struct romfs_inode_info romfs_i; struct shmem_inode_info shmem_i; struct coda_inode_info coda_i; struct smb_inode_info smbfs_i; struct hfs_inode_info hfs_i; struct adfs_inode_info adfs_i; struct qnx4_inode_info qnx4_i; struct reiserfs_inode_info reiserfs_i; struct bfs_inode_info bfs_i; struct udf_inode_info udf_i; struct ncp_inode_info ncpfs_i; struct proc_inode_info proc_i; struct socket socket_i; struct usbdev_inode_info usbdev_i; void *generic_ip; } u; }; struct fown_struct { int pid; /* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ }; struct file { struct list_head f_list; struct dentry *f_dentry; struct vfsmount *f_vfsmnt; struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; struct fown_struct f_owner; unsigned int f_uid, f_gid; int f_error; unsigned long f_version; /* needed for tty driver, and maybe others */ void *private_data; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); #define file_list_unlock() spin_unlock(&files_lock); #define get_file(x) atomic_inc(&(x)->f_count) #define file_count(x) atomic_read(&(x)->f_count) extern int init_private_file(struct file *, struct dentry *, int); #define MAX_NON_LFS ((1UL<<31) - 1) #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_BROKEN 4 /* broken flock() emulation */ #define FL_ACCESS 8 /* for processes suspended by mandatory locking */ #define FL_LOCKD 16 /* lock held by rpc.lockd */ #define FL_LEASE 32 /* lease held on this file */ /* * The POSIX file lock owner is determined by * the "struct files_struct" in the thread group * (or NULL for no owner - BSD locks). * * Lockd stuffs a "host" pointer into this. */ typedef struct files_struct *fl_owner_t; struct file_lock { struct file_lock *fl_next; /* singly linked list for this inode */ struct list_head fl_link; /* doubly linked list of all locks */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; unsigned int fl_pid; wait_queue_head_t fl_wait; struct file *fl_file; unsigned char fl_flags; unsigned char fl_type; loff_t fl_start; loff_t fl_end; void (*fl_notify)(struct file_lock *); /* unblock callback */ void (*fl_insert)(struct file_lock *); /* lock insertion callback */ void (*fl_remove)(struct file_lock *); /* lock removal callback */ struct fasync_struct * fl_fasync; /* for lease break notifications */ union { struct nfs_lock_info nfs_fl; } fl_u; }; /* The following constant reflects the upper bound of the file/locking space */ #ifndef OFFSET_MAX #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) #define OFFSET_MAX INT_LIMIT(loff_t) #define OFFT_OFFSET_MAX INT_LIMIT(off_t) #endif extern struct list_head file_lock_list; #include extern int fcntl_getlk(unsigned int, struct flock *); extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); extern int fcntl_getlk64(unsigned int, struct flock64 *); extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *); /* fs/locks.c */ extern void locks_init_lock(struct file_lock *); extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_flock(struct file *); extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, unsigned int); extern void posix_block_lock(struct file_lock *, struct file_lock *); extern void posix_unblock_lock(struct file_lock *); extern int __get_lease(struct inode *inode, unsigned int flags); extern time_t lease_get_mtime(struct inode *); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); struct fasync_struct { int magic; int fa_fd; struct fasync_struct *fa_next; /* singly linked list */ struct file *fa_file; }; #define FASYNC_MAGIC 0x4601 /* SMP safe fasync helpers: */ extern int fasync_helper(int, struct file *, int, struct fasync_struct **); /* can be called from interrupts */ extern void kill_fasync(struct fasync_struct **, int, int); /* only for net: no internal synchronization */ extern void __kill_fasync(struct fasync_struct *, int, int); struct nameidata { struct dentry *dentry; struct vfsmount *mnt; struct qstr last; unsigned int flags; int last_type; }; #define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ #define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ struct quota_mount_options { unsigned int flags; /* Flags for diskquotas on this device */ struct semaphore dqio_sem; /* lock device while I/O in progress */ struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */ time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */ char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */ }; /* * Umount options */ #define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct list_head super_blocks; #define sb_entry(list) list_entry((list), struct super_block, s_list) struct super_block { struct list_head s_list; /* Keep this first */ kdev_t s_dev; unsigned long s_blocksize; unsigned char s_blocksize_bits; unsigned char s_dirt; unsigned long long s_maxbytes; /* Max file size */ struct file_system_type *s_type; struct super_operations *s_op; struct dquot_operations *dq_op; unsigned long s_flags; unsigned long s_magic; struct dentry *s_root; struct rw_semaphore s_umount; struct semaphore s_lock; struct list_head s_dirty; /* dirty inodes */ struct list_head s_locked_inodes;/* inodes being synced */ struct list_head s_files; struct block_device *s_bdev; struct list_head s_mounts; /* vfsmount(s) of this one */ struct quota_mount_options s_dquot; /* Diskquota specific options */ union { struct minix_sb_info minix_sb; struct ext2_sb_info ext2_sb; struct hpfs_sb_info hpfs_sb; struct ntfs_sb_info ntfs_sb; struct msdos_sb_info msdos_sb; struct isofs_sb_info isofs_sb; struct nfs_sb_info nfs_sb; struct sysv_sb_info sysv_sb; struct affs_sb_info affs_sb; struct ufs_sb_info ufs_sb; struct efs_sb_info efs_sb; struct shmem_sb_info shmem_sb; struct romfs_sb_info romfs_sb; struct smb_sb_info smbfs_sb; struct hfs_sb_info hfs_sb; struct adfs_sb_info adfs_sb; struct qnx4_sb_info qnx4_sb; struct reiserfs_sb_info reiserfs_sb; struct bfs_sb_info bfs_sb; struct udf_sb_info udf_sb; struct ncp_sb_info ncpfs_sb; struct usbdev_sb_info usbdevfs_sb; void *generic_sbp; } u; /* * The next field is for VFS *only*. No filesystems have any business * even looking at it. You had been warned. */ struct semaphore s_vfs_rename_sem; /* Kludge */ /* The next field is used by knfsd when converting a (inode number based) * file handle into a dentry. As it builds a path in the dcache tree from * the bottom up, there may for a time be a subpath of dentrys which is not * connected to the main tree. This semaphore ensure that there is only ever * one such free path per filesystem. Note that unconnected files (or other * non-directories) are allowed, but not unconnected diretories. */ struct semaphore s_nfsd_free_path_sem; }; /* * VFS helper functions.. */ extern int vfs_create(struct inode *, struct dentry *, int); extern int vfs_mkdir(struct inode *, struct dentry *, int); extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t); extern int vfs_symlink(struct inode *, struct dentry *, const char *); extern int vfs_link(struct dentry *, struct inode *, struct dentry *); extern int vfs_rmdir(struct inode *, struct dentry *); extern int vfs_unlink(struct inode *, struct dentry *); extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); /* * File types */ #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 /* * This is the "filldir" function type, used by readdir() to let * the kernel specify what kind of dirent layout it wants to have. * This allows the kernel to read directories into kernel space or * to have different dirent layouts depending on the binary type. */ typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t, unsigned); struct block_device_operations { int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); int (*check_media_change) (kdev_t); int (*revalidate) (kdev_t); }; /* * NOTE: * read, write, poll, fsync, readv, writev can be called * without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; struct inode_operations { int (*create) (struct inode *,struct dentry *,int); struct dentry * (*lookup) (struct inode *,struct dentry *); int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct inode *,struct dentry *,const char *); int (*mkdir) (struct inode *,struct dentry *,int); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct inode *,struct dentry *,int,int); int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); int (*readlink) (struct dentry *, char *,int); int (*follow_link) (struct dentry *, struct nameidata *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int); int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); }; /* * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called * without the big kernel lock held in all filesystems. */ struct super_operations { void (*read_inode) (struct inode *); /* reiserfs kludge. reiserfs needs 64 bits of information to ** find an inode. We are using the read_inode2 call to get ** that information. We don't like this, and are waiting on some ** VFS changes for the real solution. ** iget4 calls read_inode2, iff it is defined */ void (*read_inode2) (struct inode *, void *) ; void (*dirty_inode) (struct inode *); void (*write_inode) (struct inode *, int); void (*put_inode) (struct inode *); void (*delete_inode) (struct inode *); void (*put_super) (struct super_block *); void (*write_super) (struct super_block *); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); int (*statfs) (struct super_block *, struct statfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); }; /* Inode state bits.. */ #define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */ #define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */ #define I_DIRTY_PAGES 4 /* Data-related inode changes pending */ #define I_LOCK 8 #define I_FREEING 16 #define I_CLEAR 32 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) extern void __mark_inode_dirty(struct inode *, int); static inline void mark_inode_dirty(struct inode *inode) { __mark_inode_dirty(inode, I_DIRTY); } static inline void mark_inode_dirty_sync(struct inode *inode) { __mark_inode_dirty(inode, I_DIRTY_SYNC); } static inline void mark_inode_dirty_pages(struct inode *inode) { __mark_inode_dirty(inode, I_DIRTY_PAGES); } struct dquot_operations { void (*initialize) (struct inode *, short); void (*drop) (struct inode *); int (*alloc_block) (const struct inode *, unsigned long, char); int (*alloc_inode) (const struct inode *, unsigned long); void (*free_block) (const struct inode *, unsigned long); void (*free_inode) (const struct inode *, unsigned long); int (*transfer) (struct dentry *, struct iattr *); }; struct file_system_type { const char *name; int fs_flags; struct super_block *(*read_super) (struct super_block *, void *, int); struct module *owner; struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */ struct file_system_type * next; }; #define DECLARE_FSTYPE(var,type,read,flags) \ struct file_system_type var = { \ name: type, \ read_super: read, \ fs_flags: flags, \ owner: THIS_MODULE, \ } #define DECLARE_FSTYPE_DEV(var,type,read) \ DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV) /* Alas, no aliases. Too much hassle with bringing module.h everywhere */ #define fops_get(fops) \ (((fops) && (fops)->owner) \ ? ( try_inc_mod_count((fops)->owner) ? (fops) : NULL ) \ : (fops)) #define fops_put(fops) \ do { \ if ((fops) && (fops)->owner) \ __MOD_DEC_USE_COUNT((fops)->owner); \ } while(0) extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); extern long do_mount(char *, char *, char *, unsigned long, void *); #define kern_umount mntput extern int vfs_statfs(struct super_block *, struct statfs *); /* Return value for VFS lock functions - tells locks.c to lock conventionally * REALLY kosha for root NFS and nfs_lock */ #define LOCK_USE_CLNT 1 #define FLOCK_VERIFY_READ 1 #define FLOCK_VERIFY_WRITE 2 extern int locks_mandatory_locked(struct inode *); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); /* * Candidates for mandatory locking have the setgid bit set * but no group execute bit - an otherwise meaningless combination. */ #define MANDATORY_LOCK(inode) \ (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) static inline int locks_verify_locked(struct inode *inode) { if (MANDATORY_LOCK(inode)) return locks_mandatory_locked(inode); return 0; } static inline int locks_verify_area(int read_write, struct inode *inode, struct file *filp, loff_t offset, size_t count) { if (inode->i_flock && MANDATORY_LOCK(inode)) return locks_mandatory_area(read_write, inode, filp, offset, count); return 0; } static inline int locks_verify_truncate(struct inode *inode, struct file *filp, loff_t size) { if (inode->i_flock && MANDATORY_LOCK(inode)) return locks_mandatory_area( FLOCK_VERIFY_WRITE, inode, filp, size < inode->i_size ? size : inode->i_size, (size < inode->i_size ? inode->i_size - size : size - inode->i_size) ); return 0; } extern inline int get_lease(struct inode *inode, unsigned int mode) { if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE)) return __get_lease(inode, mode); return 0; } /* fs/open.c */ asmlinkage long sys_open(const char *, int, int); asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ extern int do_truncate(struct dentry *, loff_t start); extern struct file *filp_open(const char *, int, int); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); extern int filp_close(struct file *, fl_owner_t id); extern char * getname(const char *); /* fs/dcache.c */ extern void vfs_caches_init(unsigned long); #define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL) #define putname(name) kmem_cache_free(names_cachep, (void *)(name)) enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW}; extern int register_blkdev(unsigned int, const char *, struct block_device_operations *); extern int unregister_blkdev(unsigned int, const char *); extern struct block_device *bdget(dev_t); extern void bdput(struct block_device *); extern struct char_device *cdget(dev_t); extern void cdput(struct char_device *); extern int blkdev_open(struct inode *, struct file *); extern struct file_operations def_blk_fops; extern struct file_operations def_fifo_fops; extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_get(struct block_device *, mode_t, unsigned, int); extern int blkdev_put(struct block_device *, int); /* fs/devices.c */ extern const struct block_device_operations *get_blkfops(unsigned int); extern int register_chrdev(unsigned int, const char *, struct file_operations *); extern int unregister_chrdev(unsigned int, const char *); extern int chrdev_open(struct inode *, struct file *); extern const char * bdevname(kdev_t); extern const char * cdevname(kdev_t); extern const char * kdevname(kdev_t); extern void init_special_inode(struct inode *, umode_t, int); /* Invalid inode operations -- fs/bad_inode.c */ extern void make_bad_inode(struct inode *); extern int is_bad_inode(struct inode *); extern struct file_operations read_fifo_fops; extern struct file_operations write_fifo_fops; extern struct file_operations rdwr_fifo_fops; extern struct file_operations read_pipe_fops; extern struct file_operations write_pipe_fops; extern struct file_operations rdwr_pipe_fops; extern int fs_may_remount_ro(struct super_block *); extern int try_to_free_buffers(struct page *, int); extern void refile_buffer(struct buffer_head * buf); /* reiserfs_writepage needs this */ extern void set_buffer_async_io(struct buffer_head *bh) ; #define BUF_CLEAN 0 #define BUF_LOCKED 1 /* Buffers scheduled for write */ #define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */ #define BUF_PROTECTED 3 /* Ramdisk persistent storage */ #define NR_LIST 4 /* * This is called by bh->b_end_io() handlers when I/O has completed. */ static inline void mark_buffer_uptodate(struct buffer_head * bh, int on) { if (on) set_bit(BH_Uptodate, &bh->b_state); else clear_bit(BH_Uptodate, &bh->b_state); } #define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state) static inline void __mark_buffer_clean(struct buffer_head *bh) { refile_buffer(bh); } static inline void mark_buffer_clean(struct buffer_head * bh) { if (atomic_set_buffer_clean(bh)) __mark_buffer_clean(bh); } #define atomic_set_buffer_protected(bh) test_and_set_bit(BH_Protected, &(bh)->b_state) static inline void __mark_buffer_protected(struct buffer_head *bh) { refile_buffer(bh); } static inline void mark_buffer_protected(struct buffer_head * bh) { if (!atomic_set_buffer_protected(bh)) __mark_buffer_protected(bh); } extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh)); extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh)); #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state) /* * If an error happens during the make_request, this function * has to be recalled. It marks the buffer as clean and not * uptodate, and it notifys the upper layer about the end * of the I/O. */ static inline void buffer_IO_error(struct buffer_head * bh) { mark_buffer_clean(bh); /* * b_end_io has to clear the BH_Uptodate bitflag in the error case! */ bh->b_end_io(bh, 0); } extern void buffer_insert_inode_queue(struct buffer_head *, struct inode *); static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) { mark_buffer_dirty(bh); buffer_insert_inode_queue(bh, inode); } extern void balance_dirty(kdev_t); extern int check_disk_change(kdev_t); extern int invalidate_inodes(struct super_block *); extern int invalidate_device(kdev_t, int); extern void invalidate_inode_pages(struct inode *); extern void invalidate_inode_buffers(struct inode *); #define invalidate_buffers(dev) __invalidate_buffers((dev), 0) #define destroy_buffers(dev) __invalidate_buffers((dev), 1) extern void __invalidate_buffers(kdev_t dev, int); extern void sync_inodes(kdev_t); extern void sync_unlocked_inodes(void); extern void write_inode_now(struct inode *, int); extern void sync_dev(kdev_t); extern int fsync_dev(kdev_t); extern int fsync_super(struct super_block *); extern void sync_inodes_sb(struct super_block *); extern int fsync_inode_buffers(struct inode *); extern int osync_inode_buffers(struct inode *); extern int inode_has_buffers(struct inode *); extern void filemap_fdatasync(struct address_space *); extern void filemap_fdatawait(struct address_space *); extern void sync_supers(kdev_t); extern int bmap(struct inode *, int); extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int); extern int vfs_permission(struct inode *, int); extern int get_write_access(struct inode *); extern int deny_write_access(struct file *); static inline void put_write_access(struct inode * inode) { atomic_dec(&inode->i_writecount); } static inline void allow_write_access(struct file *file) { if (file) atomic_inc(&file->f_dentry->d_inode->i_writecount); } extern int do_pipe(int *); extern int open_namei(const char *, int, int, struct nameidata *); extern int kernel_read(struct file *, unsigned long, char *, unsigned long); extern struct file * open_exec(const char *); /* fs/dcache.c -- generic fs support functions */ extern int is_subdir(struct dentry *, struct dentry *); extern ino_t find_inode_number(struct dentry *, struct qstr *); /* * Kernel pointers have redundant information, so we can use a * scheme where we can return either an error code or a dentry * pointer with the same return value. * * This should be a per-architecture thing, to allow different * error and pointer decisions. */ static inline void *ERR_PTR(long error) { return (void *) error; } static inline long PTR_ERR(const void *ptr) { return (long) ptr; } static inline long IS_ERR(const void *ptr) { return (unsigned long)ptr > (unsigned long)-1000L; } /* * The bitmask for a lookup event: * - follow links at the end * - require a directory * - ending slashes ok even for nonexistent files * - internal "there are more path compnents" flag */ #define LOOKUP_FOLLOW (1) #define LOOKUP_DIRECTORY (2) #define LOOKUP_CONTINUE (4) #define LOOKUP_POSITIVE (8) #define LOOKUP_PARENT (16) #define LOOKUP_NOALT (32) /* * Type of the last component on LOOKUP_PARENT */ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; /* * "descriptor" for what we're up to with a read for sendfile(). * This allows us to use the same read code yet * have multiple different users of the data that * we read from a file. * * The simplest case just copies the data to user * mode. */ typedef struct { size_t written; size_t count; char * buf; int error; } read_descriptor_t; typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long); /* needed for stackable file system support */ extern loff_t default_llseek(struct file *file, loff_t offset, int origin); extern int __user_walk(const char *, unsigned, struct nameidata *); extern int path_init(const char *, unsigned, struct nameidata *); extern int path_walk(const char *, struct nameidata *); extern void path_release(struct nameidata *); extern int follow_down(struct vfsmount **, struct dentry **); extern int follow_up(struct vfsmount **, struct dentry **); extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry * lookup_hash(struct qstr *, struct dentry *); #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd) #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd) extern void iput(struct inode *); extern void force_delete(struct inode *); extern struct inode * igrab(struct inode *); extern ino_t iunique(struct super_block *, ino_t); typedef int (*find_inode_t)(struct inode *, unsigned long, void *); extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *); static inline struct inode *iget(struct super_block *sb, unsigned long ino) { return iget4(sb, ino, NULL, NULL); } extern void clear_inode(struct inode *); extern struct inode * get_empty_inode(void); static inline struct inode * new_inode(struct super_block *sb) { struct inode *inode = get_empty_inode(); if (inode) { inode->i_sb = sb; inode->i_dev = sb->s_dev; } return inode; } extern void remove_suid(struct inode *inode); extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); extern struct file * get_empty_filp(void); extern void file_move(struct file *f, struct list_head *list); extern void file_moveto(struct file *new, struct file *old); extern struct buffer_head * get_hash_table(kdev_t, int, int); extern struct buffer_head * getblk(kdev_t, int, int); extern void ll_rw_block(int, int, struct buffer_head * bh[]); extern void submit_bh(int, struct buffer_head *); extern int is_read_only(kdev_t); extern void __brelse(struct buffer_head *); static inline void brelse(struct buffer_head *buf) { if (buf) __brelse(buf); } extern void __bforget(struct buffer_head *); static inline void bforget(struct buffer_head *buf) { if (buf) __bforget(buf); } extern void set_blocksize(kdev_t, int); extern struct buffer_head * bread(kdev_t, int, int); extern void wakeup_bdflush(int wait); extern int brw_page(int, struct page *, kdev_t, int [], int); typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int); /* Generic buffer handling for block filesystems.. */ extern int block_flushpage(struct page *, unsigned long); extern int block_symlink(struct inode *, const char *, int); extern int block_write_full_page(struct page*, get_block_t*); extern int block_read_full_page(struct page*, get_block_t*); extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*); extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, unsigned long *); extern int block_sync_page(struct page *); int generic_block_bmap(struct address_space *, long, get_block_t *); int generic_commit_write(struct file *, struct page *, unsigned, unsigned); int block_truncate_page(struct address_space *, loff_t, get_block_t *); extern int waitfor_one_page(struct page*); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *); extern struct file_operations generic_ro_fops; extern int vfs_readlink(struct dentry *, char *, int, const char *); extern int vfs_follow_link(struct nameidata *, const char *); extern int page_readlink(struct dentry *, char *, int); extern int page_follow_link(struct dentry *, struct nameidata *); extern struct inode_operations page_symlink_inode_operations; extern int vfs_readdir(struct file *, filldir_t, void *); extern int dcache_readdir(struct file *, void *, filldir_t); extern struct file_system_type *get_fs_type(const char *name); extern struct super_block *get_super(kdev_t); extern void put_super(kdev_t); static inline int is_mounted(kdev_t dev) { struct super_block *sb = get_super(dev); if (sb) { /* drop_super(sb); will go here */ return 1; } return 0; } unsigned long generate_cluster(kdev_t, int b[], int); unsigned long generate_cluster_swab32(kdev_t, int b[], int); extern kdev_t ROOT_DEV; extern char root_device_name[]; extern void show_buffers(void); extern void mount_root(void); #ifdef CONFIG_BLK_DEV_INITRD extern kdev_t real_root_dev; extern int change_root(kdev_t, const char *); #endif extern ssize_t char_read(struct file *, char *, size_t, loff_t *); extern ssize_t block_read(struct file *, char *, size_t, loff_t *); extern int read_ahead[]; extern ssize_t char_write(struct file *, const char *, size_t, loff_t *); extern ssize_t block_write(struct file *, const char *, size_t, loff_t *); extern int file_fsync(struct file *, struct dentry *, int); extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx); extern int generic_osync_inode(struct inode *, int); extern int inode_change_ok(struct inode *, struct iattr *); extern void inode_setattr(struct inode *, struct iattr *); /* * Common dentry functions for inclusion in the VFS * or in other stackable file systems. Some of these * functions were in linux/fs/ C (VFS) files. * */ /* * Locking the parent is needed to: * - serialize directory operations * - make sure the parent doesn't change from * under us in the middle of an operation. * * NOTE! Right now we'd rather use a "struct inode" * for this, but as I expect things to move toward * using dentries instead for most things it is * probably better to start with the conceptually * better interface of relying on a path of dentries. */ static inline struct dentry *lock_parent(struct dentry *dentry) { struct dentry *dir = dget(dentry->d_parent); down(&dir->d_inode->i_sem); return dir; } static inline struct dentry *get_parent(struct dentry *dentry) { return dget(dentry->d_parent); } static inline void unlock_dir(struct dentry *dir) { up(&dir->d_inode->i_sem); dput(dir); } /* * Whee.. Deadlock country. Happily there are only two VFS * operations that does this.. */ static inline void double_down(struct semaphore *s1, struct semaphore *s2) { if (s1 != s2) { if ((unsigned long) s1 < (unsigned long) s2) { struct semaphore *tmp = s2; s2 = s1; s1 = tmp; } down(s1); } down(s2); } /* * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is * not equal to 1st and not equal to 2nd - the first case (target is parent of * source) would be already caught, the second is plain impossible (target is * its own parent and that case would be caught even earlier). Very messy. * I _think_ that it works, but no warranties - please, look it through. * Pox on bloody lusers who mandated overwriting rename() for directories... */ static inline void triple_down(struct semaphore *s1, struct semaphore *s2, struct semaphore *s3) { if (s1 != s2) { if ((unsigned long) s1 < (unsigned long) s2) { if ((unsigned long) s1 < (unsigned long) s3) { struct semaphore *tmp = s3; s3 = s1; s1 = tmp; } if ((unsigned long) s1 < (unsigned long) s2) { struct semaphore *tmp = s2; s2 = s1; s1 = tmp; } } else { if ((unsigned long) s1 < (unsigned long) s3) { struct semaphore *tmp = s3; s3 = s1; s1 = tmp; } if ((unsigned long) s2 < (unsigned long) s3) { struct semaphore *tmp = s3; s3 = s2; s2 = tmp; } } down(s1); } else if ((unsigned long) s2 < (unsigned long) s3) { struct semaphore *tmp = s3; s3 = s2; s2 = tmp; } down(s2); down(s3); } static inline void double_up(struct semaphore *s1, struct semaphore *s2) { up(s1); if (s1 != s2) up(s2); } static inline void triple_up(struct semaphore *s1, struct semaphore *s2, struct semaphore *s3) { up(s1); if (s1 != s2) up(s2); up(s3); } static inline void double_lock(struct dentry *d1, struct dentry *d2) { double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem); } static inline void double_unlock(struct dentry *d1, struct dentry *d2) { double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem); dput(d1); dput(d2); } #endif /* __KERNEL__ */ #endif /* _LINUX_FS_H */ ./elilo/fs/ext2_fs.h0000644000175000017500000004674707316156505014026 0ustar jasonfjasonf/* * linux/include/linux/ext2_fs.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/include/linux/minix_fs.h * * Copyright (C) 1991, 1992 Linus Torvalds */ #ifndef _LINUX_EXT2_FS_H #define _LINUX_EXT2_FS_H /* * The second extended filesystem constants/structures */ /* * Define EXT2FS_DEBUG to produce debug messages */ #undef EXT2FS_DEBUG /* * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files */ #define EXT2_PREALLOCATE #define EXT2_DEFAULT_PREALLOC_BLOCKS 8 /* * The second extended file system version */ #define EXT2FS_DATE "95/08/09" #define EXT2FS_VERSION "0.5b" /* * Debug code */ #ifdef EXT2FS_DEBUG # define ext2_debug(f, a...) { \ printk ("EXT2-fs DEBUG (%s, %d): %s:", \ __FILE__, __LINE__, __FUNCTION__); \ printk (f, ## a); \ } #else # define ext2_debug(f, a...) /**/ #endif /* * Special inodes numbers */ #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ #define EXT2_ACL_IDX_INO 3 /* ACL inode */ #define EXT2_ACL_DATA_INO 4 /* ACL inode */ #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ /* First non-reserved inode for old ext2 filesystems */ #define EXT2_GOOD_OLD_FIRST_INO 11 /* * The second extended file system magic number */ #define EXT2_SUPER_MAGIC 0xEF53 /* * Maximal count of links to a file */ #define EXT2_LINK_MAX 32000 /* * Macro-instructions used to manage several block sizes */ #define EXT2_MIN_BLOCK_SIZE 1024 #define EXT2_MAX_BLOCK_SIZE 4096 #define EXT2_MIN_BLOCK_LOG_SIZE 10 #ifdef __KERNEL__ # define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) #else # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) #ifdef __KERNEL__ # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) #else # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #endif #ifdef __KERNEL__ #define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits) #define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size) #define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino) #else #define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ EXT2_GOOD_OLD_INODE_SIZE : \ (s)->s_inode_size) #define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ EXT2_GOOD_OLD_FIRST_INO : \ (s)->s_first_ino) #endif /* * Macro-instructions used to manage fragments */ #define EXT2_MIN_FRAG_SIZE 1024 #define EXT2_MAX_FRAG_SIZE 4096 #define EXT2_MIN_FRAG_LOG_SIZE 10 #ifdef __KERNEL__ # define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) # define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) #else # define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) #endif /* * ACL structures */ struct ext2_acl_header /* Header of Access Control Lists */ { __u32 aclh_size; __u32 aclh_file_count; __u32 aclh_acle_count; __u32 aclh_first_acle; }; struct ext2_acl_entry /* Access Control List Entry */ { __u32 acle_size; __u16 acle_perms; /* Access permissions */ __u16 acle_type; /* Type of entry */ __u16 acle_tag; /* User or group identity */ __u16 acle_pad1; __u32 acle_next; /* Pointer on next entry for the */ /* same inode or on next free entry */ }; /* * Structure of a blocks group descriptor */ struct ext2_group_desc { __u32 bg_block_bitmap; /* Blocks bitmap block */ __u32 bg_inode_bitmap; /* Inodes bitmap block */ __u32 bg_inode_table; /* Inodes table block */ __u16 bg_free_blocks_count; /* Free blocks count */ __u16 bg_free_inodes_count; /* Free inodes count */ __u16 bg_used_dirs_count; /* Directories count */ __u16 bg_pad; __u32 bg_reserved[3]; }; /* * Macro-instructions used to manage group descriptors */ #ifdef __KERNEL__ # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) # define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits) #else # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) # define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) #endif /* * Constants relative to the data blocks */ #define EXT2_NDIR_BLOCKS 12 #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) /* * Inode flags */ #define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ #define EXT2_UNRM_FL 0x00000002 /* Undelete */ #define EXT2_COMPR_FL 0x00000004 /* Compress file */ #define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ #define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ #define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ #define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ #define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ /* Reserved for compression usage... */ #define EXT2_DIRTY_FL 0x00000100 #define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ #define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ #define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ /* End compression flags --- maybe not all used */ #define EXT2_BTREE_FL 0x00001000 /* btree format dir */ #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */ #define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ /* * ioctl commands */ #define EXT2_IOC_GETFLAGS _IOR('f', 1, long) #define EXT2_IOC_SETFLAGS _IOW('f', 2, long) #define EXT2_IOC_GETVERSION _IOR('v', 1, long) #define EXT2_IOC_SETVERSION _IOW('v', 2, long) /* * Structure of an inode on the disk */ struct ext2_inode { __u16 i_mode; /* File mode */ __u16 i_uid; /* Low 16 bits of Owner Uid */ __u32 i_size; /* Size in bytes */ __u32 i_atime; /* Access time */ __u32 i_ctime; /* Creation time */ __u32 i_mtime; /* Modification time */ __u32 i_dtime; /* Deletion Time */ __u16 i_gid; /* Low 16 bits of Group Id */ __u16 i_links_count; /* Links count */ __u32 i_blocks; /* Blocks count */ __u32 i_flags; /* File flags */ union { struct { __u32 l_i_reserved1; } linux1; struct { __u32 h_i_translator; } hurd1; struct { __u32 m_i_reserved1; } masix1; } osd1; /* OS dependent 1 */ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ __u32 i_generation; /* File version (for NFS) */ __u32 i_file_acl; /* File ACL */ __u32 i_dir_acl; /* Directory ACL */ __u32 i_faddr; /* Fragment address */ union { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ __u16 i_pad1; __u16 l_i_uid_high; /* these 2 fields */ __u16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; } linux2; struct { __u8 h_i_frag; /* Fragment number */ __u8 h_i_fsize; /* Fragment size */ __u16 h_i_mode_high; __u16 h_i_uid_high; __u16 h_i_gid_high; __u32 h_i_author; } hurd2; struct { __u8 m_i_frag; /* Fragment number */ __u8 m_i_fsize; /* Fragment size */ __u16 m_pad1; __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ }; #define i_size_high i_dir_acl #if defined(__KERNEL__) || defined(__linux__) #define i_reserved1 osd1.linux1.l_i_reserved1 #define i_frag osd2.linux2.l_i_frag #define i_fsize osd2.linux2.l_i_fsize #define i_uid_low i_uid #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high #define i_reserved2 osd2.linux2.l_i_reserved2 #endif #ifdef __hurd__ #define i_translator osd1.hurd1.h_i_translator #define i_frag osd2.hurd2.h_i_frag; #define i_fsize osd2.hurd2.h_i_fsize; #define i_uid_high osd2.hurd2.h_i_uid_high #define i_gid_high osd2.hurd2.h_i_gid_high #define i_author osd2.hurd2.h_i_author #endif #ifdef __masix__ #define i_reserved1 osd1.masix1.m_i_reserved1 #define i_frag osd2.masix2.m_i_frag #define i_fsize osd2.masix2.m_i_fsize #define i_reserved2 osd2.masix2.m_i_reserved2 #endif /* * File system states */ #define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ #define EXT2_ERROR_FS 0x0002 /* Errors detected */ /* * Mount flags */ #define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ #define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ #define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ #define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ #define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ #define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ #define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt #define set_opt(o, opt) o |= EXT2_MOUNT_##opt #define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ EXT2_MOUNT_##opt) /* * Maximal mount counts between two filesystem checks */ #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ #define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ /* * Behaviour when detecting errors */ #define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ #define EXT2_ERRORS_RO 2 /* Remount fs read-only */ #define EXT2_ERRORS_PANIC 3 /* Panic */ #define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE /* * Structure of the super block */ struct ext2_super_block { __u32 s_inodes_count; /* Inodes count */ __u32 s_blocks_count; /* Blocks count */ __u32 s_r_blocks_count; /* Reserved blocks count */ __u32 s_free_blocks_count; /* Free blocks count */ __u32 s_free_inodes_count; /* Free inodes count */ __u32 s_first_data_block; /* First Data Block */ __u32 s_log_block_size; /* Block size */ __s32 s_log_frag_size; /* Fragment size */ __u32 s_blocks_per_group; /* # Blocks per group */ __u32 s_frags_per_group; /* # Fragments per group */ __u32 s_inodes_per_group; /* # Inodes per group */ __u32 s_mtime; /* Mount time */ __u32 s_wtime; /* Write time */ __u16 s_mnt_count; /* Mount count */ __s16 s_max_mnt_count; /* Maximal mount count */ __u16 s_magic; /* Magic signature */ __u16 s_state; /* File system state */ __u16 s_errors; /* Behaviour when detecting errors */ __u16 s_minor_rev_level; /* minor revision level */ __u32 s_lastcheck; /* time of last check */ __u32 s_checkinterval; /* max. time between checks */ __u32 s_creator_os; /* OS */ __u32 s_rev_level; /* Revision level */ __u16 s_def_resuid; /* Default uid for reserved blocks */ __u16 s_def_resgid; /* Default gid for reserved blocks */ /* * These fields are for EXT2_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set * in the incompatible feature set that the kernel doesn't * know about, it should refuse to mount the filesystem. * * e2fsck's requirements are more strict; if it doesn't know * about a feature in either the compatible or incompatible * feature set, it must abort and not try to meddle with * things it doesn't understand... */ __u32 s_first_ino; /* First non-reserved inode */ __u16 s_inode_size; /* size of inode structure */ __u16 s_block_group_nr; /* block group # of this superblock */ __u32 s_feature_compat; /* compatible feature set */ __u32 s_feature_incompat; /* incompatible feature set */ __u32 s_feature_ro_compat; /* readonly-compatible feature set */ __u8 s_uuid[16]; /* 128-bit uuid for volume */ char s_volume_name[16]; /* volume name */ char s_last_mounted[64]; /* directory where last mounted */ __u32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only * happen if the EXT2_COMPAT_PREALLOC flag is on. */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __u16 s_padding1; __u32 s_reserved[204]; /* Padding to the end of the block */ }; #ifdef __KERNEL__ #define EXT2_SB(sb) (&((sb)->u.ext2_sb)) #else /* Assume that user mode programs are passing in an ext2fs superblock, not * a kernel struct super_block. This will allow us to call the feature-test * macros from user land. */ #define EXT2_SB(sb) (sb) #endif /* * Codes for operating systems */ #define EXT2_OS_LINUX 0 #define EXT2_OS_HURD 1 #define EXT2_OS_MASIX 2 #define EXT2_OS_FREEBSD 3 #define EXT2_OS_LITES 4 /* * Revision levels */ #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ #define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV #define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV #define EXT2_GOOD_OLD_INODE_SIZE 128 /* * Feature set definitions */ #define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) #define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) #define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) #define EXT2_SET_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) #define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) #define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) #define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) #define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) #define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT2_FEATURE_COMPAT_SUPP 0 #define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_BTREE_DIR) /* * Default values for user and/or group using reserved blocks */ #define EXT2_DEF_RESUID 0 #define EXT2_DEF_RESGID 0 /* * Structure of a directory entry */ #define EXT2_NAME_LEN 255 struct ext2_dir_entry { __u32 inode; /* Inode number */ __u16 rec_len; /* Directory entry length */ __u16 name_len; /* Name length */ char name[EXT2_NAME_LEN]; /* File name */ }; /* * The new version of the directory entry. Since EXT2 structures are * stored in intel byte order, and the name_len field could never be * bigger than 255 chars, it's safe to reclaim the extra byte for the * file_type field. */ struct ext2_dir_entry_2 { __u32 inode; /* Inode number */ __u16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; char name[EXT2_NAME_LEN]; /* File name */ }; /* * Ext2 directory file types. Only the low 3 bits are used. The * other bits are reserved for now. */ #define EXT2_FT_UNKNOWN 0 #define EXT2_FT_REG_FILE 1 #define EXT2_FT_DIR 2 #define EXT2_FT_CHRDEV 3 #define EXT2_FT_BLKDEV 4 #define EXT2_FT_FIFO 5 #define EXT2_FT_SOCK 6 #define EXT2_FT_SYMLINK 7 #define EXT2_FT_MAX 8 /* * EXT2_DIR_PAD defines the directory entries boundaries * * NOTE: It must be a multiple of 4 */ #define EXT2_DIR_PAD 4 #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) #ifdef __KERNEL__ /* * Function prototypes */ /* * Ok, these declarations are also in but none of the * ext2 source programs needs to include it so they are duplicated here. */ # define NORET_TYPE /**/ # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, /* acl.c */ extern int ext2_permission (struct inode *, int); /* balloc.c */ extern int ext2_bg_has_super(struct super_block *sb, int group); extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); extern int ext2_new_block (const struct inode *, unsigned long, __u32 *, __u32 *, int *); extern void ext2_free_blocks (const struct inode *, unsigned long, unsigned long); extern unsigned long ext2_count_free_blocks (struct super_block *); extern void ext2_check_blocks_bitmap (struct super_block *); extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh); /* bitmap.c */ extern unsigned long ext2_count_free (struct buffer_head *, unsigned); /* dir.c */ extern int ext2_check_dir_entry (const char *, struct inode *, struct ext2_dir_entry_2 *, struct buffer_head *, unsigned long); /* file.c */ extern int ext2_read (struct inode *, struct file *, char *, int); extern int ext2_write (struct inode *, struct file *, char *, int); /* fsync.c */ extern int ext2_sync_file (struct file *, struct dentry *, int); extern int ext2_fsync_inode (struct inode *, int); /* ialloc.c */ extern struct inode * ext2_new_inode (const struct inode *, int); extern void ext2_free_inode (struct inode *); extern unsigned long ext2_count_free_inodes (struct super_block *); extern void ext2_check_inodes_bitmap (struct super_block *); /* inode.c */ extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); extern void ext2_read_inode (struct inode *); extern void ext2_write_inode (struct inode *, int); extern void ext2_put_inode (struct inode *); extern void ext2_delete_inode (struct inode *); extern int ext2_sync_inode (struct inode *); extern void ext2_discard_prealloc (struct inode *); /* ioctl.c */ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, unsigned long); /* namei.c */ extern struct inode_operations ext2_dir_inode_operations; /* super.c */ extern void ext2_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern NORET_TYPE void ext2_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((NORET_AND format (printf, 3, 4))); extern void ext2_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext2_update_dynamic_rev (struct super_block *sb); extern void ext2_put_super (struct super_block *); extern void ext2_write_super (struct super_block *); extern int ext2_remount (struct super_block *, int *, char *); extern struct super_block * ext2_read_super (struct super_block *,void *,int); extern int ext2_statfs (struct super_block *, struct statfs *); /* truncate.c */ extern void ext2_truncate (struct inode *); /* * Inodes and files operations */ /* dir.c */ extern struct file_operations ext2_dir_operations; /* file.c */ extern struct inode_operations ext2_file_inode_operations; extern struct file_operations ext2_file_operations; /* symlink.c */ extern struct inode_operations ext2_fast_symlink_inode_operations; extern struct address_space_operations ext2_aops; #endif /* __KERNEL__ */ #endif /* _LINUX_EXT2_FS_H */ ./elilo/fs/ext2fs.h0000644000175000017500000000421607720452026013644 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __EXT2FS_H__ #define __EXT2FS_H__ INTERFACE_DECL(_ext2fs_interface_t); /* * simplified stat structure * XXX: need to cleanup types ! */ typedef struct { unsigned long st_ino; unsigned long st_nlink; unsigned int st_mode; unsigned int st_uid; unsigned int st_gid; unsigned long st_size; unsigned long st_atime; unsigned long st_mtime; unsigned long st_ctime; } ext2fs_stat_t; typedef struct _ext2fs_interface_t { EFI_STATUS (*ext2fs_name)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen); EFI_STATUS (*ext2fs_open)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN *fd); EFI_STATUS (*ext2fs_read)(struct _ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size); EFI_STATUS (*ext2fs_close)(struct _ext2fs_interface_t *this, UINTN fd); EFI_STATUS (*ext2fs_fstat)(struct _ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st); EFI_STATUS (*ext2fs_seek)(struct _ext2fs_interface_t *this, UINTN fd, UINT64 newpos); } ext2fs_interface_t; #define EXT2FS_PROTOCOL \ { 0x6ea924f6, 0xc9f2, 0x4331, {0x83, 0x54, 0x19, 0xd0, 0x17, 0x50, 0xd9, 0xc7} } extern EFI_STATUS ext2fs_install(VOID); extern EFI_STATUS ext2fs_uninstall(VOID); #endif /* __EXT2FS_H__ */ ./elilo/fs/netfs.h0000644000175000017500000000501407720452015013543 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __NETLFS_H__ #define __NETLFS_H__ #include #include #define NETFS_BOOTFILE_MAXLEN 256 typedef struct { EFI_IP_ADDRESS cln_ipaddr; EFI_IP_ADDRESS srv_ipaddr; EFI_IP_ADDRESS netmask; EFI_IP_ADDRESS gw_ipaddr; UINT8 hw_addr[16]; CHAR16 hostname[255]; /* 255 limitation of DHCP protocol */ CHAR16 domainame[255]; /* 255 limitation of DHCP protocol */ CHAR16 bootfile[NETFS_BOOTFILE_MAXLEN]; /* name of file downloaded (BOOTP/DHCP) */ BOOLEAN using_pxe; BOOLEAN started; BOOLEAN using_ipv6; } netfs_info_t; INTERFACE_DECL(_netfs_interface_t); typedef struct _netfs_interface_t { EFI_STATUS (*netfs_name)(struct _netfs_interface_t *this, CHAR16 *name, UINTN maxlen); EFI_STATUS (*netfs_open)(struct _netfs_interface_t *this, CHAR16 *name, UINTN *fd); EFI_STATUS (*netfs_read)(struct _netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size); EFI_STATUS (*netfs_close)(struct _netfs_interface_t *this, UINTN fd); EFI_STATUS (*netfs_infosize)(struct _netfs_interface_t *this, UINTN fd, UINT64 *size); EFI_STATUS (*netfs_seek)(struct _netfs_interface_t *this, UINTN fd, UINT64 newpos); EFI_STATUS (*netfs_query_layer)(struct _netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str); EFI_STATUS (*netfs_getinfo)(struct _netfs_interface_t *this, netfs_info_t *info); } netfs_interface_t; #define NETFS_PROTOCOL \ { 0x6746de4f, 0xcc1e, 0x4c5f, {0xb7, 0xfb, 0x85, 0x6a, 0x5d, 0x69, 0x0f, 0x06} } extern EFI_STATUS netfs_install(VOID); extern EFI_STATUS netfs_uninstall(VOID); #endif /* __NETFS_H__ */ ./elilo/fs/ext2_fs_i.h0000644000175000017500000000157407316156505014323 0ustar jasonfjasonf/* * linux/include/linux/ext2_fs_i.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/include/linux/minix_fs_i.h * * Copyright (C) 1991, 1992 Linus Torvalds */ #ifndef _LINUX_EXT2_FS_I #define _LINUX_EXT2_FS_I /* * second extended file system inode data in memory */ struct ext2_inode_info { __u32 i_data[15]; __u32 i_flags; __u32 i_faddr; __u8 i_frag_no; __u8 i_frag_size; __u16 i_osync; __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */ __u32 i_block_group; __u32 i_next_alloc_block; __u32 i_next_alloc_goal; __u32 i_prealloc_block; __u32 i_prealloc_count; __u32 i_high_size; int i_new_inode:1; /* Is a freshly allocated inode */ }; #endif /* _LINUX_EXT2_FS_I */ ./elilo/fs/netfs.c0000644000175000017500000005636411271404161013547 0ustar jasonfjasonf/* * Copyright (C) 2001-2009 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Jason Fleischli * 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 * 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 #include #include "fs/netfs.h" #include "elilo.h" #define FS_NAME L"netfs" #define NETFS_DEFAULT_BUFSIZE 16*MB #define NETFS_DEFAULT_BUFSIZE_INC 8*MB #define NETFS_DEFAULT_BLOCKSIZE 1024 /* setting to zero is supposed to default the underlying */ /* pxe implementation to largest blocksize supported,... */ /* in reality on original older efi implementations its */ /* never set causing the pxe transfer to timeout. */ /* the spec defines the minimum supported blocksize default */ /* to be 512 bytes... a bit extreme, 1024 should work for */ /* everything */ #define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP #define NETFS_FD_MAX 2 typedef struct _netfs_fd { struct _netfs_fd *next; CHAR8 *netbuf; UINT64 netbuf_maxsize; /* currently allocated buffer */ UINTN netbuf_size; /* number of bytes currently used in the buffer */ UINT64 netbuf_pos; /* current position in the buffer */ BOOLEAN is_valid; /* avoid conflicting opens */ BOOLEAN netbuf_reuse; CHAR16 last_file[FILENAME_MAXLEN]; } netfs_fd_t; typedef struct { EFI_PXE_BASE_CODE *pxe; EFI_HANDLE dev; /* handle to device we're attached to */ BOOLEAN using_pxe; /* true if downloaded using the PXE protocol vs. regular DHCP */ EFI_IP_ADDRESS srv_ip; EFI_IP_ADDRESS cln_ip; EFI_IP_ADDRESS gw_ip; EFI_IP_ADDRESS netmask; UINT8 hw_addr[16]; netfs_fd_t fd_tab[NETFS_FD_MAX]; netfs_fd_t *free_fd; UINTN free_fd_count; } netfs_priv_state_t; #define NETFS_F2FD(l,f) (UINTN)((f)-(l)->fd_tab) #define NETFS_FD2F(l,fd) ((l)->fd_tab+fd) #define NETFS_F_INVALID(f) ((f)->is_valid == FALSE) typedef union { netfs_interface_t pub_intf; struct { netfs_interface_t pub_intf; netfs_priv_state_t priv_data; } netfs_priv; } netfs_t; #define FS_PRIVATE(n) (&(((netfs_t *)n)->netfs_priv.priv_data)) typedef union { EFI_HANDLE *dev; netfs_t *intf; } dev_tab_t; static dev_tab_t *dev_tab; /* holds all devices we found */ static UINTN ndev; /* how many entries in dev_tab */ static EFI_GUID NetFsProtocol = NETFS_PROTOCOL; #if 0 static EFI_PXE_BASE_CODE_CALLBACK_STATUS netfs_callback_func( IN EFI_PXE_BASE_CODE_CALLBACK *this, IN EFI_PXE_BASE_CODE_FUNCTION function, IN BOOLEAN received, IN UINT32 packet_len, IN EFI_PXE_BASE_CODE_PACKET *packet OPTIONAL ) { Print(L"netfs_callback called received=%d packet_len=%d\n", received, packet_len); return EFI_ABORTED; } static EFI_PXE_BASE_CODE_CALLBACK netfs_callback = { EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION, &netfs_callback_func }; #endif static netfs_fd_t * netfs_fd_alloc(netfs_priv_state_t *nfs, CHAR16 *name) { netfs_fd_t *tmp = NULL, *prev = NULL, *match; UINT8 netbuf_reuse = 0; if (nfs->free_fd == NULL) { ERR_PRT((L"out of file descriptor")); return NULL; } match = nfs->free_fd; for (tmp = nfs->free_fd; tmp; tmp = tmp->next) { if (!StrCmp(name, tmp->last_file)) { DBG_PRT((L"Using cached file %s netbuf_size=%d", tmp->last_file, tmp->netbuf_size)); netbuf_reuse = 1; match = tmp; break; } prev = tmp; } /* indicate whether or not we got a match in caching */ match->netbuf_reuse = netbuf_reuse; if (match == nfs->free_fd) nfs->free_fd = match->next; else prev->next = match->next; nfs->free_fd_count--; return match; } static VOID netfs_fd_free(netfs_priv_state_t *nfs, netfs_fd_t *f) { if (f == NULL) { ERR_PRT((L"invalid fd")); return; } f->next = nfs->free_fd; /* we keep the netbuf, in case we can reuse it */ f->is_valid = FALSE; nfs->free_fd = f; nfs->free_fd_count++; if (nfs->free_fd_count > NETFS_FD_MAX) { ERR_PRT((L"too many free descriptors %d", nfs->free_fd_count)); } } static INTN netbuf_alloc(netfs_fd_t *f) { /* we will try to reuse the existing buffer first */ if (f->netbuf != 0) return 0; f->netbuf_pos = 0; f->netbuf = (CHAR8 *)alloc_pages(EFI_SIZE_TO_PAGES(f->netbuf_maxsize), EfiLoaderData, AllocateAnyPages, 0); return f->netbuf == 0 ? -1 : 0; } static EFI_STATUS netfs_name(netfs_interface_t *this, CHAR16 *name, UINTN maxlen) { if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; StrnCpy(name, FS_NAME, maxlen-1); name[maxlen-1] = CHAR_NULL; return EFI_SUCCESS; } static VOID netfs_extract_ip(netfs_priv_state_t *nfs) { EFI_PXE_BASE_CODE *pxe = nfs->pxe; if (pxe->Mode->PxeDiscoverValid) { nfs->using_pxe = TRUE; Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); Memcpy(&nfs->hw_addr, pxe->Mode->PxeReply.Dhcpv4.BootpHwAddr, 16*sizeof(UINT8)); } else { Memcpy(&nfs->srv_ip, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); Memcpy(&nfs->hw_addr, pxe->Mode->DhcpAck.Dhcpv4.BootpHwAddr, sizeof(nfs->hw_addr)); } Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS)); Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS)); /* * the fact that we use index 0, is just a guess */ if (pxe->Mode->RouteTableEntries>0) Memcpy(&nfs->gw_ip, &pxe->Mode->RouteTable[0].GwAddr, sizeof(EFI_IP_ADDRESS)); VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)\n" : L"No (Regular DHCPD)\n")); #if 0 status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback); status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL); Print(L"PXE Callback support : %r\n", status); if (status == EFI_SUCCESS) { BOOLEAN doit = TRUE; status = pxe->SetParameters(pxe, NULL, NULL, NULL, NULL, &doit); Print(L"PXE Callback SetParameters: %r\n", status); } #endif /* * XXX: TFTPD server not quite right when using PXE, need to extract bootservers... */ VERB_PRT(1, Print(L"Local IP: %d.%d.%d.%d\n", pxe->Mode->StationIp.v4.Addr[0] & 0xff, pxe->Mode->StationIp.v4.Addr[1] & 0xff, pxe->Mode->StationIp.v4.Addr[2] & 0xff, pxe->Mode->StationIp.v4.Addr[3] & 0xff)); VERB_PRT(1, Print(L"SM: %d.%d.%d.%d\n", pxe->Mode->SubnetMask.v4.Addr[0] & 0xff, pxe->Mode->SubnetMask.v4.Addr[1] & 0xff, pxe->Mode->SubnetMask.v4.Addr[2] & 0xff, pxe->Mode->SubnetMask.v4.Addr[3] & 0xff)); VERB_PRT(1, Print(L"TFTPD IP: %d.%d.%d.%d\n", nfs->srv_ip.v4.Addr[0] & 0xff, nfs->srv_ip.v4.Addr[1] & 0xff, nfs->srv_ip.v4.Addr[2] & 0xff, nfs->srv_ip.v4.Addr[3] & 0xff)); VERB_PRT(1, Print(L"Gateway IP: %d.%d.%d.%d\n", nfs->gw_ip.v4.Addr[0] & 0xff, nfs->gw_ip.v4.Addr[1] & 0xff, nfs->gw_ip.v4.Addr[2] & 0xff, nfs->gw_ip.v4.Addr[3] & 0xff)); } static EFI_STATUS netfs_start(EFI_PXE_BASE_CODE *pxe) { EFI_STATUS status; status = uefi_call_wrapper(pxe->Start, 2, pxe, FALSE); if (EFI_ERROR(status)) return status; return pxe->Dhcp(pxe, FALSE); } static EFI_STATUS netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd) { netfs_priv_state_t *nfs; netfs_fd_t *f; EFI_STATUS status; CHAR8 ascii_name[FILENAME_MAXLEN]; UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE; UINTN prev_netbufsize, retries = 0; BOOLEAN server_provided_filesize = FALSE; if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); if (nfs->pxe == NULL) return EFI_INVALID_PARAMETER; /* * Try to start protocol if not already active */ if (nfs->pxe->Mode->Started == FALSE) { status = netfs_start(nfs->pxe); if (EFI_ERROR(status)) return status; netfs_extract_ip(nfs); } if ((f=netfs_fd_alloc(nfs, name)) == NULL) return EFI_OUT_OF_RESOURCES; if (f->netbuf_reuse) { f->netbuf_pos = 0; f->is_valid = TRUE; *fd = NETFS_F2FD(nfs, f); return EFI_SUCCESS; } f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE; f->netbuf_size = 0; if (f->netbuf == NULL && netbuf_alloc(f) == -1) { netfs_fd_free(nfs, f); return EFI_OUT_OF_RESOURCES; } /* well, we need to download ! */ U2ascii(name, ascii_name, FILENAME_MAXLEN); VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...\n", ascii_name, nfs->srv_ip.v4.Addr[0], nfs->srv_ip.v4.Addr[1], nfs->srv_ip.v4.Addr[2], nfs->srv_ip.v4.Addr[3])); retry: if (retries == 2) { netfs_fd_free(nfs, f); VERB_PRT(2, Print(L"Failed: %r\n", status)); return status; } /* * netboot bugfix SF tracker 2874380 * EFI 1.10 spec * For read operations, the return data will be placed in the buffer specified by BufferPtr. If * BufferSize is too small to contain the entire downloaded file, then * EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero or the size of * the requested file (the size of the requested file is only returned if the TFTP server supports TFTP * options). If BufferSize is large enough for the read operation, then BufferSize will be set to * the size of the downloaded file, and EFI_SUCCESS will be returned. Applications using the * PxeBc.Mtftp() services should use the get-file-size operations to determine the size of the * downloaded file prior to using the read-file operations—especially when downloading large * (greater than 64 MB) files—instead of making two calls to the read-file operation. Following this * recommendation will save time if the file is larger than expected and the TFTP server does not * support TFTP option extensions. Without TFTP option extension support, the client has to * download the entire file, counting and discarding the received packets, to determine the file size. * ... * For TFTP “get file size†operations, the size of the requested file or directory is returned in * BufferSize, and EFI_SUCCESS will be returned. If the TFTP server does not support options, * the file will be downloaded into a bit bucket and the length of the downloaded file will be returned. */ status = uefi_call_wrapper(nfs->pxe->Mtftp, 10, nfs->pxe, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, f->netbuf, FALSE, &(f->netbuf_size), // PXE writes size of file from server here &blocksize, &nfs->srv_ip, ascii_name, NULL, FALSE); /* * If options are not supported by this tftp server, according to the spec the file will be * downloaded into a bit bucket, the size calculated by efi fw and returned in the status * field of this call. YUK!!... in this case we will default to currently allocated max * if thats still not big enough it will be caught and increased following the read file attempt * then retried. * XXX need to research how this is handled or changed in the latest UEFI spec. */ if (status != EFI_SUCCESS) { f->netbuf_size = f->netbuf_maxsize; VERB_PRT(2, Print(L"setting default buffer size of %d for %a, no filesize recd from tftp server\n", f->netbuf_size, ascii_name)); } if (status == EFI_SUCCESS) { server_provided_filesize = TRUE; VERB_PRT(2, Print(L"received file size of %d for %a from tftp server.\n", f->netbuf_size, ascii_name)); } if (f->netbuf_size > f->netbuf_maxsize) { // we need a bigger buffer VERB_PRT(2, Print(L"allocated buffer too small, attempting to increase\n")); f->netbuf_maxsize += f->netbuf_size; free(f->netbuf); f->netbuf = NULL; if (netbuf_alloc(f) == -1) return EFI_OUT_OF_RESOURCES; } /* paranoid catch any corner case missed */ if (f->netbuf_size == 0) f->netbuf_size = f->netbuf_maxsize; DBG_PRT((L"\nbefore read: netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n", f->netbuf, f->netbuf_size, blocksize)); prev_netbufsize = f->netbuf_size; /* now try and download this file from the tftp server */ status = uefi_call_wrapper(nfs->pxe->Mtftp, 10, nfs->pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, f->netbuf, FALSE, &(f->netbuf_size), &blocksize, &nfs->srv_ip, ascii_name, NULL, FALSE); DBG_PRT((L"after: status=%r netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n", status, f->netbuf, f->netbuf_size, blocksize)); if ((status == EFI_TIMEOUT || status == EFI_BUFFER_TOO_SMALL) && !server_provided_filesize) { Print(L"buffer too small, need netbuf_size=%d\n", f->netbuf_size); /* * if the TFTP server supports TFTP options, then we should * get the required size. So we test to see if the size * we set has changed. If so, we got the required size. * If not, we increase the buffer size and retry. */ if (f->netbuf_size == prev_netbufsize) { f->netbuf_maxsize += NETFS_DEFAULT_BUFSIZE_INC; } else { /* we got an answer from the TFTP server, let's try it */ f->netbuf_maxsize = f->netbuf_size; server_provided_filesize = TRUE; } free(f->netbuf); f->netbuf = NULL; /* will force reallocation */ if (netbuf_alloc(f) == 0) { retries++; goto retry; } } else if (status == EFI_TIMEOUT) { //if just a simple timeout, buffers are good just retry VERB_PRT(2, Print(L"TFTP returned EFI_TIMEOUT ERROR... %d retries left.\n", (2 - retries))); retries++; goto retry; } if (status == EFI_SUCCESS) { /* start at the beginning of the file */ f->netbuf_pos = 0; /* cache file name */ StrCpy(f->last_file, name); f->is_valid = 1; *fd = NETFS_F2FD(nfs, f); VERB_PRT(2, Print(L"Done\n")); } else { netfs_fd_free(nfs, f); VERB_PRT(2, Print(L"Failed: %r\n", status)); } DBG_PRT((L"File %s netbuf_size=%d: %r", name, f->netbuf_size, status)); #if 0 Print(L"\n---\n"); { INTN i; for(i=0; i < netbuf_size; i++) { Print(L"%c", (CHAR16)netbuf[i]); } } Print(L"\n---\n"); #endif return status; } static EFI_STATUS netfs_read(netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size) { netfs_priv_state_t *nfs; netfs_fd_t *f; UINTN count; if (this == NULL || fd >= NETFS_FD_MAX || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); f = NETFS_FD2F(nfs, fd); if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER; count = MIN(*size, f->netbuf_size - f->netbuf_pos); if (count) Memcpy(buf, f->netbuf+f->netbuf_pos, count); *size = count; f->netbuf_pos += count; return EFI_SUCCESS; } static EFI_STATUS netfs_close(netfs_interface_t *this, UINTN fd) { netfs_priv_state_t *nfs; netfs_fd_t *f; if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); f = NETFS_FD2F(nfs, fd); if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER; netfs_fd_free(nfs, f); return EFI_SUCCESS; } static EFI_STATUS netfs_seek(netfs_interface_t *this, UINTN fd, UINT64 newpos) { netfs_priv_state_t *nfs; netfs_fd_t *f; if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); f = NETFS_FD2F(nfs, fd); if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER; if (newpos > f->netbuf_size) return EFI_INVALID_PARAMETER; f->netbuf_pos = newpos; return EFI_SUCCESS; } static EFI_STATUS netfs_infosize(netfs_interface_t *this, UINTN fd, UINT64 *sz) { netfs_priv_state_t *nfs; netfs_fd_t *f; if (this == NULL || fd >= NETFS_FD_MAX || sz == NULL) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); f = NETFS_FD2F(nfs, fd); if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER; *sz = f->netbuf_size; return EFI_SUCCESS; } static INTN find_dhcp_option(EFI_PXE_BASE_CODE_PACKET *packet, UINT8 use_ipv6, UINT8 option, CHAR8 *str, INTN *len) { INTN i = 0; UINT8 tag, length; UINT8 *opts = packet->Dhcpv4.DhcpOptions; *len = 0; for(;;) { if (i >= 56) { DBG_PRT((L"reach end of options (no marker)\n")); break; } tag = opts[i++]; if (tag == 0) continue; if (tag == 255) break; length = opts[i++]; #if 0 { UINT8 l = length, k = 0; Print(L"found option %d len=%d: ", tag, length); while (l--) { Print(L"%c(%d)\n", (CHAR16)opts[k], opts[k]); k++; } Print(L"\n"); } #endif if (tag == option) { *len = length; while (length--) { *str++ = opts[i++]; } return 0; } i += length; } return -1; } static EFI_STATUS netfs_getinfo(netfs_interface_t *this, netfs_info_t *info) { netfs_priv_state_t *nfs; CHAR8 str[256]; INTN len, r; if (this == NULL || info == NULL) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); Memcpy(&info->cln_ipaddr, &nfs->cln_ip, sizeof(EFI_IP_ADDRESS)); Memcpy(&info->srv_ipaddr, &nfs->srv_ip, sizeof(EFI_IP_ADDRESS)); Memcpy(&info->netmask, &nfs->netmask, sizeof(EFI_IP_ADDRESS)); Memcpy(&info->gw_ipaddr, &nfs->gw_ip, sizeof(EFI_IP_ADDRESS)); Memcpy(&info->hw_addr, &nfs->hw_addr, sizeof(info->hw_addr)); info->using_pxe = nfs->using_pxe; info->started = nfs->pxe->Mode->Started; info->using_ipv6 = nfs->pxe->Mode->UsingIpv6; if (nfs->pxe->Mode->UsingIpv6) goto skip_options; r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 15, str, &len); str[len] = '\0'; ascii2U(str, info->domainame, 255); VERB_PRT(3, Print(L"domain(15): %a\n", str)); r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 12, str, &len); str[len] = '\0'; ascii2U(str, info->hostname, 255); VERB_PRT(3, Print(L"hostname(12): %a\n", str)); /* * extract bootfile name from DHCP exchanges */ if (nfs->using_pxe == 0) { ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN); VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile)); } skip_options: return EFI_SUCCESS; } static UINT16 find_pxe_server_type(EFI_PXE_BASE_CODE *pxe) { INTN i = 0, max; UINT8 tag, length; UINT8 *opts = pxe->Mode->PxeReply.Dhcpv4.DhcpOptions; UINT16 server_type; while(i < 55) { tag = opts[i]; length = opts[i+1]; DBG_PRT((L"Tag #%d Length %d\n",tag, length)); if (tag == 43) goto found; i += 2 + length; } return NETFS_DEFAULT_SERVER_TYPE; found: max = i+2+length; i += 2; while (i < max) { tag = opts[i]; length = opts[i+1]; if (tag == 71) { server_type =(opts[i+2]<<8) | opts[i+3]; DBG_PRT((L"ServerType: %d\n", server_type)); return server_type; } i+= 2 + length; } return NETFS_DEFAULT_SERVER_TYPE; } static EFI_STATUS netfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str) { netfs_priv_state_t *nfs; EFI_STATUS status; if (this == NULL || str == NULL) return EFI_INVALID_PARAMETER; nfs = FS_PRIVATE(this); if (nfs->using_pxe == FALSE) return EFI_UNSUPPORTED; if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe); status = uefi_call_wrapper(nfs->pxe->Discover, 5, nfs->pxe, server_type, &layer, FALSE, 0); if(status == EFI_SUCCESS) { ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen); } return status; } static VOID netfs_init_state(netfs_t *netfs, EFI_HANDLE dev, EFI_PXE_BASE_CODE *pxe) { netfs_priv_state_t *nfs = FS_PRIVATE(netfs); UINTN i; /* need to do some init here on netfs_intf */ Memset(netfs, 0, sizeof(*netfs)); netfs->pub_intf.netfs_name = netfs_name; netfs->pub_intf.netfs_open = netfs_open; netfs->pub_intf.netfs_read = netfs_read; netfs->pub_intf.netfs_close = netfs_close; netfs->pub_intf.netfs_infosize = netfs_infosize; netfs->pub_intf.netfs_seek = netfs_seek; netfs->pub_intf.netfs_query_layer = netfs_query_layer; netfs->pub_intf.netfs_getinfo = netfs_getinfo; nfs->dev = dev; nfs->pxe = pxe; /* * we defer DHCP request until it is really necessary (netfs_open) */ if (pxe->Mode->Started == TRUE) netfs_extract_ip(nfs); Memset(nfs->fd_tab, 0, sizeof(nfs->fd_tab)); for (i=0; i < NETFS_FD_MAX-1; i++) { nfs->fd_tab[i].next = &nfs->fd_tab[i+1]; } /* null on last element is done by memset */ nfs->free_fd = nfs->fd_tab; nfs->free_fd_count = NETFS_FD_MAX; } static EFI_STATUS netfs_install_one(EFI_HANDLE dev, VOID **intf) { EFI_STATUS status; netfs_t *netfs; EFI_PXE_BASE_CODE *pxe; status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &NetFsProtocol, (VOID **)&netfs); if (status == EFI_SUCCESS) { ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME)); goto found; } status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &PxeBaseCodeProtocol, (VOID **)&pxe); if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER; netfs = (netfs_t *)alloc(sizeof(*netfs), EfiLoaderData); if (netfs == NULL) { ERR_PRT((L"failed to allocate %s", FS_NAME)); return EFI_OUT_OF_RESOURCES; } netfs_init_state(netfs, dev, pxe); status = LibInstallProtocolInterfaces(&dev, &NetFsProtocol, netfs, NULL); if (EFI_ERROR(status)) { ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status)); free(netfs); return status; } found: if (intf) *intf = (VOID *)netfs; VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(dev); str = DevicePathToStr(dp); Print(L"attached %s to %s\n", FS_NAME, str); FreePool(str); }); return EFI_SUCCESS; } EFI_STATUS netfs_install(VOID) { UINTN size = 0; UINTN i; EFI_STATUS status; VOID *intf; uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL); if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */ DBG_PRT((L"size=%d", size)); dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData); if (dev_tab == NULL) { ERR_PRT((L"failed to allocate handle table")); return EFI_OUT_OF_RESOURCES; } status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab); if (status != EFI_SUCCESS) { ERR_PRT((L"failed to get handles: %r", status)); free(dev_tab); return status; } ndev = size / sizeof(EFI_HANDLE); for(i=0; i < ndev; i++) { intf = NULL; netfs_install_one(dev_tab[i].dev, &intf); /* override device handle with interface pointer */ dev_tab[i].intf = intf; } return EFI_SUCCESS; } EFI_STATUS netfs_uninstall(VOID) { netfs_priv_state_t *nfs; EFI_STATUS status; UINTN i; for(i=0; i < ndev; i++) { if (dev_tab[i].intf == NULL) continue; nfs = FS_PRIVATE(dev_tab[i].intf); status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, nfs->dev, &NetFsProtocol, dev_tab[i].intf); if (EFI_ERROR(status)) { ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status)); continue; } VERB_PRT(3, { EFI_DEVICE_PATH *dp; CHAR16 *str; dp = DevicePathFromHandle(nfs->dev); str = DevicePathToStr(dp); Print(L"uninstalled %s on %s\n", FS_NAME, str); FreePool(str); }); if (nfs->pxe->Mode->Started == TRUE) uefi_call_wrapper(nfs->pxe->Stop, 1, nfs->pxe); free(dev_tab[i].intf); } if (dev_tab) free(dev_tab); return EFI_SUCCESS; } ./elilo/gunzip.c0000644000175000017500000001225210343667143013332 0ustar jasonfjasonf/* * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. * Contributed by Alex Williamson * * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 #include #include "elilo.h" #include "gzip.h" #define LD_NAME L"gunzip" #define memzero(s, n) Memset((VOID *)(s), 0, (n)) #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) /* size of output buffer */ #define WSIZE 0x8000 /* Window size must be at least 32k, */ /* and a power of two */ /* * gzip declarations */ #define OF(args) args #define FUNC_STATIC static typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; /* * static parameters to gzip helper functions * we cannot use paramters because API was not * designed that way */ static uch *inbuf; /* input buffer (compressed data) */ static uch *window; /* output buffer (uncompressed data) */ static VOID *outbuf; unsigned char *outptr; static unsigned long outsize; static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ #define get_byte() inbuf[inptr++] /* Diagnostic functions */ #ifdef INFLATE_DEBUG # define Assert(cond,msg) {if(!(cond)) error(msg);} int stderr; # define Trace(x) Print(L"line %d:\n", __LINE__); # define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;} # define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;} # define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;} # define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif static void flush_window(void); static void error(char *m); static long bytes_out; static void error(char *m); #define gzip_malloc(size) (void *)alloc(size, 0) #define gzip_free(where) free(where) #include "inflate.c" /* * Run a set of bytes through the crc shift register. If s is a NULL * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. * * Input: * S pointer to bytes to pump through. * N number of bytes in S[]. */ static void updcrc(unsigned char *s, unsigned n) { register unsigned long c; /* crc is defined in inflate.c */ c = crc; while (n--) { c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } crc = c; return; } /* * Clear input and output buffers */ static void clear_bufs(void) { outcnt = 0; inptr = 0; } /* * Write the output window window[0..outcnt-1] holding uncompressed * data and update crc. */ void flush_window(void) { /* * We'll end up relying on the CRC check and size check failing * if there's actually more data than we expect. */ if (!outcnt || bytes_out + outcnt > outsize) return; updcrc(window, outcnt); Memcpy(outptr, window, outcnt); outptr += outcnt; bytes_out += outcnt; outcnt = 0; } static void error(char *x) { ERR_PRT((L"%s : %a", LD_NAME, x)); /* will eventually exit with error from gunzip() */ } static INT32 decompress(VOID) { INT32 ret; clear_bufs(); makecrc(); Print(L"Uncompressing... "); ret = gunzip(); if (ret == 0) Print(L"done\n"); return ret == 0 ? 0 : -1; } int gunzip_image(memdesc_t *image) { UINTN pgcnt; inbuf = image->start_addr; /* * Last 4 bytes of gzip'd image indicates the uncompressed size */ outsize = inbuf[image->size - 1] << 24 | inbuf[image->size - 2] << 16 | inbuf[image->size - 3] << 8 | inbuf[image->size - 4]; pgcnt = EFI_SIZE_TO_PAGES(outsize); outbuf = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, 0); if (outbuf == NULL) { ERR_PRT((L"%s : allocate output buffer failed\n", LD_NAME)); return -1; } outptr = outbuf; window = (void *)alloc(WSIZE, 0); if (window == NULL) { ERR_PRT((L"%s : allocate output window failed\n", LD_NAME)); free(outbuf); return -1; } bytes_out = 0; if (decompress() != 0) { free(window); free(outbuf); return ELILO_LOAD_ERROR; } free(window); free(image->start_addr); image->start_addr = outbuf; image->size = outsize; image->pgcnt = pgcnt; return ELILO_LOAD_SUCCESS; } ./elilo/elf.h0000644000175000017500000004206710650210516012565 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. * * Portions of this file are derived from the LILO/x86 * Copyright 1992-1997 Werner Almesberger. */ #ifndef __LINUX_ELF_H__ #define __LINUX_ELF_H__ /* * This file was derived from . */ #include /* 32-bit ELF base types. */ typedef UINT32 Elf32_Addr; typedef UINT16 Elf32_Half; typedef UINT32 Elf32_Off; typedef INT32 Elf32_Sword; typedef UINT32 Elf32_Word; /* 64-bit ELF base types. */ typedef UINT64 Elf64_Addr; typedef UINT16 Elf64_Half; typedef INT16 Elf64_SHalf; typedef UINT64 Elf64_Off; typedef INT64 Elf64_Sword; typedef UINT64 Elf64_Word; /* These constants are for the segment types stored in the image headers */ #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff #define PT_MIPS_REGINFO 0x70000000 /* Flags in the e_flags field of the header */ #define EF_MIPS_NOREORDER 0x00000001 #define EF_MIPS_PIC 0x00000002 #define EF_MIPS_CPIC 0x00000004 #define EF_MIPS_ARCH 0xf0000000 /* These constants define the different elf file types */ #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 #define ET_LOPROC 0xff00 #define ET_HIPROC 0xffff /* These constants define the various ELF target machines */ #define EM_NONE 0 #define EM_M32 1 #define EM_SPARC 2 #define EM_386 3 #define EM_68K 4 #define EM_88K 5 #define EM_486 6 /* Perhaps disused */ #define EM_860 7 #define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ #define EM_PARISC 15 /* HPPA */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_PPC 20 /* PowerPC */ #define EM_SH 42 /* SuperH */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_IA_64 50 /* HP/Intel IA-64 */ #define EM_X86_64 62 /* Intel/AMD x86-64 */ /* * This is an interim value that we will use until the committee comes * up with a final number. */ #define EM_ALPHA 0x9026 /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 #define DT_PLTRELSZ 2 #define DT_PLTGOT 3 #define DT_HASH 4 #define DT_STRTAB 5 #define DT_SYMTAB 6 #define DT_RELA 7 #define DT_RELASZ 8 #define DT_RELAENT 9 #define DT_STRSZ 10 #define DT_SYMENT 11 #define DT_INIT 12 #define DT_FINI 13 #define DT_SONAME 14 #define DT_RPATH 15 #define DT_SYMBOLIC 16 #define DT_REL 17 #define DT_RELSZ 18 #define DT_RELENT 19 #define DT_PLTREL 20 #define DT_DEBUG 21 #define DT_TEXTREL 22 #define DT_JMPREL 23 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff #define DT_MIPS_RLD_VERSION 0x70000001 #define DT_MIPS_TIME_STAMP 0x70000002 #define DT_MIPS_ICHECKSUM 0x70000003 #define DT_MIPS_IVERSION 0x70000004 #define DT_MIPS_FLAGS 0x70000005 # define RHF_NONE 0 # define RHF_HARDWAY 1 # define RHF_NOTPOT 2 #define DT_MIPS_BASE_ADDRESS 0x70000006 #define DT_MIPS_CONFLICT 0x70000008 #define DT_MIPS_LIBLIST 0x70000009 #define DT_MIPS_LOCAL_GOTNO 0x7000000a #define DT_MIPS_CONFLICTNO 0x7000000b #define DT_MIPS_LIBLISTNO 0x70000010 #define DT_MIPS_SYMTABNO 0x70000011 #define DT_MIPS_UNREFEXTNO 0x70000012 #define DT_MIPS_GOTSYM 0x70000013 #define DT_MIPS_HIPAGENO 0x70000014 #define DT_MIPS_RLD_MAP 0x70000016 /* This info is needed when parsing the symbol table */ #define STB_LOCAL 0 #define STB_GLOBAL 1 #define STB_WEAK 2 #define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 #define ELF32_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) /* Symbolic values for the entries in the auxiliary table put on the initial stack */ #define AT_NULL 0 /* end of vector */ #define AT_IGNORE 1 /* entry should be ignored */ #define AT_EXECFD 2 /* file descriptor of program */ #define AT_PHDR 3 /* program headers for program */ #define AT_PHENT 4 /* size of program header entry */ #define AT_PHNUM 5 /* number of program headers */ #define AT_PAGESZ 6 /* system page size */ #define AT_BASE 7 /* base address of interpreter */ #define AT_FLAGS 8 /* flags */ #define AT_ENTRY 9 /* entry point of program */ #define AT_NOTELF 10 /* program is not ELF */ #define AT_UID 11 /* real uid */ #define AT_EUID 12 /* effective uid */ #define AT_GID 13 /* real gid */ #define AT_EGID 14 /* effective gid */ #define AT_PLATFORM 15 /* string identifying CPU for optimizations */ #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ typedef struct dynamic{ Elf32_Sword d_tag; union{ Elf32_Sword d_val; Elf32_Addr d_ptr; } d_un; } Elf32_Dyn; typedef struct { Elf64_Word d_tag; /* entry tag value */ union { Elf64_Word d_val; Elf64_Word d_ptr; } d_un; } Elf64_Dyn; /* The following are used with relocations */ #define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_TYPE(x) ((x) & 0xff) #define R_386_NONE 0 #define R_386_32 1 #define R_386_PC32 2 #define R_386_GOT32 3 #define R_386_PLT32 4 #define R_386_COPY 5 #define R_386_GLOB_DAT 6 #define R_386_JMP_SLOT 7 #define R_386_RELATIVE 8 #define R_386_GOTOFF 9 #define R_386_GOTPC 10 #define R_386_NUM 11 #define R_MIPS_NONE 0 #define R_MIPS_16 1 #define R_MIPS_32 2 #define R_MIPS_REL32 3 #define R_MIPS_26 4 #define R_MIPS_HI16 5 #define R_MIPS_LO16 6 #define R_MIPS_GPREL16 7 #define R_MIPS_LITERAL 8 #define R_MIPS_GOT16 9 #define R_MIPS_PC16 10 #define R_MIPS_CALL16 11 #define R_MIPS_GPREL32 12 /* The remaining relocs are defined on Irix, although they are not in the MIPS ELF ABI. */ #define R_MIPS_UNUSED1 13 #define R_MIPS_UNUSED2 14 #define R_MIPS_UNUSED3 15 #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 /* * The following two relocation types are specified in the the MIPS ABI * conformance guide version 1.2 but not yet in the psABI. */ #define R_MIPS_GOTHI16 22 #define R_MIPS_GOTLO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 /* * The following two relocation types are specified in the the MIPS ABI * conformance guide version 1.2 but not yet in the psABI. */ #define R_MIPS_CALLHI16 30 #define R_MIPS_CALLLO16 31 /* * This range is reserved for vendor specific relocations. */ #define R_MIPS_LOVENDOR 100 #define R_MIPS_HIVENDOR 127 /* * Sparc ELF relocation types */ #define R_SPARC_NONE 0 #define R_SPARC_8 1 #define R_SPARC_16 2 #define R_SPARC_32 3 #define R_SPARC_DISP8 4 #define R_SPARC_DISP16 5 #define R_SPARC_DISP32 6 #define R_SPARC_WDISP30 7 #define R_SPARC_WDISP22 8 #define R_SPARC_HI22 9 #define R_SPARC_22 10 #define R_SPARC_13 11 #define R_SPARC_LO10 12 #define R_SPARC_GOT10 13 #define R_SPARC_GOT13 14 #define R_SPARC_GOT22 15 #define R_SPARC_PC10 16 #define R_SPARC_PC22 17 #define R_SPARC_WPLT30 18 #define R_SPARC_COPY 19 #define R_SPARC_GLOB_DAT 20 #define R_SPARC_JMP_SLOT 21 #define R_SPARC_RELATIVE 22 #define R_SPARC_UA32 23 #define R_SPARC_PLT32 24 #define R_SPARC_HIPLT22 25 #define R_SPARC_LOPLT10 26 #define R_SPARC_PCPLT32 27 #define R_SPARC_PCPLT22 28 #define R_SPARC_PCPLT10 29 #define R_SPARC_10 30 #define R_SPARC_11 31 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_7 43 #define R_SPARC_5 44 #define R_SPARC_6 45 /* Bits present in AT_HWCAP, primarily for Sparc32. */ #define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ #define HWCAP_SPARC_STBAR 2 #define HWCAP_SPARC_SWAP 4 #define HWCAP_SPARC_MULDIV 8 #define HWCAP_SPARC_V9 16 /* * 68k ELF relocation types */ #define R_68K_NONE 0 #define R_68K_32 1 #define R_68K_16 2 #define R_68K_8 3 #define R_68K_PC32 4 #define R_68K_PC16 5 #define R_68K_PC8 6 #define R_68K_GOT32 7 #define R_68K_GOT16 8 #define R_68K_GOT8 9 #define R_68K_GOT32O 10 #define R_68K_GOT16O 11 #define R_68K_GOT8O 12 #define R_68K_PLT32 13 #define R_68K_PLT16 14 #define R_68K_PLT8 15 #define R_68K_PLT32O 16 #define R_68K_PLT16O 17 #define R_68K_PLT8O 18 #define R_68K_COPY 19 #define R_68K_GLOB_DAT 20 #define R_68K_JMP_SLOT 21 #define R_68K_RELATIVE 22 /* * Alpha ELF relocation types */ #define R_ALPHA_NONE 0 /* No reloc */ #define R_ALPHA_REFLONG 1 /* Direct 32 bit */ #define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ #define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ #define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ #define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ #define R_ALPHA_GPDISP 6 /* Add displacement to GP */ #define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ #define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ #define R_ALPHA_OP_PUSH 12 /* OP stack push */ #define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ #define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ #define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ #define R_ALPHA_GPVALUE 16 #define R_ALPHA_GPRELHIGH 17 #define R_ALPHA_GPRELLOW 18 #define R_ALPHA_IMMED_GP_16 19 #define R_ALPHA_IMMED_GP_HI32 20 #define R_ALPHA_IMMED_SCN_HI32 21 #define R_ALPHA_IMMED_BR_HI32 22 #define R_ALPHA_IMMED_LO32 23 #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ typedef struct elf32_rel { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel; typedef struct elf64_rel { Elf64_Addr r_offset; /* Location at which to apply the action */ Elf64_Word r_info; /* index and type of relocation */ } Elf64_Rel; typedef struct elf32_rela{ Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } Elf32_Rela; typedef struct elf64_rela { Elf64_Addr r_offset; /* Location at which to apply the action */ Elf64_Word r_info; /* index and type of relocation */ Elf64_Word r_addend; /* Constant addend used to compute value */ } Elf64_Rela; typedef struct elf32_sym{ Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; typedef struct elf64_sym { Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */ unsigned char st_info; /* Type and binding attributes */ unsigned char st_other; /* No defined meaning, 0 */ Elf64_Half st_shndx; /* Associated section index */ Elf64_Addr st_value; /* Value of the symbol */ Elf64_Word st_size; /* Associated symbol size */ } Elf64_Sym; #define EI_NIDENT 16 typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; /* Entry point */ Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr; typedef struct elf64_hdr { unsigned char e_ident[16]; /* ELF "magic number" */ Elf64_SHalf e_type; Elf64_Half e_machine; INT32 e_version; Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ INT32 e_flags; Elf64_SHalf e_ehsize; Elf64_SHalf e_phentsize; Elf64_SHalf e_phnum; Elf64_SHalf e_shentsize; Elf64_SHalf e_shnum; Elf64_SHalf e_shstrndx; } Elf64_Ehdr; /* These constants define the permissions on sections in the program header, p_flags. */ #define PF_R 0x4 #define PF_W 0x2 #define PF_X 0x1 typedef struct elf32_phdr{ Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr; typedef struct elf64_phdr { INT32 p_type; INT32 p_flags; Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Word p_filesz; /* Segment size in file */ Elf64_Word p_memsz; /* Segment size in memory */ Elf64_Word p_align; /* Segment alignment, file & memory */ } Elf64_Phdr; /* sh_type */ #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_NUM 12 #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xffffffff #define SHT_MIPS_LIST 0x70000000 #define SHT_MIPS_CONFLICT 0x70000002 #define SHT_MIPS_GPTAB 0x70000003 #define SHT_MIPS_UCODE 0x70000004 /* sh_flags */ #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MASKPROC 0xf0000000 #define SHF_MIPS_GPREL 0x10000000 /* special section indexes */ #define SHN_UNDEF 0 #define SHN_LORESERVE 0xff00 #define SHN_LOPROC 0xff00 #define SHN_HIPROC 0xff1f #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff #define SHN_MIPS_ACCOMON 0xff00 typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; typedef struct elf64_shdr { Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */ Elf32_Word sh_type; /* Type of section (yes Elf32) */ Elf64_Word sh_flags; /* Miscellaneous section attributes */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ Elf64_Word sh_size; /* Size of section in bytes */ Elf32_Word sh_link; /* Index of another section (yes Elf32) */ Elf32_Word sh_info; /* Additional section information (yes Elf32) */ Elf64_Word sh_addralign; /* Section alignment */ Elf64_Word sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; #define EI_MAG0 0 /* e_ident[] indexes */ #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_PAD 7 #define ELFMAG0 0x7f /* EI_MAG */ #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' #define ELFMAG "\177ELF" #define SELFMAG 4 #define ELFCLASSNONE 0 /* EI_CLASS */ #define ELFCLASS32 1 #define ELFCLASS64 2 #define ELFCLASSNUM 3 #define ELFDATANONE 0 /* e_ident[EI_DATA] */ #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 #define EV_NONE 0 /* e_version, EI_VERSION */ #define EV_CURRENT 1 #define EV_NUM 2 /* Notes used in ET_CORE */ #define NT_PRSTATUS 1 #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 /* Note header in a PT_NOTE section */ typedef struct elf32_note { Elf32_Word n_namesz; /* Name size */ Elf32_Word n_descsz; /* Content size */ Elf32_Word n_type; /* Content type */ } Elf32_Nhdr; /* Note header in a PT_NOTE section */ /* * For now we use the 32 bit version of the structure until we figure * out whether we need anything better. Note - on the Alpha, "unsigned int" * is only 32 bits. */ typedef struct elf64_note { Elf32_Word n_namesz; /* Name size */ Elf32_Word n_descsz; /* Content size */ Elf32_Word n_type; /* Content type */ } Elf64_Nhdr; #if ELF_CLASS == ELFCLASS32 extern Elf32_Dyn _DYNAMIC []; #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_note elf32_note #else extern Elf64_Dyn _DYNAMIC []; #define elfhdr elf64_hdr #define elf_phdr elf64_phdr #define elf_note elf64_note #endif #endif /* __LINUX_ELF_H__ */ ./elilo/glue_localfs.c0000644000175000017500000001165010015235410014436 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 #include #include "fs/localfs.h" #include "glue_localfs.h" #include "strops.h" #include "elilo.h" static INTN glue(fileops_t *this, VOID *intf); /* object exported to fileops */ fileops_fs_t localfs_glue = { LOCALFS_PROTOCOL, glue, localfs_install, localfs_uninstall}; static CHAR16 localfs_default_path[FILENAME_MAXLEN]; /* * remove /.\ pattern from path name: * * Example 1: I am in fs0:\efi\debian, which contains elilo.efi, and I * have typed 'elilo' at the efishell prompt. set_default_path() gets * called with string "\EFI\debian/.\elilo.efi". The final path name * must then be set to "\EFI\debian\". * * Example 2: I am in fs0:\ and type 'efi\debian\elilo' at the shell * prompt. set_default_path() is called with "\/.\efi\debian\elilo.efi", * the path must then be set to "\efi\debian\". * * Example 3: I am in fs0:\efi and type '\efi\debian\elilo'. * set_default_path() is called with "\efi\debian\elilo.efi", the * path is "\efi\debian". */ static VOID set_default_path(CHAR16 *sptr) { #define is_sep(h) (h == CHAR_SLASH || h == CHAR_BACKSLASH) CHAR16 *dptr, *last_sep = NULL; UINTN len = FILENAME_MAXLEN - 1; UINTN last_was_sep = 0; CHAR16 c; dptr = localfs_default_path; while (len-- && *sptr) { c = sptr[0]; if (is_sep(c)) { if (last_was_sep) { sptr++; continue; } c = CHAR_BACKSLASH; last_was_sep = 1; last_sep = dptr; } else { last_was_sep = 0; } *dptr++ = c; sptr++; } if (last_sep) *++last_sep = CHAR_NULL; else *dptr = CHAR_NULL; DBG_PRT((L"localfs_default_path=%s\n", localfs_default_path)); } /* * The following glue functions are the only ones which need * to know about the way the underlying interface is working */ #define LOCALFS_DEFAULT_KERNEL L"vmlinux" #define LOCALFS_DEFAULT_CONFIG L"elilo.conf" static EFI_STATUS localfs_setdefaults(VOID *this, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) { StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1); kname[maxlen-1] = CHAR_NULL; StrnCpy(config[0].fname, LOCALFS_DEFAULT_CONFIG, maxlen-1); config[0].fname[maxlen-1] = CHAR_NULL; set_default_path(devpath); return EFI_SUCCESS; } static EFI_STATUS localfs_getdefault_path(CHAR16 *path, UINTN maxlen) { if (maxlen <= StrLen(localfs_default_path)) return EFI_BUFFER_TOO_SMALL; StrCpy(path, localfs_default_path); return EFI_SUCCESS; } /* * If the supplied path is a relative path, then prepend the path to * the elilo.efi executable. This ensures that elilo will look in * its own directory for its config file, kernel images, etc, rather * than the root directory of the disk. Also * convert forward slashes * into backward slashes. */ static EFI_STATUS glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd) { CHAR16 *p; localfs_interface_t *localfs = (localfs_interface_t *)intf; CHAR16 fullname[FILENAME_MAXLEN]; /* * XXX: modification to passed argument (name) */ for (p= name; *p != CHAR_NULL; p++) { if (*p == CHAR_SLASH) *p = CHAR_BACKSLASH; } if (name[0] != CHAR_BACKSLASH && localfs_default_path[0] != CHAR_NULL) { if (StrLen(localfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN) return EFI_INVALID_PARAMETER; StrCpy(fullname, localfs_default_path); StrCat(fullname, name); name = fullname; } return localfs->localfs_open(intf, name, fd); } static INTN glue(fileops_t *fp, VOID *intf) { localfs_interface_t *localfs = (localfs_interface_t *)intf; fp->open = glue_open; fp->read = (fops_read_t)localfs->localfs_read; fp->close = (fops_close_t)localfs->localfs_close; fp->infosize = (fops_infosize_t)localfs->localfs_infosize; fp->seek = (fops_seek_t)localfs->localfs_seek; fp->setdefaults = (fops_setdefaults_t)localfs_setdefaults; fp->getdefault_path = (fops_getdefault_path_t)localfs_getdefault_path; fp->intf = intf; /* fill out the name of the underlying file system */ localfs->localfs_name(localfs, fp->name, FILEOPS_NAME_MAXLEN); return 0; } ./elilo/tools/0000755000175000017500000000000011513632716013006 5ustar jasonfjasonf./elilo/tools/Makefile0000644000175000017500000000242207720452272014450 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES=eliloalt.o TARGET=eliloalt all: $(TARGET) # # redefine local rule (we build a Linux/ia64 binary here) # %.o: %.c $(CC) $(OPTIMFLAGS) $(DEBUGFLAGS) -c $< -o $@ $(TARGET): %:%.o $(CC) -o $@ $(OPTIMFLAGS) $(DEBUGFLAGS) $^ clean: $(RM) -f $(TARGET) $(FILES) ./elilo/tools/eliloalt.c0000644000175000017500000001565511466352317014776 0ustar jasonfjasonf/* * eliloalt.c * * Copyright (C) 2002-2003 Hewlett-Packard Co * Contributed by Stephane Eranian * * 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. * */ /* * This program is used to set the EliloAlt EFI variable to influence * how elilo will behave at the next reboot. This variable is used * to boot a certain kernel/configuration only once (debug, for instance). * * This is is supposed to be installed in /usr/sbin/eliloalt and must only * be run by root. */ #include #include #include #include #include #include #include #include #include #include #include #define ELILOALT_VERSION "0.02" #define ELILO_ALT_NAME "EliloAlt" #define EFIVAR_DIR "/sys/firmware/efi/vars" #define OFIVAR_DIR "/proc/efi/vars" #define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000" #define OLILO_ALTVAR OFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000" #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 typedef unsigned long efi_status_t; typedef uint8_t efi_bool_t; typedef uint16_t efi_char16_t; /* UNICODE character */ /* * EFI GUID type definition */ typedef struct { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; } efi_guid_t; /* * EFI variable structure */ typedef struct _efi_variable_t { efi_char16_t variablename[1024/sizeof(efi_char16_t)]; efi_guid_t vendorguid; uint64_t datasize; uint8_t data[1024]; efi_status_t status; uint32_t attributes; } __attribute__((packed)) efi_variable_t; static char *efivar_dir = EFIVAR_DIR; static char *elilo_alt_name = ELILO_ALT_NAME; static char *elilo_altvar = ELILO_ALTVAR; static struct option cmd_options[]={ { "version", 0, 0, 1}, { "help", 0, 0, 2}, { "delete", 0, 0, 3}, { "print", 0, 0, 4}, { "set", 1, 0, 5}, { 0, 0, 0, 0} }; static void fatal_error(char *fmt,...) __attribute__((noreturn)); static void fatal_error(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } static void usage(char **argv) { printf("Usage: %s [OPTIONS] cmdline\n", argv[0]); printf( "-h, --help\t\tdisplay this help and exit\n" "--version\t\toutput version information and exit\n" "-s, --set cmdline\tset elilo alternate variable to cmdline\n" "-p, --print\t\tprint elilo alternate variable\n" "-d, --delete\t\tprint elilo alternate variable\n" ); } static char * check_proc_efi(int find_entry) { DIR *efi_vars; struct dirent *entry; static char name[1024]; if (getuid() != 0) { fatal_error("This program must be run as root\n"); } efi_vars = opendir(efivar_dir); if (efi_vars == NULL) { efivar_dir = OFIVAR_DIR; elilo_altvar = OLILO_ALTVAR; efi_vars = opendir(efivar_dir); } if (efi_vars == NULL) { fatal_error("Can access neither %s nor %s\n", EFIVAR_DIR, efivar_dir); } if (!find_entry) { closedir(efi_vars); return NULL; } /* Find one entry we can open */ while ((entry = readdir(efi_vars)) != NULL) { if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) break; } if (entry == NULL) { fatal_error("Cannot find entry in %s\n", efivar_dir); } snprintf(name, 1023, "%s/%s", efivar_dir, entry->d_name); name[1023] = 0; closedir(efi_vars); return name; } static void delete_var(void) { efi_variable_t var; int fd, r, i; check_proc_efi(0); fd = open(elilo_altvar, O_WRONLY); if (fd == -1) { fatal_error("variable not defined\n"); } memset(&var, 0, sizeof(var)); for (i=0; i < sizeof(elilo_alt_name); i++) { var.variablename[i] = (efi_char16_t)elilo_alt_name[i]; } /* * we use NULL GUID so no need to initialize it now memset() did it * writing with a datasize=0 will effectively delete the variable. */ r = write(fd, &var, sizeof(var)); if (r != sizeof(var)) { fatal_error("Variable %s defined but invalid content\n", elilo_altvar); } close(fd); } static void print_var(void) { efi_variable_t var; int fd, r, i; check_proc_efi(0); fd = open(elilo_altvar, O_RDONLY); if (fd == -1) { fatal_error("variable not defined\n"); } memset(&var, 0, sizeof(var)); r = read(fd, &var, sizeof(var)); if (r != sizeof(var)) { fatal_error("Variable %s defined but invalid content\n", elilo_altvar); } printf("EliloAlt=\""); for(i=0; i < var.datasize; i+=1){ printf("%c", var.data[i]); } printf("\"\n"); close(fd); } static void set_var(char *cmdline) { efi_variable_t var; int fd, r, i, j, l; char *name; name = check_proc_efi(1); if (cmdline == NULL) { fatal_error("invalid cmdline argument\n"); } l = strlen(cmdline); if (l >= 1024) { fatal_error("Variable content is too long, must be <= 512 characters\n"); } fd = open(name, O_WRONLY); if (fd == -1) { fatal_error("can't open %s: %s\n", elilo_altvar, strerror(errno)); } memset(&var, 0, sizeof(var)); for (i=0; i < sizeof(elilo_alt_name); i++) { var.variablename[i] = (efi_char16_t)elilo_alt_name[i]; } for (i=0, j=0; i < l; i++, j+=2) { var.data[j] = (efi_char16_t)cmdline[i]; } /* +2 = include char16 for null termination */ var.datasize = j+2; var.attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; /* * we use NULL GUID so no need to initialize it now memset() did it * writing with a datasize=0 will effectively delete the variable. */ r = write(fd, &var, sizeof(var)); if (r != sizeof(var)) { fatal_error("Variable %s defined but invalid content %d\n", elilo_altvar, r); } close(fd); } int main(int argc, char **argv) { int c; while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) { switch(c) { case 0: continue; /* fast path for options */ case 1: printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__); exit(0); case 2: case 'h': usage(argv); exit(0); case 3: case 'd': delete_var(); exit(0); case 4: case 'p': print_var(); exit(0); case 5: case 's': set_var(optarg); exit(0); default: fatal_error("Unknown option\n"); } } print_var(); return 0; } ./elilo/sysdeps.h0000644000175000017500000000264710650210516013511 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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. */ #ifndef __ELILO_SYSDEPS_H__ #define __ELILO_SYSDEPS_H__ #ifdef CONFIG_ia64 #include "ia64/sysdeps.h" #elif defined CONFIG_ia32 #include "ia32/sysdeps.h" #elif defined CONFIG_x86_64 #include "x86_64/sysdeps.h" #endif #endif /* __ELILO_SYSDEPS_H__ */ ./elilo/console.c0000644000175000017500000000360511271404161013450 0ustar jasonfjasonf/* * console.c - Console screen handling functions * * Copyright (C) 2006 Christoph Pfisterer * * 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 #include #include "elilo.h" #include static EFI_GUID console_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; static BOOLEAN console_inited = FALSE; static EFI_CONSOLE_CONTROL_PROTOCOL *console_control; /* * Initialize console functions */ static VOID console_init(VOID) { EFI_STATUS status; if (!console_inited) { console_inited = TRUE; status = LibLocateProtocol(&console_guid, (VOID **) &console_control); if (EFI_ERROR(status)) console_control = NULL; } } /* * Switch the console to text mode */ VOID console_textmode(VOID) { EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode; console_init(); if (console_control != NULL) { uefi_call_wrapper(console_control->GetMode, 4, console_control, &console_mode, NULL, NULL); if (console_mode == EfiConsoleControlScreenGraphics) uefi_call_wrapper(console_control->SetMode, 2, console_control, EfiConsoleControlScreenText); } } ./elilo/loader.h0000644000175000017500000000252107720452237013270 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __LOADER_H__ #define __LOADER_H__ #include "fileops.h" typedef struct __loader_ops_t { struct __loader_ops_t *next; CHAR16 *ld_name; INTN (*ld_probe)(CHAR16 *kname); INTN (*ld_load_kernel)(CHAR16 *kname, kdesc_t *kd); } loader_ops_t; extern loader_ops_t *loader_probe(CHAR16 *kname); extern INTN loader_register(loader_ops_t *ldops); #endif /* __LOADER_H__ */ ./elilo/inflate.c0000644000175000017500000010764410743003127013440 0ustar jasonfjasonf#define DEBG(x) #define DEBG1(x) /* inflate.c -- Not copyrighted 1992 by Mark Adler version c10p1, 10 January 1993 */ /* * Adapted for booting Linux by Hannu Savolainen 1993 * based on gzip-1.0.3 * * Nicolas Pitre , 1999/04/14 : * Little mods for all variable to reside either into rodata or bss segments * by marking constant variables with 'const' and initializing all the others * at run-time only. This allows for the kernel uncompressor to run * directly from Flash or ROM memory on embeded systems. */ /* Inflate deflated (PKZIP's method 8 compressed) data. The compression method searches for as much of the current string of bytes (up to a length of 258) in the previous 32 K bytes. If it doesn't find any matches (of at least length 3), it codes the next byte. Otherwise, it codes the length of the matched string and its distance backwards from the current position. There is a single Huffman code that codes both single bytes (called "literals") and match lengths. A second Huffman code codes the distance information, which follows a length code. Each length or distance code actually represents a base value and a number of "extra" (sometimes zero) bits to get to add to the base value. At the end of each deflated block is a special end-of-block (EOB) literal/ length code. The decoding process is basically: get a literal/length code; if EOB then done; if a literal, emit the decoded byte; if a length then get the distance and emit the referred-to bytes from the sliding window of previously emitted data. There are (currently) three kinds of inflate blocks: stored, fixed, and dynamic. The compressor deals with some chunk of data at a time, and decides which method to use on a chunk-by-chunk basis. A chunk might typically be 32 K or 64 K. If the chunk is incompressible, then the "stored" method is used. In this case, the bytes are simply stored as is, eight bits per byte, with none of the above coding. The bytes are preceded by a count, since there is no longer an EOB code. If the data is compressible, then either the fixed or dynamic methods are used. In the dynamic method, the compressed data is preceded by an encoding of the literal/length and distance Huffman codes that are to be used to decode this block. The representation is itself Huffman coded, and so is preceded by a description of that code. These code descriptions take up a little space, and so for small blocks, there is a predefined set of codes, called the fixed codes. The fixed method is used if the block codes up smaller that way (usually for quite small chunks), otherwise the dynamic method is used. In the latter case, the codes are customized to the probabilities in the current block, and so can code it much better than the pre-determined fixed codes. The Huffman codes themselves are decoded using a multi-level table lookup, in order to maximize the speed of decoding plus the speed of building the decoding tables. See the comments below that precede the lbits and dbits tuning parameters. */ /* Notes beyond the 1.93a appnote.txt: 1. Distance pointers never point before the beginning of the output stream. 2. Distance pointers can point back across blocks, up to 32k away. 3. There is an implied maximum of 7 bits for the bit length table and 15 bits for the actual data. 4. If only one code exists, then it is encoded using one bit. (Zero would be more efficient, but perhaps a little confusing.) If two codes exist, they are coded using one bit each (0 and 1). 5. There is no way of sending zero distance codes--a dummy must be sent if there are none. (History: a pre 2.0 version of PKZIP would store blocks with no distance codes, but this was discovered to be too harsh a criterion.) Valid only for 1.93a. 2.04c does allow zero distance codes, which is sent as one code of zero bits in length. 6. There are up to 286 literal/length codes. Code 256 represents the end-of-block. Note however that the static length tree defines 288 codes just to fill out the Huffman codes. Codes 286 and 287 cannot be used though, since there is no length base or extra bits defined for them. Similarly, there are up to 30 distance codes. However, static trees define 32 codes (all 5 bits) to fill out the Huffman codes, but the last two had better not show up in the data. 7. Unzip can check dynamic Huffman blocks for complete code sets. The exception is that a single code would not be complete (see #4). 8. The five bits following the block type is really the number of literal codes sent minus 257. 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits (1+6+6). Therefore, to output three times the length, you output three codes (1+1+1), whereas to output four times the same length, you only need two codes (1+3). Hmm. 10. In the tree reconstruction algorithm, Code = Code + Increment only if BitLength(i) is not zero. (Pretty obvious.) 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) 12. Note: length code 284 can represent 227-258, but length code 285 really is 258. The last length deserves its own, short code since it gets used a lot in very redundant files. The length 258 is special since 258 - 3 (the min match length) is 255. 13. The literal/length and distance code bit lengths are read as a single stream of lengths. It is possible (and advantageous) for a repeat code (16, 17, or 18) to go across the boundary between the two sets of lengths. */ #ifdef RCSID static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #"; #endif #ifndef FUNC_STATIC #if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) # include # include #endif #include "gzip.h" #define FUNC_STATIC #endif /* !FUNC_STATIC */ #define slide window /* Huffman code lookup table entry--this entry is four bytes for machines that have 16-bit pointers (e.g. PC's in the small or medium model). Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 means that v is a literal, 16 < e < 32 means that v is a pointer to the next table, which codes e - 16 bits, and lastly e == 99 indicates an unused code. If a code with e == 99 is looked up, this implies an error in the data. */ struct huft { uch e; /* number of extra bits or operation */ uch b; /* number of bits in this code or subcode */ union { ush n; /* literal, length base, or distance base */ struct huft *t; /* pointer to next level of table */ } v; }; /* Function prototypes */ FUNC_STATIC int huft_build OF((unsigned *, unsigned, unsigned, const ush *, const ush *, struct huft **, int *)); FUNC_STATIC int huft_free OF((struct huft *)); FUNC_STATIC int inflate_codes OF((struct huft *, struct huft *, int, int)); FUNC_STATIC int inflate_stored OF((void)); FUNC_STATIC int inflate_fixed OF((void)); FUNC_STATIC int inflate_dynamic OF((void)); FUNC_STATIC int inflate_block OF((int *)); FUNC_STATIC int inflate OF((void)); /* The inflate algorithm uses a sliding 32 K byte window on the uncompressed stream to find repeated byte strings. This is implemented here as a circular buffer. The index is updated simply by incrementing and then ANDing with 0x7fff (32K-1). */ /* It is left to other modules to supply the 32 K area. It is assumed to be usable as if it were declared "uch slide[32768];" or as just "uch *slide;" and then malloc'ed in the latter case. The definition must be in unzip.h, included above. */ /* unsigned wp; current position in slide */ #define wp outcnt #define flush_output(w) (wp=(w),flush_window()) /* Tables for deflate from PKZIP's appnote.txt. */ static const unsigned border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static const ush cplens[] = { /* Copy lengths for literal codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; /* note: see note #13 above about the 258 in this list. */ static const ush cplext[] = { /* Extra bits for literal codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ static const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static const ush cpdext[] = { /* Extra bits for distance codes */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /* Macros for inflate() bit peeking and grabbing. The usage is: NEEDBITS(j) x = b & mask_bits[j]; DUMPBITS(j) where NEEDBITS makes sure that b has at least j bits in it, and DUMPBITS removes the bits from b. The macros use the variable k for the number of bits in b. Normally, b and k are register variables for speed, and are initialized at the beginning of a routine that uses these macros from a global bit buffer and count. If we assume that EOB will be the longest code, then we will never ask for bits with NEEDBITS that are beyond the end of the stream. So, NEEDBITS should not read any more bytes than are needed to meet the request. Then no bytes need to be "returned" to the buffer at the end of the last block. However, this assumption is not true for fixed blocks--the EOB code is 7 bits, but the other literal/length codes can be 8 or 9 bits. (The EOB code is shorter than other codes because fixed blocks are generally short. So, while a block always has an EOB, many other literal/length codes have a significantly lower probability of showing up at all.) However, by making the first table have a lookup of seven bits, the EOB code will be found in that first lookup, and so will not require that too many bits be pulled from the stream. */ FUNC_STATIC ulg bb; /* bit buffer */ FUNC_STATIC unsigned bk; /* bits in bit buffer */ FUNC_STATIC const ush mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; #define NEXTBYTE() (uch)get_byte() #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} /* Huffman code decoding is performed using a multi-level table lookup. The fastest way to decode is to simply build a lookup table whose size is determined by the longest code. However, the time it takes to build this table can also be a factor if the data being decoded is not very long. The most common codes are necessarily the shortest codes, so those codes dominate the decoding time, and hence the speed. The idea is you can have a shorter table that decodes the shorter, more probable codes, and then point to subsidiary tables for the longer codes. The time it costs to decode the longer codes is then traded against the time it takes to make longer tables. This results of this trade are in the variables lbits and dbits below. lbits is the number of bits the first level table for literal/ length codes can decode in one step, and dbits is the same thing for the distance codes. Subsequent tables are also less than or equal to those sizes. These values may be adjusted either when all of the codes are shorter than that, in which case the longest code length in bits is used, or when the shortest code is *longer* than the requested table size, in which case the length of the shortest code in bits is used. There are two different values for the two tables, since they code a different number of possibilities each. The literal/length table codes 286 possible values, or in a flat code, a little over eight bits. The distance table codes 30 possible values, or a little less than five bits, flat. The optimum values for speed end up being about one bit more than those, so lbits is 8+1 and dbits is 5+1. The optimum values may differ though from machine to machine, and possibly even between compilers. Your mileage may vary. */ FUNC_STATIC const int lbits = 9; /* bits in base literal/length lookup table */ FUNC_STATIC const int dbits = 6; /* bits in base distance lookup table */ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ FUNC_STATIC unsigned hufts; /* track memory usage */ FUNC_STATIC int huft_build(b, n, s, d, e, t, m) unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ unsigned n; /* number of codes (assumed <= N_MAX) */ unsigned s; /* number of simple-valued codes (0..s-1) */ const ush *d; /* list of base values for non-simple codes */ const ush *e; /* list of extra bits for non-simple codes */ struct huft **t; /* result: starting table */ int *m; /* maximum lookup bits, returns actual */ /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return zero on success, one if the given code set is incomplete (the tables are still built in this case), two if the input is invalid (all zero length codes or an oversubscribed set of lengths), and three if not enough memory. */ { unsigned a; /* counter for codes of length k */ unsigned c[BMAX+1]; /* bit length count table */ unsigned f; /* i repeats in table every f entries */ int g; /* maximum code length */ int h; /* table level */ register unsigned i; /* counter, current code */ register unsigned j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ register unsigned *p; /* pointer into c[], b[], or v[] */ register struct huft *q; /* points to current table */ struct huft r; /* table entry for structure assignment */ struct huft *u[BMAX]; /* table stack */ unsigned v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ unsigned x[BMAX+1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ DEBG("huft1 "); /* Generate counts for each bit length */ memzero(c, sizeof(c)); p = b; i = n; do { Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), n-i, *p)); c[*p]++; /* assume all entries <= BMAX */ p++; /* Can't combine with above line (Solaris bug) */ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { *t = (struct huft *)NULL; *m = 0; return 0; } DEBG("huft2 "); /* Find minimum and maximum length, bound *m by those */ l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; /* minimum code length */ if ((unsigned)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; /* maximum code length */ if ((unsigned)l > i) l = i; *m = l; DEBG("huft3 "); /* Adjust last length count to fill out codes, if needed */ for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return 2; /* bad input: more codes than bits */ if ((y -= c[i]) < 0) return 2; c[i] += y; DEBG("huft4 "); /* Generate starting offsets into the value table for each length */ x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { /* note that i == g from above */ *xp++ = (j += *p++); } DEBG("huft5 "); /* Make a table of values in order of bit lengths */ p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); DEBG("h6 "); /* Generate the Huffman codes and for each, make the table entries */ x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ u[0] = (struct huft *)NULL; /* just to keep compilers happy */ q = (struct huft *)NULL; /* ditto */ z = 0; /* ditto */ DEBG("h6a "); /* go through the bit lengths (k already is bits in shortest code) */ for (; k <= g; k++) { DEBG("h6b "); a = c[k]; while (a--) { DEBG("h6b1 "); /* here i is the Huffman code of length k bits for value *p */ /* make tables up to required level */ while (k > w + l) { DEBG1("1 "); h++; w += l; /* previous table always l bits */ /* compute minimum size table less than or equal to l bits */ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ { /* too few codes for k-w bit table */ DEBG1("2 "); f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) /* try smaller tables up to z bits */ { if ((f <<= 1) <= *++xp) break; /* enough codes to use up j bits */ f -= *xp; /* else deduct codes from patterns */ } } DEBG1("3 "); z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ if ((q = (struct huft *)gzip_malloc((z + 1)*sizeof(struct huft))) == (struct huft *)NULL) { if (h) huft_free(u[0]); return 3; /* not enough memory */ } DEBG1("4 "); hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = (struct huft *)NULL; u[h] = ++q; /* table starts after link */ DEBG1("5 "); /* connect to last table, if there is one */ if (h) { x[h] = i; /* save pattern for backing up */ r.b = (uch)l; /* bits to dump before this table */ r.e = (uch)(16 + j); /* bits in this table */ r.v.t = q; /* pointer to this table */ j = i >> (w - l); /* (get around Turbo C bug) */ u[h-1][j] = r; /* connect to last table */ } DEBG1("6 "); } DEBG("h6c "); /* set up table entry in r */ r.b = (uch)(k - w); if (p >= v + n) r.e = 99; /* out of values--invalid code */ else if (*p < s) { r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (ush)(*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ } else { r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } DEBG("h6d "); /* fill code-like entries with r */ f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; /* backwards increment the k-bit code i */ for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; /* backup over finished tables */ while ((i & ((1 << w) - 1)) != x[h]) { h--; /* don't need to update q */ w -= l; } DEBG("h6e "); } DEBG("h6f "); } DEBG("huft7 "); /* Return true (1) if we were given an incomplete table */ return y != 0 && g != 1; } FUNC_STATIC int huft_free(t) struct huft *t; /* table to free */ /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ { register struct huft *p, *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; while (p != (struct huft *)NULL) { q = (--p)->v.t; gzip_free((char*)p); p = q; } return 0; } FUNC_STATIC int inflate_codes(tl, td, bl, bd) struct huft *tl, *td; /* literal/length and distance decoder tables */ int bl, bd; /* number of bits decoded by tl[] and td[] */ /* inflate (decompress) the codes in a deflated (compressed) block. Return an error code or zero if it all goes ok. */ { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ unsigned w; /* current window position */ struct huft *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ b = bb; /* initialize bit buffer */ k = bk; w = wp; /* initialize window position */ /* inflate the coded data */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; for (;;) /* do until end of block */ { NEEDBITS((unsigned)bl) if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) if (e == 16) /* then it's a literal */ { slide[w++] = (uch)t->v.n; Tracevv((stderr, "%c", slide[w-1])); if (w == WSIZE) { flush_output(w); w = 0; } } else /* it's an EOB or a length */ { /* exit if end of block */ if (e == 15) break; /* get length of block to copy */ NEEDBITS(e) n = t->v.n + ((unsigned)b & mask_bits[e]); DUMPBITS(e); /* decode distance of block to copy */ NEEDBITS((unsigned)bd) if ((e = (t = td + ((unsigned)b & md))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) NEEDBITS(e) d = w - t->v.n - ((unsigned)b & mask_bits[e]); DUMPBITS(e) Tracevv((stderr,"\\[%d,%d]", w-d, n)); /* do the copy */ do { n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); #if !defined(NOMEMCPY) && !defined(INFLATE_DEBUG) if (w - d >= e) /* (this test assumes unsigned comparison) */ { memcpy(slide + w, slide + d, e); w += e; d += e; } else /* do it slow to avoid memcpy() overlap */ #endif /* !NOMEMCPY */ do { slide[w++] = slide[d++]; Tracevv((stderr, "%c", slide[w-1])); } while (--e); if (w == WSIZE) { flush_output(w); w = 0; } } while (n); } } /* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk = k; /* done */ return 0; } FUNC_STATIC int inflate_stored() /* "decompress" an inflated type 0 (stored) block. */ { unsigned n; /* number of bytes in block */ unsigned w; /* current window position */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(""); return 0; } FUNC_STATIC int inflate_fixed() /* decompress an inflated type 1 (fixed Huffman codes) block. We should either replace this with a custom decoder, or at least precompute the Huffman tables. */ { int i; /* temporary variable */ struct huft *tl; /* literal/length code table */ struct huft *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned l[288]; /* length list for huft_build */ DEBG(" 1) { huft_free(tl); DEBG(">"); return i; } /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; /* free the decoding tables, return */ huft_free(tl); huft_free(td); return 0; } FUNC_STATIC int inflate_dynamic() /* decompress an inflated type 2 (dynamic Huffman codes) block. */ { int i; /* temporary variables */ unsigned j; unsigned l; /* last length */ unsigned m; /* mask for bit lengths table */ unsigned n; /* number of lengths to get */ struct huft *tl; /* literal/length code table */ struct huft *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned nb; /* number of bit length codes */ unsigned nl; /* number of literal/length codes */ unsigned nd; /* number of distance codes */ #ifdef PKZIP_BUG_WORKAROUND unsigned ll[288+32]; /* literal/length and distance code lengths */ #else unsigned ll[286+30]; /* literal/length and distance code lengths */ #endif register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(" 288 || nd > 32) #else if (nl > 286 || nd > 30) #endif return 1; /* bad lengths */ DEBG("dyn1 "); /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { NEEDBITS(3) ll[border[j]] = (unsigned)b & 7; DUMPBITS(3) } for (; j < 19; j++) ll[border[j]] = 0; DEBG("dyn2 "); /* build decoding table for trees--single level, 7 bit lookup */ bl = 7; if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { if (i == 1) huft_free(tl); return i; /* incomplete code set */ } DEBG("dyn3 "); /* read in literal and distance code lengths */ n = nl + nd; m = mask_bits[bl]; i = l = 0; while ((unsigned)i < n) { NEEDBITS((unsigned)bl) j = (td = tl + ((unsigned)b & m))->b; DUMPBITS(j) j = td->v.n; if (j < 16) /* length of code in bits (0..15) */ ll[i++] = l = j; /* save last length in l */ else if (j == 16) /* repeat last length 3 to 6 times */ { NEEDBITS(2) j = 3 + ((unsigned)b & 3); DUMPBITS(2) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = l; } else if (j == 17) /* 3 to 10 zero length codes */ { NEEDBITS(3) j = 3 + ((unsigned)b & 7); DUMPBITS(3) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } else /* j == 18: 11 to 138 zero length codes */ { NEEDBITS(7) j = 11 + ((unsigned)b & 0x7f); DUMPBITS(7) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } } DEBG("dyn4 "); /* free decoding table for trees */ huft_free(tl); DEBG("dyn5 "); /* restore the global bit buffer */ bb = b; bk = k; DEBG("dyn5a "); /* build the decoding tables for literal/length and distance codes */ bl = lbits; if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { DEBG("dyn5b "); if (i == 1) { error(" incomplete literal tree\n"); huft_free(tl); } return i; /* incomplete code set */ } DEBG("dyn5c "); bd = dbits; if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { DEBG("dyn5d "); if (i == 1) { error(" incomplete distance tree\n"); #ifdef PKZIP_BUG_WORKAROUND i = 0; } #else huft_free(td); } huft_free(tl); return i; /* incomplete code set */ #endif } DEBG("dyn6 "); /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; DEBG("dyn7 "); /* free the decoding tables, return */ huft_free(tl); huft_free(td); DEBG(">"); return 0; } FUNC_STATIC int inflate_block(e) int *e; /* last block flag */ /* decompress an inflated block */ { unsigned t; /* block type */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(""); /* bad block type */ return 2; } FUNC_STATIC int inflate() /* decompress an inflated entry */ { int e; /* last block flag */ int r; /* result code */ unsigned h; /* maximum struct huft's malloc'ed */ /* initialize window, bit buffer */ wp = 0; bk = 0; bb = 0; /* decompress until the last block */ h = 0; do { hufts = 0; if ((r = inflate_block(&e)) != 0) { return r; } if (hufts > h) h = hufts; } while (!e); /* Undo too much lookahead. The next read will be byte aligned so we * can discard unused bits in the last meaningful byte. */ while (bk >= 8) { bk -= 8; inptr--; } /* flush out slide */ flush_output(wp); /* return success */ #ifdef INFLATE_DEBUG #ifdef EFI_COMPILE Print(L"<%d> ", h); #else printf("<%d> ", h); #endif #endif /* INFLATE_DEBUG */ return 0; } /********************************************************************** * * The following are support routines for inflate.c * **********************************************************************/ static ulg crc_32_tab[256]; static ulg crc; /* initialized in makecrc() so it'll reside in bss */ #define CRC_VALUE (crc ^ 0xffffffffUL) /* * Code to compute the CRC-32 table. Borrowed from * gzip-1.0.3/makecrc.c. */ static void makecrc(void) { /* Not copyrighted 1990 Mark Adler */ unsigned long c; /* crc shift register */ unsigned long e; /* polynomial exclusive-or pattern */ int i; /* counter for all possible eight bit values */ int k; /* byte being shifted into crc apparatus */ /* terms of polynomial defining this crc (except x^32): */ static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* Make exclusive-or pattern from polynomial */ e = 0; for (i = 0; i < sizeof(p)/sizeof(int); i++) e |= 1L << (31 - p[i]); crc_32_tab[0] = 0; for (i = 1; i < 256; i++) { c = 0; for (k = i | 256; k != 1; k >>= 1) { c = c & 1 ? (c >> 1) ^ e : c >> 1; if (k & 1) c ^= e; } crc_32_tab[i] = c; } /* this is initialized here so this code could reside in ROM */ crc = (ulg)0xffffffffUL; /* shift register contents */ } /* * Do the uncompression! */ static int gunzip(void) { uch flags; unsigned char magic[2]; /* magic header */ char method; ulg orig_crc = 0; /* original crc */ ulg orig_len = 0; /* original uncompressed length */ int res; magic[0] = (unsigned char)get_byte(); magic[1] = (unsigned char)get_byte(); method = (unsigned char)get_byte(); if (magic[0] != 037 || ((magic[1] != 0213) && (magic[1] != 0236))) { error("bad gzip magic numbers"); return -1; } /* We only support method #8, DEFLATED */ if (method != 8) { error("internal error, invalid method"); return -1; } flags = (uch)get_byte(); if ((flags & ENCRYPTED) != 0) { error("Input is encrypted\n"); return -1; } if ((flags & CONTINUATION) != 0) { error("Multi part input\n"); return -1; } if ((flags & RESERVED) != 0) { error("Input has invalid flags\n"); return -1; } (void)get_byte(); /* Get timestamp - 4 bytes */ (void)get_byte(); (void)get_byte(); (void)get_byte(); (void)get_byte(); /* Ignore extra flags for the moment */ (void)get_byte(); /* Ignore OS type for the moment */ if ((flags & EXTRA_FIELD) != 0) { unsigned len = (unsigned)get_byte(); len |= ((unsigned)get_byte())<<8; while (len--) (void)get_byte(); } /* Get original file name if it was truncated */ if ((flags & ORIG_NAME) != 0) { /* Discard the old name */ while (get_byte() != 0) /* null */ ; } /* Discard file comment if any */ if ((flags & COMMENT) != 0) { while (get_byte() != 0) /* null */ ; } /* Decompress */ if ((res = inflate())) { switch (res) { case 0: break; case 1: error("invalid compressed format (err=1)"); break; case 2: error("invalid compressed format (err=2)"); break; case 3: error("out of memory"); break; default: error("invalid compressed format (other)"); } return -1; } /* Get the crc and original length */ /* crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ orig_crc = (ulg) get_byte(); orig_crc |= (ulg) get_byte() << 8; orig_crc |= (ulg) get_byte() << 16; orig_crc |= (ulg) get_byte() << 24; orig_len = (ulg) get_byte(); orig_len |= (ulg) get_byte() << 8; orig_len |= (ulg) get_byte() << 16; orig_len |= (ulg) get_byte() << 24; /* Validate decompression */ if (orig_crc != CRC_VALUE) { error("crc error"); return -1; } if (orig_len != bytes_out) { error("length error"); return -1; } return 0; } ./elilo/gzip.h0000644000175000017500000000414210343667143012773 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __GZIP_H__ #define __GZIP_H__ int gunzip_image(memdesc_t *); int gunzip_kernel(fops_fd_t, kdesc_t *); /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ /* * check for valid gzip signature * return: * 0 : valid gzip archive * -1: invalid gzip archive */ static inline int gzip_probe(unsigned char *buf, unsigned long size) { if (size < 4) return -1; if (buf[0] != 037 || ((buf[1] != 0213) && (buf[1] != 0236))) return -1; /* We only support method #8, DEFLATED */ if (buf[2] != 8) return -1; if ((buf[3] & ENCRYPTED) != 0) return -1; if ((buf[3] & CONTINUATION) != 0) return -1; if ((buf[3] & RESERVED) != 0) return -1; return 0; } #endif /* __GZIP_H__ */ ./elilo/glue_netfs.h0000644000175000017500000000214107720452062014147 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __GLUE_NETFS_H__ #define __GLUE_NETFS_H__ #include "fileops.h" extern fileops_fs_t netfs_glue; #endif /* __GLUE_NETFS_H__ */ ./elilo/config.h0000644000175000017500000000450207720451670013270 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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. */ #ifndef __ELILO_CONFIG_H__ #define __ELILO_CONFIG_H__ #define opt_offsetof(opt) (&((boot_image_t *)(0x0))->opt) typedef enum { OPT_NOTUSED, OPT_STR, OPT_CMD, OPT_BOOL, OPT_NUM, OPT_FILE } config_option_type_t; typedef enum { OPT_GLOBAL, /* global and shared among architectures */ OPT_IMAGE, /* per image only and shared among architectures */ OPT_IMAGE_SYS /* per image and architecture specific (offset base in sys_img_opts) */ } config_option_scope_t; typedef enum { OPTIONS_GROUP_GLOBAL, /* group must be added to global set of options */ OPTIONS_GROUP_IMAGE, /* group must be added to per-image set of options */ } config_option_group_scope_t; struct _config_option_t; typedef INTN option_action_t(struct _config_option_t *, VOID *); typedef struct _config_option_t { config_option_type_t type; /* option type: OPT_CMD, OPT_BOOL, ... */ config_option_scope_t scope; /* option scope: global, per image, per image_sys */ CHAR16 *name; /* unicode string for the option */ option_action_t *action; /* option specific action */ INTN (*check)(void *); /* check valid arguments, NULL=don't need */ VOID *data; /* which data structure to record the option */ } config_option_t; extern INTN register_config_options(config_option_t *opt, UINTN nentries, config_option_group_scope_t); #endif /* __ELILO_CONFIG_H__ */ ./elilo/fileops.c0000644000175000017500000003571011466353142013461 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #include "fileops.h" /* * import filesystems */ #ifdef CONFIG_LOCALFS #include "glue_localfs.h" #endif #ifdef CONFIG_NETFS #include "glue_netfs.h" #endif #ifdef CONFIG_EXT2FS #include "glue_ext2fs.h" #endif /* * table of device naming schemes. * we will probe each one in sequential order and stop at first match. */ extern devname_scheme_t simple_devname_scheme; static devname_scheme_t *devname_scheme_tab[]={ &simple_devname_scheme, NULL }; /* * Once we are able to create Boot Services drivers we won't need * this hack and we'll be able to load the driver from the boot manager * or EFI shell. So for now we explicitely invoke the probe routine * of each driver that we know about */ typedef EFI_STATUS (fops_fixups_t)(EFI_HANDLE dev, device_t *d); /* * List of filesystem we currently support */ static fileops_fs_t *fs_tab[]={ #ifdef CONFIG_LOCALFS &localfs_glue, #endif #ifdef CONFIG_EXT2FS &ext2fs_glue, #endif #ifdef CONFIG_NETFS &netfs_glue, #endif NULL }; static device_t *dev_tab; static UINTN ndev, ndev_boot; static device_t *boot_dev; typedef struct _fdesc_t { struct _fdesc_t *next; /* pointer to next free (when in free list) */ fileops_t *fops; /* pointer to filesystem-specific glue interface */ UINTN fh; /* file descriptor from lower level protocol */ } fdesc_t; #define FILEOPS_FD_MAX 16 static fdesc_t fd_tab[FILEOPS_FD_MAX]; static fdesc_t *free_fd; static devname_scheme_t *current_devname_scheme; #define FDESC_IDX(f) (fops_fd_t)(f-fd_tab) #define FDESC_INVALID_FD(fd) (fd >= FILEOPS_FD_MAX || fd_tab[(fd)].fops == NULL) #define FDESC_F(fd) (fd_tab+(fd)) static fdesc_t * fd_alloc(VOID) { fdesc_t *tmp = NULL; if (free_fd == NULL) { ERR_PRT((L"out of file descriptor")); } else { tmp = free_fd; free_fd = free_fd->next; } return tmp; } static VOID fd_free(fdesc_t *fd) { if (fd == NULL) { ERR_PRT((L"invalid fd")); } fd->fops = NULL; /* mark as invalid */ fd->next = free_fd; free_fd = fd; } static fileops_t * glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue) { fileops_t *fops; VOID *intf = NULL; EFI_STATUS status; status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, proto, &intf); if (EFI_ERROR(status)) { ERR_PRT((L"unable to locate %g: should not happen", proto)); return NULL; /* should not happen */ } fops = (fileops_t *)alloc(sizeof(*fops), EfiLoaderData); if (fops == NULL) { ERR_PRT((L"failed to allocate fileops")); return NULL; /* XXX uninstall protocol */ } Memset(fops, 0, sizeof(*fops)); fops->dev = dev; /* initialize private interface now */ glue(fops, intf); return fops; } INTN fops_split_path(CHAR16 *path, CHAR16 *dev) { CHAR16 *p, *d = dev; UINTN len = FILEOPS_DEVNAME_MAXLEN; # define CHAR_COLON L':' p = StrChr(path, CHAR_COLON); if (p == NULL) { *dev = CHAR_NULL; return 0; } /* copy device part of the name */ for (d = dev ; path != p ;) { if (--len == 0) return -1; /* too long */ *d++ = *path++; } *d = CHAR_NULL; return 0; } static device_t * find_device_byname(CHAR16 *dev) { UINTN i; for(i=0; i < ndev; i++) { if (!StrCmp(dev, dev_tab[i].name)) return dev_tab+i; } return NULL; } /* * This function is used to walk through the device list and get names. * arguments: * - pidx = opaque cookie returned by previous call (must be zero for initial call) * - type is the type of filesystem to look for, e.g., vfat or ext2fs. NULL means ANY * - maxlen is the size in bytes of the returned string buffer * - idx is the opaque cookie returned (can be reused by next call) * - name a string buffer to hold the name of the next matching device * - dev will receive the EFI_HANDLE corresponding to the device if not NULL * * return: * - EFI_INVALID_PARAMETER: when NULL values are passed for required arguments. * - EFI_NOT_FOUND: when reached the end of the list of invalid cookie * - EFI_BUFFER_TOO_SMALL is device name does not fit into string buffer * - EFI_SUCCESS otherwise */ EFI_STATUS fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev) { UINTN i; if (name == NULL || idx == NULL) return EFI_INVALID_PARAMETER; for(i=pidx; i < ndev; i++) { if (type == NULL || !StrCmp(dev_tab[i].fops->name, type)) goto found; } return EFI_NOT_FOUND; found: if (StrLen(dev_tab[i].name) >= maxlen) { *idx = pidx; /* will restart from same place! */ return EFI_BUFFER_TOO_SMALL; } StrCpy(name, dev_tab[i].name); *idx = i+1; if (dev) *dev = dev_tab[i].dev; return EFI_SUCCESS; } EFI_STATUS fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev) { UINTN i; if (name == NULL || dev == NULL) return EFI_INVALID_PARAMETER; for(i=0; i < ndev; i++) { if (!StrCmp(dev_tab[i].name, name)) goto found; } return EFI_NOT_FOUND; found: *dev = dev_tab[i].dev; return EFI_SUCCESS; } EFI_STATUS fops_open(CHAR16 *fullname, fops_fd_t *fd) { fdesc_t *f; EFI_STATUS status; fileops_t *fops; device_t *dev; CHAR16 dev_name[FILEOPS_DEVNAME_MAXLEN]; CHAR16 *name; if (fd == NULL || fullname == NULL || *fullname == CHAR_NULL || fops_split_path(fullname, dev_name) == -1) return EFI_INVALID_PARAMETER; DBG_PRT((L"fops_open(%s), dev:%s:", fullname ? fullname : L"(NULL)", dev_name)); name = fullname; if (dev_name[0] == CHAR_NULL) { if (boot_dev == NULL) return EFI_INVALID_PARAMETER; fops = boot_dev->fops; } else { if ((dev=find_device_byname(dev_name)) == NULL) return EFI_INVALID_PARAMETER; name += StrLen(dev_name)+1; fops = dev->fops; } if (fops == NULL) return EFI_INVALID_PARAMETER; if ((f=fd_alloc()) == NULL) return EFI_OUT_OF_RESOURCES; DBG_PRT((L"dev:%s: fullname:%s: name:%s: f=%d", dev_name, fullname, name, f - fd_tab)); status = fops->open(fops->intf, name, &f->fh); if (EFI_ERROR(status)) goto error; f->fops = fops; *fd = FDESC_IDX(f); return EFI_SUCCESS; error: fd_free(f); return status; } EFI_STATUS fops_read(fops_fd_t fd, VOID *buf, UINTN *size) { fdesc_t *f; if (buf == NULL || FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER; f = FDESC_F(fd); return f->fops->read(f->fops->intf, f->fh, buf, size); } EFI_STATUS fops_close(fops_fd_t fd) { fdesc_t *f; EFI_STATUS status; if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER; f = FDESC_F(fd); status = f->fops->close(f->fops->intf, f->fh); fd_free(f); return status; } EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size) { fdesc_t *f; if (FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER; f = FDESC_F(fd); return f->fops->infosize(f->fops->intf, f->fh, size); } EFI_STATUS fops_seek(fops_fd_t fd, UINT64 newpos) { fdesc_t *f; if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER; f = FDESC_F(fd); return f->fops->seek(f->fops->intf, f->fh, newpos); } EFI_STATUS fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) { INTN i; /* * The first default config file is architecture dependent. This is useful * in case of network booting where the server is used for both types of * architectures. */ #if defined(CONFIG_ia64) #define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf" #elif defined (CONFIG_ia32) #define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf" #elif defined (CONFIG_x86_64) #define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-x86_64.conf" #else #error "You need to specfy your default arch config file" #endif /* * last resort config file. Common to all architectures */ #define FILEOPS_DEFAULT_CONFIG L"elilo.conf" #define FILEOPS_DEFAULT_KERNEL L"vmlinux" #ifdef ELILO_DEBUG if (defconf == NULL || kname == NULL) return EFI_INVALID_PARAMETER; #endif for (i=0; ifops == NULL) { if (boot_dev == NULL) Print(L"Warning boot device not recognized\n"); else Print(L"Unknown filesystem on boot device\n"); Print(L"Using builtin defaults for kernel and config file\n"); StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1); } else { boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath); } i=0; while (i= MAX_DEFAULT_CONFIGS) { Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i); return EFI_INVALID_PARAMETER; } #endif StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); #ifdef ELILO_DEBUG VERB_PRT(3,Print(L"Default config filename list:\n")); for (i=0; ifops->getdefault_path) return boot_dev->fops->getdefault_path(path, maxlen); path[0] = CHAR_NULL; return EFI_SUCCESS; } CHAR16 * fops_bootdev_name(VOID) { return boot_dev ? boot_dev->name : L"not supported"; } static INTN add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t glue) { EFI_STATUS status; EFI_HANDLE *tab; UINTN i; static UINTN idx; if (size == 0) return 0; tab = (EFI_HANDLE *)alloc(size, EfiLoaderData); if (tab == NULL) { ERR_PRT((L"failed to allocate handle table")); return -1; } Memset(tab, 0, size); /* * get the actual device handles now */ status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, proto, NULL, &size, tab); if (status != EFI_SUCCESS) { ERR_PRT((L"failed to get handles for proto %g size=%d: %r", proto, size, status)); free(tab); return -1; } size /= sizeof(EFI_HANDLE); for(i=0; i < size; i++) { dev_tab[idx].dev = tab[i]; dev_tab[idx].fops = glue_filesystem(proto, tab[i], glue); if (tab[i] == boot_handle) boot_dev = dev_tab+idx; /* count the ones we recognized */ if (dev_tab[idx].fops) ndev_boot++; /* assign a generic name for now */ dev_tab[idx].name[0] = L'd'; dev_tab[idx].name[1] = L'e'; dev_tab[idx].name[2] = L'v'; dev_tab[idx].name[3] = L'0' + idx/100; dev_tab[idx].name[4] = L'0' + (idx%100)/10; dev_tab[idx].name[5] = L'0' + (idx%100) % 10; dev_tab[idx].name[6] = CHAR_NULL; #ifdef ELILO_DEBUG if (elilo_opt.debug) { EFI_DEVICE_PATH *dp; CHAR16 *str, *str2; str = NULL; dp = DevicePathFromHandle(dev_tab[idx].dev); if (dp) str = DevicePathToStr(dp); str2 = str == NULL ? L"Unknown" : str; DBG_PRT((L"%s : %-8s : %s", dev_tab[idx].name, (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2)); if (str) FreePool(str); } #endif idx++; } free(tab); /* remember actual number of bootable devices */ ndev = idx; return 0; } static INTN probe_devname_schemes(device_t *dev_tab, INTN ndev) { devname_scheme_t **p; for (p = devname_scheme_tab; *p ; p++) { if ((*p)->install_scheme(dev_tab, ndev) == 0) goto found; } ERR_PRT((L"No devname schemes worked, using builtin\n")); return -1; found: VERB_PRT(3, Print(L"devname scheme: %s\n", (*p)->name)); current_devname_scheme = *p; return 0; } static INTN find_filesystems(EFI_HANDLE boot_handle) { UINTN size, total = 0; fileops_fs_t **fs; /* * 1st pass, figure out how big a table we need */ for(fs = fs_tab; *fs; fs++) { size = 0; uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &(*fs)->proto, NULL, &size, NULL); total += size; } if (total == 0) { ERR_PRT((L"No useable filesystem found")); return -1; } total /= sizeof(EFI_HANDLE); DBG_PRT((L"found %d filesystems", total)); dev_tab = (device_t *)alloc(total*sizeof(device_t), EfiLoaderData); if (dev_tab == NULL) { ERR_PRT((L"failed to allocate handle table")); return -1; } Memset(dev_tab, 0, total*sizeof(device_t)); /* * do a 2nd pass to initialize the table now */ for(fs = fs_tab; *fs; fs++) { size = 0; uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &(*fs)->proto, NULL, &size, NULL); if (size == 0) continue; add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue); } probe_devname_schemes(dev_tab, ndev); return 0; } static INTN fileops_init(VOID) { UINTN i; for (i=0; i < FILEOPS_FD_MAX-1; i++) { fd_tab[i].next = &fd_tab[i+1]; } fd_tab[i].next = NULL; free_fd = fd_tab; return 0; } /* * both functions will go away once we go with boottime drivers */ static INTN install_filesystems(VOID) { fileops_fs_t **fs; for(fs = fs_tab; *fs; fs++) (*fs)->install(); return 0; } static INTN uninstall_filesystems(VOID) { fileops_fs_t **fs; for(fs = fs_tab; *fs; fs++) (*fs)->uninstall(); return 0; } INTN init_devices(EFI_HANDLE boot_handle) { /* simulate driver installation */ install_filesystems(); /* * now let's do our part */ fileops_init(); return find_filesystems(boot_handle); } INTN close_devices(VOID) { INTN i; for(i=0; i < FILEOPS_FD_MAX; i++) { fops_close(i); } free(dev_tab); /* * simulate driver removal */ uninstall_filesystems(); return 0; } VOID print_devices(VOID) { UINTN idx; EFI_DEVICE_PATH *dp; CHAR16 *str, *str2; for(idx=0; idx< ndev; idx++) { str = NULL; dp = DevicePathFromHandle(dev_tab[idx].dev); if (dp) str = DevicePathToStr(dp); str2 = str == NULL ? L"Unknown" : str; Print(L"%8s : %-6s : %s\n", dev_tab[idx].name, (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2); if (str) FreePool(str); } Print(L"%d devices available for booting\n", ndev_boot); if (boot_dev == NULL) { Print(L"boot device not detected\n"); } else { Print(L"boot device %s: %s\n", boot_dev->name, (boot_dev->fops ? boot_dev->fops->name : L"No file access")); } } ./elilo/vars.h0000644000175000017500000000414607720452316013000 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * This file is part of the ELILO, the EFI Linux boot loader. * * GNU EFI 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. * * GNU EFI 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 GNU EFI; 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. */ #ifndef __ELILO_VARS_H__ #define __ELILO_VARS_H__ /* * This file contains the list of defined variables. * It is expected that every module which uses a variable add its entry * here. * The syntax for the name is: VAR_modulename_meaning L'X' * where: * - modulename: a string representing the module that uses the variable * - meaning : a string representing the meaning of the variable for the module * - X : the variable name [A-Za-z] */ /* from glue_netfs.c */ #define VAR_NETFS_IPADDR L'I' /* the IP address obtained by DHCP/PXE */ #define VAR_NETFS_NETMASK L'M' /* the netmask obtained by DHCP/PXE */ #define VAR_NETFS_GATEWAY L'G' /* the gateway obtained by DHCP/PXE */ #define VAR_NETFS_HOSTNAME L'H' /* the hostname obtained by DHCP/PXE */ #define VAR_NETFS_DOMAINAME L'D' /* the domain name obtained by DHCP/PXE */ extern INTN set_var(CHAR16 v, CHAR16 *value); extern CHAR16 * get_var(CHAR16 v); extern VOID print_vars(VOID); extern INTN subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen); #endif /* __ELILO_VARS_H__ */ ./elilo/getopt.h0000644000175000017500000000206707316156505013331 0ustar jasonfjasonf/* * Simplistic getopt() function header file for EFI * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian * * 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. */ #ifndef __EFI_GETOPT_H__ #define __EFI_GETOPT_H__ extern CHAR16 *Optarg; extern INTN Optind, Optopt; extern INTN Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring); #endif /* __EFI_GETOPT_H__ */ ./elilo/TODO0000644000175000017500000000100010016471451012317 0ustar jasonfjasonfSome of the things TO DO: ------------------------- - a better device naming scheme (take into account removable media) - ability to rescan devices like when something gets inserted just before invoking elilo and the efi shell is not used (the mount()) - ability to list files from the interactive mode - GUI-based chooser (a la RH9.x)! - UGA support? - Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead - cleanup x86 loader: use the same structure as IA-64 ./elilo/README0000644000175000017500000000570410650210515012522 0ustar jasonfjasonf ELILO: the IA-32,IA-64 and x86_64 Linux Loader ---------------------------------------------- Stephane Eranian August 2003 Copyright (C) 2000-2003 Hewlett-Packard Co. Copyright (C) 2006-2010 Intel Co. This package contains version 3.7 of elilo, the EFI boot loader for IA-64(IPF),IA-32(x86) and x86_64 EFI-based platforms. RELEASE NOTES: -------------- Take a look at the Changelog for a detailed list of changes since 3.3a. - The major new feature of this release pertains to netbooting. With elilo-3.4, the bootloader will look for files ONLY in the directory if was downloaded from on the TFTP server. Of course, if you specific absolute path, files can be placed anywhere in the TFTP directory structure. This may break some setup but an explicit error message is printed warning the user. - There were a bunch of important bug fixes, including handling of paths when booting from the local disk. - Downloading of large files work with EFI versions prior to 14.60 where there was a bug but also with the fixed version of EFI starting at 14.60. - There were also some updates for elilo on IA-32. The loader can load unmodified Linux kernel/initrd image from either the local disk or via netbooting. Thanks to Matt Tolentino at Intel for the IA-32 updates. - The ext2fs support code is still present but is not compiled in anymore. This code does not understand ext3fs and might lead to errors because it does not understand the journal. This package is known to compile and produce working binaries when used in conjunction with gnu-efi-3.0a. This package is available from the HP Labs FTP site: ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-3.0a.tar.gz For IA-64, a toolchain know to produce working binaries is: gcc-3.1 binutiuls 2.13.90 Your may have problems with newer toolchains due to some dependencies in the gnu-efi package. Those dependencies will be fixed eventually. For IA-32, the Redhat 8.0 toolchain is known to produce working binaries when used with gnu-efi-3.0a + loader script patch which is included in the gnu-efi-3.0a-ia32.patch in this package. The toolchain includes: gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7) as : GNU assembler version 2.13.90.0.2 (i386-redhat-linux) using BFD version 2.13.90.0.2 20020802 ld : GNU ld version 2.13.90.0.2 20020802 The Redhat 9.0 toolchain does not work at the moment. For x86_64, a toolchain known to produce working binaries is: gcc-4.1.1 or above binutils-2.17.50.0.14 with Intel64 EFI support For x86_64, the following libraries are required for the elilo build gnu-efi library with x86_64 DOCUMENTATION: -------------- PLEASE READ THE docs/elilo.txt file for some documentation on how to use this program. For netbooting refer to docs/netbooting.txt. Make sure you read the README.gnu-efi file for required packages. ./elilo/x86_64/0000755000175000017500000000000011513632716012604 5ustar jasonfjasonf./elilo/x86_64/bzimage.c0000644000175000017500000002141111466353731014371 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * * 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 #include #include "elilo.h" #include "loader.h" boot_params_t *param_start = NULL; UINTN param_size = 0; UINTN kernel_size = 0x800000; /* 8M (default x86_64 bzImage size limit) */ static VOID * bzImage_alloc() { UINTN pages = EFI_SIZE_TO_PAGES(kernel_size); int reloc_kernel = 0; VOID *kla, *kend = kernel_start + kernel_size; UINT32 kalign, kmask; boot_params_t *ps = param_start; /* * Get address for kernel from header, if applicable & available. */ if ((ps->s.hdr_major < 2) || (ps->s.hdr_major == 2 && ps->s.hdr_minor < 5)) { reloc_kernel = 0; } else { if (ps->s.kernel_start >= DEFAULT_KERNEL_START) kernel_start = (void *)(UINT64)ps->s.kernel_start; reloc_kernel = ps->s.relocatable_kernel; kalign = ps->s.kernel_alignment; kmask = kalign - 1; VERB_PRT(3, Print(L"kernel header (%d.%d) suggests kernel " "start at address "PTR_FMT" (%srelocatable!)\n", ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start, (reloc_kernel ? L"": L"not "))); } /* * Best effort for old (< 2.6.20) and non-relocatable kernels */ if (alloc_kmem(kernel_start, pages) == 0) { VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d\n", kernel_start, kernel_size)); return kernel_start; } else if ( ! reloc_kernel ) { /* * Couldn't get desired address--just load it anywhere and * (try to) move it later. It's the only chance for non- * relocatable kernels, but it breaks occassionally... */ ERR_PRT((L"Kernel header (%d.%d) suggests kernel " "start at address "PTR_FMT" (non relocatable!)\n" "This address is not available, so an attempt" "is made to copy the kernel there later on\n" "BEWARE: this is unsupported and may not work. " "Please update your kernel.\n", ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start)); kla = (VOID *)(UINT32_MAX - kernel_size); /* NULL would preserve the "anywhere" semantic, */ /* but it would not prevent allocation above 4GB! */ if (alloc_kmem_anywhere(&kla, pages) != 0) { /* out of luck */ return NULL; } VERB_PRT(3, Print(L"kernel_start: "PTR_FMT " kernel_size: %d loading at: "PTR_FMT"\n", kernel_start, kernel_size, kla)); return kla; } /* Is 'ps->s.kernel_alignment' guaranteed to be sane? */ if (kalign < EFI_PAGE_SIZE) { kalign = EFI_PAGE_SIZE; kmask = EFI_PAGE_MASK; } DBG_PRT((L"alignment: kernel=0x%x efi_page=0x%x : 0x%x\n", ps->s.kernel_alignment, EFI_PAGE_SIZE, kalign)); /* * Couldn't get the preferred address, but luckily it's * a relocatable kernel, so ... * * 1. use 'find_kernel_memory()' (like Itanium) * 2. try out the 16 lowest possible aligned addresses (> 0) * 3. get enough memory to align "creatively" * 4. forget alignment (and start praying)... */ /* 1. */ if ((find_kernel_memory(kernel_start, kend, kalign, &kla) != 0) || (alloc_kmem(kla, pages) != 0)) { kla = NULL; } /* 2. */ if ( ! kla && (UINT64)kernel_start < kalign ) { int i; for ( i = 1; i < 16 && !kla; i++ ) { VOID *tmp = (VOID *)((UINT64)kalign * i); if (alloc_kmem(tmp, pages) == 0) { kla = tmp; } } } /* 3. */ if ( ! kla ) { UINTN apages = EFI_SIZE_TO_PAGES(kernel_size + kmask); kla = (VOID *)(UINT32_MAX - kernel_size - kmask); if (alloc_kmem_anywhere(&kla, apages) == 0) { kla = (VOID *)(((UINT64)kla + kmask) & ~kmask); } else { kla = NULL; } } /* 4. last resort */ if ( ! kla ) { kla = (VOID *)(UINT32_MAX - kernel_size); if (alloc_kmem_anywhere(&kla, pages) != 0) { return NULL; } } kernel_start = kla; VERB_PRT(1, Print(L"relocating kernel_start: "PTR_FMT " kernel_size: %d\n", kernel_start, kernel_size)); return kla; } static INTN bzImage_probe(CHAR16 *kname) { EFI_STATUS efi_status; UINTN size; fops_fd_t fd; UINT8 bootsect[512]; DBG_PRT((L"probe_bzImage_boot()\n")); if (!kname) { ERR_PRT((L"kname == %xh", kname)); free_kmem(); return -1; } /* * Open kernel image. */ DBG_PRT((L"opening %s...\n", kname)); efi_status = fops_open(kname, &fd); if (EFI_ERROR(efi_status)) { ERR_PRT((L"Could not open %s.", kname)); free_kmem(); return -1; } /* * Read boot sector. */ DBG_PRT((L"\nreading boot sector...\n")); size = sizeof bootsect; efi_status = fops_read(fd, bootsect, &size); if (EFI_ERROR(efi_status) || size != sizeof bootsect) { ERR_PRT((L"Could not read boot sector from %s.", kname)); fops_close(fd); free_kmem(); return -1; } /* * Verify boot sector signature. */ if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) { ERR_PRT((L"%s is not a bzImage kernel image.\n", kname)); fops_close(fd); free_kmem(); return -1; } /* * Check for out of range setup data size. * Will almost always be 7, but we will accept 1 to 64. */ DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1])); if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) { ERR_PRT((L"%s is not a valid bzImage kernel image.", kname)); fops_close(fd); free_kmem(); return -1; } /* * Allocate and read setup data. */ DBG_PRT((L"reading setup data...\n")); param_size = (bootsect[0x1F1] + 1) * 512; param_start = alloc(param_size, EfiLoaderData); DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start)); if (!param_start) { ERR_PRT((L"Could not allocate %d bytes of setup data.", param_size)); fops_close(fd); free_kmem(); return -1; } CopyMem(param_start, bootsect, sizeof bootsect); size = param_size - 512; efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size); if (EFI_ERROR(efi_status) || size != param_size - 512) { ERR_PRT((L"Could not read %d bytes of setup data.", param_size - 512)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } /* * Check for setup data signature. */ { UINT8 *c = ((UINT8 *)param_start)+514; DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3])); } if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) { ERR_PRT((L"%s does not have a setup signature.", kname)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } /* * Allocate memory for kernel. */ kernel_load_address = bzImage_alloc(); if ( ! kernel_load_address ) { ERR_PRT((L"Could not allocate memory for kernel.")); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); return -1; } /* * Now read the rest of the kernel image into memory. */ Print(L"Loading kernel %s... ", kname); size = kernel_size; efi_status = fops_read(fd, kernel_load_address, &size); if (EFI_ERROR(efi_status) || size < 0x10000) { ERR_PRT((L"Error reading kernel image (0x%x).", efi_status)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; } else { Print(L" done\n"); } DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024)); /* * Boot sector, setup data and kernel image loaded. */ fops_close(fd); return 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static INTN bzImage_load(CHAR16 *kname, kdesc_t *kd) { DBG_PRT((L"load_bzImage_boot()\n")); if (!kname || !kd) { ERR_PRT((L"kname="PTR_FMT" kd="PTR_FMT"", kname, kd)); free(param_start); param_start = NULL; param_size = 0; free_kmem(); return -1; } kd->kstart = kd->kentry = kernel_start; kd->kend = ((UINT8 *)kd->kstart) + kernel_size; DBG_PRT((L"kstart="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n", kd->kstart, kd->kentry, kd->kend)); return 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ loader_ops_t bzimage_loader = { NULL, L"bzImage_loader", &bzImage_probe, &bzImage_load }; ./elilo/x86_64/plain_loader.c0000644000175000017500000001717711165216511015410 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 * 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 #include #include "elilo.h" #include "loader.h" #include "elf.h" #include "private.h" #define LD_NAME L"plain_elf64" static INTN is_valid_header(Elf64_Ehdr *ehdr) { UINT16 type, machine; type = ehdr->e_type; machine = ehdr->e_machine; DBG_PRT((L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS64 && type == ET_EXEC /* must be executable */ && machine == EM_X86_64? 0 : -1; } static INTN plain_probe(CHAR16 *kname) { Elf64_Ehdr ehdr; EFI_STATUS status; INTN ret = -1; fops_fd_t fd; UINTN size = sizeof(ehdr); status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; VERB_PRT(3, { Print(L"plain_probe: kname=%s\n", kname); }); status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error; ret = is_valid_header(&ehdr); error: fops_close(fd); return ret; } static INTN load_elf(fops_fd_t fd, kdesc_t *kd) { Elf64_Ehdr ehdr; Elf64_Phdr *phdrs; EFI_STATUS status; INTN ret = ELILO_LOAD_ERROR; UINTN i, total_size = 0; UINTN pages, size, bss_sz, osize; VOID *low_addr = (VOID *)~0; VOID *max_addr = (VOID *)0; UINTN paddr, memsz, filesz; UINT16 phnum; Print(L"Loading Linux... "); size = sizeof(ehdr); status = fops_read(fd, &ehdr, &size); if (EFI_ERROR(status) || size < sizeof(ehdr)) return ELILO_LOAD_ERROR; if (is_valid_header(&ehdr) == -1) { ERR_PRT((L"%s : not a 64-bit ELF image\n", LD_NAME)); return ELILO_LOAD_ERROR; } VERB_PRT(3, { Print(L"ELF Header information: \n"); Print(L"\tEntry point "PTR_FMT"\n", (ehdr.e_entry & PADDR_MASK)); Print(L"\t%d program headers\n", ehdr.e_phnum); Print(L"\t%d segment headers\n", ehdr.e_shnum); }); phnum = ehdr.e_phnum; if (fops_seek(fd, ehdr.e_phoff) < 0) { ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff)); return ELILO_LOAD_ERROR; } size = osize = (phnum * sizeof(Elf64_Phdr)); DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n", LD_NAME, size, phnum, sizeof(Elf64_Phdr), ehdr.e_phentsize)); phdrs = (Elf64_Phdr *)alloc(size, 0); if (phdrs == NULL) { ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME)); return ELILO_LOAD_ERROR; } status = fops_read(fd, phdrs, &size); if (EFI_ERROR(status) || size != osize) { ERR_PRT((L"%s : phdr load failed", LD_NAME, status)); goto out; } /* * First pass to figure out total memory footprint */ for (i = 0; i < phnum; i++) { paddr = (phdrs[i].p_paddr & PADDR_MASK); memsz = phdrs[i].p_memsz; DBG_PRT((L"Phdr %d paddr ["PTR_FMT"-"PTR_FMT"] offset "PTR_FMT"" " filesz "PTR_FMT" memsz="PTR_FMT" bss_sz="PTR_FMT" p_type="PTR_FMT"\n", 1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset, phdrs[i].p_filesz, memsz, (memsz - phdrs[i].p_filesz), phdrs[i].p_type)); if (phdrs[i].p_type != PT_LOAD) continue; if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr; if (paddr + memsz > (UINTN)max_addr) max_addr = (VOID *)paddr + memsz; } if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : kernel low address "PTR_FMT" not page aligned\n", LD_NAME, low_addr)); goto out; } /* how many bytes are needed to hold the kernel? */ total_size = (UINTN)max_addr - (UINTN)low_addr; /* round up to get required number of pages */ pages = EFI_SIZE_TO_PAGES(total_size); /* keep track of location where kernel starts and ends */ kd->kstart = low_addr; kd->kend = (low_addr + (pages << EFI_PAGE_SHIFT)); kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK); VERB_PRT(3, { Print(L"Lowest PhysAddr: "PTR_FMT"\nTotalMemSize:%d bytes (%d pages)\n", low_addr, total_size, pages); Print(L"Kernel entry @ "PTR_FMT"\n", kd->kentry); }); /* now allocate memory for the kernel at the exact requested spot */ if (alloc_kmem(low_addr, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); ERR_PRT((L"%s : Could not alloc %d pages for the kernel at 0x%lx " " and relocation is not not been implemented!\n", LD_NAME, pages, low_addr)); goto load_abort; } /* Pure paranoia. Clear the memory first. Just in case... */ Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT)); VERB_PRT(1, Print(L"Press any key to interrupt\n")); /* * Walk through the program headers * and actually load data into physical memory */ for (i = 0; i < phnum; i++) { /* Check for pure loadable segment; ignore if not loadable */ if (phdrs[i].p_type != PT_LOAD) continue; VERB_PRT(3, Print(L"poffs: "PTR_FMT" (phdrs[%d].p_offset)\n", phdrs[i].p_offset, i)); filesz = phdrs[i].p_filesz; low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK); /* Move to the right position */ if (fops_seek(fd, phdrs[i].p_offset) < 0) goto out_kernel; /* How many BSS bytes to clear */ bss_sz = phdrs[i].p_memsz - filesz; VERB_PRT(4, { Print(L"\nHeader #%d\n", i); Print(L"Offset in file "PTR_FMT"\n", phdrs[i].p_offset); Print(L"Physical addr "PTR_FMT"\n", low_addr); Print(L"BSS size %d bytes\n", bss_sz); }); /* * Read actual segment into memory */ ret = fops_read(fd, low_addr, &filesz); if (ret == ELILO_LOAD_ABORTED) goto load_abort; if (ret == ELILO_LOAD_ERROR) goto out; /* * Clear bss section */ if (bss_sz) Memset((VOID *)low_addr+filesz, 0, bss_sz); } free(phdrs); return ELILO_LOAD_SUCCESS; load_abort: Print(L"..Aborted\n"); ret = ELILO_LOAD_ABORTED; out_kernel: /* free kernel memory */ free_kmem(); out: free(phdrs); return ret; } static INTN plain_load_kernel(CHAR16 *kname, kdesc_t *kd) { INTN ret; fops_fd_t fd; EFI_STATUS status; /* * Moving the open here simplifies the load_elf() error handling */ status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; Print(L"Loading %s...", kname); ret = load_elf(fd, kd); fops_close(fd); return ret; } loader_ops_t plain_loader={ NULL, LD_NAME, plain_probe, plain_load_kernel }; /*void plain_loader_init() { loader_ops_t plain={ NULL, LD_NAME, plain_probe, plain_load_kernel }; *plain_loader=*plain; }*/ ./elilo/x86_64/bin_to_h.c0000644000175000017500000000053710650210516014525 0ustar jasonfjasonf#include #include int main(void) { unsigned n = 0; int c; printf("UINT8 rmswitch_image[] = {\n"); while ((c = getchar()) != EOF) { printf("0x%02x,%s", c & 0xFF, (++n & 0x07) ? " " : "\n"); } if (n & 0x07) { printf("\n"); } printf( "};\n" "UINTN rmswitch_size = sizeof rmswitch_image;\n"); return 0; } ./elilo/x86_64/rmswitch.S0000644000175000017500000000335010650210517014561 0ustar jasonfjasonf# # Switch from protected mode to real mode and jump to setup.S # image located at %cx:0. # # This module must be placed into physical memory at 0:7C00h. # EFI has some real mode thunking code at 2000:0h. # # Processor and non-maskable interrupts should be disabled # before control is passed to this module. # .global _start .code32 .text _start: # # Load identity mapped GDT & real mode IDT. # Add 7C00h to the addresses since this is linked to start # at 0h and it is being placed at 7C00h. # lgdt %cs:gdt_48 + 0x7C00 lidt %cs:idt_48 + 0x7C00 # # Turn off PG bit in CR0 and set CR3 to zero. # movl %cr0, %eax andl $0x7FFFFFFF, %eax movl %eax, %cr0 xorl %eax, %eax movl %eax, %cr3 # # Reload CS. # Now we add 7B00h because we need to force the segment # address and selector to be the same. # .byte 0xEA .long pm_reload + 0x7B00 .word 0x10 pm_reload: .code16 # # Reload DS, ES, FS, GS & SS. # movw $0x18, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss # # Switch to real mode. Clear PE bit in CR0. # movl %cr0, %eax andl $0xFFFFFFFE, %eax movl %eax, %cr0 # # Reload CS. # .byte 0xEA .word rm_reload + 0x7C00 .word 0 rm_reload: # # Reload SS & SP. # xorw %ax, %ax movw %ax, %ss movw $0x7BFE, %sp # # Start running setup.S # .byte 0xEA .word 0 .word 0x9020 # # GDT & IDT stuff for switching into real mode. # gdt: .word 0, 0, 0, 0 # unused (00h) .word 0, 0, 0, 0 # dummy (08h) .word 0xFFFF, 0x100 # code (10h) .word 0x9A00, 0 .word 0xFFFF, 0x180 # data (18h) .word 0x9200, 0 gdt_48: .word 0x08 * 0x400 .long gdt + 0x7C00 idt_48: .word 0x400 .long 0 # # Be careful not to exceed 1F0h or the the bootsect.S # parameters will be lost! # .end ./elilo/x86_64/private.h0000644000175000017500000000243710650210517014425 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 * 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. */ #ifndef __ELILO_PRIVATE_X86_64_H__ #define __ELILO_PRIVATE_X86_64_H__ #endif /* __ELILO_PRIVATE_X86_64_H__ */ ./elilo/x86_64/Makefile0000644000175000017500000000300310650210516014227 0ustar jasonfjasonf# # Copyright (C) 2001-2003 Hewlett-Packard Co. # Contributed by Stephane Eranian # # 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 ../Make.defaults include ../Make.rules TOPDIR=$(CDIR)/.. FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o #FILES=system.o config.o plain_loader.o TARGET=sysdeps.o all: $(TARGET) system.o: rmswitch.h rmswitch.h: bin_to_h.c rmswitch.S $(CC) -o bin_to_h bin_to_h.c $(AS) -o rmswitch.o rmswitch.S $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o ./bin_to_h rmswitch.h $(TARGET): $(FILES) $(LD) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) $(RM) -f bin_to_h.o bin_to_h $(RM) -f rmswitch.h rmswitch.o rmswitch ./elilo/x86_64/system.c0000644000175000017500000006407411511435355014305 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * Contributed by Fenghua Yu * Contributed by Bibo Mao * Contributed by chandramouli narayanan * Edgar Hucek * * Updated with code to fill bootparam converting EFI memory map to E820 * based on a Linux kernel patch provided by Edgar Hucek * - mouli 06/20/2007 * * 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. */ /* * This file contains all the x86_64 specific code expected by generic loader */ #include #include #include #include "elilo.h" #include "loader.h" #include "rmswitch.h" #define DEBUG_CREATE_BOOT_PARAMS 0 #if DEBUG_CREATE_BOOT_PARAMS #define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 ) #else #define DPR(a) #endif extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; /* * Descriptor table base addresses & limits for Linux startup. */ dt_addr_t gdt_addr = { 0x800, 0x94000 }; dt_addr_t idt_addr = { 0, 0 }; /* * Initial GDT layout for Linux startup. */ UINT16 init_gdt[] = { /* gdt[0]: dummy */ 0, 0, 0, 0, /* gdt[1]: unused */ 0, 0, 0, 0, /* gdt[2]: code */ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */ 0x0000, /* base address=0 */ 0x9A00, /* code read/exec */ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */ /* gdt[3]: data */ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */ 0x0000, /* base address=0 */ 0x9200, /* data read/write */ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */ }; UINTN sizeof_init_gdt = sizeof init_gdt; /* * Highest available base memory address. * * For traditional kernels and loaders this is always at 0x90000. * For updated kernels and loaders this is computed by taking the * highest available base memory address and rounding down to the * nearest 64 kB boundary and then subtracting 64 kB. * * A non-compressed kernel is automatically assumed to be an updated * kernel. A compressed kernel that has bit 6 (0x40) set in the * loader_flags field is also assumed to be an updated kernel. */ UINTN high_base_mem = 0x90000; /* * Highest available extended memory address. * * This is computed by taking the highest available extended memory * address and rounding down to the nearest EFI_PAGE_SIZE (usually * 4 kB) boundary. * This is only used for backward compatibility. */ UINTN high_ext_mem = 32 * 1024 * 1024; /* This starting address will hold true for all of the loader types for now */ VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START; /* The kernel may load elsewhere if EFI firmware reserves kernel_start */ VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START; VOID *initrd_start = NULL; UINTN initrd_size = 0; INTN e820_map_overflow = 0; INTN sysdeps_init(EFI_HANDLE dev) { DBG_PRT((L"sysdeps_init()\n")); /* * Register our loader(s)... */ loader_register(&bzimage_loader); loader_register(&plain_loader); loader_register(&gzip_loader); return 0; } /* * initrd_get_addr() * Compute a starting address for the initial RAMdisk image. * For now we suggest 'initrd_addr_max' with room for 32MB, * as image->pgcnt is not initialized yet. */ INTN sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) { DBG_PRT((L"initrd_get_addr()\n")); if (!kd || !imem) { ERR_PRT((L"kd="PTR_FMT" imem="PTR_FMT"", kd, imem)); return -1; } VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n", param_start->s.initrd_addr_max, 32*MB)); imem->start_addr = (VOID *) (((UINT64)param_start->s.initrd_addr_max - 32*MB + 1) & ~EFI_PAGE_MASK); VERB_PRT(3, Print(L"initrd start_addr="PTR_FMT" pgcnt=%d\n", imem->start_addr, imem->pgcnt)); return 0; } /* * checkfix_initrd() * Check and possibly fix allocation of initrd memory. */ VOID * sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) { UINTN pgcnt = EFI_SIZE_TO_PAGES(imem->size); UINT64 initrd_addr_max = (UINT64)param_start->s.initrd_addr_max; UINT64 ki_max = initrd_addr_max - imem->size + 1; VOID *ki_max_addr; VERB_PRT( 3, Print(L"loadfile: start_addr="PTR_FMT " ki_max_addr="PTR_FMT"\n", start_addr, (VOID *)ki_max)); if (ki_max > UINT32_MAX) { ERR_PRT((L"Force kernel specified initrd_addr_max="PTR_FMT " below 4GB\n", (VOID *)initrd_addr_max)); ki_max = UINT32_MAX - imem->size + 1; } ki_max_addr = (VOID *)ki_max; if ((UINT64)start_addr > ki_max) { VERB_PRT(1, Print(L"initrd start_addr="PTR_FMT" above " "limit="PTR_FMT"\n", start_addr, ki_max_addr)); free(start_addr); start_addr = NULL; } /* so either the initial allocation failed or it's been to high! */ if (start_addr == NULL) { start_addr = alloc_pages(pgcnt, EfiLoaderData, AllocateMaxAddress, ki_max_addr); } if ((UINT64)start_addr > ki_max) { ERR_PRT((L"Failed to allocate %d pages below %dMB", pgcnt, (param_start->s.initrd_addr_max+1)>>20)); free(start_addr); start_addr = NULL; } return start_addr; } VOID sysdeps_free_boot_params(boot_params_t *bp) { mmap_desc_t md; ZeroMem(&md, sizeof md); md.md = (VOID *)(UINT64)bp->s.efi_mem_map; free_memmap(&md); } static VOID find_bits(unsigned long mask, UINT8 *first, UINT8* len) { unsigned char bit_pos = 0, bit_len = 0; *first =0; *len = 0; if (mask == 0) return; while (!(mask & 0x1)) { mask = mask >> 1; bit_pos++; } while (mask & 0x1) { mask = mask >> 1; bit_len++; } *first = bit_pos; *len = bit_len; } /* * Get video information. */ static INTN get_video_info(boot_params_t * bp) { EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info; EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Gop_mode = NULL; EFI_HANDLE *Gop_handle = NULL; EFI_STATUS efi_status; UINTN size = 0; UINTN size1; UINT8 i; if (x86_64_text_mode() == 1) { Print((L"Skip GOP init, force text-mode.\n")); return -1; } efi_status = uefi_call_wrapper( BS->LocateHandle, 5, ByProtocol, &GopProtocol, NULL, &size, (VOID **)Gop_handle); if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { Print(L"LocateHandle GopProtocol failed.\n"); Print(L"--Either no graphics head is installed,\n" \ "--efi console is set to serial, or,\n" \ "--the EFI firmware version of this machine is\n" \ "--older than UEFI 2.0. and does not support GOP"); Print(L"you can SAFELY IGNORE this error. elilo will\n" \ "default to text-mode.\n Alternatively you can " \ "now force text mode by setting config variable\n" \ "text_mode=1 for x86 in elilo.conf or via cmdline.\n\n"); Print(L"However if this is the last text output you see\n" \ "ensure that your kernel console command line\n " \ "variable matches up with the actual efi boot menu\n" \ "console output settings.\n\n"); return -1; } Gop_handle = alloc(size, 0); efi_status = uefi_call_wrapper( BS->LocateHandle, 5, ByProtocol, &GopProtocol, NULL, &size, (VOID **)Gop_handle); if (EFI_ERROR(efi_status)) { ERR_PRT((L"LocateHandle GopProtocol failed.")); free(Gop_handle); return -1; } for (i=0; i < size/sizeof(EFI_HANDLE); i++) { Gop_handle += i; efi_status = uefi_call_wrapper( BS->HandleProtocol, 3, *Gop_handle, &GopProtocol, &Gop_interface); if (EFI_ERROR(efi_status)) { continue; } Gop_mode = Gop_interface->Mode; efi_status = uefi_call_wrapper( Gop_interface->QueryMode, 4, Gop_interface, Gop_mode->Mode, &size1, &Gop_info); if (!EFI_ERROR(efi_status)) break; if (EFI_ERROR(efi_status)) { continue; } } if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) { ERR_PRT((L"HandleProtocol GopProtocol failed.")); free(Gop_handle); return -1; } bp->s.is_vga = 0x70; bp->s.orig_cursor_col = 0; bp->s.orig_cursor_row = 0; bp->s.orig_video_page = 0; bp->s.orig_video_mode = 0; bp->s.orig_video_cols = 0; bp->s.orig_video_rows = 0; bp->s.orig_ega_bx = 0; bp->s.orig_video_points = 0; bp->s.lfb_width = Gop_info->HorizontalResolution; bp->s.lfb_height = Gop_info->VerticalResolution; bp->s.lfb_base = Gop_mode->FrameBufferBase; bp->s.lfb_size = Gop_mode->FrameBufferSize; bp->s.lfb_pages = 1; bp->s.vesa_seg = 0; bp->s.vesa_off = 0; if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { bp->s.lfb_depth = 32; bp->s.lfb_red_size = 8; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 8; bp->s.lfb_green_pos = 8; bp->s.lfb_blue_size = 8; bp->s.lfb_blue_pos = 16; bp->s.lfb_rsvd_size = 8; bp->s.lfb_rsvd_pos = 24; bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4; } else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { bp->s.lfb_depth = 32; bp->s.lfb_red_size = 8; bp->s.lfb_red_pos = 16; bp->s.lfb_green_size = 8; bp->s.lfb_green_pos = 8; bp->s.lfb_blue_size = 8; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 8; bp->s.lfb_rsvd_pos = 24; bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4; } else if (Gop_info->PixelFormat == PixelBitMask) { find_bits(Gop_info->PixelInformation.RedMask, &bp->s.lfb_red_pos, &bp->s.lfb_red_size); find_bits(Gop_info->PixelInformation.GreenMask, &bp->s.lfb_green_pos, &bp->s.lfb_green_size); find_bits(Gop_info->PixelInformation.BlueMask, &bp->s.lfb_blue_pos, &bp->s.lfb_blue_size); find_bits(Gop_info->PixelInformation.ReservedMask, &bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size); bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size + bp->s.lfb_blue_size + bp->s.lfb_rsvd_size; bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8; } else { bp->s.lfb_depth = 4; bp->s.lfb_red_size = 0; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 0; bp->s.lfb_green_pos = 0; bp->s.lfb_blue_size = 0; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 0; bp->s.lfb_rsvd_pos = 0; bp->s.lfb_line_len = bp->s.lfb_width / 2; } return 0; } CHAR16 * StrStr(IN const CHAR16 *h, IN const CHAR16 *n) { const CHAR16 *t = h; CHAR16 *res; int len = 0, i; len = StrLen((CHAR16 *)n); while(*t != CHAR_NULL) { res = StrChr( t, n[0]); if (!res) return res; for( i = 1; i < len && res[i] != CHAR_NULL && res[i] == n[i]; i++); if ( i == len ) return res; t = res + 1; if (t > h + CMDLINE_MAXLEN) return (CHAR16 *)0; } return (CHAR16 *)0; } CHAR8 * StrStr8(IN const CHAR8 *h, IN const CHAR8 *n) { const CHAR8 *t = h; CHAR8 *res; int len = 0, i; len = strlena((CHAR8 *)n); while(*t != 0) { res = strchra( t, n[0]); if (!res) return res; for( i = 1; i < len && res[i] != 0 && res[i] == n[i]; i++); if ( i == len ) return res; t = res + 1; if (t > (h + CMDLINE_MAXLEN)) return (CHAR8 *)0; } return (CHAR8 *)0; } /* Convert EFI memory map to E820 map for the operating system * This code is based on a Linux kernel patch submitted by Edgar Hucek */ #if DEBUG_CREATE_BOOT_PARAMS static int e820_max = 6; #else static int e820_max = E820_MAX; #endif /* Add a memory region to the e820 map */ static void add_memory_region (struct e820entry *e820_map, int *e820_nr_map, unsigned long long start, unsigned long size, unsigned int type) { int x = *e820_nr_map; static unsigned long long estart = 0ULL; static unsigned long esize = 0L; static unsigned int etype = -1; static int merge = 0; if (x == 0) DPR((L"AMR: %3s %4s %16s/%12s/%s\n", L"idx", L" ", L"start", L"size", L"type")); /* merge adjacent regions of same type */ if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start && e820_map[x-1].type == type) { e820_map[x-1].size += size; estart = e820_map[x-1].addr; esize = e820_map[x-1].size; etype = e820_map[x-1].type; merge++; return; } /* fill up to E820_MAX */ if ( x < e820_max ) { e820_map[x].addr = start; e820_map[x].size = size; e820_map[x].type = type; (*e820_nr_map)++; if (merge) DPR((L"AMR: %3d ==> %016llx/%012lx/%d (%d)\n", x-1, estart, esize, etype, merge)); merge=0; DPR((L"AMR: %3d add %016llx/%012lx/%d\n", x, start, size, type)); return; } /* different type means another region didn't fit */ /* or same type, but there's a hole */ if (etype != type || (estart + esize) != start) { if (merge) DPR((L"AMR: %3d ===> %016llx/%012lx/%d (%d)\n", e820_map_overflow, estart, esize, etype, merge)); merge = 0; estart = start; esize = size; etype = type; e820_map_overflow++; DPR((L"AMR: %3d OVER %016llx/%012lx/%d\n", e820_map_overflow, start, size, type)); return; } /* same type and no hole, merge it */ estart += esize; esize += size; merge++; } void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) { int nr_map, e820_nr_map = 0, i; UINT64 start, end, size; EFI_MEMORY_DESCRIPTOR *md, *p; struct e820entry *e820_map; nr_map = mdesc->map_size/mdesc->desc_size; e820_map = (struct e820entry *)bp->s.e820_map; for (i = 0, p = mdesc->md; i < nr_map; i++) { md = p; switch (md->Type) { case EfiACPIReclaimMemory: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_ACPI); break; case EfiRuntimeServicesCode: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_EXEC_CODE); break; case EfiRuntimeServicesData: case EfiReservedMemoryType: case EfiMemoryMappedIO: case EfiMemoryMappedIOPortSpace: case EfiUnusableMemory: case EfiPalCode: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_RESERVED); break; case EfiLoaderCode: case EfiLoaderData: case EfiBootServicesCode: case EfiBootServicesData: case EfiConventionalMemory: start = md->PhysicalStart; size = md->NumberOfPages << EFI_PAGE_SHIFT; end = start + size; /* Fix up for BIOS that claims RAM in 640K-1MB region */ if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) { /* start < 640K * set memory map from start to 640K */ add_memory_region(e820_map, &e820_nr_map, start, 0xA0000ULL-start, E820_RAM); } if (end <= 0x100000ULL) continue; /* end > 1MB * set memory map avoiding 640K to 1MB hole */ start = 0x100000ULL; size = end - start; } add_memory_region(e820_map, &e820_nr_map, start, size, E820_RAM); break; case EfiACPIMemoryNVS: add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_NVS); break; default: /* We should not hit this case */ DBG_PRT((L"hit default!?")); add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, E820_RESERVED); break; } p = NextMemoryDescriptor(p, mdesc->desc_size); } bp->s.e820_nrmap = e820_nr_map; } /* * x86_64 specific boot parameters initialization routine * * Note: debug and verbose messages have already been turned off! */ INTN sysdeps_create_boot_params( boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie) { mmap_desc_t mdesc; EFI_STATUS efi_status; UINTN rows, cols; UINT8 row, col; UINT8 mode; UINT16 hdr_version; UINT8 e820_map_overflow_warned = 0; #if DEBUG_CREATE_BOOT_PARAMS elilo_opt.debug=1; elilo_opt.verbose=5; #endif DBG_PRT((L"fill_boot_params()\n")); if (!bp || !cmdline || !initrd || !cookie) { ERR_PRT((L"bp="PTR_FMT" cmdline="PTR_FMT" initrd="PTR_FMT" cookie="PTR_FMT"", bp, cmdline, initrd, cookie)); if (param_start != NULL) { free(param_start); param_start = NULL; param_size = 0; } free_kmem(); return -1; } /* * Copy temporary boot sector and setup data storage to * elilo allocated boot parameter storage. We only need * the first two sectors (1K). The rest of the storage * can be used by the command line. */ if (param_start != NULL) { CopyMem(bp, param_start, 0x2000); free(param_start); param_start = NULL; param_size = 0; } /* * Save off our header revision information. */ hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor; /* * Do NOT clear out unknown memory in boot sector image. * This breaks boot protocol >= 2.10 (2.6.31). */ /* * Tell kernel this was loaded by an advanced loader type. * If this field is zero, the initrd_start and initrd_size * fields are ignored by the kernel. */ bp->s.loader_type = LDRTYPE_ELILO; /* * Setup command line information. */ bp->s.cmdline_magik = CMDLINE_MAGIK; bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp; /* * Clear out the cmdline_addr field so the kernel can find * the cmdline. */ bp->s.cmdline_addr = 0x0; /* * Setup hard drive parameters. * %%TBD - It should be okay to zero fill the hard drive * info buffers. The kernel should do its own detection. */ ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info); ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info); /* * Memory info. */ bp->s.alt_mem_k = high_ext_mem / 1024; if (bp->s.alt_mem_k <= 65535) bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k; else bp->s.ext_mem_k = 65535; /* * Initial RAMdisk and root device stuff. */ DBG_PRT((L"initrd->start_addr="PTR_FMT" initrd->pgcnt=%d\n", initrd->start_addr, initrd->pgcnt)); /* These RAMdisk flags are not needed, just zero them. NOT!*/ /* 'ramdisk_flags' (@0x1F8) is called 'ram_size' in the meantime, */ /* see Documentation/x86/boot.txt. */ if (initrd->start_addr && initrd->pgcnt) { if ( (UINT64)initrd->start_addr > UINT32_MAX ) { ERR_PRT((L"Start of initrd out of reach (>4GB).")); free_kmem(); return -1; } /* %%TBD - This will probably have to be changed. */ bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr; bp->s.initrd_size = (UINT32)(initrd->size); } else { bp->s.initrd_start = 0; bp->s.initrd_size = 0; } /* * APM BIOS info. */ bp->s.apm_bios_ver = NO_APM_BIOS; bp->s.bios_code_seg = 0; bp->s.bios_entry_point = 0; bp->s.bios_code_seg16 = 0; bp->s.bios_data_seg = 0; bp->s.apm_bios_flags = 0; bp->s.bios_code_len = 0; bp->s.bios_data_len = 0; /* * MCA BIOS info (misnomer). */ bp->s.mca_info_len = 0; ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf); /* * EFI loader signature */ CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_X64, 4); /* * Kernel entry point. */ if ( (UINT64)kernel_start != (UINT32)(UINT64)kernel_start ) { ERR_PRT((L"Start of kernel (will be) out of reach (>4GB).")); free_kmem(); return -1; } bp->s.kernel_start = (UINT32)(UINT64)kernel_start; /* * When changing stuff in the parameter structure compare * the offsets of the fields with the offsets used in the * boot sector and setup source files. * arch/x86_64/boot/bootsect.S * arch/x86_64/boot/setup.S * arch/x86_64/kernel/setup.c * include/asm-x86_64/setup.h (2.5/2.6) */ #define CHECK_OFFSET(n, o, f) \ { \ UINTN p = (UINT8 *)&bp->s.n - (UINT8 *)bp; \ UINTN q = (UINTN)(o); \ if (p != q) { \ test |= 1; \ Print(L"%20a: %3xh %3xh ", #n, p, q); \ if (*f) { \ Print(f, bp->s.n); \ } \ Print(L"\n"); \ } \ } #define WAIT_FOR_KEY() \ { \ EFI_INPUT_KEY key; \ while (uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key) != EFI_SUCCESS) { \ ; \ } \ } { UINTN test = 0; CHECK_OFFSET(orig_cursor_col, 0x00, L"%xh"); CHECK_OFFSET(orig_cursor_row, 0x01, L"%xh"); CHECK_OFFSET(ext_mem_k, 0x02, L"%xh"); CHECK_OFFSET(orig_video_page, 0x04, L"%xh"); CHECK_OFFSET(orig_video_mode, 0x06, L"%xh"); CHECK_OFFSET(orig_video_cols, 0x07, L"%xh"); CHECK_OFFSET(orig_ega_bx, 0x0A, L"%xh"); CHECK_OFFSET(orig_video_rows, 0x0E, L"%xh"); CHECK_OFFSET(is_vga, 0x0F, L"%xh"); CHECK_OFFSET(orig_video_points, 0x10, L"%xh"); CHECK_OFFSET(lfb_width, 0x12, L"%xh"); CHECK_OFFSET(lfb_height, 0x14, L"%xh"); CHECK_OFFSET(lfb_depth, 0x16, L"%xh"); CHECK_OFFSET(lfb_base, 0x18, L"%xh"); CHECK_OFFSET(lfb_size, 0x1C, L"%xh"); CHECK_OFFSET(cmdline_magik, 0x20, L"%xh"); CHECK_OFFSET(cmdline_offset, 0x22, L"%xh"); CHECK_OFFSET(lfb_line_len, 0x24, L"%xh"); CHECK_OFFSET(lfb_red_size, 0x26, L"%xh"); CHECK_OFFSET(lfb_red_pos, 0x27, L"%xh"); CHECK_OFFSET(lfb_green_size, 0x28, L"%xh"); CHECK_OFFSET(lfb_green_pos, 0x29, L"%xh"); CHECK_OFFSET(lfb_blue_size, 0x2A, L"%xh"); CHECK_OFFSET(lfb_blue_pos, 0x2B, L"%xh"); CHECK_OFFSET(lfb_rsvd_size, 0x2C, L"%xh"); CHECK_OFFSET(lfb_rsvd_pos, 0x2D, L"%xh"); CHECK_OFFSET(vesa_seg, 0x2E, L"%xh"); CHECK_OFFSET(vesa_off, 0x30, L"%xh"); CHECK_OFFSET(lfb_pages, 0x32, L"%xh"); CHECK_OFFSET(lfb_reserved, 0x34, L""); CHECK_OFFSET(apm_bios_ver, 0x40, L"%xh"); CHECK_OFFSET(bios_code_seg, 0x42, L"%xh"); CHECK_OFFSET(bios_entry_point, 0x44, L"%xh"); CHECK_OFFSET(bios_code_seg16, 0x48, L"%xh"); CHECK_OFFSET(bios_data_seg, 0x4A, L"%xh"); CHECK_OFFSET(apm_bios_flags, 0x4C, L"%xh"); CHECK_OFFSET(bios_code_len, 0x4E, L"%xh"); CHECK_OFFSET(bios_data_len, 0x52, L"%xh"); CHECK_OFFSET(hd0_info, 0x80, L""); CHECK_OFFSET(hd1_info, 0x90, L""); CHECK_OFFSET(mca_info_len, 0xA0, L"%xh"); CHECK_OFFSET(mca_info_buf, 0xA2, L""); CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'"); CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh"); CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh"); CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh"); CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh"); CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh"); CHECK_OFFSET(efi_sys_tbl_hi, 0x1D8, L"%xh"); CHECK_OFFSET(efi_mem_map_hi, 0x1DC, L"%xh"); CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh"); CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh"); CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh"); CHECK_OFFSET(sys_size, 0x1F4, L"%xh"); CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh"); CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh"); CHECK_OFFSET(boot_flag, 0x1FE, L"%xh"); CHECK_OFFSET(jump, 0x200, L"%xh"); CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'"); CHECK_OFFSET(hdr_minor, 0x206, L"%xh"); CHECK_OFFSET(hdr_major, 0x207, L"%xh"); CHECK_OFFSET(rm_switch, 0x208, L"%xh"); CHECK_OFFSET(start_sys_seg, 0x20C, L"%xh"); CHECK_OFFSET(kernel_verstr_offset, 0x20E, L"%xh"); CHECK_OFFSET(loader_type, 0x210, L"%xh"); CHECK_OFFSET(loader_flags, 0x211, L"%xh"); CHECK_OFFSET(setup_move_size, 0x212, L"%xh"); CHECK_OFFSET(kernel_start, 0x214, L"%xh"); CHECK_OFFSET(initrd_start, 0x218, L"%xh"); CHECK_OFFSET(initrd_size, 0x21C, L"%xh"); CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh"); CHECK_OFFSET(cmdline_addr, 0x228, L"%xh"); CHECK_OFFSET(e820_map, 0x2D0, L"%xh"); if (test) { ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); free_kmem(); return -1; } } /* * Get video information. * Do this last so that any other cursor positioning done * in the fill routine gets accounted for. */ if (!get_video_info(bp)) goto do_memmap; /* Do the old text mode */ efi_status = uefi_call_wrapper( ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &cols, &rows); if (EFI_ERROR(efi_status)) { ERR_PRT((L"QueryMode failed. Fake it.")); mode = 3; rows = 25; cols = 80; row = 24; col = 0; } else { mode = (UINT8)ST->ConOut->Mode->Mode; col = (UINT8)ST->ConOut->Mode->CursorColumn; row = (UINT8)ST->ConOut->Mode->CursorRow; } bp->s.orig_cursor_col = col; bp->s.orig_cursor_row = row; bp->s.orig_video_page = 0; bp->s.orig_video_mode = mode; bp->s.orig_video_cols = (UINT8)cols; bp->s.orig_video_rows = (UINT8)rows; bp->s.orig_ega_bx = 0; bp->s.is_vga = 0; bp->s.orig_video_points = 16; bp->s.lfb_width = 0; bp->s.lfb_height = 0; bp->s.lfb_depth = 0; bp->s.lfb_base = 0; bp->s.lfb_size = 0; bp->s.lfb_line_len = 0; bp->s.lfb_red_size = 0; bp->s.lfb_red_pos = 0; bp->s.lfb_green_size = 0; bp->s.lfb_green_pos = 0; bp->s.lfb_blue_size = 0; bp->s.lfb_blue_pos = 0; bp->s.lfb_rsvd_size = 0; bp->s.lfb_rsvd_pos = 0; bp->s.lfb_pages = 0; bp->s.vesa_seg = 0; bp->s.vesa_off = 0; do_memmap: /* * Get memory map description and cookie for ExitBootServices() */ if (get_memmap(&mdesc)) { ERR_PRT((L"Could not get memory map.")); free_kmem(); return -1; } *cookie = mdesc.cookie; bp->s.efi_mem_map = (UINT32)(unsigned long)mdesc.md; bp->s.efi_mem_map_size = mdesc.map_size; bp->s.efi_mem_desc_size = mdesc.desc_size; bp->s.efi_mem_desc_ver = mdesc.desc_version; bp->s.efi_sys_tbl = (UINT32)(unsigned long)systab; bp->s.efi_mem_map_hi = (unsigned long)mdesc.md >> 32; bp->s.efi_sys_tbl_hi = (unsigned long)systab >> 32; /* Now that we have EFI memory map, convert it to E820 map * and update the bootparam accordingly */ fill_e820map(bp, &mdesc); #if DEBUG_CREATE_BOOT_PARAMS if ( e820_map_overflow == 0 ) e820_map_overflow = -1; /* force second get_memmap()! */ #endif if (e820_map_overflow && !e820_map_overflow_warned) { CHAR8 *aem = (CHAR8 *)"add_efi_memmap"; e820_map_overflow_warned++; #if DEBUG_CREATE_BOOT_PARAMS elilo_opt.debug=0; elilo_opt.verbose=0; #endif if (e820_map_overflow == -1 || StrStr8(cmdline, aem)) { /* Print(L"...mapping again, silently!\n"); */ goto do_memmap; } Print(L"\nCAUTION: EFI memory map has %d more entr%a" " than E820 map supports.\n" "To access all memory, '%a' may be necessary.\n\n", e820_map_overflow, (e820_map_overflow==1)?"y":"ies", aem); goto do_memmap; } return 0; } ./elilo/x86_64/config.c0000644000175000017500000000534311466354123014222 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Chris Ahna * * 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 #include #include "elilo.h" #include "config.h" #include "private.h" typedef struct { UINTN legacy_free_boot; UINTN text_mode; } x86_64_global_config_t; #define x86_64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option) static x86_64_global_config_t x86_64_gconf; static config_option_t sysdeps_global_options[]={ {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot} }; static config_option_t sysdeps_image_options[]={ {OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)} }; /* * X86_64 operations that need to be done only once and just before * entering the main loop of the loader * Return: * 0 if sucessful * -1 otherwise (will abort execution) */ INTN sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image) { return 0; } #define X86_64_CMDLINE_OPTIONS L"" CHAR16 * sysdeps_get_cmdline_opts(VOID) { return X86_64_CMDLINE_OPTIONS; } INTN sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg) { return -1; } VOID sysdeps_print_cmdline_opts(VOID) { } INTN x86_64_use_legacy_free_boot(VOID) { return x86_64_gconf.legacy_free_boot ? 1 : 0; } INTN x86_64_text_mode(VOID) { return (elilo_opt.sys_img_opts && elilo_opt.sys_img_opts->text_mode == TRUE) ? 1 : 0; } INTN sysdeps_register_options(VOID) { INTN ret; ret = register_config_options(sysdeps_global_options, sizeof(sysdeps_global_options)/sizeof(config_option_t), OPTIONS_GROUP_GLOBAL); if (ret == -1 ) return ret; ret = register_config_options(sysdeps_image_options, sizeof(sysdeps_image_options)/sizeof(config_option_t), OPTIONS_GROUP_IMAGE); return ret; } ./elilo/x86_64/gzip.c0000644000175000017500000003274711271404162013727 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant * * 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 * 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 #include #include "elf.h" #include "elilo.h" #include "gzip.h" #include "private.h" #define memzero(s, n) Memset((VOID *)(s), 0, (n)) #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) /* size of output buffer */ #define WSIZE 0x8000 /* Window size must be at least 32k, */ /* and a power of two */ /* size of input buffer */ #define INBUFSIZE 0x8000 /* * gzip declarations */ #define OF(args) args #define FUNC_STATIC static typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; typedef struct segment { unsigned long addr; /* start address */ unsigned long offset; /* file offset */ unsigned long size; /* file size */ unsigned long bss_sz; /* BSS size */ UINT8 flags; /* indicates whether to load or not */ } segment_t; #define CHUNK_FL_VALID 0x1 #define CHUNK_FL_LOAD 0x2 #define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD #define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD #define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD) #define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID #define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0 #define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID) /* * static parameters to gzip helper functions * we cannot use paramters because API was not * designed that way */ static segment_t *chunks; /* holds the list of segments */ static segment_t *cur_chunk; static UINTN nchunks; static UINTN chunk; /* current segment */ static UINTN input_fd; static VOID *kernel_entry, *kernel_base, *kernel_end; static uch *inbuf; /* input buffer (compressed data) */ static uch *window; /* output buffer (uncompressed data) */ static unsigned long file_offset; /* position in the file */ static unsigned insize = 0; /* valid bytes in inbuf */ static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) /* Diagnostic functions */ #ifdef INFLATE_DEBUG # define Assert(cond,msg) {if(!(cond)) error(msg);} int stderr; # define Trace(x) Print(L"line %d:\n", __LINE__); # define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;} # define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;} # define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;} # define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif static int fill_inbuf(void); static void flush_window(void); static void error(char *m); static long bytes_out; static void error(char *m); static int error_return; static void * gzip_malloc(int size) { return (void *)alloc(size, 0); } static void gzip_free(void *where) { return free(where); } #include "inflate.c" /* * Fill the input buffer and return the first byte in it. This is called * only when the buffer is empty and at least one byte is really needed. */ int fill_inbuf(void) { UINTN expected, nread; EFI_STATUS status; expected = nread = INBUFSIZE; status = fops_read(input_fd, inbuf, &nread); if (EFI_ERROR(status)) { error("elilo: Read failed"); } #ifdef DEBUG_GZIP DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected)); #endif insize = nread; inptr = 1; return inbuf[0]; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ /* * Run a set of bytes through the crc shift register. If s is a NULL * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. * * Input: * S pointer to bytes to pump through. * N number of bytes in S[]. */ unsigned long updcrc(unsigned char *s, unsigned n) { register unsigned long c; /* crc is defined in inflate.c */ if (!s) { c = 0xffffffffL; } else { c = crc; while (n--) { c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } } crc = c; return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */ } /* * Clear input and output buffers */ void clear_bufs(void) { outcnt = 0; inptr = 0; chunk = 0; cur_chunk = NULL; file_offset = 0; } static INTN is_valid_header(Elf64_Ehdr *ehdr) { UINT16 type, machine; type = ehdr->e_type; machine = ehdr->e_machine; VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS64 && type == ET_EXEC /* must be executable */ && machine == EM_X86_64 ? 0 : -1; } /* * will invalidate loadble segments which overlap with others */ void check_overlap(int i) { int j; unsigned long iend = chunks[i].addr + chunks[i].size; for(j=0; j < nchunks; j++) { if (j ==i) continue; if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) { DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j)); CHUNK_INVALIDATE(i); /* nullyify segment */ break; } } } void analyze_chunks(void) { INTN i; for (i=0; i < nchunks; i++) { if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i); } } /* * The decompression code calls this function after decompressing the * first block of the object file. The first block must contain all * the relevant header information. */ int first_block (const unsigned char *buf, long blocksize) { Elf64_Ehdr *elf; Elf64_Phdr *phdrs; UINTN total_size, pages; UINTN low_addr, max_addr; UINTN offs = 0; UINT16 phnum; UINTN paddr, memsz; INTN i; elf = (Elf64_Ehdr *)buf; if (is_valid_header(elf) == -1) return -1; offs = elf->e_phoff; phnum = elf->e_phnum; VERB_PRT(3, { Print(L"Entry point 0x%lx\n", elf->e_entry); Print(L"%d program headers\n", phnum); Print(L"%d segment headers\n", elf->e_shnum); }); if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) { ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs)); return -1; } kernel_entry = (VOID *)(elf->e_entry & PADDR_MASK); phdrs = (Elf64_Phdr *) (buf + offs); low_addr = ~0; max_addr = 0; /* * allocate chunk table * Convention: a segment that does not need loading will * have chunk[].addr = 0. */ chunks = (void *)alloc(sizeof(struct segment)*phnum, 0); if (chunks == NULL) { ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME)); return -1; } nchunks = phnum; /* * find lowest and higest virtual addresses * don't assume FULLY sorted ! */ for (i = 0; i < phnum; ++i) { /* * record chunk no matter what because no load may happen * anywhere in archive, not just as the last segment */ paddr = (phdrs[i].p_paddr & PADDR_MASK); memsz = phdrs[i].p_memsz, chunks[i].addr = paddr; chunks[i].offset = phdrs[i].p_offset; chunks[i].size = phdrs[i].p_filesz; chunks[i].bss_sz = phdrs[i].p_memsz - phdrs[i].p_filesz; CHUNK_VALIDATE(i); if (phdrs[i].p_type != PT_LOAD) { CHUNK_NO_LOAD(i); /* mark no load chunk */ DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i)); continue; } CHUNK_CAN_LOAD(i); /* mark no load chunk */ VERB_PRT(3, Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld " "memsz=%ld bss_sz=%ld\n", LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+phdrs[i].p_filesz, chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz)); if (paddr < low_addr) low_addr = paddr; if (paddr + memsz > max_addr) max_addr = paddr + memsz; } if (low_addr & (EFI_PAGE_SIZE - 1)) { ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr)); goto error; } analyze_chunks(); DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n", LD_NAME, phnum, kernel_entry, low_addr, max_addr)); total_size = (UINTN)max_addr - (UINTN)low_addr; pages = EFI_SIZE_TO_PAGES(total_size); /* * Record end of kernel for initrd */ kernel_base = (void *)low_addr; kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT)); /* allocate memory for the kernel */ if (alloc_kmem((void *)low_addr, pages) == -1) { ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); ERR_PRT((L"%s : Could not load kernel at 0x%lx\n", LD_NAME, low_addr)); ERR_PRT((L"%s : Bailing\n", LD_NAME)); goto error; } return 0; error: if (chunks) free(chunks); return -1; } /* * Determine which chunk in the Elf file will be coming out of the expand * code next. */ static void nextchunk(void) { int i; segment_t *cp; cp = NULL; for(i=0; i < nchunks; i++) { if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue; if (file_offset > chunks[i].offset) continue; if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i]; } cur_chunk = cp; } /* * Write the output window window[0..outcnt-1] holding uncompressed * data and update crc. */ void flush_window(void) { static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' }; static UINTN heli_count; struct segment *cp; unsigned char *src, *dst; long cnt; if (!outcnt) return; #ifdef DEBUG_GZIP DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset)); #endif Print(L"%c\b",helicopter[heli_count++%4]); updcrc(window, outcnt); /* first time, we extract the headers */ if (!bytes_out) { if (first_block(window, outcnt) < 0) error("invalid exec header"); nextchunk(); } bytes_out += outcnt; src = window; tail: /* check if user wants to abort */ if (check_abort() == EFI_SUCCESS) goto load_abort; cp = cur_chunk; if (cp == NULL || file_offset + outcnt <= cp->offset) { file_offset += outcnt; return; } /* Does this window begin before the current chunk? */ if (file_offset < cp->offset) { unsigned long skip = cp->offset - file_offset; src += skip; file_offset += skip; outcnt -= skip; } dst = (unsigned char *)cp->addr + (file_offset - cp->offset); cnt = cp->offset + cp->size - file_offset; if (cnt > outcnt) cnt = outcnt; Memcpy(dst, src, cnt); file_offset += cnt; outcnt -= cnt; src += cnt; /* See if we are at the end of this chunk */ if (file_offset == cp->offset + cp->size) { if (cp->bss_sz) { dst = (unsigned char *)cp->addr + cp->size; Memset(dst, 0, cp->bss_sz); } nextchunk(); /* handle remaining bytes */ if (outcnt) goto tail; } return; load_abort: free_kmem(); error_return = ELILO_LOAD_ABORTED; } static void error(char *x) { ERR_PRT((L"%s : %a", LD_NAME, x)); /* will eventually exit with error from gunzip() */ } INT32 decompress_kernel(VOID) { INT32 ret; clear_bufs(); makecrc(); Print(L"Uncompressing Linux... "); ret = gunzip(); if (ret == 0) Print(L"done\n"); return ret == 0 ? 0 : -1; } int gunzip_kernel(fops_fd_t fd, kdesc_t *kd) { int ret = -1; error_return = ELILO_LOAD_ERROR; window = (void *)alloc(WSIZE, 0); if (window == NULL) { ERR_PRT((L"%s : allocate output window failed\n", LD_NAME)); return -1; } inbuf = (void *)alloc(INBUFSIZE, 0); if (inbuf == NULL) { ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME)); goto error; } input_fd = fd; insize = 0; bytes_out = 0; ret = decompress_kernel(); error: if (window) free(window); if (inbuf) free(inbuf); if (ret == 0) { kd->kentry = kernel_entry; kd->kend = kernel_end; kd->kstart = kernel_base; error_return = ELILO_LOAD_SUCCESS; } return error_return; } ./elilo/x86_64/sysdeps.h0000644000175000017500000002753211466354123014460 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * Contributed by Mike Johnston * Contributed by Chris Ahna * 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 * 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. */ /* * This file is used to define all the x86_64-specific data structures * and constant used by the generic ELILO */ #ifndef __ELILO_SYSDEPS_X86_64_H__ #define __ELILO_SYSDEPS_X86_64_H__ #define ELILO_ARCH "x86_64" /* ASCII string */ #define PADDR_MASK 0xfffffff /* for now use library versions */ #define Memset(a,v,n) SetMem((a),(n),(v)) #define Memcpy(a,b,n) CopyMem((a),(b),(n)) /* Put initrd to far away from kernel image to avoid conflict. * May need to adjust this number if it is not big enough. */ #define INITRD_START (50*1024*1024) /* Default start address for kernel. */ #define DEFAULT_KERNEL_START 0x100000 /* * This version must match the one in the kernel. * * This table was put together using information from the * following Linux kernel source files: * linux/include/tty.h * linux/arch/i386/kernel/setup.c * linux/arch/i386/boot/bootsect.S * linux/arch/i386/boot/setup.S * linux/arch/i386/boot/video.S * * New fields in this structure for EFI and ELILO are: * efi_loader_sig * efi_st_addr * * A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags * field is also defined in this file. */ #pragma pack(1) /* Definitions for converting EFI memory map to E820 map for Linux * These definitions are from include/linux/asm-x86_64/e820.h * The structure x86_64_boot_params below is updated to accommodate E820 map * EFI memory map is converted to E820 map in this structure and passed * to Linux. This way the OS does not need to do the conversion. */ #define E820_RAM 1 #define E820_RESERVED 2 #define E820_ACPI 3 #define E820_NVS 4 #define E820_EXEC_CODE 5 #define E820_MAX 128 struct e820entry { UINT64 addr; /* start of memory segment */ UINT64 size; /* size of memory segment */ UINT32 type; /* type of memory segment */ } __attribute__((packed)); typedef union x86_64_boot_params { UINT8 raw[0x2000]; struct { /* Cursor position before passing control to kernel. */ /* 0x00 */ UINT8 orig_cursor_col; /* LDR */ /* 0x01 */ UINT8 orig_cursor_row; /* LDR */ /* Available contiguous extended memory in KB. */ /* 0x02 */ UINT16 ext_mem_k; /* LDR */ /* Video page, mode and screen width before passing control to kernel. */ /* 0x04 */ UINT16 orig_video_page; /* LDR */ /* 0x06 */ UINT8 orig_video_mode; /* LDR */ /* 0x07 */ UINT8 orig_video_cols; /* LDR */ /* 0x08 */ UINT16 pad_1; /* unused */ /* %%TBD */ /* 0x0A */ UINT16 orig_ega_bx; /* LDR */ /* 0x0C */ UINT16 pad_2; /* unused */ /* Screen height before passing control to kernel. */ /* 0x0E */ UINT8 orig_video_rows; /* LDR */ /* %%TBD */ /* 0x0F */ UINT8 is_vga; /* LDR */ /* 0x10 */ UINT16 orig_video_points; /* LDR */ /* %%TBD */ /* 0x12 */ UINT16 lfb_width; /* LDR */ /* 0x14 */ UINT16 lfb_height; /* LDR */ /* 0x16 */ UINT16 lfb_depth; /* LDR */ /* 0x18 */ UINT32 lfb_base; /* LDR */ /* 0x1C */ UINT32 lfb_size; /* LDR */ /* Offset of command line (from start of ia32_boot_param struct). */ /* The command line magik number must be set for the kernel setup */ /* code to use the command line offset. */ /* 0x20 */ UINT16 cmdline_magik; /* LDR */ #define CMDLINE_MAGIK 0xA33F /* 0x22 */ UINT16 cmdline_offset; /* LDR */ /* %%TBD */ /* 0x24 */ UINT16 lfb_line_len; /* LDR */ /* %%TBD */ /* 0x26 */ UINT8 lfb_red_size; /* LDR */ /* 0x27 */ UINT8 lfb_red_pos; /* LDR */ /* 0x28 */ UINT8 lfb_green_size; /* LDR */ /* 0x29 */ UINT8 lfb_green_pos; /* LDR */ /* 0x2A */ UINT8 lfb_blue_size; /* LDR */ /* 0x2B */ UINT8 lfb_blue_pos; /* LDR */ /* 0x2C */ UINT8 lfb_rsvd_size; /* LDR */ /* 0x2D */ UINT8 lfb_rsvd_pos; /* LDR */ /* %%TBD */ /* 0x2E */ UINT16 vesa_seg; /* LDR */ /* 0x30 */ UINT16 vesa_off; /* LDR */ /* %%TBD */ /* 0x32 */ UINT16 lfb_pages; /* LDR */ /* 0x34 */ UINT8 lfb_reserved[0x0C]; /* reserved */ /* %%TBD */ /* 0x40 */ UINT16 apm_bios_ver; /* LDR */ #define NO_APM_BIOS 0x0000 /* %%TBD */ /* 0x42 */ UINT16 bios_code_seg; /* LDR */ /* 0x44 */ UINT32 bios_entry_point; /* LDR */ /* 0x48 */ UINT16 bios_code_seg16; /* LDR */ /* 0x4A */ UINT16 bios_data_seg; /* LDR */ /* %%TBD */ /* 0x4C */ UINT16 apm_bios_flags; /* LDR */ #define NO_32BIT_APM_MASK 0xFFFD /* %%TBD */ /* 0x4E */ UINT32 bios_code_len; /* LDR */ /* 0x52 */ UINT16 bios_data_len; /* LDR */ /* 0x54 */ UINT8 pad_3[0x2C]; /* unused */ /* %%TBD */ /* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */ /* 0x90 */ UINT8 hd1_info[0x10]; /* LDR */ /* %%TBD */ /* 0xA0 */ UINT16 mca_info_len; /* LDR */ /* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */ /* 0xB2 */ UINT8 pad_4[0x10E]; /* unused */ /* EFI boot loader signature. */ /* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */ #define EFI_LOADER_SIG_X64 "EL64" /* Address of the EFI system table. */ /* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */ /* EFI memory descriptor size. */ /* 0x1C8 */ UINT32 efi_mem_desc_size; /* LDR */ /* EFI memory descriptor version. */ /* 0x1CC */ UINT32 efi_mem_desc_ver; /* LDR */ /* Address & size of EFI memory map. */ /* 0x1D0 */ UINT32 efi_mem_map; /* LDR */ /* 0x1D4 */ UINT32 efi_mem_map_size; /* LDR */ /* 0x1D8 */ UINT32 efi_sys_tbl_hi; /* LDR */ /* 0x1DC */ UINT32 efi_mem_map_hi; /* LDR */ /* Available contiguous extended memory in KB. */ /* 0x1E0 */ UINT32 alt_mem_k; /* LDR */ /* 0x1E4 */ UINT32 pad_51; /* unused */ /* 0x1E8 */ UINT8 e820_nrmap; /* 0x1E9 */ UINT32 pad_52[2]; /* unused */ /* Size of setup code in sectors (1 sector == 512 bytes). */ /* 0x1F1 */ UINT8 setup_sectors; /* BLD */ /* %%TBD */ /* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */ /* %%TBD */ /* 0x1F4 */ UINT32 sys_size; /* BLD */ /* %%TBD */ /* 0x1F8 */ UINT16 ram_size_DNU; /* BLD */ /* %%TBD */ /* 0x1FA */ UINT16 video_mode_flag; /* BLD */ /* %%TBD */ /* 0x1FC */ UINT16 orig_root_dev; /* BLD */ /* %%TBD */ /* 0x1FE */ UINT16 boot_flag; /* ? */ /* Jump past setup data (not used in EFI). */ /* 0x200 */ UINT16 jump; /* BLD */ /* Setup data signature. */ /* 0x202 */ UINT8 setup_sig[4]; /* BLD */ #define SETUP_SIG "HdrS" /* %%TBD */ /* 0x206 */ UINT8 hdr_minor; /* BLD */ /* 0x207 */ UINT8 hdr_major; /* BLD */ /* %%TBD */ /* 0x208 */ UINT32 rm_switch; /* LDD */ /* %%TBD */ /* 0x20C */ UINT16 start_sys_seg; /* BLD */ /* %%TBD */ /* 0x20E */ UINT16 kernel_verstr_offset; /* BLD */ /* Loader type & version. */ /* 0x210 */ UINT8 loader_type; /* LDR */ #define LDRTYPE_ELILO 0x50 /* 5?h == elilo */ /* ?0h == revision */ /* 0x211 */ UINT8 loader_flags; /* BLD and LDR */ #define LDRFLAG_CAN_USE_HEAP 0x80 #define LDRFLAG_BOOT_PARAM_RELOC 0x40 /* %%TBD */ /* 0x212 */ UINT16 setup_move_size; /* BLD */ /* %%TBD */ /* 0x214 */ UINT32 kernel_start; /* LDR */ /* %%TBD */ /* 0x218 */ UINT32 initrd_start; /* LDR */ /* 0x21C */ UINT32 initrd_size; /* LDR */ /* %%TBD */ /* 0x220 */ UINT32 bootsect_helper_DNU; /* BLD */ /* %%TBD */ /* 0x224 */ UINT16 heap_end_ptr; /* LDR */ /* %%TBD */ /* 0x226 */ UINT8 ext_loader_ver; /* LDR */ /* 0x227 */ UINT8 ext_loader_type; /* LDR */ /* 0x228 */ UINT32 cmdline_addr; /* LDR */ /* 0x22C */ UINT32 initrd_addr_max; /* BLD */ /* 0x230 */ UINT32 kernel_alignment; /* BLD */ /* 0x234 */ UINT8 relocatable_kernel; /* BLD */ /* 0x235 */ UINT8 pad_8[3]; /* 0x238 */ UINT32 pad_9[38]; /* 0x2D0 */ UINT8 e820_map[2560]; } s; } boot_params_t; #pragma pack() /* * The stuff below here is for jumping to the kernel. */ /* * Some macros to copy and set memory after EFI has been * stopped. */ #define MEMCPY(to, from, cnt) { \ UINT8 *t = (UINT8 *)(to); \ UINT8 *f = (UINT8 *)(from); \ UINTN n = cnt; \ if (t && f && n && (tf)) { \ t += n; \ f += n; \ while (n--) { \ *t-- = *f--; \ } \ } \ } #define MEMSET(ptr, size, val) { \ UINT8 *p = (UINT8 *)(ptr); \ UINTN n = (UINTN)(size); \ UINT8 v = (UINT8)(val); \ if (p && n) { \ while (n--) { \ *p++ = v; \ } \ } \ } /* * Descriptor table pointer format. */ #pragma pack(1) typedef struct { UINT16 limit; UINT64 base; } dt_addr_t; #pragma pack() extern UINTN high_base_mem; extern UINTN high_ext_mem; extern boot_params_t *param_start; extern UINTN param_size; extern VOID *kernel_start; extern UINTN kernel_size; extern VOID *kernel_load_address; extern VOID *initrd_start; extern UINTN initrd_size; extern dt_addr_t gdt_addr; extern dt_addr_t idt_addr; extern UINT16 init_gdt[]; extern UINTN sizeof_init_gdt; extern UINT8 rmswitch_image[]; extern UINTN rmswitch_size; extern INTN x86_64_use_legacy_free_boot(); extern INTN x86_64_text_mode(); /* * How to jump to kernel code */ static inline void start_kernel(VOID *kentry, boot_params_t *bp) { struct { UINT32 kernel_entry; UINT16 kernel_cs; } jumpvector; VOID *jump_start; /* * Disable interrupts. */ asm volatile ( "cli" : : ); /* * Relocate kernel (if needed). * This assumes that the initrd didn't get loaded overlapping where * we're planning to copy the kernel, but that's pretty unlikely * since we couldn't alloc that space for the kernel (or the kernel * would already be there). */ if (kernel_start != kernel_load_address) { MEMCPY(kernel_start, kernel_load_address, kernel_size); } /* * Copy boot sector, setup data and command line * to final resting place. We need to copy * BOOT_PARAM_MEMSIZE bytes. */ MEMCPY(high_base_mem, bp, 0x4000); bp = (boot_params_t *)high_base_mem; bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset; /* * Initialize Linux GDT. */ MEMSET(gdt_addr.base, gdt_addr.limit, 0); MEMCPY(gdt_addr.base, init_gdt, sizeof_init_gdt); // fixme: why x86_64_use_legacy_free_boot() goes to _relocate? #if 0 if (! x86_64_use_legacy_free_boot()) { /* * Copy our real mode transition code to 0x7C00. */ MEMCPY(0x7C00, rmswitch_image, rmswitch_size); asm volatile ( "mov $0x7C00, %%rbx" : : ); asm volatile ( "jmp *%%rbx" : : ); } #endif /* * Load descriptor table pointers. */ asm volatile ( "lidt %0" : : "m" (idt_addr) ); asm volatile ( "lgdt %0" : : "m" (gdt_addr) ); /* * rsi := address of boot sector and setup data */ asm volatile ( "mov %0, %%rsi" : : "m" (high_base_mem) ); /* * Jump to kernel entry point. * * Cast is to tell gcc that we know we're going from * 64-bit ptr to 32-bit integer. */ jumpvector.kernel_entry=(UINT32)((UINT64)kentry); jumpvector.kernel_cs=0x10; jump_start = (VOID *)&jumpvector; //asm volatile ( "mov %0, %%rcx" : : "m" (&jumpvector) ); asm volatile ( "mov %0, %%rcx" : : "m" (jump_start) ); asm volatile ( "ljmp *(%%rcx)" : :); /* Never come back to here. */ } typedef struct sys_img_options { UINT8 dummy; /* forces non-zero offset for first field */ UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */ } sys_img_options_t; #endif /* __ELILO_SYSDEPS_X86_64_H__ */ ./elilo/x86_64/gzip_loader.c0000644000175000017500000000403010650210517015234 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #include "loader.h" #include "gzip.h" static INTN gzip_probe_format(CHAR16 *kname) { UINT8 buf[4]; EFI_STATUS status; INTN ret = -1; UINTN size; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return -1; size = sizeof(buf); status = fops_read(fd, buf, &size); if (EFI_ERROR(status) || size != sizeof(buf)) goto error; ret = gzip_probe(buf, sizeof(buf)); error: fops_close(fd); return ret; } static INTN gzip_load_kernel(CHAR16 *kname, kdesc_t *kd) { EFI_STATUS status; INT32 ret; fops_fd_t fd; status = fops_open(kname, &fd); if (EFI_ERROR(status)) return ELILO_LOAD_ERROR; ret = gunzip_kernel(fd, kd); fops_close(fd); return ret; /* could be success, error, or abort */ } loader_ops_t gzip_loader={ NULL, LD_NAME, gzip_probe_format, gzip_load_kernel }; ./elilo/x86_64/inflate.c0000644000175000017500000011166410650210517014373 0ustar jasonfjasonf#define DEBG(x) #define DEBG1(x) /* inflate.c -- Not copyrighted 1992 by Mark Adler version c10p1, 10 January 1993 */ /* * Adapted for booting Linux by Hannu Savolainen 1993 * based on gzip-1.0.3 * * Nicolas Pitre , 1999/04/14 : * Little mods for all variable to reside either into rodata or bss segments * by marking constant variables with 'const' and initializing all the others * at run-time only. This allows for the kernel uncompressor to run * directly from Flash or ROM memory on embeded systems. */ /* Inflate deflated (PKZIP's method 8 compressed) data. The compression method searches for as much of the current string of bytes (up to a length of 258) in the previous 32 K bytes. If it doesn't find any matches (of at least length 3), it codes the next byte. Otherwise, it codes the length of the matched string and its distance backwards from the current position. There is a single Huffman code that codes both single bytes (called "literals") and match lengths. A second Huffman code codes the distance information, which follows a length code. Each length or distance code actually represents a base value and a number of "extra" (sometimes zero) bits to get to add to the base value. At the end of each deflated block is a special end-of-block (EOB) literal/ length code. The decoding process is basically: get a literal/length code; if EOB then done; if a literal, emit the decoded byte; if a length then get the distance and emit the referred-to bytes from the sliding window of previously emitted data. There are (currently) three kinds of inflate blocks: stored, fixed, and dynamic. The compressor deals with some chunk of data at a time, and decides which method to use on a chunk-by-chunk basis. A chunk might typically be 32 K or 64 K. If the chunk is incompressible, then the "stored" method is used. In this case, the bytes are simply stored as is, eight bits per byte, with none of the above coding. The bytes are preceded by a count, since there is no longer an EOB code. If the data is compressible, then either the fixed or dynamic methods are used. In the dynamic method, the compressed data is preceded by an encoding of the literal/length and distance Huffman codes that are to be used to decode this block. The representation is itself Huffman coded, and so is preceded by a description of that code. These code descriptions take up a little space, and so for small blocks, there is a predefined set of codes, called the fixed codes. The fixed method is used if the block codes up smaller that way (usually for quite small chunks), otherwise the dynamic method is used. In the latter case, the codes are customized to the probabilities in the current block, and so can code it much better than the pre-determined fixed codes. The Huffman codes themselves are decoded using a multi-level table lookup, in order to maximize the speed of decoding plus the speed of building the decoding tables. See the comments below that precede the lbits and dbits tuning parameters. */ /* Notes beyond the 1.93a appnote.txt: 1. Distance pointers never point before the beginning of the output stream. 2. Distance pointers can point back across blocks, up to 32k away. 3. There is an implied maximum of 7 bits for the bit length table and 15 bits for the actual data. 4. If only one code exists, then it is encoded using one bit. (Zero would be more efficient, but perhaps a little confusing.) If two codes exist, they are coded using one bit each (0 and 1). 5. There is no way of sending zero distance codes--a dummy must be sent if there are none. (History: a pre 2.0 version of PKZIP would store blocks with no distance codes, but this was discovered to be too harsh a criterion.) Valid only for 1.93a. 2.04c does allow zero distance codes, which is sent as one code of zero bits in length. 6. There are up to 286 literal/length codes. Code 256 represents the end-of-block. Note however that the static length tree defines 288 codes just to fill out the Huffman codes. Codes 286 and 287 cannot be used though, since there is no length base or extra bits defined for them. Similarly, there are up to 30 distance codes. However, static trees define 32 codes (all 5 bits) to fill out the Huffman codes, but the last two had better not show up in the data. 7. Unzip can check dynamic Huffman blocks for complete code sets. The exception is that a single code would not be complete (see #4). 8. The five bits following the block type is really the number of literal codes sent minus 257. 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits (1+6+6). Therefore, to output three times the length, you output three codes (1+1+1), whereas to output four times the same length, you only need two codes (1+3). Hmm. 10. In the tree reconstruction algorithm, Code = Code + Increment only if BitLength(i) is not zero. (Pretty obvious.) 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) 12. Note: length code 284 can represent 227-258, but length code 285 really is 258. The last length deserves its own, short code since it gets used a lot in very redundant files. The length 258 is special since 258 - 3 (the min match length) is 255. 13. The literal/length and distance code bit lengths are read as a single stream of lengths. It is possible (and advantageous) for a repeat code (16, 17, or 18) to go across the boundary between the two sets of lengths. */ #ifdef RCSID static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #"; #endif #ifndef FUNC_STATIC #if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) # include # include #endif #include "gzip.h" #define FUNC_STATIC #endif /* !FUNC_STATIC */ #define slide window /* Huffman code lookup table entry--this entry is four bytes for machines that have 16-bit pointers (e.g. PC's in the small or medium model). Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 means that v is a literal, 16 < e < 32 means that v is a pointer to the next table, which codes e - 16 bits, and lastly e == 99 indicates an unused code. If a code with e == 99 is looked up, this implies an error in the data. */ struct huft { uch e; /* number of extra bits or operation */ uch b; /* number of bits in this code or subcode */ union { ush n; /* literal, length base, or distance base */ struct huft *t; /* pointer to next level of table */ } v; }; /* Function prototypes */ FUNC_STATIC int huft_build OF((unsigned *, unsigned, unsigned, const ush *, const ush *, struct huft **, int *)); FUNC_STATIC int huft_free OF((struct huft *)); FUNC_STATIC int inflate_codes OF((struct huft *, struct huft *, int, int)); FUNC_STATIC int inflate_stored OF((void)); FUNC_STATIC int inflate_fixed OF((void)); FUNC_STATIC int inflate_dynamic OF((void)); FUNC_STATIC int inflate_block OF((int *)); FUNC_STATIC int inflate OF((void)); /* The inflate algorithm uses a sliding 32 K byte window on the uncompressed stream to find repeated byte strings. This is implemented here as a circular buffer. The index is updated simply by incrementing and then ANDing with 0x7fff (32K-1). */ /* It is left to other modules to supply the 32 K area. It is assumed to be usable as if it were declared "uch slide[32768];" or as just "uch *slide;" and then malloc'ed in the latter case. The definition must be in unzip.h, included above. */ /* unsigned wp; current position in slide */ #define wp outcnt #define flush_output(w) (wp=(w),flush_window()) /* Tables for deflate from PKZIP's appnote.txt. */ static const unsigned border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static const ush cplens[] = { /* Copy lengths for literal codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; /* note: see note #13 above about the 258 in this list. */ static const ush cplext[] = { /* Extra bits for literal codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ static const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static const ush cpdext[] = { /* Extra bits for distance codes */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /* Macros for inflate() bit peeking and grabbing. The usage is: NEEDBITS(j) x = b & mask_bits[j]; DUMPBITS(j) where NEEDBITS makes sure that b has at least j bits in it, and DUMPBITS removes the bits from b. The macros use the variable k for the number of bits in b. Normally, b and k are register variables for speed, and are initialized at the beginning of a routine that uses these macros from a global bit buffer and count. If we assume that EOB will be the longest code, then we will never ask for bits with NEEDBITS that are beyond the end of the stream. So, NEEDBITS should not read any more bytes than are needed to meet the request. Then no bytes need to be "returned" to the buffer at the end of the last block. However, this assumption is not true for fixed blocks--the EOB code is 7 bits, but the other literal/length codes can be 8 or 9 bits. (The EOB code is shorter than other codes because fixed blocks are generally short. So, while a block always has an EOB, many other literal/length codes have a significantly lower probability of showing up at all.) However, by making the first table have a lookup of seven bits, the EOB code will be found in that first lookup, and so will not require that too many bits be pulled from the stream. */ FUNC_STATIC ulg bb; /* bit buffer */ FUNC_STATIC unsigned bk; /* bits in bit buffer */ FUNC_STATIC const ush mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; #define NEXTBYTE() (uch)get_byte() #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} /* Huffman code decoding is performed using a multi-level table lookup. The fastest way to decode is to simply build a lookup table whose size is determined by the longest code. However, the time it takes to build this table can also be a factor if the data being decoded is not very long. The most common codes are necessarily the shortest codes, so those codes dominate the decoding time, and hence the speed. The idea is you can have a shorter table that decodes the shorter, more probable codes, and then point to subsidiary tables for the longer codes. The time it costs to decode the longer codes is then traded against the time it takes to make longer tables. This results of this trade are in the variables lbits and dbits below. lbits is the number of bits the first level table for literal/ length codes can decode in one step, and dbits is the same thing for the distance codes. Subsequent tables are also less than or equal to those sizes. These values may be adjusted either when all of the codes are shorter than that, in which case the longest code length in bits is used, or when the shortest code is *longer* than the requested table size, in which case the length of the shortest code in bits is used. There are two different values for the two tables, since they code a different number of possibilities each. The literal/length table codes 286 possible values, or in a flat code, a little over eight bits. The distance table codes 30 possible values, or a little less than five bits, flat. The optimum values for speed end up being about one bit more than those, so lbits is 8+1 and dbits is 5+1. The optimum values may differ though from machine to machine, and possibly even between compilers. Your mileage may vary. */ FUNC_STATIC const int lbits = 9; /* bits in base literal/length lookup table */ FUNC_STATIC const int dbits = 6; /* bits in base distance lookup table */ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ FUNC_STATIC unsigned hufts; /* track memory usage */ FUNC_STATIC int huft_build(b, n, s, d, e, t, m) unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ unsigned n; /* number of codes (assumed <= N_MAX) */ unsigned s; /* number of simple-valued codes (0..s-1) */ const ush *d; /* list of base values for non-simple codes */ const ush *e; /* list of extra bits for non-simple codes */ struct huft **t; /* result: starting table */ int *m; /* maximum lookup bits, returns actual */ /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return zero on success, one if the given code set is incomplete (the tables are still built in this case), two if the input is invalid (all zero length codes or an oversubscribed set of lengths), and three if not enough memory. */ { unsigned a; /* counter for codes of length k */ unsigned c[BMAX+1]; /* bit length count table */ unsigned f; /* i repeats in table every f entries */ int g; /* maximum code length */ int h; /* table level */ register unsigned i; /* counter, current code */ register unsigned j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ register unsigned *p; /* pointer into c[], b[], or v[] */ register struct huft *q; /* points to current table */ struct huft r; /* table entry for structure assignment */ struct huft *u[BMAX]; /* table stack */ unsigned v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ unsigned x[BMAX+1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ DEBG("huft1 "); /* Generate counts for each bit length */ memzero(c, sizeof(c)); p = b; i = n; do { Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), n-i, *p)); c[*p]++; /* assume all entries <= BMAX */ p++; /* Can't combine with above line (Solaris bug) */ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { *t = (struct huft *)NULL; *m = 0; return 0; } DEBG("huft2 "); /* Find minimum and maximum length, bound *m by those */ l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; /* minimum code length */ if ((unsigned)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; /* maximum code length */ if ((unsigned)l > i) l = i; *m = l; DEBG("huft3 "); /* Adjust last length count to fill out codes, if needed */ for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return 2; /* bad input: more codes than bits */ if ((y -= c[i]) < 0) return 2; c[i] += y; DEBG("huft4 "); /* Generate starting offsets into the value table for each length */ x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { /* note that i == g from above */ *xp++ = (j += *p++); } DEBG("huft5 "); /* Make a table of values in order of bit lengths */ p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); DEBG("h6 "); /* Generate the Huffman codes and for each, make the table entries */ x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ u[0] = (struct huft *)NULL; /* just to keep compilers happy */ q = (struct huft *)NULL; /* ditto */ z = 0; /* ditto */ DEBG("h6a "); /* go through the bit lengths (k already is bits in shortest code) */ for (; k <= g; k++) { DEBG("h6b "); a = c[k]; while (a--) { DEBG("h6b1 "); /* here i is the Huffman code of length k bits for value *p */ /* make tables up to required level */ while (k > w + l) { DEBG1("1 "); h++; w += l; /* previous table always l bits */ /* compute minimum size table less than or equal to l bits */ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ { /* too few codes for k-w bit table */ DEBG1("2 "); f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) /* try smaller tables up to z bits */ { if ((f <<= 1) <= *++xp) break; /* enough codes to use up j bits */ f -= *xp; /* else deduct codes from patterns */ } } DEBG1("3 "); z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ if ((q = (struct huft *)gzip_malloc((z + 1)*sizeof(struct huft))) == (struct huft *)NULL) { if (h) huft_free(u[0]); return 3; /* not enough memory */ } DEBG1("4 "); hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = (struct huft *)NULL; u[h] = ++q; /* table starts after link */ DEBG1("5 "); /* connect to last table, if there is one */ if (h) { x[h] = i; /* save pattern for backing up */ r.b = (uch)l; /* bits to dump before this table */ r.e = (uch)(16 + j); /* bits in this table */ r.v.t = q; /* pointer to this table */ j = i >> (w - l); /* (get around Turbo C bug) */ u[h-1][j] = r; /* connect to last table */ } DEBG1("6 "); } DEBG("h6c "); /* set up table entry in r */ r.b = (uch)(k - w); if (p >= v + n) r.e = 99; /* out of values--invalid code */ else if (*p < s) { r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (ush)(*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ } else { r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } DEBG("h6d "); /* fill code-like entries with r */ f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; /* backwards increment the k-bit code i */ for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; /* backup over finished tables */ while ((i & ((1 << w) - 1)) != x[h]) { h--; /* don't need to update q */ w -= l; } DEBG("h6e "); } DEBG("h6f "); } DEBG("huft7 "); /* Return true (1) if we were given an incomplete table */ return y != 0 && g != 1; } FUNC_STATIC int huft_free(t) struct huft *t; /* table to free */ /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ { register struct huft *p, *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; while (p != (struct huft *)NULL) { q = (--p)->v.t; gzip_free((char*)p); p = q; } return 0; } FUNC_STATIC int inflate_codes(tl, td, bl, bd) struct huft *tl, *td; /* literal/length and distance decoder tables */ int bl, bd; /* number of bits decoded by tl[] and td[] */ /* inflate (decompress) the codes in a deflated (compressed) block. Return an error code or zero if it all goes ok. */ { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ unsigned w; /* current window position */ struct huft *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ b = bb; /* initialize bit buffer */ k = bk; w = wp; /* initialize window position */ /* inflate the coded data */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; for (;;) /* do until end of block */ { NEEDBITS((unsigned)bl) if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) if (e == 16) /* then it's a literal */ { slide[w++] = (uch)t->v.n; Tracevv((stderr, "%c", slide[w-1])); if (w == WSIZE) { flush_output(w); w = 0; } } else /* it's an EOB or a length */ { /* exit if end of block */ if (e == 15) break; /* get length of block to copy */ NEEDBITS(e) n = t->v.n + ((unsigned)b & mask_bits[e]); DUMPBITS(e); /* decode distance of block to copy */ NEEDBITS((unsigned)bd) if ((e = (t = td + ((unsigned)b & md))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) NEEDBITS(e) d = w - t->v.n - ((unsigned)b & mask_bits[e]); DUMPBITS(e) Tracevv((stderr,"\\[%d,%d]", w-d, n)); /* do the copy */ do { n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); #if !defined(NOMEMCPY) && !defined(INFLATE_DEBUG) if (w - d >= e) /* (this test assumes unsigned comparison) */ { memcpy(slide + w, slide + d, e); w += e; d += e; } else /* do it slow to avoid memcpy() overlap */ #endif /* !NOMEMCPY */ do { slide[w++] = slide[d++]; Tracevv((stderr, "%c", slide[w-1])); } while (--e); if (w == WSIZE) { flush_output(w); w = 0; } } while (n); } } /* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk = k; /* done */ return 0; } FUNC_STATIC int inflate_stored() /* "decompress" an inflated type 0 (stored) block. */ { unsigned n; /* number of bytes in block */ unsigned w; /* current window position */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(""); return 0; } FUNC_STATIC int inflate_fixed() /* decompress an inflated type 1 (fixed Huffman codes) block. We should either replace this with a custom decoder, or at least precompute the Huffman tables. */ { int i; /* temporary variable */ struct huft *tl; /* literal/length code table */ struct huft *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned l[288]; /* length list for huft_build */ DEBG(" 1) { huft_free(tl); DEBG(">"); return i; } /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; /* free the decoding tables, return */ huft_free(tl); huft_free(td); return 0; } FUNC_STATIC int inflate_dynamic() /* decompress an inflated type 2 (dynamic Huffman codes) block. */ { int i; /* temporary variables */ unsigned j; unsigned l; /* last length */ unsigned m; /* mask for bit lengths table */ unsigned n; /* number of lengths to get */ struct huft *tl; /* literal/length code table */ struct huft *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned nb; /* number of bit length codes */ unsigned nl; /* number of literal/length codes */ unsigned nd; /* number of distance codes */ #ifdef PKZIP_BUG_WORKAROUND unsigned ll[288+32]; /* literal/length and distance code lengths */ #else unsigned ll[286+30]; /* literal/length and distance code lengths */ #endif register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(" 288 || nd > 32) #else if (nl > 286 || nd > 30) #endif return 1; /* bad lengths */ DEBG("dyn1 "); /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { NEEDBITS(3) ll[border[j]] = (unsigned)b & 7; DUMPBITS(3) } for (; j < 19; j++) ll[border[j]] = 0; DEBG("dyn2 "); /* build decoding table for trees--single level, 7 bit lookup */ bl = 7; if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { if (i == 1) huft_free(tl); return i; /* incomplete code set */ } DEBG("dyn3 "); /* read in literal and distance code lengths */ n = nl + nd; m = mask_bits[bl]; i = l = 0; while ((unsigned)i < n) { NEEDBITS((unsigned)bl) j = (td = tl + ((unsigned)b & m))->b; DUMPBITS(j) j = td->v.n; if (j < 16) /* length of code in bits (0..15) */ ll[i++] = l = j; /* save last length in l */ else if (j == 16) /* repeat last length 3 to 6 times */ { NEEDBITS(2) j = 3 + ((unsigned)b & 3); DUMPBITS(2) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = l; } else if (j == 17) /* 3 to 10 zero length codes */ { NEEDBITS(3) j = 3 + ((unsigned)b & 7); DUMPBITS(3) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } else /* j == 18: 11 to 138 zero length codes */ { NEEDBITS(7) j = 11 + ((unsigned)b & 0x7f); DUMPBITS(7) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } } DEBG("dyn4 "); /* free decoding table for trees */ huft_free(tl); DEBG("dyn5 "); /* restore the global bit buffer */ bb = b; bk = k; DEBG("dyn5a "); /* build the decoding tables for literal/length and distance codes */ bl = lbits; if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { DEBG("dyn5b "); if (i == 1) { error(" incomplete literal tree\n"); huft_free(tl); } return i; /* incomplete code set */ } DEBG("dyn5c "); bd = dbits; if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { DEBG("dyn5d "); if (i == 1) { error(" incomplete distance tree\n"); #ifdef PKZIP_BUG_WORKAROUND i = 0; } #else huft_free(td); } huft_free(tl); return i; /* incomplete code set */ #endif } DEBG("dyn6 "); /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; DEBG("dyn7 "); /* free the decoding tables, return */ huft_free(tl); huft_free(td); DEBG(">"); return 0; } FUNC_STATIC int inflate_block(e) int *e; /* last block flag */ /* decompress an inflated block */ { unsigned t; /* block type */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ DEBG(""); /* bad block type */ return 2; } FUNC_STATIC int inflate() /* decompress an inflated entry */ { int e; /* last block flag */ int r; /* result code */ unsigned h; /* maximum struct huft's malloc'ed */ /* initialize window, bit buffer */ wp = 0; bk = 0; bb = 0; /* decompress until the last block */ h = 0; do { hufts = 0; if ((r = inflate_block(&e)) != 0) { return r; } if (hufts > h) h = hufts; } while (!e); /* Undo too much lookahead. The next read will be byte aligned so we * can discard unused bits in the last meaningful byte. */ while (bk >= 8) { bk -= 8; inptr--; } /* flush out slide */ flush_output(wp); /* return success */ #ifdef INFLATE_DEBUG #ifdef EFI_COMPILE Print(L"<%d> ", h); #else printf("<%d> ", h); #endif #endif /* INFLATE_DEBUG */ return 0; } /********************************************************************** * * The following are support routines for inflate.c * **********************************************************************/ static ulg crc_32_tab[256]; static ulg crc; /* initialized in makecrc() so it'll reside in bss */ #define CRC_VALUE (crc ^ 0xffffffffUL) /* * Code to compute the CRC-32 table. Borrowed from * gzip-1.0.3/makecrc.c. */ static void makecrc(void) { /* Not copyrighted 1990 Mark Adler */ unsigned long c; /* crc shift register */ unsigned long e; /* polynomial exclusive-or pattern */ int i; /* counter for all possible eight bit values */ int k; /* byte being shifted into crc apparatus */ /* terms of polynomial defining this crc (except x^32): */ static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* Make exclusive-or pattern from polynomial */ e = 0; for (i = 0; i < sizeof(p)/sizeof(int); i++) e |= 1L << (31 - p[i]); crc_32_tab[0] = 0; for (i = 1; i < 256; i++) { c = 0; for (k = i | 256; k != 1; k >>= 1) { c = c & 1 ? (c >> 1) ^ e : c >> 1; if (k & 1) c ^= e; } crc_32_tab[i] = c; } /* this is initialized here so this code could reside in ROM */ crc = (ulg)0xffffffffUL; /* shift register contents */ } /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ /* * check for valid gzip signature * return: * 0 : valid gzip archive * -1: invalid gzip archive */ int gzip_probe(uch *buf, unsigned long size) { /* FIXME this is wrong here! FIXME!!!!*/ if (size < 4) return -1; if (buf[0] != 037 || ((buf[1] != 0213) && (buf[1] != 0236))) return -1; /* We only support method #8, DEFLATED */ if (buf[2] != 8) return -1; if ((buf[3] & ENCRYPTED) != 0) return -1; if ((buf[3] & CONTINUATION) != 0) return -1; if ((buf[3] & RESERVED) != 0) return -1; return 0; } /* * Do the uncompression! */ static int gunzip(void) { uch flags; unsigned char magic[2]; /* magic header */ char method; ulg orig_crc = 0; /* original crc */ ulg orig_len = 0; /* original uncompressed length */ int res; magic[0] = (unsigned char)get_byte(); magic[1] = (unsigned char)get_byte(); method = (unsigned char)get_byte(); if (magic[0] != 037 || ((magic[1] != 0213) && (magic[1] != 0236))) { error("bad gzip magic numbers"); return -1; } /* We only support method #8, DEFLATED */ if (method != 8) { error("internal error, invalid method"); return -1; } flags = (uch)get_byte(); if ((flags & ENCRYPTED) != 0) { error("Input is encrypted\n"); return -1; } if ((flags & CONTINUATION) != 0) { error("Multi part input\n"); return -1; } if ((flags & RESERVED) != 0) { error("Input has invalid flags\n"); return -1; } (ulg)get_byte(); /* Get timestamp */ ((ulg)get_byte()) << 8; ((ulg)get_byte()) << 16; ((ulg)get_byte()) << 24; (void)get_byte(); /* Ignore extra flags for the moment */ (void)get_byte(); /* Ignore OS type for the moment */ if ((flags & EXTRA_FIELD) != 0) { unsigned len = (unsigned)get_byte(); len |= ((unsigned)get_byte())<<8; while (len--) (void)get_byte(); } /* Get original file name if it was truncated */ if ((flags & ORIG_NAME) != 0) { /* Discard the old name */ while (get_byte() != 0) /* null */ ; } /* Discard file comment if any */ if ((flags & COMMENT) != 0) { while (get_byte() != 0) /* null */ ; } /* Decompress */ if ((res = inflate())) { switch (res) { case 0: break; case 1: error("invalid compressed format (err=1)"); break; case 2: error("invalid compressed format (err=2)"); break; case 3: error("out of memory"); break; default: error("invalid compressed format (other)"); } return -1; } /* Get the crc and original length */ /* crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ orig_crc = (ulg) get_byte(); orig_crc |= (ulg) get_byte() << 8; orig_crc |= (ulg) get_byte() << 16; orig_crc |= (ulg) get_byte() << 24; orig_len = (ulg) get_byte(); orig_len |= (ulg) get_byte() << 8; orig_len |= (ulg) get_byte() << 16; orig_len |= (ulg) get_byte() << 24; /* Validate decompression */ if (orig_crc != CRC_VALUE) { error("crc error"); return -1; } if (orig_len != bytes_out) { error("length error"); return -1; } return 0; } ./elilo/x86_64/gzip.h0000644000175000017500000000255210650210517013722 0ustar jasonfjasonf/* * Copyright (C) 2001-2002 Hewlett-Packard Co. * Contributed by Stephane Eranian * * 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 * 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. */ #ifndef __GZIP_H__ #define __GZIP_H__ int gzip_probe(unsigned char *, unsigned long); int gunzip_kernel(fops_fd_t, kdesc_t *); #define LD_NAME L"gzip_x86_64" #endif /* __GZIP_H__ */ ./elilo/alternate.c0000644000175000017500000000674310742000575013776 0ustar jasonfjasonf/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian * 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 * 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 #include #include "elilo.h" #define ELILO_ALTK_VAR L"EliloAlt" /* * we use a NULL GUID for now because it is more convenient */ static EFI_GUID altk_guid={0,}; /* * Check for the existence of an EFI variable named EliloAlt. * It contains the name of an alternate kernel (and possible options) * to boot ONLY once. * The variable is then deleted. This ensures that next reboot won't * pick it up. * * The content of the variable is assumed to be Unicode string. It is * preferrably NULL terminated but the code can deal with this as well. * * The size of the buffer MUST be expressed in bytes (not CHAR16). * * Return: * - 0 if successful * - -1 in case nothing happened (no variable found) * Please note that no fatal error is reported by this function */ INTN alternate_kernel(CHAR16 *buffer, UINTN size) { EFI_STATUS status; INTN ret = -1; /* * size of the buffer is expressed in bytes * * we reserve one Unicode for CHAR_NULL (forced), so * the buffer must be at least 2 more bytes to accomodate one Unicode */ if (size < 4) return -1; /* * reserve for CHAR_NULL */ size-=2; /* * Look if the variable exists. * We may fail because: * - the variable does not exist * - our buffer size is too small. */ status = uefi_call_wrapper(RT->GetVariable, 5, ELILO_ALTK_VAR, &altk_guid, NULL, &size, buffer); if (EFI_ERROR(status)) { DBG_PRT((L"cannot access variable %s: %r", ELILO_ALTK_VAR, status)); /* if buffer is too small, erase variable because it's unuseable */ if (status == EFI_BUFFER_TOO_SMALL) goto delete_var; return -1; } /* * sanity check * * verify that size (expressed in bytes) is multiple of 2. If * not then it can't possibly be representing a UNICODE string * (2bytes/character). * * We also consider empty as useless (2nd test). */ if (size & 0x1) { Print(L"invalid content for %s variable, erasing variable\n", ELILO_ALTK_VAR); goto delete_var; } /* We also consider empty as useless (2nd test) */ if (size == 2) goto delete_var; buffer[size] = CHAR_NULL; VERB_PRT(2, Print(L"found alternate variable %s : %s\n", ELILO_ALTK_VAR, buffer)); ret = 0; delete_var: status = uefi_call_wrapper(RT->SetVariable, 5, ELILO_ALTK_VAR, &altk_guid, 0, 0, NULL); if (EFI_ERROR(status)) { ERR_PRT((L"cannot erase variable %s", ELILO_ALTK_VAR)); } return ret; }