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>
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Toomas Soome <tsoome@me.com>

  14  */
  15 
  16 /*
  17  * This module adds support for loading and booting illumos multiboot2
  18  * kernel. This code is only built to support the illumos kernel, it does
  19  * not support xen.
  20  */
  21 
  22 #include <sys/cdefs.h>
  23 #include <sys/stddef.h>
  24 
  25 #include <sys/param.h>
  26 #include <sys/exec.h>
  27 #include <sys/linker.h>
  28 #include <sys/module.h>
  29 #include <sys/stdint.h>
  30 #include <sys/multiboot2.h>
  31 #include <stand.h>
  32 #include <stdbool.h>
  33 #include <machine/elf.h>


 782         if (bootp_response != NULL) {
 783                 size += sizeof (multiboot_tag_network_t) + bootp_response_size;
 784                 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
 785         }
 786 
 787         if (rsdp != NULL) {
 788                 if (rsdp->Revision == 0) {
 789                         size += sizeof (multiboot_tag_old_acpi_t) +
 790                             sizeof (ACPI_RSDP_COMMON);
 791                 } else {
 792                         size += sizeof (multiboot_tag_new_acpi_t) +
 793                             rsdp->Length;
 794                 }
 795                 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
 796         }
 797         size += sizeof (multiboot_tag_t);
 798 
 799         return (size);
 800 }
 801 















 802 static int
 803 multiboot2_exec(struct preloaded_file *fp)
 804 {

 805         struct preloaded_file *mfp;
 806         multiboot2_info_header_t *mbi;
 807         char *cmdline = NULL;
 808         struct devdesc *rootdev;
 809         struct file_metadata *md;
 810         int i, error, num;
 811         int rootfs = 0;
 812         size_t size;
 813         struct bios_smap *smap;
 814 #if defined(EFI)
 815         multiboot_tag_module_t *module, *mp;

 816         EFI_MEMORY_DESCRIPTOR *map;
 817         UINTN map_size, desc_size;
 818         struct relocator *relocator;
 819         struct chunk_head *head;
 820         struct chunk *chunk;
 821         vm_offset_t tmp;
 822 
 823         efi_getdev((void **)(&rootdev), NULL, NULL);




















 824 #else
 825         i386_getdev((void **)(&rootdev), NULL, NULL);
 826 
 827         if (have_framebuffer == false) {
 828                 /* make sure we have text mode */
 829                 bios_set_text_mode(VGA_TEXT_MODE);
 830         }
 831 #endif
 832 
 833         mbi = NULL;
 834         error = EINVAL;
 835         if (rootdev == NULL) {
 836                 printf("can't determine root device\n");
 837                 goto error;
 838         }
 839 
 840         /*
 841          * Set the image command line.
 842          */
 843         if (fp->f_args == NULL) {
 844                 cmdline = getenv("boot-args");
 845                 if (cmdline != NULL) {
 846                         fp->f_args = strdup(cmdline);
 847                         if (fp->f_args == NULL) {
 848                                 error = ENOMEM;
 849                                 goto error;
 850                         }
 851                 }
 852         }
 853 


1158 
1159                 map_size = 0;
1160                 status = BS->GetMemoryMap(&map_size,
1161                     (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1162                     &desc_size, &tag->mb_descr_vers);
1163                 if (status != EFI_BUFFER_TOO_SMALL) {
1164                         error = EINVAL;
1165                         goto error;
1166                 }
1167                 status = BS->GetMemoryMap(&map_size,
1168                     (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1169                     &desc_size, &tag->mb_descr_vers);
1170                 if (EFI_ERROR(status)) {
1171                         error = EINVAL;
1172                         goto error;
1173                 }
1174                 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
1175                 tag->mb_size = sizeof (*tag) + map_size;
1176                 tag->mb_descr_size = (uint32_t)desc_size;
1177 
1178                 /*
1179                  * Find relocater pages. We assume we have free pages
1180                  * below kernel load address.
1181                  * In this version we are using 5 pages:
1182                  * relocator data, trampoline, copy, memmove, stack.
1183                  */
1184                 for (i = 0, map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
1185                     i < map_size / desc_size;
1186                     i++, map = NextMemoryDescriptor(map, desc_size)) {
1187                         if (map->PhysicalStart == 0)
1188                                 continue;
1189                         if (map->Type != EfiConventionalMemory)
1190                                 continue;
1191                         if (map->PhysicalStart < load_addr &&
1192                             map->NumberOfPages > 5)
1193                                 break;
1194                 }
1195                 if (map->PhysicalStart == 0)
1196                         panic("Could not find memory for relocater");
1197 
1198                 if (keep_bs == 0) {
1199                         status = BS->ExitBootServices(IH, key);
1200                         if (EFI_ERROR(status)) {
1201                                 printf("Call to ExitBootServices failed\n");
1202                                 error = EINVAL;
1203                                 goto error;
1204                         }
1205                 }
1206 
1207                 last_addr += map_size;
1208                 last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
1209         }
1210 #endif /* EFI */
1211 
1212         /*
1213          * MB tag list end marker.
1214          */
1215         {
1216                 multiboot_tag_t *tag = (multiboot_tag_t *)
1217                     mb_malloc(sizeof (*tag));
1218                 tag->mb_type = MULTIBOOT_TAG_TYPE_END;
1219                 tag->mb_size = sizeof (*tag);
1220         }
1221 
1222         mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
1223         mbi->mbi_reserved = 0;
1224 
1225 #if defined(EFI)
1226         /*
1227          * At this point we have load_addr pointing to kernel load
1228          * address, module list in MBI having physical addresses,
1229          * module list in fp having logical addresses and tmp pointing to
1230          * physical address for MBI.
1231          * Now we must move all pieces to place and start the kernel.
1232          */
1233         relocator = (struct relocator *)(uintptr_t)map->PhysicalStart;
1234         head = &relocator->rel_chunk_head;
1235         STAILQ_INIT(head);
1236 
1237         i = 0;
1238         chunk = &relocator->rel_chunklist[i++];
1239         chunk->chunk_vaddr = fp->f_addr;
1240         chunk->chunk_paddr = load_addr;
1241         chunk->chunk_size = fp->f_size;
1242 
1243         STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1244 
1245         mp = module;
1246         for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
1247                 chunk = &relocator->rel_chunklist[i++];
1248                 chunk->chunk_vaddr = mfp->f_addr;
1249 
1250                 /*
1251                  * fix the mb_mod_start and mb_mod_end.
1252                  */
1253                 mp->mb_mod_start = efi_physaddr(module, tmp, map,


1273 
1274         trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE;
1275         memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE);
1276 
1277         relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE;
1278         memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE);
1279 
1280         relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE;
1281         memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE);
1282         relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8;
1283 
1284         trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr);
1285 #else
1286         dev_cleanup();
1287         __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
1288             (void *)entry_addr, (void *)VTOP(mbi));
1289 #endif /* EFI */
1290         panic("exec returned");
1291 
1292 error:
1293         if (cmdline != NULL)
1294                 free(cmdline);

