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);
}