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
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.
13 * Copyright 2017 Toomas Soome <tsoome@me.com>
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
22 #include <sys/cdefs.h>
23 #include <sys/stddef.h>
25 #include <sys/param.h>
27 #include <sys/linker.h>
28 #include <sys/module.h>
29 #include <sys/stdint.h>
30 #include <sys/multiboot2.h>
33 #include <machine/elf.h>
36 #include "bootstrap.h"
37 #include <sys/consplat.h>
39 #include <machine/metadata.h>
40 #include <machine/pc/bios.h>
46 #include "../i386/btx/lib/btxv86.h"
53 #include "loader_efi.h"
55 static void (*trampoline
)(uint32_t, struct relocator
*, uint64_t);
58 #include "platform/acfreebsd.h"
60 #define ACPI_SYSTEM_XFACE
64 extern ACPI_TABLE_RSDP
*rsdp
;
66 /* MB data heap pointer. */
67 static vm_offset_t last_addr
;
69 static int multiboot2_loadfile(char *, u_int64_t
, struct preloaded_file
**);
70 static int multiboot2_exec(struct preloaded_file
*);
72 struct file_format multiboot2
= { multiboot2_loadfile
, multiboot2_exec
};
73 static bool keep_bs
= false;
74 static bool have_framebuffer
= false;
75 static vm_offset_t load_addr
;
76 static vm_offset_t entry_addr
;
79 * Validate tags in info request. This function is provided just to
80 * recognize the current tag list and only serves as a limited
81 * safe guard against possibly corrupt information.
84 is_info_request_valid(multiboot_header_tag_information_request_t
*rtag
)
89 * If the tag is optional and we do not support it, we do not
90 * have to do anything special, so we skip optional tags.
92 if (rtag
->mbh_flags
& MULTIBOOT_HEADER_TAG_OPTIONAL
)
95 for (i
= 0; i
< (rtag
->mbh_size
- sizeof (*rtag
)) /
96 sizeof (rtag
->mbh_requests
[0]); i
++)
97 switch (rtag
->mbh_requests
[i
]) {
98 case MULTIBOOT_TAG_TYPE_END
:
99 case MULTIBOOT_TAG_TYPE_CMDLINE
:
100 case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME
:
101 case MULTIBOOT_TAG_TYPE_MODULE
:
102 case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
:
103 case MULTIBOOT_TAG_TYPE_BOOTDEV
:
104 case MULTIBOOT_TAG_TYPE_MMAP
:
105 case MULTIBOOT_TAG_TYPE_FRAMEBUFFER
:
106 case MULTIBOOT_TAG_TYPE_VBE
:
107 case MULTIBOOT_TAG_TYPE_ELF_SECTIONS
:
108 case MULTIBOOT_TAG_TYPE_APM
:
109 case MULTIBOOT_TAG_TYPE_EFI32
:
110 case MULTIBOOT_TAG_TYPE_EFI64
:
111 case MULTIBOOT_TAG_TYPE_ACPI_OLD
:
112 case MULTIBOOT_TAG_TYPE_ACPI_NEW
:
113 case MULTIBOOT_TAG_TYPE_NETWORK
:
114 case MULTIBOOT_TAG_TYPE_EFI_MMAP
:
115 case MULTIBOOT_TAG_TYPE_EFI_BS
:
116 case MULTIBOOT_TAG_TYPE_EFI32_IH
:
117 case MULTIBOOT_TAG_TYPE_EFI64_IH
:
118 case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR
:
121 printf("unsupported information tag: 0x%x\n",
122 rtag
->mbh_requests
[i
]);
129 multiboot2_loadfile(char *filename
, u_int64_t dest
,
130 struct preloaded_file
**result
)
135 caddr_t header_search
;
136 multiboot2_header_t
*header
;
137 multiboot_header_tag_t
*tag
;
138 multiboot_header_tag_address_t
*addr_tag
= NULL
;
139 multiboot_header_tag_entry_address_t
*entry_tag
= NULL
;
140 struct preloaded_file
*fp
;
142 /* This allows to check other file formats from file_formats array. */
144 if (filename
== NULL
)
147 /* is kernel already loaded? */
148 fp
= file_findfile(NULL
, NULL
);
152 if ((fd
= open(filename
, O_RDONLY
)) == -1)
156 * Read MULTIBOOT_SEARCH size in order to search for the
157 * multiboot magic header.
159 header_search
= malloc(MULTIBOOT_SEARCH
);
160 if (header_search
== NULL
) {
165 if (read(fd
, header_search
, MULTIBOOT_SEARCH
) != MULTIBOOT_SEARCH
)
169 for (i
= 0; i
<= (MULTIBOOT_SEARCH
- sizeof (multiboot2_header_t
));
170 i
+= MULTIBOOT_HEADER_ALIGN
) {
171 header
= (multiboot2_header_t
*)(header_search
+ i
);
173 /* Do we have match on magic? */
174 if (header
->mb2_magic
!= MULTIBOOT2_HEADER_MAGIC
) {
179 * Validate checksum, the sum of magic + architecture +
180 * header_length + checksum must equal 0.
182 if (header
->mb2_magic
+ header
->mb2_architecture
+
183 header
->mb2_header_length
+ header
->mb2_checksum
!= 0) {
188 * Finally, the entire header must fit within MULTIBOOT_SEARCH.
190 if (i
+ header
->mb2_header_length
> MULTIBOOT_SEARCH
) {
200 have_framebuffer
= false;
201 for (tag
= header
->mb2_tags
; tag
->mbh_type
!= MULTIBOOT_TAG_TYPE_END
;
202 tag
= (multiboot_header_tag_t
*)((uintptr_t)tag
+
203 roundup2(tag
->mbh_size
, MULTIBOOT_TAG_ALIGN
))) {
204 switch (tag
->mbh_type
) {
205 case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
:
206 if (is_info_request_valid((void*)tag
) == false)
209 case MULTIBOOT_HEADER_TAG_ADDRESS
:
210 addr_tag
= (multiboot_header_tag_address_t
*)tag
;
212 case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
:
214 (multiboot_header_tag_entry_address_t
*)tag
;
216 case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS
:
218 case MULTIBOOT_HEADER_TAG_FRAMEBUFFER
:
219 have_framebuffer
= true;
221 case MULTIBOOT_HEADER_TAG_MODULE_ALIGN
:
222 /* we always align modules */
224 case MULTIBOOT_HEADER_TAG_EFI_BS
:
228 if (!(tag
->mbh_flags
& MULTIBOOT_HEADER_TAG_OPTIONAL
)) {
229 printf("unsupported tag: 0x%x\n",
237 * We must have addr_tag and entry_tag to load a 64-bit kernel.
238 * If these tags are missing, we either have a 32-bit kernel, or
239 * this is not our kernel at all.
241 if (addr_tag
!= NULL
&& entry_tag
!= NULL
) {
247 if (lseek(fd
, 0, SEEK_SET
) == -1) {
248 printf("lseek failed\n");
253 if (fstat(fd
, &st
) < 0) {
254 printf("fstat failed\n");
260 load_addr
= addr_tag
->mbh_load_addr
;
261 entry_addr
= entry_tag
->mbh_entry_addr
;
262 fp
->f_addr
= archsw
.arch_loadaddr(LOAD_KERN
, filename
,
263 addr_tag
->mbh_load_addr
);
264 if (fp
->f_addr
== 0) {
269 fp
->f_size
= archsw
.arch_readin(fd
, fp
->f_addr
, st
.st_size
);
271 if (fp
->f_size
!= st
.st_size
) {
272 printf("error reading: %s", strerror(errno
));
278 fp
->f_name
= strdup(filename
);
279 fp
->f_type
= strdup("aout multiboot2 kernel");
280 if (fp
->f_name
== NULL
|| fp
->f_type
== NULL
) {
286 fp
->f_metadata
= NULL
;
290 /* 32-bit kernel is not yet supported for EFI */
291 printf("32-bit kernel is not supported by UEFI loader\n");
295 /* elf32_loadfile_raw will fill the attributes in fp. */
296 error
= elf32_loadfile_raw(filename
, dest
, &fp
, 2);
298 printf("elf32_loadfile_raw failed: %d unable to "
299 "load multiboot2 kernel\n", error
);
302 entry_addr
= fp
->f_addr
;
304 * We want the load_addr to have some legal value,
305 * so we set it same as the entry_addr.
306 * The distinction is important with UEFI, but not
307 * with BIOS version, because BIOS version does not use
310 load_addr
= fp
->f_addr
;
313 setenv("kernelname", fp
->f_name
, 1);
317 bios_addsmapdata(fp
);
327 * Search the command line for named property.
330 * 0 The name is found, we return the data in value and len.
331 * ENOENT The name is not found.
332 * EINVAL The provided command line is badly formed.
335 find_property_value(const char *cmd
, const char *name
, const char **value
,
338 const char *namep
, *valuep
;
339 size_t name_len
, value_len
;
348 while (*cmd
!= '\0') {
349 if (cmd
[0] != '-' || cmd
[1] != 'B') {
353 cmd
+= 2; /* Skip -B */
354 while (cmd
[0] == ' ' || cmd
[0] == '\t')
355 cmd
++; /* Skip whitespaces. */
356 while (*cmd
!= '\0' && cmd
[0] != ' ' && cmd
[0] != '\t') {
358 valuep
= strchr(cmd
, '=');
361 name_len
= valuep
- namep
;
365 for (; ; ++value_len
) {
366 if (valuep
[value_len
] == '\0')
369 /* Is this value quoted? */
370 if (value_len
== 0 &&
371 (valuep
[0] == '\'' || valuep
[0] == '"')) {
377 * In the quote accept any character,
378 * but look for ending quote.
381 if (valuep
[value_len
] == quoted
)
386 /* A comma or white space ends the value. */
387 if (valuep
[value_len
] == ',' ||
388 valuep
[value_len
] == ' ' ||
389 valuep
[value_len
] == '\t')
393 printf("Missing closing '%c' in \"%s\"\n",
397 if (value_len
!= 0) {
398 if (strncmp(namep
, name
, name_len
) == 0) {
404 cmd
= valuep
+ value_len
;
413 * If command line has " -B ", insert property after "-B ", otherwise
414 * append to command line.
417 insert_cmdline(const char *head
, const char *prop
)
419 const char *prop_opt
= " -B ";
420 char *cmdline
, *tail
;
423 tail
= strstr(head
, prop_opt
);
426 tail
+= strlen(prop_opt
);
434 asprintf(&cmdline
, "%s%s%s", head
, prop_opt
, prop
);
436 asprintf(&cmdline
, "%.*s%s,%s", len
, head
, prop
, tail
);
442 * Since we have no way to pass the environment to the mb1 kernel other than
443 * through arguments, we need to take care of console setup.
445 * If the console is in mirror mode, set the kernel console from $os_console.
446 * If it's unset, use first item from $console.
447 * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by
450 * In case of memory allocation errors, just return the original command line
451 * so we have a chance of booting.
453 * On success, cl will be freed and a new, allocated command line string is
456 * For the mb2 kernel, we only set command line console if os_console is set.
457 * We can not overwrite console in the environment, as it can disrupt the
458 * loader console messages, and we do not want to deal with the os_console
462 update_cmdline(char *cl
, bool mb2
)
464 char *os_console
= getenv("os_console");
465 char *ttymode
= NULL
;
472 if (mb2
== true && os_console
== NULL
)
475 if (os_console
== NULL
) {
476 tmp
= strdup(getenv("console"));
477 os_console
= strsep(&tmp
, ", ");
479 os_console
= strdup(os_console
);
482 if (os_console
== NULL
)
485 if (mb2
== false && strncmp(os_console
, "tty", 3) == 0) {
486 snprintf(mode
, sizeof (mode
), "%s-mode", os_console
);
488 * The ttyX-mode variable is set by our serial console
489 * driver for ttya-ttyd. However, since the os_console
490 * values are not verified, it is possible we get bogus
491 * name and no mode variable. If so, we do not set console
492 * property and let the kernel use defaults.
494 if ((ttymode
= getenv(mode
)) == NULL
)
498 rv
= find_property_value(cl
, "console", &prop
, &plen
);
499 if (rv
!= 0 && rv
!= ENOENT
) {
504 /* If console is set and this is MB2 boot, we are done. */
505 if (rv
== 0 && mb2
== true) {
510 /* If console is set, do we need to set tty mode? */
512 const char *ttyp
= NULL
;
518 if (strncmp(prop
, "tty", 3) == 0 && plen
== 4) {
519 strncpy(mode
, prop
, plen
);
521 strncat(mode
, "-mode", 5);
522 find_property_value(cl
, mode
, &ttyp
, &ttylen
);
525 if (*mode
!= '\0' && ttyp
== NULL
)
526 ttymode
= getenv(mode
);
531 /* Build updated command line. */
532 if (os_console
!= NULL
) {
535 asprintf(&propstr
, "console=%s", os_console
);
537 if (propstr
== NULL
) {
541 tmp
= insert_cmdline(cl
, propstr
);
549 if (ttymode
!= NULL
) {
552 asprintf(&propstr
, "%s=\"%s\"", mode
, ttymode
);
556 tmp
= insert_cmdline(cl
, propstr
);
568 * Build the kernel command line. Shared function between MB1 and MB2.
570 * In both cases, if fstype is set and is not zfs, we do not set up
571 * zfs-bootfs property. But we set kernel file name and options.
573 * For the MB1, we only can pass properties on command line, so
574 * we will set console, ttyX-mode (for serial console) and zfs-bootfs.
576 * For the MB2, we can pass properties in environment, but if os_console
577 * is set in environment, we need to add console property on the kernel
580 * The console properties are managed in update_cmdline().
583 mb_kernel_cmdline(struct preloaded_file
*fp
, struct devdesc
*rootdev
,
586 const char *fs
= getenv("fstype");
589 bool zfs_root
= false;
594 * 64-bit kernel has aout header, 32-bit kernel is elf, and the
595 * type strings are different. Lets just search for "multiboot2".
597 if (strstr(fp
->f_type
, "multiboot2") == NULL
)
602 if (rootdev
->d_dev
->dv_type
== DEVT_ZFS
)
605 /* If we have fstype set in env, reset zfs_root if needed. */
606 if (fs
!= NULL
&& strcmp(fs
, "zfs") != 0)
610 * If we have fstype set on the command line,
611 * reset zfs_root if needed.
613 rv
= find_property_value(fp
->f_args
, "fstype", &fs
, &len
);
614 if (rv
!= 0 && rv
!= ENOENT
)
617 if (fs
!= NULL
&& strncmp(fs
, "zfs", len
) != 0)
620 /* zfs_bootfs() will set the environment, it must be called. */
621 if (zfs_root
== true)
622 fs
= zfs_bootfs(rootdev
);
624 if (fp
->f_args
== NULL
)
625 cmdline
= strdup(fp
->f_name
);
627 asprintf(&cmdline
, "%s %s", fp
->f_name
, fp
->f_args
);
632 /* Append zfs-bootfs for MB1 command line. */
633 if (mb2
== false && zfs_root
== true) {
636 tmp
= insert_cmdline(cmdline
, fs
);
643 *line
= update_cmdline(cmdline
, mb2
);
648 * Returns allocated virtual address from MB info area.
653 vm_offset_t ptr
= last_addr
;
654 last_addr
= roundup(last_addr
+ n
, MULTIBOOT_TAG_ALIGN
);
659 * Calculate size for module tag list.
662 module_size(struct preloaded_file
*fp
)
665 struct preloaded_file
*mfp
;
668 for (mfp
= fp
->f_next
; mfp
!= NULL
; mfp
= mfp
->f_next
) {
669 len
= strlen(mfp
->f_name
) + 1;
670 len
+= strlen(mfp
->f_type
) + 5 + 1; /* 5 is for "type=" */
671 if (mfp
->f_args
!= NULL
)
672 len
+= strlen(mfp
->f_args
) + 1;
673 size
+= sizeof (multiboot_tag_module_t
) + len
;
674 size
= roundup(size
, MULTIBOOT_TAG_ALIGN
);
681 * Calculate size for UEFI memory map tag.
686 UINTN size
, cur_size
, desc_size
;
687 EFI_MEMORY_DESCRIPTOR
*mmap
;
690 size
= EFI_PAGE_SIZE
; /* Start with 4k. */
693 mmap
= malloc(cur_size
);
696 ret
= BS
->GetMemoryMap(&cur_size
, mmap
, NULL
, &desc_size
, NULL
);
698 if (ret
== EFI_SUCCESS
)
700 if (ret
== EFI_BUFFER_TOO_SMALL
) {
703 size
+= (EFI_PAGE_SIZE
);
708 /* EFI MMAP will grow when we allocate MBI, set some buffer. */
709 size
+= (3 << EFI_PAGE_SHIFT
);
710 size
= roundup(size
, desc_size
);
711 return (sizeof (multiboot_tag_efi_mmap_t
) + size
);
716 * Calculate size for bios smap tag.
719 biossmap_size(struct preloaded_file
*fp
)
722 struct file_metadata
*md
;
724 md
= file_findmetadata(fp
, MODINFOMD_SMAP
);
728 num
= md
->md_size
/ sizeof(struct bios_smap
); /* number of entries */
729 return (sizeof (multiboot_tag_mmap_t
) +
730 num
* sizeof (multiboot_mmap_entry_t
));
734 mbi_size(struct preloaded_file
*fp
, char *cmdline
)
738 extern multiboot_tag_framebuffer_t gfx_fb
;
741 size
= sizeof (uint32_t) * 2; /* first 2 fields from MBI header */
742 size
+= sizeof (multiboot_tag_string_t
) + strlen(cmdline
) + 1;
743 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
744 size
+= sizeof (multiboot_tag_string_t
) + strlen(bootprog_info
) + 1;
745 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
747 size
+= sizeof (multiboot_tag_basic_meminfo_t
);
748 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
750 size
+= module_size(fp
);
751 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
753 size
+= sizeof (multiboot_tag_efi64_t
);
754 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
755 size
+= efimemmap_size();
756 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
758 if (have_framebuffer
== true) {
759 size
+= sizeof (multiboot_tag_framebuffer_t
);
760 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
764 size
+= biossmap_size(fp
);
765 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
768 if (gfx_fb
.framebuffer_common
.framebuffer_type
==
769 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED
) {
770 size
+= sizeof (struct multiboot_tag_framebuffer_common
);
771 size
+= gfx_fb
.u
.fb1
.framebuffer_palette_num_colors
*
772 sizeof (multiboot_color_t
);
774 size
+= sizeof (multiboot_tag_framebuffer_t
);
776 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
778 size
+= sizeof (multiboot_tag_vbe_t
);
779 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
782 if (bootp_response
!= NULL
) {
783 size
+= sizeof(multiboot_tag_network_t
) + bootp_response_size
;
784 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
788 if (rsdp
->Revision
== 0) {
789 size
+= sizeof (multiboot_tag_old_acpi_t
) +
790 sizeof(ACPI_RSDP_COMMON
);
792 size
+= sizeof (multiboot_tag_new_acpi_t
) +
795 size
= roundup2(size
, MULTIBOOT_TAG_ALIGN
);
797 size
+= sizeof(multiboot_tag_t
);
803 multiboot2_exec(struct preloaded_file
*fp
)
805 struct preloaded_file
*mfp
;
806 multiboot2_info_header_t
*mbi
;
807 char *cmdline
= NULL
;
808 struct devdesc
*rootdev
;
809 struct file_metadata
*md
;
813 struct bios_smap
*smap
;
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
;
823 efi_getdev((void **)(&rootdev
), NULL
, NULL
);
825 i386_getdev((void **)(&rootdev
), NULL
, NULL
);
827 if (have_framebuffer
== false) {
828 /* make sure we have text mode */
829 bios_set_text_mode(VGA_TEXT_MODE
);
835 if (rootdev
== NULL
) {
836 printf("can't determine root device\n");
841 * Set the image command line.
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
) {
854 error
= mb_kernel_cmdline(fp
, rootdev
, &cmdline
);
858 /* mb_kernel_cmdline() updates the environment. */
859 build_environment_module();
861 if (have_framebuffer
== true) {
862 /* Pass the loaded console font for kernel. */
866 size
= mbi_size(fp
, cmdline
); /* Get the size for MBI. */
868 /* Set up the base for mb_malloc. */
870 for (mfp
= fp
; mfp
->f_next
!= NULL
; mfp
= mfp
->f_next
)
874 /* We need space for kernel + MBI + # modules */
875 num
= (EFI_PAGE_SIZE
- offsetof(struct relocator
, rel_chunklist
)) /
876 sizeof (struct chunk
);
878 printf("Too many modules, do not have space for relocator.\n");
883 last_addr
= efi_loadaddr(LOAD_MEM
, &size
, mfp
->f_addr
+ mfp
->f_size
);
884 mbi
= (multiboot2_info_header_t
*)last_addr
;
889 last_addr
= (vm_offset_t
)mbi
->mbi_tags
;
891 /* Start info block from the new page. */
892 last_addr
= i386_loadaddr(LOAD_MEM
, &size
, mfp
->f_addr
+ mfp
->f_size
);
894 /* Do we have space for multiboot info? */
895 if (last_addr
+ size
>= memtop_copyin
) {
900 mbi
= (multiboot2_info_header_t
*)PTOV(last_addr
);
901 last_addr
= (vm_offset_t
)mbi
->mbi_tags
;
905 multiboot_tag_string_t
*tag
;
906 i
= sizeof (multiboot_tag_string_t
) + strlen(cmdline
) + 1;
907 tag
= (multiboot_tag_string_t
*) mb_malloc(i
);
909 tag
->mb_type
= MULTIBOOT_TAG_TYPE_CMDLINE
;
911 memcpy(tag
->mb_string
, cmdline
, strlen(cmdline
) + 1);
917 multiboot_tag_string_t
*tag
;
918 i
= sizeof (multiboot_tag_string_t
) + strlen(bootprog_info
) + 1;
919 tag
= (multiboot_tag_string_t
*) mb_malloc(i
);
921 tag
->mb_type
= MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME
;
923 memcpy(tag
->mb_string
, bootprog_info
,
924 strlen(bootprog_info
) + 1);
928 /* Only set in case of BIOS. */
930 multiboot_tag_basic_meminfo_t
*tag
;
931 tag
= (multiboot_tag_basic_meminfo_t
*)
932 mb_malloc(sizeof (*tag
));
934 tag
->mb_type
= MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
;
935 tag
->mb_size
= sizeof (*tag
);
936 tag
->mb_mem_lower
= bios_basemem
/ 1024;
937 tag
->mb_mem_upper
= bios_extmem
/ 1024;
942 for (mfp
= fp
->f_next
; mfp
!= NULL
; mfp
= mfp
->f_next
) {
944 if (mfp
->f_type
!= NULL
&& strcmp(mfp
->f_type
, "rootfs") == 0)
948 if (num
== 0 || rootfs
== 0) {
949 /* We need at least one module - rootfs. */
950 printf("No rootfs module provided, aborting\n");
956 * Set the stage for physical memory layout:
957 * - We have kernel at load_addr.
958 * - Modules are aligned to page boundary.
959 * - MBI is aligned to page boundary.
960 * - Set the tmp to point to physical address of the first module.
961 * - tmp != mfp->f_addr only in case of EFI.
964 tmp
= roundup2(load_addr
+ fp
->f_size
+ 1, MULTIBOOT_MOD_ALIGN
);
965 module
= (multiboot_tag_module_t
*)last_addr
;
968 for (mfp
= fp
->f_next
; mfp
!= NULL
; mfp
= mfp
->f_next
) {
969 multiboot_tag_module_t
*tag
;
971 num
= strlen(mfp
->f_name
) + 1;
972 num
+= strlen(mfp
->f_type
) + 5 + 1;
973 if (mfp
->f_args
!= NULL
) {
974 num
+= strlen(mfp
->f_args
) + 1;
976 cmdline
= malloc(num
);
977 if (cmdline
== NULL
) {
982 if (mfp
->f_args
!= NULL
)
983 snprintf(cmdline
, num
, "%s type=%s %s",
984 mfp
->f_name
, mfp
->f_type
, mfp
->f_args
);
986 snprintf(cmdline
, num
, "%s type=%s",
987 mfp
->f_name
, mfp
->f_type
);
989 tag
= (multiboot_tag_module_t
*)mb_malloc(sizeof (*tag
) + num
);
991 tag
->mb_type
= MULTIBOOT_TAG_TYPE_MODULE
;
992 tag
->mb_size
= sizeof (*tag
) + num
;
995 * We can assign module addresses only after BS have been
998 tag
->mb_mod_start
= 0;
999 tag
->mb_mod_end
= mfp
->f_size
;
1001 tag
->mb_mod_start
= mfp
->f_addr
;
1002 tag
->mb_mod_end
= mfp
->f_addr
+ mfp
->f_size
;
1004 memcpy(tag
->mb_cmdline
, cmdline
, num
);
1009 md
= file_findmetadata(fp
, MODINFOMD_SMAP
);
1011 printf("no memory smap\n");
1016 smap
= (struct bios_smap
*)md
->md_data
;
1017 num
= md
->md_size
/ sizeof(struct bios_smap
); /* number of entries */
1020 multiboot_tag_mmap_t
*tag
;
1021 multiboot_mmap_entry_t
*mmap_entry
;
1023 tag
= (multiboot_tag_mmap_t
*)
1024 mb_malloc(sizeof (*tag
) +
1025 num
* sizeof (multiboot_mmap_entry_t
));
1027 tag
->mb_type
= MULTIBOOT_TAG_TYPE_MMAP
;
1028 tag
->mb_size
= sizeof (*tag
) +
1029 num
* sizeof (multiboot_mmap_entry_t
);
1030 tag
->mb_entry_size
= sizeof (multiboot_mmap_entry_t
);
1031 tag
->mb_entry_version
= 0;
1032 mmap_entry
= (multiboot_mmap_entry_t
*)tag
->mb_entries
;
1034 for (i
= 0; i
< num
; i
++) {
1035 mmap_entry
[i
].mmap_addr
= smap
[i
].base
;
1036 mmap_entry
[i
].mmap_len
= smap
[i
].length
;
1037 mmap_entry
[i
].mmap_type
= smap
[i
].type
;
1038 mmap_entry
[i
].mmap_reserved
= 0;
1042 if (bootp_response
!= NULL
) {
1043 multiboot_tag_network_t
*tag
;
1044 tag
= (multiboot_tag_network_t
*)
1045 mb_malloc(sizeof(*tag
) + bootp_response_size
);
1047 tag
->mb_type
= MULTIBOOT_TAG_TYPE_NETWORK
;
1048 tag
->mb_size
= sizeof(*tag
) + bootp_response_size
;
1049 memcpy(tag
->mb_dhcpack
, bootp_response
, bootp_response_size
);
1054 multiboot_tag_vbe_t
*tag
;
1055 extern multiboot_tag_vbe_t vbestate
;
1057 if (VBE_VALID_MODE(vbestate
.vbe_mode
)) {
1058 tag
= (multiboot_tag_vbe_t
*)mb_malloc(sizeof(*tag
));
1059 memcpy(tag
, &vbestate
, sizeof(*tag
));
1060 tag
->mb_type
= MULTIBOOT_TAG_TYPE_VBE
;
1061 tag
->mb_size
= sizeof(*tag
);
1067 multiboot_tag_new_acpi_t
*ntag
;
1068 multiboot_tag_old_acpi_t
*otag
;
1071 if (rsdp
->Revision
== 0) {
1072 tsize
= sizeof (*otag
) + sizeof (ACPI_RSDP_COMMON
);
1073 otag
= (multiboot_tag_old_acpi_t
*)mb_malloc(tsize
);
1074 otag
->mb_type
= MULTIBOOT_TAG_TYPE_ACPI_OLD
;
1075 otag
->mb_size
= tsize
;
1076 memcpy(otag
->mb_rsdp
, rsdp
, sizeof (ACPI_RSDP_COMMON
));
1078 tsize
= sizeof (*ntag
) + rsdp
->Length
;
1079 ntag
= (multiboot_tag_new_acpi_t
*)mb_malloc(tsize
);
1080 ntag
->mb_type
= MULTIBOOT_TAG_TYPE_ACPI_NEW
;
1081 ntag
->mb_size
= tsize
;
1082 memcpy(ntag
->mb_rsdp
, rsdp
, rsdp
->Length
);
1089 multiboot_tag_efi64_t
*tag
;
1090 tag
= (multiboot_tag_efi64_t
*)
1091 mb_malloc(sizeof (*tag
));
1093 tag
->mb_type
= MULTIBOOT_TAG_TYPE_EFI64
;
1094 tag
->mb_size
= sizeof (*tag
);
1095 tag
->mb_pointer
= (uint64_t)(uintptr_t)ST
;
1099 multiboot_tag_efi32_t
*tag
;
1100 tag
= (multiboot_tag_efi32_t
*)
1101 mb_malloc(sizeof (*tag
));
1103 tag
->mb_type
= MULTIBOOT_TAG_TYPE_EFI32
;
1104 tag
->mb_size
= sizeof (*tag
);
1105 tag
->mb_pointer
= (uint32_t)ST
;
1107 #endif /* __LP64__ */
1110 if (have_framebuffer
== true) {
1111 multiboot_tag_framebuffer_t
*tag
;
1112 extern multiboot_tag_framebuffer_t gfx_fb
;
1115 tag
= (multiboot_tag_framebuffer_t
*) mb_malloc(sizeof (*tag
));
1116 memcpy(tag
, &gfx_fb
, sizeof (*tag
));
1117 tag
->framebuffer_common
.mb_type
=
1118 MULTIBOOT_TAG_TYPE_FRAMEBUFFER
;
1119 tag
->framebuffer_common
.mb_size
= sizeof (*tag
);
1121 extern multiboot_color_t
*cmap
;
1124 if (gfx_fb
.framebuffer_common
.framebuffer_type
==
1125 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED
) {
1127 nc
= gfx_fb
.u
.fb1
.framebuffer_palette_num_colors
;
1128 size
= sizeof (struct multiboot_tag_framebuffer_common
)
1130 + nc
* sizeof (multiboot_color_t
);
1132 size
= sizeof (gfx_fb
);
1135 tag
= (multiboot_tag_framebuffer_t
*) mb_malloc(size
);
1136 memcpy(tag
, &gfx_fb
, sizeof (*tag
));
1138 tag
->framebuffer_common
.mb_type
=
1139 MULTIBOOT_TAG_TYPE_FRAMEBUFFER
;
1140 tag
->framebuffer_common
.mb_size
= size
;
1142 if (gfx_fb
.framebuffer_common
.framebuffer_type
==
1143 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED
) {
1144 memcpy(tag
->u
.fb1
.framebuffer_palette
, cmap
,
1145 sizeof (multiboot_color_t
) *
1146 gfx_fb
.u
.fb1
.framebuffer_palette_num_colors
);
1152 /* Leave EFI memmap last as we will also switch off the BS. */
1154 multiboot_tag_efi_mmap_t
*tag
;
1158 tag
= (multiboot_tag_efi_mmap_t
*)
1159 mb_malloc(sizeof (*tag
));
1162 status
= BS
->GetMemoryMap(&map_size
,
1163 (EFI_MEMORY_DESCRIPTOR
*)tag
->mb_efi_mmap
, &key
,
1164 &desc_size
, &tag
->mb_descr_vers
);
1165 if (status
!= EFI_BUFFER_TOO_SMALL
) {
1169 status
= BS
->GetMemoryMap(&map_size
,
1170 (EFI_MEMORY_DESCRIPTOR
*)tag
->mb_efi_mmap
, &key
,
1171 &desc_size
, &tag
->mb_descr_vers
);
1172 if (EFI_ERROR(status
)) {
1176 tag
->mb_type
= MULTIBOOT_TAG_TYPE_EFI_MMAP
;
1177 tag
->mb_size
= sizeof (*tag
) + map_size
;
1178 tag
->mb_descr_size
= (uint32_t) desc_size
;
1181 * Find relocater pages. We assume we have free pages
1182 * below kernel load address.
1183 * In this version we are using 5 pages:
1184 * relocator data, trampoline, copy, memmove, stack.
1186 for (i
= 0, map
= (EFI_MEMORY_DESCRIPTOR
*)tag
->mb_efi_mmap
;
1187 i
< map_size
/ desc_size
;
1188 i
++, map
= NextMemoryDescriptor(map
, desc_size
)) {
1189 if (map
->PhysicalStart
== 0)
1191 if (map
->Type
!= EfiConventionalMemory
)
1193 if (map
->PhysicalStart
< load_addr
&&
1194 map
->NumberOfPages
> 5)
1197 if (map
->PhysicalStart
== 0)
1198 panic("Could not find memory for relocater\n");
1201 status
= BS
->ExitBootServices(IH
, key
);
1202 if (EFI_ERROR(status
)) {
1203 printf("Call to ExitBootServices failed\n");
1209 last_addr
+= map_size
;
1210 last_addr
= roundup2(last_addr
, MULTIBOOT_TAG_ALIGN
);
1215 * MB tag list end marker.
1218 multiboot_tag_t
*tag
= (multiboot_tag_t
*)
1219 mb_malloc(sizeof(*tag
));
1220 tag
->mb_type
= MULTIBOOT_TAG_TYPE_END
;
1221 tag
->mb_size
= sizeof(*tag
);
1224 mbi
->mbi_total_size
= last_addr
- (vm_offset_t
)mbi
;
1225 mbi
->mbi_reserved
= 0;
1228 /* At this point we have load_addr pointing to kernel load
1229 * address, module list in MBI having physical addresses,
1230 * module list in fp having logical addresses and tmp pointing to
1231 * physical address for MBI.
1232 * Now we must move all pieces to place and start the kernel.
1234 relocator
= (struct relocator
*)(uintptr_t)map
->PhysicalStart
;
1235 head
= &relocator
->rel_chunk_head
;
1239 chunk
= &relocator
->rel_chunklist
[i
++];
1240 chunk
->chunk_vaddr
= fp
->f_addr
;
1241 chunk
->chunk_paddr
= load_addr
;
1242 chunk
->chunk_size
= fp
->f_size
;
1244 STAILQ_INSERT_TAIL(head
, chunk
, chunk_next
);
1247 for (mfp
= fp
->f_next
; mfp
!= NULL
; mfp
= mfp
->f_next
) {
1248 chunk
= &relocator
->rel_chunklist
[i
++];
1249 chunk
->chunk_vaddr
= mfp
->f_addr
;
1252 * fix the mb_mod_start and mb_mod_end.
1254 mp
->mb_mod_start
= efi_physaddr(module
, tmp
, map
,
1255 map_size
/ desc_size
, desc_size
, mp
->mb_mod_end
);
1256 if (mp
->mb_mod_start
== 0)
1257 panic("Could not find memory for module\n");
1259 mp
->mb_mod_end
+= mp
->mb_mod_start
;
1260 chunk
->chunk_paddr
= mp
->mb_mod_start
;
1261 chunk
->chunk_size
= mfp
->f_size
;
1262 STAILQ_INSERT_TAIL(head
, chunk
, chunk_next
);
1264 mp
= (multiboot_tag_module_t
*)
1265 roundup2((uintptr_t)mp
+ mp
->mb_size
,
1266 MULTIBOOT_TAG_ALIGN
);
1268 chunk
= &relocator
->rel_chunklist
[i
++];
1269 chunk
->chunk_vaddr
= (EFI_VIRTUAL_ADDRESS
)(uintptr_t)mbi
;
1270 chunk
->chunk_paddr
= efi_physaddr(module
, tmp
, map
,
1271 map_size
/ desc_size
, desc_size
, mbi
->mbi_total_size
);
1272 chunk
->chunk_size
= mbi
->mbi_total_size
;
1273 STAILQ_INSERT_TAIL(head
, chunk
, chunk_next
);
1275 trampoline
= (void *)(uintptr_t)relocator
+ EFI_PAGE_SIZE
;
1276 memmove(trampoline
, multiboot_tramp
, EFI_PAGE_SIZE
);
1278 relocator
->rel_copy
= (uintptr_t)trampoline
+ EFI_PAGE_SIZE
;
1279 memmove((void *)relocator
->rel_copy
, efi_copy_finish
, EFI_PAGE_SIZE
);
1281 relocator
->rel_memmove
= (uintptr_t)relocator
->rel_copy
+ EFI_PAGE_SIZE
;
1282 memmove((void *)relocator
->rel_memmove
, memmove
, EFI_PAGE_SIZE
);
1283 relocator
->rel_stack
= relocator
->rel_memmove
+ EFI_PAGE_SIZE
- 8;
1285 trampoline(MULTIBOOT2_BOOTLOADER_MAGIC
, relocator
, entry_addr
);
1288 __exec((void *)VTOP(multiboot_tramp
), MULTIBOOT2_BOOTLOADER_MAGIC
,
1289 (void *)entry_addr
, (void *)VTOP(mbi
));
1291 panic("exec returned");
1294 if (cmdline
!= NULL
)
1298 efi_free_loadaddr((vm_offset_t
)mbi
, EFI_SIZE_TO_PAGES(size
));