1295 #if defined(EFI)


1296         if (mbi != NULL)
1297                 efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
1298 #endif

1299         return (error);
1300 }
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Toomas Soome <tsoome@me.com>
  14  * Copyright 2019, Joyent, Inc.
  15  */
  16 
  17 /*
  18  * This module adds support for loading and booting illumos multiboot2
  19  * kernel. This code is only built to support the illumos kernel, it does
  20  * not support xen.
  21  */
  22 
  23 #include <sys/cdefs.h>
  24 #include <sys/stddef.h>
  25 
  26 #include <sys/param.h>
  27 #include <sys/exec.h>
  28 #include <sys/linker.h>
  29 #include <sys/module.h>
  30 #include <sys/stdint.h>
  31 #include <sys/multiboot2.h>
  32 #include <stand.h>
  33 #include <stdbool.h>
  34 #include <machine/elf.h>


 783         if (bootp_response != NULL) {
 784                 size += sizeof (multiboot_tag_network_t) + bootp_response_size;
 785                 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
 786         }
 787 
 788         if (rsdp != NULL) {
 789                 if (rsdp->Revision == 0) {
 790                         size += sizeof (multiboot_tag_old_acpi_t) +
 791                             sizeof (ACPI_RSDP_COMMON);
 792                 } else {
 793                         size += sizeof (multiboot_tag_new_acpi_t) +
 794                             rsdp->Length;
 795                 }
 796                 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
 797         }
 798         size += sizeof (multiboot_tag_t);
 799 
 800         return (size);
 801 }
 802 
 803 #if defined(EFI)
 804 static bool
 805 overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2)
 806 {
 807         if (start1 < start2 + size2 &&
 808             start1 + size1 >= start2) {
 809                 printf("overlaps: %zx-%zx, %zx-%zx\n",
 810                     start1, start1 + size1, start2, start2 + size2);
 811                 return (true);
 812         }
 813 
 814         return (false);
 815 }
 816 #endif
 817 
 818 static int
 819 multiboot2_exec(struct preloaded_file *fp)
 820 {
 821         multiboot2_info_header_t *mbi = NULL;
 822         struct preloaded_file *mfp;

 823         char *cmdline = NULL;
 824         struct devdesc *rootdev;
 825         struct file_metadata *md;
 826         int i, error, num;
 827         int rootfs = 0;
 828         size_t size;
 829         struct bios_smap *smap;
 830 #if defined(EFI)
 831         multiboot_tag_module_t *module, *mp;
 832         struct relocator *relocator = NULL;
 833         EFI_MEMORY_DESCRIPTOR *map;
 834         UINTN map_size, desc_size;

 835         struct chunk_head *head;
 836         struct chunk *chunk;
 837         vm_offset_t tmp;
 838 
 839         efi_getdev((void **)(&rootdev), NULL, NULL);
 840 
 841         /*
 842          * We need 5 pages for relocation. We'll allocate from the heap: while
 843          * it's possible that our heap got placed low down enough to be in the
 844          * way of where we're going to relocate our kernel, it's hopefully not
 845          * likely.
 846          */
 847         if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) {
 848                 printf("relocator malloc failed!\n");
 849                 error = ENOMEM;
 850                 goto error;
 851         }
 852 
 853         if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5,
 854             load_addr, fp->f_size)) {
 855                 printf("relocator pages overlap the kernel!\n");
 856                 error = EINVAL;
 857                 goto error;
 858         }
 859 
 860 #else
 861         i386_getdev((void **)(&rootdev), NULL, NULL);
 862 
 863         if (have_framebuffer == false) {
 864                 /* make sure we have text mode */
 865                 bios_set_text_mode(VGA_TEXT_MODE);
 866         }
 867 #endif
 868 

 869         error = EINVAL;
 870         if (rootdev == NULL) {
 871                 printf("can't determine root device\n");
 872                 goto error;
 873         }
 874 
 875         /*
 876          * Set the image command line.
 877          */
 878         if (fp->f_args == NULL) {
 879                 cmdline = getenv("boot-args");
 880                 if (cmdline != NULL) {
 881                         fp->f_args = strdup(cmdline);
 882                         if (fp->f_args == NULL) {
 883                                 error = ENOMEM;
 884                                 goto error;
 885                         }
 886                 }
 887         }
 888 


