Merge tag 'upstream/3.14'
[debian/elilo] / x86_64 / system.c
index 0755ff4e2807dbb442a27785e4ae7cc931dd95c0..44c2e467a6f3f05d2f33028c11d0c9d1405cc99f 100644 (file)
  */
 #include <efi.h>
 #include <efilib.h>
+#include <string.h>
 
 #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,11 +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 *)0x100000; /* 1M */
+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)
 {
@@ -128,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)
@@ -139,28 +150,72 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
        DBG_PRT((L"initrd_get_addr()\n"));
 
        if (!kd || !imem) {
-               ERR_PRT((L"kd=0x%x imem=0x%x", kd, imem));
+               ERR_PRT((L"kd="PTR_FMT" imem="PTR_FMT"", kd, imem));
                return -1;
        }
 
-       VERB_PRT(3, Print(L"kstart=0x%x  kentry=0x%x  kend=0x%x\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=0x%x pgcnt=%d\n", 
+       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 *)bp->s.efi_mem_map;
+       md.md = (VOID *)(UINT64)bp->s.efi_mem_map;
        free_memmap(&md);
 }
 
@@ -189,12 +244,17 @@ 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;
-        EFI_HANDLE *Gop_handle;
+        EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE   *Gop_mode = NULL;
+        EFI_HANDLE *Gop_handle = NULL;
         EFI_STATUS efi_status;
-        UINTN size, size1;
+        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,
@@ -205,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);
@@ -255,7 +327,7 @@ static INTN get_video_info(boot_params_t * bp) {
                return -1;
        }
                
-       bp->s.is_vga = 0x24;
+       bp->s.is_vga = 0x70;
        bp->s.orig_cursor_col = 0;
        bp->s.orig_cursor_row = 0;
        bp->s.orig_video_page = 0;
@@ -322,34 +394,141 @@ 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,
+                              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, i;
+       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;
-       bp->s.e820_nrmap = nr_map;
                        
        for (i = 0, p = mdesc->md; i < nr_map; i++)
        {
                md = p;
                switch (md->Type) {
                case EfiACPIReclaimMemory:
-                       e820_map->addr = md->PhysicalStart;
-                       e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
-                       e820_map->type = E820_ACPI;
+                       add_memory_region(e820_map, &e820_nr_map,
+                                         md->PhysicalStart,
+                                         md->NumberOfPages << EFI_PAGE_SHIFT,
+                                         E820_ACPI);
                        break;
                case EfiRuntimeServicesCode:
-                       e820_map->addr = md->PhysicalStart;
-                       e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
-                       e820_map->type = E820_EXEC_CODE;
+                       add_memory_region(e820_map, &e820_nr_map,
+                                         md->PhysicalStart,
+                                         md->NumberOfPages << EFI_PAGE_SHIFT,
+                                         E820_EXEC_CODE);
                        break;
                case EfiRuntimeServicesData:
                case EfiReservedMemoryType:
@@ -357,9 +536,10 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
                case EfiMemoryMappedIOPortSpace:
                case EfiUnusableMemory:
                case EfiPalCode:
-                       e820_map->addr = md->PhysicalStart;
-                       e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
-                       e820_map->type = E820_RESERVED;
+                       add_memory_region(e820_map, &e820_nr_map,
+                                         md->PhysicalStart,
+                                         md->NumberOfPages << EFI_PAGE_SHIFT,
+                                         E820_RESERVED);
                        break;
                case EfiLoaderCode:
                case EfiLoaderData:
@@ -375,10 +555,11 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
                                        /* start < 640K
                                         * set memory map from start to 640K
                                         */
-                                       e820_map->addr = start;
-                                       e820_map->size = 0xA0000ULL-start;
-                                       e820_map->type = E820_RAM;
-                                       e820_map++;
+                                       add_memory_region(e820_map,
+                                                         &e820_nr_map,
+                                                         start,
+                                                         0xA0000ULL-start,
+                                                         E820_RAM);
                                }
                                if (end <= 0x100000ULL)
                                        continue;
@@ -388,29 +569,33 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
                                start = 0x100000ULL;
                                size = end - start;
                        }
-                       e820_map->addr = start;
-                       e820_map->size = size;
-                       e820_map->type = E820_RAM;
+                       add_memory_region(e820_map, &e820_nr_map,
+                                         start, size, E820_RAM);
                        break;
                case EfiACPIMemoryNVS:
-                       e820_map->addr = md->PhysicalStart;
-                       e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
-                       e820_map->type = E820_NVS;
+                       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 */
-                       e820_map->addr = md->PhysicalStart;
-                       size = md->NumberOfPages << EFI_PAGE_SHIFT;
-                       e820_map->type = E820_RESERVED;
+                       DBG_PRT((L"hit default!?"));
+                       add_memory_region(e820_map, &e820_nr_map,
+                                         md->PhysicalStart,
+                                         md->NumberOfPages << EFI_PAGE_SHIFT,
+                                         E820_RESERVED);
                        break;
                }
-               e820_map++;
                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(
@@ -426,11 +611,17 @@ 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"));
 
        if (!bp || !cmdline || !initrd || !cookie) {
-               ERR_PRT((L"bp=0x%x  cmdline=0x%x  initrd=0x%x cookie=0x%x",
+               ERR_PRT((L"bp="PTR_FMT"  cmdline="PTR_FMT"  initrd="PTR_FMT" cookie="PTR_FMT"",
                        bp, cmdline, initrd, cookie));
 
                if (param_start != NULL) {
@@ -460,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.
@@ -517,22 +700,22 @@ sysdeps_create_boot_params(
         * Initial RAMdisk and root device stuff.
         */
 
-       DBG_PRT((L"initrd->start_addr=0x%x  initrd->pgcnt=%d\n",
+       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)initrd->start_addr;
+               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;
@@ -556,20 +739,20 @@ 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 
         */
-       CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
+       CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_X64, 4);
 
        /*
         * Kernel entry point.
         */
-       bp->s.kernel_start = (UINT32)kernel_start;
+       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
@@ -647,23 +830,21 @@ sysdeps_create_boot_params(
                CHECK_OFFSET(hd1_info, 0x90, L"");
                CHECK_OFFSET(mca_info_len, 0xA0, L"%xh");
                CHECK_OFFSET(mca_info_buf, 0xA2, L"");
-               CHECK_OFFSET(efi_sys_tbl, 0x1B8, L"%xh");
                CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'");
-               CHECK_OFFSET(efi_mem_desc_size, 0x1C4, L"%xh");
-               CHECK_OFFSET(efi_mem_desc_ver, 0x1C8, L"%xh");
-               CHECK_OFFSET(efi_mem_map_size, 0x1CC, L"%xh");
+               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(loader_start, 0x1D8, L"%xh");
-               CHECK_OFFSET(loader_size, 0x1DC, 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(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");
@@ -677,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."));
@@ -758,15 +939,42 @@ do_memmap:
                return -1;
        }
        *cookie = mdesc.cookie;
-       bp->s.efi_mem_map = (UINTN)mdesc.md;
+       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 = (UINTN)systab;
+       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;
 }