Print this page
10807 loader fails to boot Dell R510 in UEFI mode
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>

@@ -9,10 +9,11 @@
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
  * Copyright 2017 Toomas Soome <tsoome@me.com>
+ * Copyright 2019, Joyent, Inc.
  */
 
 /*
  * This module adds support for loading and booting illumos multiboot2
  * kernel. This code is only built to support the illumos kernel, it does

@@ -797,42 +798,76 @@
         size += sizeof (multiboot_tag_t);
 
         return (size);
 }
 
+#if defined(EFI)
+static bool
+overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2)
+{
+        if (start1 < start2 + size2 &&
+            start1 + size1 >= start2) {
+                printf("overlaps: %zx-%zx, %zx-%zx\n",
+                    start1, start1 + size1, start2, start2 + size2);
+                return (true);
+        }
+
+        return (false);
+}
+#endif
+
 static int
 multiboot2_exec(struct preloaded_file *fp)
 {
+        multiboot2_info_header_t *mbi = NULL;
         struct preloaded_file *mfp;
-        multiboot2_info_header_t *mbi;
         char *cmdline = NULL;
         struct devdesc *rootdev;
         struct file_metadata *md;
         int i, error, num;
         int rootfs = 0;
         size_t size;
         struct bios_smap *smap;
 #if defined(EFI)
         multiboot_tag_module_t *module, *mp;
+        struct relocator *relocator = NULL;
         EFI_MEMORY_DESCRIPTOR *map;
         UINTN map_size, desc_size;
-        struct relocator *relocator;
         struct chunk_head *head;
         struct chunk *chunk;
         vm_offset_t tmp;
 
         efi_getdev((void **)(&rootdev), NULL, NULL);
+
+        /*
+         * We need 5 pages for relocation. We'll allocate from the heap: while
+         * it's possible that our heap got placed low down enough to be in the
+         * way of where we're going to relocate our kernel, it's hopefully not
+         * likely.
+         */
+        if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) {
+                printf("relocator malloc failed!\n");
+                error = ENOMEM;
+                goto error;
+        }
+
+        if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5,
+            load_addr, fp->f_size)) {
+                printf("relocator pages overlap the kernel!\n");
+                error = EINVAL;
+                goto error;
+        }
+
 #else
         i386_getdev((void **)(&rootdev), NULL, NULL);
 
         if (have_framebuffer == false) {
                 /* make sure we have text mode */
                 bios_set_text_mode(VGA_TEXT_MODE);
         }
 #endif
 
-        mbi = NULL;
         error = EINVAL;
         if (rootdev == NULL) {
                 printf("can't determine root device\n");
                 goto error;
         }

@@ -1173,29 +1208,11 @@
                 }
                 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
                 tag->mb_size = sizeof (*tag) + map_size;
                 tag->mb_descr_size = (uint32_t)desc_size;
 
-                /*
-                 * Find relocater pages. We assume we have free pages
-                 * below kernel load address.
-                 * In this version we are using 5 pages:
-                 * relocator data, trampoline, copy, memmove, stack.
-                 */
-                for (i = 0, map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
-                    i < map_size / desc_size;
-                    i++, map = NextMemoryDescriptor(map, desc_size)) {
-                        if (map->PhysicalStart == 0)
-                                continue;
-                        if (map->Type != EfiConventionalMemory)
-                                continue;
-                        if (map->PhysicalStart < load_addr &&
-                            map->NumberOfPages > 5)
-                                break;
-                }
-                if (map->PhysicalStart == 0)
-                        panic("Could not find memory for relocater");
+                map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
 
                 if (keep_bs == 0) {
                         status = BS->ExitBootServices(IH, key);
                         if (EFI_ERROR(status)) {
                                 printf("Call to ExitBootServices failed\n");

@@ -1228,11 +1245,10 @@
          * address, module list in MBI having physical addresses,
          * module list in fp having logical addresses and tmp pointing to
          * physical address for MBI.
          * Now we must move all pieces to place and start the kernel.
          */
-        relocator = (struct relocator *)(uintptr_t)map->PhysicalStart;
         head = &relocator->rel_chunk_head;
         STAILQ_INIT(head);
 
         i = 0;
         chunk = &relocator->rel_chunklist[i++];

@@ -1288,13 +1304,16 @@
             (void *)entry_addr, (void *)VTOP(mbi));
 #endif /* EFI */
         panic("exec returned");
 
 error:
-        if (cmdline != NULL)
                 free(cmdline);
+
 #if defined(EFI)
+        free(relocator);
+
         if (mbi != NULL)
                 efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
 #endif
+
         return (error);
 }