1193 
1194                 map_size = 0;
1195                 status = BS->GetMemoryMap(&map_size,
1196                     (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1197                     &desc_size, &tag->mb_descr_vers);
1198                 if (status != EFI_BUFFER_TOO_SMALL) {
1199                         error = EINVAL;
1200                         goto error;
1201                 }
1202                 status = BS->GetMemoryMap(&map_size,
1203                     (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1204                     &desc_size, &tag->mb_descr_vers);
1205                 if (EFI_ERROR(status)) {
1206                         error = EINVAL;
1207                         goto error;
1208                 }
1209                 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
1210                 tag->mb_size = sizeof (*tag) + map_size;
1211                 tag->mb_descr_size = (uint32_t)desc_size;
1212 
1213                 map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;


















1214 
1215                 if (keep_bs == 0) {
1216                         status = BS->ExitBootServices(IH, key);
1217                         if (EFI_ERROR(status)) {
1218                                 printf("Call to ExitBootServices failed\n");
1219                                 error = EINVAL;
1220                                 goto error;
1221                         }
1222                 }
1223 
1224                 last_addr += map_size;
1225                 last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
1226         }
1227 #endif /* EFI */
1228 
1229         /*
1230          * MB tag list end marker.
1231          */
1232         {
1233                 multiboot_tag_t *tag = (multiboot_tag_t *)
1234                     mb_malloc(sizeof (*tag));
1235                 tag->mb_type = MULTIBOOT_TAG_TYPE_END;
1236                 tag->mb_size = sizeof (*tag);
1237         }
1238 
1239         mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
1240         mbi->mbi_reserved = 0;
1241 
1242 #if defined(EFI)
1243         /*
1244          * At this point we have load_addr pointing to kernel load
1245          * address, module list in MBI having physical addresses,
1246          * module list in fp having logical addresses and tmp pointing to
1247          * physical address for MBI.
1248          * Now we must move all pieces to place and start the kernel.
1249          */

1250         head = &relocator->rel_chunk_head;
1251         STAILQ_INIT(head);
1252 
1253         i = 0;
1254         chunk = &relocator->rel_chunklist[i++];
1255         chunk->chunk_vaddr = fp->f_addr;
1256         chunk->chunk_paddr = load_addr;
1257         chunk->chunk_size = fp->f_size;
1258 
1259         STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1260 
1261         mp = module;
1262         for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
1263                 chunk = &relocator->rel_chunklist[i++];
1264                 chunk->chunk_vaddr = mfp->f_addr;
1265 
1266                 /*
1267                  * fix the mb_mod_start and mb_mod_end.
1268                  */
1269                 mp->mb_mod_start = efi_physaddr(module, tmp, map,


1289 
1290         trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE;
1291         memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE);
1292 
1293         relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE;
1294         memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE);
1295 
1296         relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE;
1297         memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE);
1298         relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8;
1299 
1300         trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr);
1301 #else
1302         dev_cleanup();
1303         __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
1304             (void *)entry_addr, (void *)VTOP(mbi));
1305 #endif /* EFI */
1306         panic("exec returned");
1307 
1308 error:

1309         free(cmdline);
1310 
1311 #if defined(EFI)
1312         free(relocator);
1313 
1314         if (mbi != NULL)
1315                 efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
1316 #endif
1317 
1318         return (error);
1319 }