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