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,18 **** --- 9,19 ---- * 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,838 **** size += sizeof (multiboot_tag_t); return (size); } static int multiboot2_exec(struct preloaded_file *fp) { 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; 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); #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; } --- 798,873 ---- 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; 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 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 error = EINVAL; if (rootdev == NULL) { printf("can't determine root device\n"); goto error; }
*** 1173,1201 **** } 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"); if (keep_bs == 0) { status = BS->ExitBootServices(IH, key); if (EFI_ERROR(status)) { printf("Call to ExitBootServices failed\n"); --- 1208,1218 ---- } tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP; tag->mb_size = sizeof (*tag) + map_size; tag->mb_descr_size = (uint32_t)desc_size; ! 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,1238 **** * 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++]; --- 1245,1254 ----
*** 1288,1300 **** (void *)entry_addr, (void *)VTOP(mbi)); #endif /* EFI */ panic("exec returned"); error: - if (cmdline != NULL) free(cmdline); #if defined(EFI) if (mbi != NULL) efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size)); #endif return (error); } --- 1304,1319 ---- (void *)entry_addr, (void *)VTOP(mbi)); #endif /* EFI */ panic("exec returned"); error: 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); }