X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=x86_64%2Fsystem.c;h=44c2e467a6f3f05d2f33028c11d0c9d1405cc99f;hb=4386d0ddc988a11e8f55d774f577e4ca4f83cea9;hp=6874acc51aa32e2eea7b9d07231a06e916211624;hpb=90dc485b21e0c6b3417e22e86f637f45e62748f2;p=debian%2Felilo diff --git a/x86_64/system.c b/x86_64/system.c index 6874acc..44c2e46 100644 --- a/x86_64/system.c +++ b/x86_64/system.c @@ -38,11 +38,19 @@ */ #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; /* @@ -105,14 +113,16 @@ UINTN high_base_mem = 0x90000; 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; +VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START; /* The kernel may load elsewhere if EFI firmware reserves kernel_start */ -VOID *kernel_load_address = DEFAULT_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) { @@ -131,10 +141,8 @@ sysdeps_init(EFI_HANDLE dev) /* * 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. + * 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) @@ -146,10 +154,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return -1; } - VERB_PRT(3, Print(L"kstart="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n", - kd->kstart, kd->kentry, kd->kend)); + VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n", + param_start->s.initrd_addr_max, 32*MB)); - imem->start_addr = kd->kend; + 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)); @@ -157,6 +167,48 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) 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) { @@ -199,6 +251,10 @@ static INTN get_video_info(boot_params_t * bp) { 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, @@ -209,7 +265,19 @@ static INTN get_video_info(boot_params_t * bp) { (VOID **)Gop_handle); if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { - ERR_PRT((L"LocateHandle GopProtocol failed.")); + 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); @@ -326,10 +394,56 @@ static INTN get_video_info(boot_params_t * bp) { 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, @@ -338,21 +452,56 @@ static void add_memory_region (struct e820entry *e820_map, 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 == E820_MAX) { - Print(L"Too many entries in the memory map!\n"); - return; - } + 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].type == type) { e820_map[x-1].size += size; - else { + 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) @@ -431,6 +580,7 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) 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, @@ -444,6 +594,8 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) /* * x86_64 specific boot parameters initialization routine + * + * Note: debug and verbose messages have already been turned off! */ INTN sysdeps_create_boot_params( @@ -459,6 +611,12 @@ sysdeps_create_boot_params( 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")); @@ -493,17 +651,9 @@ sysdeps_create_boot_params( hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor; /* - * Clear out unused memory in boot sector image. + * Do NOT clear out unknown memory in boot sector image. + * This breaks boot protocol >= 2.10 (2.6.31). */ - 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. @@ -553,19 +703,19 @@ sysdeps_create_boot_params( 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; + /* 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); - /* - * 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; @@ -589,11 +739,6 @@ sysdeps_create_boot_params( 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 */ @@ -602,6 +747,11 @@ sysdeps_create_boot_params( /* * 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; /* @@ -692,11 +842,9 @@ sysdeps_create_boot_params( 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(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"); @@ -710,9 +858,9 @@ sysdeps_create_boot_params( 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"%xh"); if (test) { ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); @@ -802,6 +950,31 @@ do_memmap: * 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; }