114ee0d29SToomas Soome /*
214ee0d29SToomas Soome * This file and its contents are supplied under the terms of the
314ee0d29SToomas Soome * Common Development and Distribution License ("CDDL"), version 1.0.
414ee0d29SToomas Soome * You may only use this file in accordance with the terms of version
514ee0d29SToomas Soome * 1.0 of the CDDL.
614ee0d29SToomas Soome *
714ee0d29SToomas Soome * A full copy of the text of the CDDL should have accompanied this
814ee0d29SToomas Soome * source. A copy of the CDDL is also available via the Internet at
914ee0d29SToomas Soome * http://www.illumos.org/license/CDDL.
1014ee0d29SToomas Soome */
1114ee0d29SToomas Soome
1214ee0d29SToomas Soome /*
1314ee0d29SToomas Soome * Copyright 2017 Toomas Soome <tsoome@me.com>
14287d0250SJohn Levon * Copyright 2019, Joyent, Inc.
1514ee0d29SToomas Soome */
1614ee0d29SToomas Soome
1714ee0d29SToomas Soome /*
1814ee0d29SToomas Soome * This module adds support for loading and booting illumos multiboot2
1914ee0d29SToomas Soome * kernel. This code is only built to support the illumos kernel, it does
2014ee0d29SToomas Soome * not support xen.
2114ee0d29SToomas Soome */
22f9feecc1SToomas Soome
2314ee0d29SToomas Soome #include <sys/cdefs.h>
24ade2ca5bSToomas Soome #include <sys/stddef.h>
2514ee0d29SToomas Soome
2614ee0d29SToomas Soome #include <sys/param.h>
2714ee0d29SToomas Soome #include <sys/exec.h>
2814ee0d29SToomas Soome #include <sys/linker.h>
2914ee0d29SToomas Soome #include <sys/module.h>
3014ee0d29SToomas Soome #include <sys/stdint.h>
3114ee0d29SToomas Soome #include <sys/multiboot2.h>
3214ee0d29SToomas Soome #include <stand.h>
3314ee0d29SToomas Soome #include <stdbool.h>
34f9feecc1SToomas Soome #include <machine/elf.h>
3514ee0d29SToomas Soome #include "libzfs.h"
3614ee0d29SToomas Soome
3714ee0d29SToomas Soome #include "bootstrap.h"
389890ff83SToomas Soome #include <sys/consplat.h>
3914ee0d29SToomas Soome
4014ee0d29SToomas Soome #include <machine/metadata.h>
4114ee0d29SToomas Soome #include <machine/pc/bios.h>
4214ee0d29SToomas Soome
43f9feecc1SToomas Soome #define SUPPORT_DHCP
44f9feecc1SToomas Soome #include <bootp.h>
45f9feecc1SToomas Soome
46f9feecc1SToomas Soome #if !defined(EFI)
4714ee0d29SToomas Soome #include "../i386/btx/lib/btxv86.h"
489890ff83SToomas Soome #include "libi386.h"
499890ff83SToomas Soome #include "vbe.h"
5014ee0d29SToomas Soome
51f9feecc1SToomas Soome #else
52f9feecc1SToomas Soome #include <efi.h>
53f9feecc1SToomas Soome #include <efilib.h>
54f9feecc1SToomas Soome #include "loader_efi.h"
55f9feecc1SToomas Soome
56f9feecc1SToomas Soome static void (*trampoline)(uint32_t, struct relocator *, uint64_t);
5715ab2c88SToomas Soome static UINTN efi_map_size; /* size of efi memory map */
58f9feecc1SToomas Soome #endif
5914ee0d29SToomas Soome
6014ee0d29SToomas Soome #include "platform/acfreebsd.h"
6114ee0d29SToomas Soome #include "acconfig.h"
6286759c82SToomas Soome #define ACPI_SYSTEM_XFACE
6314ee0d29SToomas Soome #include "actypes.h"
6414ee0d29SToomas Soome #include "actbl.h"
6514ee0d29SToomas Soome
6614ee0d29SToomas Soome extern ACPI_TABLE_RSDP *rsdp;
6714ee0d29SToomas Soome
6814ee0d29SToomas Soome /* MB data heap pointer. */
6914ee0d29SToomas Soome static vm_offset_t last_addr;
7014ee0d29SToomas Soome
7186759c82SToomas Soome static int multiboot2_loadfile(char *, uint64_t, struct preloaded_file **);
7214ee0d29SToomas Soome static int multiboot2_exec(struct preloaded_file *);
7314ee0d29SToomas Soome
7414ee0d29SToomas Soome struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec };
7514ee0d29SToomas Soome static bool keep_bs = false;
7614ee0d29SToomas Soome static bool have_framebuffer = false;
7714ee0d29SToomas Soome static vm_offset_t load_addr;
7814ee0d29SToomas Soome static vm_offset_t entry_addr;
79190f051bSToomas Soome bool has_boot_services = true;
8014ee0d29SToomas Soome
8114ee0d29SToomas Soome /*
8214ee0d29SToomas Soome * Validate tags in info request. This function is provided just to
8314ee0d29SToomas Soome * recognize the current tag list and only serves as a limited
8414ee0d29SToomas Soome * safe guard against possibly corrupt information.
8514ee0d29SToomas Soome */
8614ee0d29SToomas Soome static bool
is_info_request_valid(multiboot_header_tag_information_request_t * rtag)8714ee0d29SToomas Soome is_info_request_valid(multiboot_header_tag_information_request_t *rtag)
8814ee0d29SToomas Soome {
8914ee0d29SToomas Soome int i;
9014ee0d29SToomas Soome
9114ee0d29SToomas Soome /*
9214ee0d29SToomas Soome * If the tag is optional and we do not support it, we do not
9314ee0d29SToomas Soome * have to do anything special, so we skip optional tags.
9414ee0d29SToomas Soome */
9514ee0d29SToomas Soome if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
9614ee0d29SToomas Soome return (true);
9714ee0d29SToomas Soome
9814ee0d29SToomas Soome for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) /
9914ee0d29SToomas Soome sizeof (rtag->mbh_requests[0]); i++)
10014ee0d29SToomas Soome switch (rtag->mbh_requests[i]) {
10114ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_END:
10214ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_CMDLINE:
10314ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
10414ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_MODULE:
10514ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
10614ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_BOOTDEV:
10714ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_MMAP:
10814ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
10914ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_VBE:
11014ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
11114ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_APM:
11214ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI32:
11314ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI64:
11414ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_ACPI_OLD:
11514ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_ACPI_NEW:
11614ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_NETWORK:
11714ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI_MMAP:
11814ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI_BS:
11914ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI32_IH:
12014ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_EFI64_IH:
12114ee0d29SToomas Soome case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
12214ee0d29SToomas Soome break;
12314ee0d29SToomas Soome default:
12414ee0d29SToomas Soome printf("unsupported information tag: 0x%x\n",
12514ee0d29SToomas Soome rtag->mbh_requests[i]);
12614ee0d29SToomas Soome return (false);
12714ee0d29SToomas Soome }
12814ee0d29SToomas Soome return (true);
12914ee0d29SToomas Soome }
13014ee0d29SToomas Soome
13114ee0d29SToomas Soome static int
multiboot2_loadfile(char * filename,uint64_t dest,struct preloaded_file ** result)13286759c82SToomas Soome multiboot2_loadfile(char *filename, uint64_t dest,
13314ee0d29SToomas Soome struct preloaded_file **result)
13414ee0d29SToomas Soome {
13514ee0d29SToomas Soome int fd, error;
13614ee0d29SToomas Soome uint32_t i;
13714ee0d29SToomas Soome struct stat st;
13814ee0d29SToomas Soome caddr_t header_search;
13914ee0d29SToomas Soome multiboot2_header_t *header;
14014ee0d29SToomas Soome multiboot_header_tag_t *tag;
14114ee0d29SToomas Soome multiboot_header_tag_address_t *addr_tag = NULL;
14214ee0d29SToomas Soome multiboot_header_tag_entry_address_t *entry_tag = NULL;
14314ee0d29SToomas Soome struct preloaded_file *fp;
14414ee0d29SToomas Soome
14514ee0d29SToomas Soome /* This allows to check other file formats from file_formats array. */
14614ee0d29SToomas Soome error = EFTYPE;
14714ee0d29SToomas Soome if (filename == NULL)
14814ee0d29SToomas Soome return (error);
14914ee0d29SToomas Soome
15014ee0d29SToomas Soome /* is kernel already loaded? */
15114ee0d29SToomas Soome fp = file_findfile(NULL, NULL);
15214ee0d29SToomas Soome if (fp != NULL)
15314ee0d29SToomas Soome return (error);
15414ee0d29SToomas Soome
15514ee0d29SToomas Soome if ((fd = open(filename, O_RDONLY)) == -1)
15614ee0d29SToomas Soome return (errno);
15714ee0d29SToomas Soome
15814ee0d29SToomas Soome /*
15914ee0d29SToomas Soome * Read MULTIBOOT_SEARCH size in order to search for the
16014ee0d29SToomas Soome * multiboot magic header.
16114ee0d29SToomas Soome */
16214ee0d29SToomas Soome header_search = malloc(MULTIBOOT_SEARCH);
16314ee0d29SToomas Soome if (header_search == NULL) {
16414ee0d29SToomas Soome close(fd);
16514ee0d29SToomas Soome return (ENOMEM);
16614ee0d29SToomas Soome }
16714ee0d29SToomas Soome
16814ee0d29SToomas Soome if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH)
16914ee0d29SToomas Soome goto out;
17014ee0d29SToomas Soome
17114ee0d29SToomas Soome header = NULL;
17214ee0d29SToomas Soome for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t));
17314ee0d29SToomas Soome i += MULTIBOOT_HEADER_ALIGN) {
17414ee0d29SToomas Soome header = (multiboot2_header_t *)(header_search + i);
17514ee0d29SToomas Soome
17614ee0d29SToomas Soome /* Do we have match on magic? */
17714ee0d29SToomas Soome if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) {
17814ee0d29SToomas Soome header = NULL;
17914ee0d29SToomas Soome continue;
18014ee0d29SToomas Soome }
18114ee0d29SToomas Soome /*
18214ee0d29SToomas Soome * Validate checksum, the sum of magic + architecture +
18314ee0d29SToomas Soome * header_length + checksum must equal 0.
18414ee0d29SToomas Soome */
18514ee0d29SToomas Soome if (header->mb2_magic + header->mb2_architecture +
18614ee0d29SToomas Soome header->mb2_header_length + header->mb2_checksum != 0) {
18714ee0d29SToomas Soome header = NULL;
18814ee0d29SToomas Soome continue;
18914ee0d29SToomas Soome }
19014ee0d29SToomas Soome /*
19114ee0d29SToomas Soome * Finally, the entire header must fit within MULTIBOOT_SEARCH.
19214ee0d29SToomas Soome */
19314ee0d29SToomas Soome if (i + header->mb2_header_length > MULTIBOOT_SEARCH) {
19414ee0d29SToomas Soome header = NULL;
19514ee0d29SToomas Soome continue;
19614ee0d29SToomas Soome }
19714ee0d29SToomas Soome break;
19814ee0d29SToomas Soome }
19914ee0d29SToomas Soome
20014ee0d29SToomas Soome if (header == NULL)
20114ee0d29SToomas Soome goto out;
20214ee0d29SToomas Soome
2039890ff83SToomas Soome have_framebuffer = false;
20414ee0d29SToomas Soome for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END;
20514ee0d29SToomas Soome tag = (multiboot_header_tag_t *)((uintptr_t)tag +
20614ee0d29SToomas Soome roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) {
20714ee0d29SToomas Soome switch (tag->mbh_type) {
20814ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
20914ee0d29SToomas Soome if (is_info_request_valid((void*)tag) == false)
21014ee0d29SToomas Soome goto out;
21114ee0d29SToomas Soome break;
21214ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_ADDRESS:
21314ee0d29SToomas Soome addr_tag = (multiboot_header_tag_address_t *)tag;
21414ee0d29SToomas Soome break;
21514ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
21614ee0d29SToomas Soome entry_tag =
21714ee0d29SToomas Soome (multiboot_header_tag_entry_address_t *)tag;
21814ee0d29SToomas Soome break;
21914ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
22014ee0d29SToomas Soome break;
22114ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
22214ee0d29SToomas Soome have_framebuffer = true;
22314ee0d29SToomas Soome break;
22414ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
22514ee0d29SToomas Soome /* we always align modules */
22614ee0d29SToomas Soome break;
22714ee0d29SToomas Soome case MULTIBOOT_HEADER_TAG_EFI_BS:
22814ee0d29SToomas Soome keep_bs = true;
22914ee0d29SToomas Soome break;
23014ee0d29SToomas Soome default:
23114ee0d29SToomas Soome if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) {
23214ee0d29SToomas Soome printf("unsupported tag: 0x%x\n",
23314ee0d29SToomas Soome tag->mbh_type);
23414ee0d29SToomas Soome goto out;
23514ee0d29SToomas Soome }
23614ee0d29SToomas Soome }
23714ee0d29SToomas Soome }
23814ee0d29SToomas Soome
23914ee0d29SToomas Soome /*
24014ee0d29SToomas Soome * We must have addr_tag and entry_tag to load a 64-bit kernel.
24114ee0d29SToomas Soome * If these tags are missing, we either have a 32-bit kernel, or
24214ee0d29SToomas Soome * this is not our kernel at all.
24314ee0d29SToomas Soome */
24414ee0d29SToomas Soome if (addr_tag != NULL && entry_tag != NULL) {
24514ee0d29SToomas Soome fp = file_alloc();
24614ee0d29SToomas Soome if (fp == NULL) {
24714ee0d29SToomas Soome error = ENOMEM;
24814ee0d29SToomas Soome goto out;
24914ee0d29SToomas Soome }
25014ee0d29SToomas Soome if (lseek(fd, 0, SEEK_SET) == -1) {
25114ee0d29SToomas Soome printf("lseek failed\n");
25214ee0d29SToomas Soome error = EIO;
25314ee0d29SToomas Soome file_discard(fp);
25414ee0d29SToomas Soome goto out;
25514ee0d29SToomas Soome }
25614ee0d29SToomas Soome if (fstat(fd, &st) < 0) {
25714ee0d29SToomas Soome printf("fstat failed\n");
25814ee0d29SToomas Soome error = EIO;
25914ee0d29SToomas Soome file_discard(fp);
26014ee0d29SToomas Soome goto out;
26114ee0d29SToomas Soome }
26214ee0d29SToomas Soome
26314ee0d29SToomas Soome load_addr = addr_tag->mbh_load_addr;
26414ee0d29SToomas Soome entry_addr = entry_tag->mbh_entry_addr;
26514ee0d29SToomas Soome fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename,
26614ee0d29SToomas Soome addr_tag->mbh_load_addr);
26714ee0d29SToomas Soome if (fp->f_addr == 0) {
26814ee0d29SToomas Soome error = ENOMEM;
26914ee0d29SToomas Soome file_discard(fp);
27014ee0d29SToomas Soome goto out;
27114ee0d29SToomas Soome }
27214ee0d29SToomas Soome fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size);
27314ee0d29SToomas Soome
27414ee0d29SToomas Soome if (fp->f_size != st.st_size) {
275eddd1134SToomas Soome printf("error reading %s: %s\n", filename,
276eddd1134SToomas Soome strerror(errno));
27714ee0d29SToomas Soome file_discard(fp);
27814ee0d29SToomas Soome error = EIO;
27914ee0d29SToomas Soome goto out;
28014ee0d29SToomas Soome }
28114ee0d29SToomas Soome
28214ee0d29SToomas Soome fp->f_name = strdup(filename);
28314ee0d29SToomas Soome fp->f_type = strdup("aout multiboot2 kernel");
28414ee0d29SToomas Soome if (fp->f_name == NULL || fp->f_type == NULL) {
28514ee0d29SToomas Soome error = ENOMEM;
28614ee0d29SToomas Soome file_discard(fp);
28714ee0d29SToomas Soome goto out;
28814ee0d29SToomas Soome }
28914ee0d29SToomas Soome
29014ee0d29SToomas Soome fp->f_metadata = NULL;
29114ee0d29SToomas Soome error = 0;
29214ee0d29SToomas Soome } else {
293f9feecc1SToomas Soome #if defined(EFI)
294f9feecc1SToomas Soome /* 32-bit kernel is not yet supported for EFI */
295f9feecc1SToomas Soome printf("32-bit kernel is not supported by UEFI loader\n");
296f9feecc1SToomas Soome error = ENOTSUP;
297f9feecc1SToomas Soome goto out;
298f9feecc1SToomas Soome #endif
29914ee0d29SToomas Soome /* elf32_loadfile_raw will fill the attributes in fp. */
30014ee0d29SToomas Soome error = elf32_loadfile_raw(filename, dest, &fp, 2);
30114ee0d29SToomas Soome if (error != 0) {
30214ee0d29SToomas Soome printf("elf32_loadfile_raw failed: %d unable to "
30314ee0d29SToomas Soome "load multiboot2 kernel\n", error);
30414ee0d29SToomas Soome goto out;
30514ee0d29SToomas Soome }
30614ee0d29SToomas Soome entry_addr = fp->f_addr;
30714ee0d29SToomas Soome /*
30814ee0d29SToomas Soome * We want the load_addr to have some legal value,
30914ee0d29SToomas Soome * so we set it same as the entry_addr.
31014ee0d29SToomas Soome * The distinction is important with UEFI, but not
31114ee0d29SToomas Soome * with BIOS version, because BIOS version does not use
31214ee0d29SToomas Soome * staging area.
31314ee0d29SToomas Soome */
31414ee0d29SToomas Soome load_addr = fp->f_addr;
31514ee0d29SToomas Soome }
31614ee0d29SToomas Soome
31714ee0d29SToomas Soome setenv("kernelname", fp->f_name, 1);
318f9feecc1SToomas Soome #if defined(EFI)
319f9feecc1SToomas Soome efi_addsmapdata(fp);
320f9feecc1SToomas Soome #else
32114ee0d29SToomas Soome bios_addsmapdata(fp);
322f9feecc1SToomas Soome #endif
32314ee0d29SToomas Soome *result = fp;
32414ee0d29SToomas Soome out:
32514ee0d29SToomas Soome free(header_search);
32614ee0d29SToomas Soome close(fd);
32714ee0d29SToomas Soome return (error);
32814ee0d29SToomas Soome }
32914ee0d29SToomas Soome
33014ee0d29SToomas Soome /*
33114ee0d29SToomas Soome * Search the command line for named property.
33214ee0d29SToomas Soome *
33314ee0d29SToomas Soome * Return codes:
33414ee0d29SToomas Soome * 0 The name is found, we return the data in value and len.
33514ee0d29SToomas Soome * ENOENT The name is not found.
33614ee0d29SToomas Soome * EINVAL The provided command line is badly formed.
33714ee0d29SToomas Soome */
33814ee0d29SToomas Soome static int
find_property_value(const char * cmd,const char * name,const char ** value,size_t * len)33914ee0d29SToomas Soome find_property_value(const char *cmd, const char *name, const char **value,
34014ee0d29SToomas Soome size_t *len)
34114ee0d29SToomas Soome {
34214ee0d29SToomas Soome const char *namep, *valuep;
34314ee0d29SToomas Soome size_t name_len, value_len;
34414ee0d29SToomas Soome int quoted;
34514ee0d29SToomas Soome
34614ee0d29SToomas Soome *value = NULL;
34714ee0d29SToomas Soome *len = 0;
34814ee0d29SToomas Soome
34914ee0d29SToomas Soome if (cmd == NULL)
35014ee0d29SToomas Soome return (ENOENT);
35114ee0d29SToomas Soome
35214ee0d29SToomas Soome while (*cmd != '\0') {
35314ee0d29SToomas Soome if (cmd[0] != '-' || cmd[1] != 'B') {
35414ee0d29SToomas Soome cmd++;
35514ee0d29SToomas Soome continue;
35614ee0d29SToomas Soome }
35714ee0d29SToomas Soome cmd += 2; /* Skip -B */
35814ee0d29SToomas Soome while (cmd[0] == ' ' || cmd[0] == '\t')
35914ee0d29SToomas Soome cmd++; /* Skip whitespaces. */
36014ee0d29SToomas Soome while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') {
36114ee0d29SToomas Soome namep = cmd;
36214ee0d29SToomas Soome valuep = strchr(cmd, '=');
36314ee0d29SToomas Soome if (valuep == NULL)
36414ee0d29SToomas Soome break;
36514ee0d29SToomas Soome name_len = valuep - namep;
36614ee0d29SToomas Soome valuep++;
36714ee0d29SToomas Soome value_len = 0;
36814ee0d29SToomas Soome quoted = 0;
369*b72c8d00SToomas Soome for (;; ++value_len) {
37014ee0d29SToomas Soome if (valuep[value_len] == '\0')
37114ee0d29SToomas Soome break;
37214ee0d29SToomas Soome
37314ee0d29SToomas Soome /* Is this value quoted? */
37414ee0d29SToomas Soome if (value_len == 0 &&
37514ee0d29SToomas Soome (valuep[0] == '\'' || valuep[0] == '"')) {
37614ee0d29SToomas Soome quoted = valuep[0];
37714ee0d29SToomas Soome ++value_len;
37814ee0d29SToomas Soome }
37914ee0d29SToomas Soome
38014ee0d29SToomas Soome /*
38114ee0d29SToomas Soome * In the quote accept any character,
38214ee0d29SToomas Soome * but look for ending quote.
38314ee0d29SToomas Soome */
38414ee0d29SToomas Soome if (quoted != 0) {
38514ee0d29SToomas Soome if (valuep[value_len] == quoted)
38614ee0d29SToomas Soome quoted = 0;
38714ee0d29SToomas Soome continue;
38814ee0d29SToomas Soome }
38914ee0d29SToomas Soome
39014ee0d29SToomas Soome /* A comma or white space ends the value. */
39114ee0d29SToomas Soome if (valuep[value_len] == ',' ||
39214ee0d29SToomas Soome valuep[value_len] == ' ' ||
39314ee0d29SToomas Soome valuep[value_len] == '\t')
39414ee0d29SToomas Soome break;
39514ee0d29SToomas Soome }
39614ee0d29SToomas Soome if (quoted != 0) {
39714ee0d29SToomas Soome printf("Missing closing '%c' in \"%s\"\n",
39814ee0d29SToomas Soome quoted, valuep);
39914ee0d29SToomas Soome return (EINVAL);
40014ee0d29SToomas Soome }
40114ee0d29SToomas Soome if (value_len != 0) {
40214ee0d29SToomas Soome if (strncmp(namep, name, name_len) == 0) {
40314ee0d29SToomas Soome *value = valuep;
40414ee0d29SToomas Soome *len = value_len;
40514ee0d29SToomas Soome return (0);
40614ee0d29SToomas Soome }
40714ee0d29SToomas Soome }
40814ee0d29SToomas Soome cmd = valuep + value_len;
40914ee0d29SToomas Soome while (*cmd == ',')
41014ee0d29SToomas Soome cmd++;
41114ee0d29SToomas Soome }
41214ee0d29SToomas Soome }
41314ee0d29SToomas Soome return (ENOENT);
41414ee0d29SToomas Soome }
41514ee0d29SToomas Soome
416ade2ca5bSToomas Soome /*
417ade2ca5bSToomas Soome * If command line has " -B ", insert property after "-B ", otherwise
418ade2ca5bSToomas Soome * append to command line.
419ade2ca5bSToomas Soome */
420ade2ca5bSToomas Soome static char *
insert_cmdline(const char * head,const char * prop)421ade2ca5bSToomas Soome insert_cmdline(const char *head, const char *prop)
422ade2ca5bSToomas Soome {
423ade2ca5bSToomas Soome const char *prop_opt = " -B ";
424ade2ca5bSToomas Soome char *cmdline, *tail;
425ade2ca5bSToomas Soome int len = 0;
426ade2ca5bSToomas Soome
427ade2ca5bSToomas Soome tail = strstr(head, prop_opt);
428ade2ca5bSToomas Soome if (tail != NULL) {
429ade2ca5bSToomas Soome ptrdiff_t diff;
430ade2ca5bSToomas Soome tail += strlen(prop_opt);
431ade2ca5bSToomas Soome diff = tail - head;
432ade2ca5bSToomas Soome if (diff >= INT_MAX)
433ade2ca5bSToomas Soome return (NULL);
434ade2ca5bSToomas Soome len = (int)diff;
435ade2ca5bSToomas Soome }
436ade2ca5bSToomas Soome
437ade2ca5bSToomas Soome if (tail == NULL)
438ade2ca5bSToomas Soome asprintf(&cmdline, "%s%s%s", head, prop_opt, prop);
439ade2ca5bSToomas Soome else
440ade2ca5bSToomas Soome asprintf(&cmdline, "%.*s%s,%s", len, head, prop, tail);
441ade2ca5bSToomas Soome
442ade2ca5bSToomas Soome return (cmdline);
443ade2ca5bSToomas Soome }
444ade2ca5bSToomas Soome
445ade2ca5bSToomas Soome /*
446ade2ca5bSToomas Soome * Since we have no way to pass the environment to the mb1 kernel other than
447ade2ca5bSToomas Soome * through arguments, we need to take care of console setup.
448ade2ca5bSToomas Soome *
449ade2ca5bSToomas Soome * If the console is in mirror mode, set the kernel console from $os_console.
450ade2ca5bSToomas Soome * If it's unset, use first item from $console.
451ade2ca5bSToomas Soome * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by
452ade2ca5bSToomas Soome * the user.
453ade2ca5bSToomas Soome *
454ade2ca5bSToomas Soome * In case of memory allocation errors, just return the original command line
455ade2ca5bSToomas Soome * so we have a chance of booting.
456ade2ca5bSToomas Soome *
457ade2ca5bSToomas Soome * On success, cl will be freed and a new, allocated command line string is
458ade2ca5bSToomas Soome * returned.
459ade2ca5bSToomas Soome *
460ade2ca5bSToomas Soome * For the mb2 kernel, we only set command line console if os_console is set.
461ade2ca5bSToomas Soome * We can not overwrite console in the environment, as it can disrupt the
462ade2ca5bSToomas Soome * loader console messages, and we do not want to deal with the os_console
463ade2ca5bSToomas Soome * in the kernel.
464ade2ca5bSToomas Soome */
465ade2ca5bSToomas Soome static char *
update_cmdline(char * cl,bool mb2)466ade2ca5bSToomas Soome update_cmdline(char *cl, bool mb2)
467ade2ca5bSToomas Soome {
468ade2ca5bSToomas Soome char *os_console = getenv("os_console");
469ade2ca5bSToomas Soome char *ttymode = NULL;
470ade2ca5bSToomas Soome char mode[10];
471ade2ca5bSToomas Soome char *tmp;
472ade2ca5bSToomas Soome const char *prop;
473ade2ca5bSToomas Soome size_t plen;
474ade2ca5bSToomas Soome int rv;
475ade2ca5bSToomas Soome
476ade2ca5bSToomas Soome if (mb2 == true && os_console == NULL)
477ade2ca5bSToomas Soome return (cl);
478ade2ca5bSToomas Soome
479ade2ca5bSToomas Soome if (os_console == NULL) {
480ade2ca5bSToomas Soome tmp = strdup(getenv("console"));
481ade2ca5bSToomas Soome os_console = strsep(&tmp, ", ");
482ade2ca5bSToomas Soome } else {
483ade2ca5bSToomas Soome os_console = strdup(os_console);
484ade2ca5bSToomas Soome }
485ade2ca5bSToomas Soome
486ade2ca5bSToomas Soome if (os_console == NULL)
487ade2ca5bSToomas Soome return (cl);
488ade2ca5bSToomas Soome
489ade2ca5bSToomas Soome if (mb2 == false && strncmp(os_console, "tty", 3) == 0) {
490ade2ca5bSToomas Soome snprintf(mode, sizeof (mode), "%s-mode", os_console);
491ade2ca5bSToomas Soome /*
492ade2ca5bSToomas Soome * The ttyX-mode variable is set by our serial console
493ade2ca5bSToomas Soome * driver for ttya-ttyd. However, since the os_console
494ade2ca5bSToomas Soome * values are not verified, it is possible we get bogus
495ade2ca5bSToomas Soome * name and no mode variable. If so, we do not set console
496ade2ca5bSToomas Soome * property and let the kernel use defaults.
497ade2ca5bSToomas Soome */
498ade2ca5bSToomas Soome if ((ttymode = getenv(mode)) == NULL)
499ade2ca5bSToomas Soome return (cl);
500ade2ca5bSToomas Soome }
501ade2ca5bSToomas Soome
502ade2ca5bSToomas Soome rv = find_property_value(cl, "console", &prop, &plen);
503ade2ca5bSToomas Soome if (rv != 0 && rv != ENOENT) {
504ade2ca5bSToomas Soome free(os_console);
505ade2ca5bSToomas Soome return (cl);
506ade2ca5bSToomas Soome }
507ade2ca5bSToomas Soome
508ade2ca5bSToomas Soome /* If console is set and this is MB2 boot, we are done. */
509ade2ca5bSToomas Soome if (rv == 0 && mb2 == true) {
510ade2ca5bSToomas Soome free(os_console);
511ade2ca5bSToomas Soome return (cl);
512ade2ca5bSToomas Soome }
513ade2ca5bSToomas Soome
514ade2ca5bSToomas Soome /* If console is set, do we need to set tty mode? */
515ade2ca5bSToomas Soome if (rv == 0) {
516ade2ca5bSToomas Soome const char *ttyp = NULL;
517ade2ca5bSToomas Soome size_t ttylen;
518ade2ca5bSToomas Soome
519ade2ca5bSToomas Soome free(os_console);
520ade2ca5bSToomas Soome os_console = NULL;
521ade2ca5bSToomas Soome *mode = '\0';
522ade2ca5bSToomas Soome if (strncmp(prop, "tty", 3) == 0 && plen == 4) {
523ade2ca5bSToomas Soome strncpy(mode, prop, plen);
524ade2ca5bSToomas Soome mode[plen] = '\0';
525ade2ca5bSToomas Soome strncat(mode, "-mode", 5);
526ade2ca5bSToomas Soome find_property_value(cl, mode, &ttyp, &ttylen);
527ade2ca5bSToomas Soome }
528ade2ca5bSToomas Soome
529ade2ca5bSToomas Soome if (*mode != '\0' && ttyp == NULL)
530ade2ca5bSToomas Soome ttymode = getenv(mode);
531ade2ca5bSToomas Soome else
532ade2ca5bSToomas Soome return (cl);
533ade2ca5bSToomas Soome }
534ade2ca5bSToomas Soome
535ade2ca5bSToomas Soome /* Build updated command line. */
536ade2ca5bSToomas Soome if (os_console != NULL) {
537ade2ca5bSToomas Soome char *propstr;
538ade2ca5bSToomas Soome
539ade2ca5bSToomas Soome asprintf(&propstr, "console=%s", os_console);
540ade2ca5bSToomas Soome free(os_console);
541ade2ca5bSToomas Soome if (propstr == NULL) {
542ade2ca5bSToomas Soome return (cl);
543ade2ca5bSToomas Soome }
544ade2ca5bSToomas Soome
545ade2ca5bSToomas Soome tmp = insert_cmdline(cl, propstr);
54686759c82SToomas Soome free(propstr);
54786759c82SToomas Soome if (tmp == NULL)
548ade2ca5bSToomas Soome return (cl);
549ade2ca5bSToomas Soome
55086759c82SToomas Soome free(cl);
55186759c82SToomas Soome cl = tmp;
552ade2ca5bSToomas Soome }
553ade2ca5bSToomas Soome if (ttymode != NULL) {
554ade2ca5bSToomas Soome char *propstr;
555ade2ca5bSToomas Soome
556ade2ca5bSToomas Soome asprintf(&propstr, "%s=\"%s\"", mode, ttymode);
557ade2ca5bSToomas Soome if (propstr == NULL)
558ade2ca5bSToomas Soome return (cl);
559ade2ca5bSToomas Soome
560ade2ca5bSToomas Soome tmp = insert_cmdline(cl, propstr);
56186759c82SToomas Soome free(propstr);
56286759c82SToomas Soome if (tmp == NULL)
563ade2ca5bSToomas Soome return (cl);
56486759c82SToomas Soome free(cl);
56586759c82SToomas Soome cl = tmp;
566ade2ca5bSToomas Soome }
567ade2ca5bSToomas Soome
568ade2ca5bSToomas Soome return (cl);
569ade2ca5bSToomas Soome }
570ade2ca5bSToomas Soome
57114ee0d29SToomas Soome /*
57214ee0d29SToomas Soome * Build the kernel command line. Shared function between MB1 and MB2.
573ade2ca5bSToomas Soome *
574ade2ca5bSToomas Soome * In both cases, if fstype is set and is not zfs, we do not set up
575ade2ca5bSToomas Soome * zfs-bootfs property. But we set kernel file name and options.
576ade2ca5bSToomas Soome *
577ade2ca5bSToomas Soome * For the MB1, we only can pass properties on command line, so
578ade2ca5bSToomas Soome * we will set console, ttyX-mode (for serial console) and zfs-bootfs.
579ade2ca5bSToomas Soome *
580ade2ca5bSToomas Soome * For the MB2, we can pass properties in environment, but if os_console
581ade2ca5bSToomas Soome * is set in environment, we need to add console property on the kernel
582ade2ca5bSToomas Soome * command line.
583ade2ca5bSToomas Soome *
584ade2ca5bSToomas Soome * The console properties are managed in update_cmdline().
58514ee0d29SToomas Soome */
58614ee0d29SToomas Soome int
mb_kernel_cmdline(struct preloaded_file * fp,struct devdesc * rootdev,char ** line)58714ee0d29SToomas Soome mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev,
58814ee0d29SToomas Soome char **line)
58914ee0d29SToomas Soome {
59014ee0d29SToomas Soome const char *fs = getenv("fstype");
591ade2ca5bSToomas Soome char *cmdline;
59214ee0d29SToomas Soome size_t len;
59314ee0d29SToomas Soome bool zfs_root = false;
594ade2ca5bSToomas Soome bool mb2;
595ade2ca5bSToomas Soome int rv;
596ade2ca5bSToomas Soome
597*b72c8d00SToomas Soome /*
598*b72c8d00SToomas Soome * With multiple console devices and "os_console" variable not
599*b72c8d00SToomas Soome * set, set os_console to last input device.
600*b72c8d00SToomas Soome */
601*b72c8d00SToomas Soome rv = cons_inputdev();
602*b72c8d00SToomas Soome if (rv != -1)
603*b72c8d00SToomas Soome (void) setenv("os_console", consoles[rv]->c_name, 0);
604*b72c8d00SToomas Soome
605ade2ca5bSToomas Soome /*
606ade2ca5bSToomas Soome * 64-bit kernel has aout header, 32-bit kernel is elf, and the
607ade2ca5bSToomas Soome * type strings are different. Lets just search for "multiboot2".
608ade2ca5bSToomas Soome */
609ade2ca5bSToomas Soome if (strstr(fp->f_type, "multiboot2") == NULL)
610ade2ca5bSToomas Soome mb2 = false;
611ade2ca5bSToomas Soome else
612ade2ca5bSToomas Soome mb2 = true;
61314ee0d29SToomas Soome
614c142ce19SToomas Soome if (rootdev->d_dev->dv_type == DEVT_ZFS)
61514ee0d29SToomas Soome zfs_root = true;
61614ee0d29SToomas Soome
61714ee0d29SToomas Soome /* If we have fstype set in env, reset zfs_root if needed. */
61814ee0d29SToomas Soome if (fs != NULL && strcmp(fs, "zfs") != 0)
61914ee0d29SToomas Soome zfs_root = false;
62014ee0d29SToomas Soome
62114ee0d29SToomas Soome /*
62214ee0d29SToomas Soome * If we have fstype set on the command line,
62314ee0d29SToomas Soome * reset zfs_root if needed.
62414ee0d29SToomas Soome */
62514ee0d29SToomas Soome rv = find_property_value(fp->f_args, "fstype", &fs, &len);
626ade2ca5bSToomas Soome if (rv != 0 && rv != ENOENT)
62714ee0d29SToomas Soome return (rv);
62814ee0d29SToomas Soome
62914ee0d29SToomas Soome if (fs != NULL && strncmp(fs, "zfs", len) != 0)
63014ee0d29SToomas Soome zfs_root = false;
63114ee0d29SToomas Soome
632ade2ca5bSToomas Soome /* zfs_bootfs() will set the environment, it must be called. */
63314ee0d29SToomas Soome if (zfs_root == true)
634ade2ca5bSToomas Soome fs = zfs_bootfs(rootdev);
635ade2ca5bSToomas Soome
636ade2ca5bSToomas Soome if (fp->f_args == NULL)
637ade2ca5bSToomas Soome cmdline = strdup(fp->f_name);
638ade2ca5bSToomas Soome else
639ade2ca5bSToomas Soome asprintf(&cmdline, "%s %s", fp->f_name, fp->f_args);
64014ee0d29SToomas Soome
64114ee0d29SToomas Soome if (cmdline == NULL)
64214ee0d29SToomas Soome return (ENOMEM);
64314ee0d29SToomas Soome
644ade2ca5bSToomas Soome /* Append zfs-bootfs for MB1 command line. */
645ade2ca5bSToomas Soome if (mb2 == false && zfs_root == true) {
646ade2ca5bSToomas Soome char *tmp;
647ade2ca5bSToomas Soome
648ade2ca5bSToomas Soome tmp = insert_cmdline(cmdline, fs);
649ade2ca5bSToomas Soome free(cmdline);
650ade2ca5bSToomas Soome if (tmp == NULL)
651ade2ca5bSToomas Soome return (ENOMEM);
652ade2ca5bSToomas Soome cmdline = tmp;
653ade2ca5bSToomas Soome }
65414ee0d29SToomas Soome
655ade2ca5bSToomas Soome *line = update_cmdline(cmdline, mb2);
65614ee0d29SToomas Soome return (0);
65714ee0d29SToomas Soome }
65814ee0d29SToomas Soome
65914ee0d29SToomas Soome /*
66014ee0d29SToomas Soome * Returns allocated virtual address from MB info area.
66114ee0d29SToomas Soome */
66214ee0d29SToomas Soome static vm_offset_t
mb_malloc(size_t n)66314ee0d29SToomas Soome mb_malloc(size_t n)
66414ee0d29SToomas Soome {
66514ee0d29SToomas Soome vm_offset_t ptr = last_addr;
66614ee0d29SToomas Soome last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN);
66714ee0d29SToomas Soome return (ptr);
66814ee0d29SToomas Soome }
66914ee0d29SToomas Soome
67014ee0d29SToomas Soome /*
67114ee0d29SToomas Soome * Calculate size for module tag list.
67214ee0d29SToomas Soome */
67314ee0d29SToomas Soome static size_t
module_size(struct preloaded_file * fp)67414ee0d29SToomas Soome module_size(struct preloaded_file *fp)
67514ee0d29SToomas Soome {
67614ee0d29SToomas Soome size_t len, size;
67714ee0d29SToomas Soome struct preloaded_file *mfp;
67814ee0d29SToomas Soome
67914ee0d29SToomas Soome size = 0;
68014ee0d29SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
68114ee0d29SToomas Soome len = strlen(mfp->f_name) + 1;
68214ee0d29SToomas Soome len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */
68314ee0d29SToomas Soome if (mfp->f_args != NULL)
68414ee0d29SToomas Soome len += strlen(mfp->f_args) + 1;
68514ee0d29SToomas Soome size += sizeof (multiboot_tag_module_t) + len;
68614ee0d29SToomas Soome size = roundup(size, MULTIBOOT_TAG_ALIGN);
68714ee0d29SToomas Soome }
68814ee0d29SToomas Soome return (size);
68914ee0d29SToomas Soome }
69014ee0d29SToomas Soome
69186759c82SToomas Soome #if defined(EFI)
692f9feecc1SToomas Soome /*
693f9feecc1SToomas Soome * Calculate size for UEFI memory map tag.
694f9feecc1SToomas Soome */
69515ab2c88SToomas Soome #define EFI_EXTRA_PAGES 3
69615ab2c88SToomas Soome
697f9feecc1SToomas Soome static int
efimemmap_size(void)698f9feecc1SToomas Soome efimemmap_size(void)
699f9feecc1SToomas Soome {
700f9feecc1SToomas Soome UINTN size, cur_size, desc_size;
701f9feecc1SToomas Soome EFI_MEMORY_DESCRIPTOR *mmap;
702f9feecc1SToomas Soome EFI_STATUS ret;
703f9feecc1SToomas Soome
704f9feecc1SToomas Soome size = EFI_PAGE_SIZE; /* Start with 4k. */
705f9feecc1SToomas Soome while (1) {
706f9feecc1SToomas Soome cur_size = size;
707f9feecc1SToomas Soome mmap = malloc(cur_size);
708f9feecc1SToomas Soome if (mmap == NULL)
709f9feecc1SToomas Soome return (0);
710f9feecc1SToomas Soome ret = BS->GetMemoryMap(&cur_size, mmap, NULL, &desc_size, NULL);
711f9feecc1SToomas Soome free(mmap);
712f9feecc1SToomas Soome if (ret == EFI_SUCCESS)
713f9feecc1SToomas Soome break;
714f9feecc1SToomas Soome if (ret == EFI_BUFFER_TOO_SMALL) {
715f9feecc1SToomas Soome if (size < cur_size)
716f9feecc1SToomas Soome size = cur_size;
717f9feecc1SToomas Soome size += (EFI_PAGE_SIZE);
718f9feecc1SToomas Soome } else
719f9feecc1SToomas Soome return (0);
720f9feecc1SToomas Soome }
721f9feecc1SToomas Soome
722f9feecc1SToomas Soome /* EFI MMAP will grow when we allocate MBI, set some buffer. */
72315ab2c88SToomas Soome size += (EFI_EXTRA_PAGES << EFI_PAGE_SHIFT);
72415ab2c88SToomas Soome size = roundup2(size, EFI_PAGE_SIZE);
72515ab2c88SToomas Soome efi_map_size = size; /* Record the calculated size. */
726f9feecc1SToomas Soome return (sizeof (multiboot_tag_efi_mmap_t) + size);
727f9feecc1SToomas Soome }
728f9feecc1SToomas Soome #endif
729f9feecc1SToomas Soome
73014ee0d29SToomas Soome /*
73114ee0d29SToomas Soome * Calculate size for bios smap tag.
73214ee0d29SToomas Soome */
73314ee0d29SToomas Soome static size_t
biossmap_size(struct preloaded_file * fp)73414ee0d29SToomas Soome biossmap_size(struct preloaded_file *fp)
73514ee0d29SToomas Soome {
73614ee0d29SToomas Soome int num;
73714ee0d29SToomas Soome struct file_metadata *md;
73814ee0d29SToomas Soome
73914ee0d29SToomas Soome md = file_findmetadata(fp, MODINFOMD_SMAP);
74014ee0d29SToomas Soome if (md == NULL)
74114ee0d29SToomas Soome return (0);
74214ee0d29SToomas Soome
74386759c82SToomas Soome num = md->md_size / sizeof (struct bios_smap); /* number of entries */
74414ee0d29SToomas Soome return (sizeof (multiboot_tag_mmap_t) +
74514ee0d29SToomas Soome num * sizeof (multiboot_mmap_entry_t));
74614ee0d29SToomas Soome }
74714ee0d29SToomas Soome
74814ee0d29SToomas Soome static size_t
mbi_size(struct preloaded_file * fp,char * cmdline)74914ee0d29SToomas Soome mbi_size(struct preloaded_file *fp, char *cmdline)
75014ee0d29SToomas Soome {
75114ee0d29SToomas Soome size_t size;
75286759c82SToomas Soome #if !defined(EFI)
7539890ff83SToomas Soome extern multiboot_tag_framebuffer_t gfx_fb;
7549890ff83SToomas Soome #endif
75514ee0d29SToomas Soome
75614ee0d29SToomas Soome size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */
75714ee0d29SToomas Soome size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
75814ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
75914ee0d29SToomas Soome size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
76014ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
76186759c82SToomas Soome #if !defined(EFI)
76214ee0d29SToomas Soome size += sizeof (multiboot_tag_basic_meminfo_t);
76314ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
764f9feecc1SToomas Soome #endif
76514ee0d29SToomas Soome size += module_size(fp);
76614ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
76786759c82SToomas Soome #if defined(EFI)
768f9feecc1SToomas Soome size += sizeof (multiboot_tag_efi64_t);
769f9feecc1SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
770f9feecc1SToomas Soome size += efimemmap_size();
771f9feecc1SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
772f9feecc1SToomas Soome
773f9feecc1SToomas Soome if (have_framebuffer == true) {
774f9feecc1SToomas Soome size += sizeof (multiboot_tag_framebuffer_t);
775f9feecc1SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
776f9feecc1SToomas Soome }
777f9feecc1SToomas Soome #endif
7789890ff83SToomas Soome
77914ee0d29SToomas Soome size += biossmap_size(fp);
78014ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
78114ee0d29SToomas Soome
78286759c82SToomas Soome #if !defined(EFI)
7839890ff83SToomas Soome if (gfx_fb.framebuffer_common.framebuffer_type ==
7849890ff83SToomas Soome MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
7859890ff83SToomas Soome size += sizeof (struct multiboot_tag_framebuffer_common);
78691061836SToomas Soome size += CMAP_SIZE * sizeof (multiboot_color_t);
7879890ff83SToomas Soome } else {
7889890ff83SToomas Soome size += sizeof (multiboot_tag_framebuffer_t);
7899890ff83SToomas Soome }
7909890ff83SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
7919890ff83SToomas Soome
7929890ff83SToomas Soome size += sizeof (multiboot_tag_vbe_t);
7939890ff83SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
7949890ff83SToomas Soome #endif
7959890ff83SToomas Soome
796f9feecc1SToomas Soome if (bootp_response != NULL) {
79786759c82SToomas Soome size += sizeof (multiboot_tag_network_t) + bootp_response_size;
79814ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
79914ee0d29SToomas Soome }
80014ee0d29SToomas Soome
80114ee0d29SToomas Soome if (rsdp != NULL) {
80214ee0d29SToomas Soome if (rsdp->Revision == 0) {
80314ee0d29SToomas Soome size += sizeof (multiboot_tag_old_acpi_t) +
80486759c82SToomas Soome sizeof (ACPI_RSDP_COMMON);
80514ee0d29SToomas Soome } else {
80614ee0d29SToomas Soome size += sizeof (multiboot_tag_new_acpi_t) +
80714ee0d29SToomas Soome rsdp->Length;
80814ee0d29SToomas Soome }
80914ee0d29SToomas Soome size = roundup2(size, MULTIBOOT_TAG_ALIGN);
81014ee0d29SToomas Soome }
81186759c82SToomas Soome size += sizeof (multiboot_tag_t);
81214ee0d29SToomas Soome
81314ee0d29SToomas Soome return (size);
81414ee0d29SToomas Soome }
81514ee0d29SToomas Soome
816287d0250SJohn Levon #if defined(EFI)
817287d0250SJohn Levon static bool
overlaps(uintptr_t start1,size_t size1,uintptr_t start2,size_t size2)818287d0250SJohn Levon overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2)
819287d0250SJohn Levon {
820287d0250SJohn Levon if (start1 < start2 + size2 &&
821287d0250SJohn Levon start1 + size1 >= start2) {
822287d0250SJohn Levon printf("overlaps: %zx-%zx, %zx-%zx\n",
823287d0250SJohn Levon start1, start1 + size1, start2, start2 + size2);
824287d0250SJohn Levon return (true);
825287d0250SJohn Levon }
826287d0250SJohn Levon
827287d0250SJohn Levon return (false);
828287d0250SJohn Levon }
829287d0250SJohn Levon #endif
830287d0250SJohn Levon
83114ee0d29SToomas Soome static int
multiboot2_exec(struct preloaded_file * fp)83214ee0d29SToomas Soome multiboot2_exec(struct preloaded_file *fp)
83314ee0d29SToomas Soome {
834287d0250SJohn Levon multiboot2_info_header_t *mbi = NULL;
83514ee0d29SToomas Soome struct preloaded_file *mfp;
83614ee0d29SToomas Soome char *cmdline = NULL;
83714ee0d29SToomas Soome struct devdesc *rootdev;
83814ee0d29SToomas Soome struct file_metadata *md;
83914ee0d29SToomas Soome int i, error, num;
84014ee0d29SToomas Soome int rootfs = 0;
84114ee0d29SToomas Soome size_t size;
84214ee0d29SToomas Soome struct bios_smap *smap;
84386759c82SToomas Soome #if defined(EFI)
844af8443c4SToomas Soome multiboot_tag_module_t *module, *mp;
845287d0250SJohn Levon struct relocator *relocator = NULL;
846f9feecc1SToomas Soome EFI_MEMORY_DESCRIPTOR *map;
847af8443c4SToomas Soome UINTN map_size, desc_size;
848f9feecc1SToomas Soome struct chunk_head *head;
849f9feecc1SToomas Soome struct chunk *chunk;
8508600fd4dSToomas Soome vm_offset_t tmp;
851f9feecc1SToomas Soome
852f9feecc1SToomas Soome efi_getdev((void **)(&rootdev), NULL, NULL);
853287d0250SJohn Levon
854287d0250SJohn Levon /*
855287d0250SJohn Levon * We need 5 pages for relocation. We'll allocate from the heap: while
856287d0250SJohn Levon * it's possible that our heap got placed low down enough to be in the
857287d0250SJohn Levon * way of where we're going to relocate our kernel, it's hopefully not
858287d0250SJohn Levon * likely.
859287d0250SJohn Levon */
860287d0250SJohn Levon if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) {
861287d0250SJohn Levon printf("relocator malloc failed!\n");
862287d0250SJohn Levon error = ENOMEM;
863287d0250SJohn Levon goto error;
864287d0250SJohn Levon }
865287d0250SJohn Levon
866287d0250SJohn Levon if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5,
867287d0250SJohn Levon load_addr, fp->f_size)) {
868287d0250SJohn Levon printf("relocator pages overlap the kernel!\n");
869287d0250SJohn Levon error = EINVAL;
870287d0250SJohn Levon goto error;
871287d0250SJohn Levon }
872287d0250SJohn Levon
873f9feecc1SToomas Soome #else
87414ee0d29SToomas Soome i386_getdev((void **)(&rootdev), NULL, NULL);
8759890ff83SToomas Soome
8769890ff83SToomas Soome if (have_framebuffer == false) {
8779890ff83SToomas Soome /* make sure we have text mode */
8789890ff83SToomas Soome bios_set_text_mode(VGA_TEXT_MODE);
8799890ff83SToomas Soome }
880f9feecc1SToomas Soome #endif
88114ee0d29SToomas Soome
88214ee0d29SToomas Soome error = EINVAL;
88314ee0d29SToomas Soome if (rootdev == NULL) {
88414ee0d29SToomas Soome printf("can't determine root device\n");
88514ee0d29SToomas Soome goto error;
88614ee0d29SToomas Soome }
88714ee0d29SToomas Soome
88814ee0d29SToomas Soome /*
88914ee0d29SToomas Soome * Set the image command line.
89014ee0d29SToomas Soome */
89114ee0d29SToomas Soome if (fp->f_args == NULL) {
89214ee0d29SToomas Soome cmdline = getenv("boot-args");
89314ee0d29SToomas Soome if (cmdline != NULL) {
89414ee0d29SToomas Soome fp->f_args = strdup(cmdline);
89514ee0d29SToomas Soome if (fp->f_args == NULL) {
89614ee0d29SToomas Soome error = ENOMEM;
89714ee0d29SToomas Soome goto error;
89814ee0d29SToomas Soome }
89914ee0d29SToomas Soome }
90014ee0d29SToomas Soome }
90114ee0d29SToomas Soome
90214ee0d29SToomas Soome error = mb_kernel_cmdline(fp, rootdev, &cmdline);
90314ee0d29SToomas Soome if (error != 0)
90414ee0d29SToomas Soome goto error;
90514ee0d29SToomas Soome
90676608ff7SToomas Soome /* mb_kernel_cmdline() updates the environment. */
90776608ff7SToomas Soome build_environment_module();
90876608ff7SToomas Soome
90945cf6faaSToomas Soome /* Pass the loaded console font for kernel. */
91045cf6faaSToomas Soome build_font_module();
9119890ff83SToomas Soome
91214ee0d29SToomas Soome size = mbi_size(fp, cmdline); /* Get the size for MBI. */
91314ee0d29SToomas Soome
91414ee0d29SToomas Soome /* Set up the base for mb_malloc. */
915f9feecc1SToomas Soome i = 0;
916f9feecc1SToomas Soome for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next)
917f9feecc1SToomas Soome i++;
918f9feecc1SToomas Soome
91986759c82SToomas Soome #if defined(EFI)
920f9feecc1SToomas Soome /* We need space for kernel + MBI + # modules */
921f9feecc1SToomas Soome num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) /
922f9feecc1SToomas Soome sizeof (struct chunk);
923f9feecc1SToomas Soome if (i + 2 >= num) {
924f9feecc1SToomas Soome printf("Too many modules, do not have space for relocator.\n");
925f9feecc1SToomas Soome error = ENOMEM;
926f9feecc1SToomas Soome goto error;
927f9feecc1SToomas Soome }
92814ee0d29SToomas Soome
929f9feecc1SToomas Soome last_addr = efi_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size);
930f9feecc1SToomas Soome mbi = (multiboot2_info_header_t *)last_addr;
931f9feecc1SToomas Soome if (mbi == NULL) {
932f9feecc1SToomas Soome error = ENOMEM;
933f9feecc1SToomas Soome goto error;
934f9feecc1SToomas Soome }
935f9feecc1SToomas Soome last_addr = (vm_offset_t)mbi->mbi_tags;
936f9feecc1SToomas Soome #else
93714ee0d29SToomas Soome /* Start info block from the new page. */
9388600fd4dSToomas Soome last_addr = i386_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size);
93914ee0d29SToomas Soome
94014ee0d29SToomas Soome /* Do we have space for multiboot info? */
94114ee0d29SToomas Soome if (last_addr + size >= memtop_copyin) {
94214ee0d29SToomas Soome error = ENOMEM;
94314ee0d29SToomas Soome goto error;
94414ee0d29SToomas Soome }
94514ee0d29SToomas Soome
94614ee0d29SToomas Soome mbi = (multiboot2_info_header_t *)PTOV(last_addr);
94714ee0d29SToomas Soome last_addr = (vm_offset_t)mbi->mbi_tags;
948f9feecc1SToomas Soome #endif /* EFI */
94914ee0d29SToomas Soome
95014ee0d29SToomas Soome {
95114ee0d29SToomas Soome multiboot_tag_string_t *tag;
95214ee0d29SToomas Soome i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
95386759c82SToomas Soome tag = (multiboot_tag_string_t *)mb_malloc(i);
95414ee0d29SToomas Soome
95514ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE;
95614ee0d29SToomas Soome tag->mb_size = i;
95714ee0d29SToomas Soome memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1);
95814ee0d29SToomas Soome free(cmdline);
95914ee0d29SToomas Soome cmdline = NULL;
96014ee0d29SToomas Soome }
96114ee0d29SToomas Soome
96214ee0d29SToomas Soome {
96314ee0d29SToomas Soome multiboot_tag_string_t *tag;
96414ee0d29SToomas Soome i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
96586759c82SToomas Soome tag = (multiboot_tag_string_t *)mb_malloc(i);
96614ee0d29SToomas Soome
96714ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
96814ee0d29SToomas Soome tag->mb_size = i;
96914ee0d29SToomas Soome memcpy(tag->mb_string, bootprog_info,
97014ee0d29SToomas Soome strlen(bootprog_info) + 1);
97114ee0d29SToomas Soome }
97214ee0d29SToomas Soome
97386759c82SToomas Soome #if !defined(EFI)
974f9feecc1SToomas Soome /* Only set in case of BIOS. */
97514ee0d29SToomas Soome {
97614ee0d29SToomas Soome multiboot_tag_basic_meminfo_t *tag;
97714ee0d29SToomas Soome tag = (multiboot_tag_basic_meminfo_t *)
97814ee0d29SToomas Soome mb_malloc(sizeof (*tag));
97914ee0d29SToomas Soome
98014ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
98114ee0d29SToomas Soome tag->mb_size = sizeof (*tag);
98214ee0d29SToomas Soome tag->mb_mem_lower = bios_basemem / 1024;
98314ee0d29SToomas Soome tag->mb_mem_upper = bios_extmem / 1024;
98414ee0d29SToomas Soome }
985f9feecc1SToomas Soome #endif
98614ee0d29SToomas Soome
98714ee0d29SToomas Soome num = 0;
98814ee0d29SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
98914ee0d29SToomas Soome num++;
99014ee0d29SToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
99114ee0d29SToomas Soome rootfs++;
99214ee0d29SToomas Soome }
99314ee0d29SToomas Soome
99414ee0d29SToomas Soome if (num == 0 || rootfs == 0) {
99514ee0d29SToomas Soome /* We need at least one module - rootfs. */
99614ee0d29SToomas Soome printf("No rootfs module provided, aborting\n");
99714ee0d29SToomas Soome error = EINVAL;
99814ee0d29SToomas Soome goto error;
99914ee0d29SToomas Soome }
100014ee0d29SToomas Soome
100114ee0d29SToomas Soome /*
100214ee0d29SToomas Soome * Set the stage for physical memory layout:
100314ee0d29SToomas Soome * - We have kernel at load_addr.
100414ee0d29SToomas Soome * - Modules are aligned to page boundary.
100514ee0d29SToomas Soome * - MBI is aligned to page boundary.
100614ee0d29SToomas Soome * - Set the tmp to point to physical address of the first module.
1007f9feecc1SToomas Soome * - tmp != mfp->f_addr only in case of EFI.
100814ee0d29SToomas Soome */
100986759c82SToomas Soome #if defined(EFI)
1010af8443c4SToomas Soome tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN);
1011f9feecc1SToomas Soome module = (multiboot_tag_module_t *)last_addr;
1012f9feecc1SToomas Soome #endif
101314ee0d29SToomas Soome
101414ee0d29SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
101514ee0d29SToomas Soome multiboot_tag_module_t *tag;
101614ee0d29SToomas Soome
101714ee0d29SToomas Soome num = strlen(mfp->f_name) + 1;
101814ee0d29SToomas Soome num += strlen(mfp->f_type) + 5 + 1;
101914ee0d29SToomas Soome if (mfp->f_args != NULL) {
102014ee0d29SToomas Soome num += strlen(mfp->f_args) + 1;
102114ee0d29SToomas Soome }
102214ee0d29SToomas Soome cmdline = malloc(num);
102314ee0d29SToomas Soome if (cmdline == NULL) {
102414ee0d29SToomas Soome error = ENOMEM;
102514ee0d29SToomas Soome goto error;
102614ee0d29SToomas Soome }
102714ee0d29SToomas Soome
102814ee0d29SToomas Soome if (mfp->f_args != NULL)
102914ee0d29SToomas Soome snprintf(cmdline, num, "%s type=%s %s",
103014ee0d29SToomas Soome mfp->f_name, mfp->f_type, mfp->f_args);
103114ee0d29SToomas Soome else
103214ee0d29SToomas Soome snprintf(cmdline, num, "%s type=%s",
103314ee0d29SToomas Soome mfp->f_name, mfp->f_type);
103414ee0d29SToomas Soome
103514ee0d29SToomas Soome tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num);
103614ee0d29SToomas Soome
103714ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE;
103814ee0d29SToomas Soome tag->mb_size = sizeof (*tag) + num;
103986759c82SToomas Soome #if defined(EFI)
1040af8443c4SToomas Soome /*
1041af8443c4SToomas Soome * We can assign module addresses only after BS have been
1042af8443c4SToomas Soome * switched off.
1043af8443c4SToomas Soome */
1044af8443c4SToomas Soome tag->mb_mod_start = 0;
1045af8443c4SToomas Soome tag->mb_mod_end = mfp->f_size;
10468600fd4dSToomas Soome #else
10478600fd4dSToomas Soome tag->mb_mod_start = mfp->f_addr;
10488600fd4dSToomas Soome tag->mb_mod_end = mfp->f_addr + mfp->f_size;
10498600fd4dSToomas Soome #endif
105014ee0d29SToomas Soome memcpy(tag->mb_cmdline, cmdline, num);
105114ee0d29SToomas Soome free(cmdline);
105214ee0d29SToomas Soome cmdline = NULL;
105314ee0d29SToomas Soome }
105414ee0d29SToomas Soome
105514ee0d29SToomas Soome md = file_findmetadata(fp, MODINFOMD_SMAP);
105614ee0d29SToomas Soome if (md == NULL) {
105714ee0d29SToomas Soome printf("no memory smap\n");
105814ee0d29SToomas Soome error = EINVAL;
105914ee0d29SToomas Soome goto error;
106014ee0d29SToomas Soome }
106114ee0d29SToomas Soome
106214ee0d29SToomas Soome smap = (struct bios_smap *)md->md_data;
106386759c82SToomas Soome num = md->md_size / sizeof (struct bios_smap); /* number of entries */
106414ee0d29SToomas Soome
106514ee0d29SToomas Soome {
106614ee0d29SToomas Soome multiboot_tag_mmap_t *tag;
106714ee0d29SToomas Soome multiboot_mmap_entry_t *mmap_entry;
106814ee0d29SToomas Soome
106914ee0d29SToomas Soome tag = (multiboot_tag_mmap_t *)
107014ee0d29SToomas Soome mb_malloc(sizeof (*tag) +
107114ee0d29SToomas Soome num * sizeof (multiboot_mmap_entry_t));
107214ee0d29SToomas Soome
107314ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP;
107414ee0d29SToomas Soome tag->mb_size = sizeof (*tag) +
107514ee0d29SToomas Soome num * sizeof (multiboot_mmap_entry_t);
107614ee0d29SToomas Soome tag->mb_entry_size = sizeof (multiboot_mmap_entry_t);
107714ee0d29SToomas Soome tag->mb_entry_version = 0;
107814ee0d29SToomas Soome mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries;
107914ee0d29SToomas Soome
108014ee0d29SToomas Soome for (i = 0; i < num; i++) {
108114ee0d29SToomas Soome mmap_entry[i].mmap_addr = smap[i].base;
108214ee0d29SToomas Soome mmap_entry[i].mmap_len = smap[i].length;
108314ee0d29SToomas Soome mmap_entry[i].mmap_type = smap[i].type;
108414ee0d29SToomas Soome mmap_entry[i].mmap_reserved = 0;
108514ee0d29SToomas Soome }
108614ee0d29SToomas Soome }
108714ee0d29SToomas Soome
1088f9feecc1SToomas Soome if (bootp_response != NULL) {
108914ee0d29SToomas Soome multiboot_tag_network_t *tag;
109014ee0d29SToomas Soome tag = (multiboot_tag_network_t *)
109186759c82SToomas Soome mb_malloc(sizeof (*tag) + bootp_response_size);
109214ee0d29SToomas Soome
109314ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK;
109486759c82SToomas Soome tag->mb_size = sizeof (*tag) + bootp_response_size;
1095859472daSToomas Soome memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size);
109614ee0d29SToomas Soome }
109714ee0d29SToomas Soome
109886759c82SToomas Soome #if !defined(EFI)
109986759c82SToomas Soome multiboot_tag_vbe_t *tag;
110086759c82SToomas Soome extern multiboot_tag_vbe_t vbestate;
110186759c82SToomas Soome
110286759c82SToomas Soome if (VBE_VALID_MODE(vbestate.vbe_mode)) {
110386759c82SToomas Soome tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof (*tag));
110486759c82SToomas Soome memcpy(tag, &vbestate, sizeof (*tag));
110586759c82SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_VBE;
110686759c82SToomas Soome tag->mb_size = sizeof (*tag);
11079890ff83SToomas Soome }
11089890ff83SToomas Soome #endif
11099890ff83SToomas Soome
111014ee0d29SToomas Soome if (rsdp != NULL) {
111114ee0d29SToomas Soome multiboot_tag_new_acpi_t *ntag;
111214ee0d29SToomas Soome multiboot_tag_old_acpi_t *otag;
1113d9e07fb5SToomas Soome uint32_t tsize;
111414ee0d29SToomas Soome
111514ee0d29SToomas Soome if (rsdp->Revision == 0) {
1116d9e07fb5SToomas Soome tsize = sizeof (*otag) + sizeof (ACPI_RSDP_COMMON);
1117d9e07fb5SToomas Soome otag = (multiboot_tag_old_acpi_t *)mb_malloc(tsize);
111814ee0d29SToomas Soome otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
1119d9e07fb5SToomas Soome otag->mb_size = tsize;
112014ee0d29SToomas Soome memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON));
112114ee0d29SToomas Soome } else {
1122d9e07fb5SToomas Soome tsize = sizeof (*ntag) + rsdp->Length;
1123d9e07fb5SToomas Soome ntag = (multiboot_tag_new_acpi_t *)mb_malloc(tsize);
112414ee0d29SToomas Soome ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
1125d9e07fb5SToomas Soome ntag->mb_size = tsize;
112614ee0d29SToomas Soome memcpy(ntag->mb_rsdp, rsdp, rsdp->Length);
112714ee0d29SToomas Soome }
112814ee0d29SToomas Soome }
112914ee0d29SToomas Soome
113086759c82SToomas Soome #if defined(EFI)
113183b4671eSToomas Soome #ifdef __LP64__
1132f9feecc1SToomas Soome {
1133f9feecc1SToomas Soome multiboot_tag_efi64_t *tag;
1134f9feecc1SToomas Soome tag = (multiboot_tag_efi64_t *)
1135f9feecc1SToomas Soome mb_malloc(sizeof (*tag));
1136f9feecc1SToomas Soome
1137f9feecc1SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_EFI64;
1138f9feecc1SToomas Soome tag->mb_size = sizeof (*tag);
1139f9feecc1SToomas Soome tag->mb_pointer = (uint64_t)(uintptr_t)ST;
1140f9feecc1SToomas Soome }
114183b4671eSToomas Soome #else
114283b4671eSToomas Soome {
114383b4671eSToomas Soome multiboot_tag_efi32_t *tag;
114483b4671eSToomas Soome tag = (multiboot_tag_efi32_t *)
114583b4671eSToomas Soome mb_malloc(sizeof (*tag));
114683b4671eSToomas Soome
114783b4671eSToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_EFI32;
114883b4671eSToomas Soome tag->mb_size = sizeof (*tag);
114983b4671eSToomas Soome tag->mb_pointer = (uint32_t)ST;
115083b4671eSToomas Soome }
115183b4671eSToomas Soome #endif /* __LP64__ */
11529890ff83SToomas Soome #endif /* EFI */
1153f9feecc1SToomas Soome
1154f9feecc1SToomas Soome if (have_framebuffer == true) {
1155f9feecc1SToomas Soome multiboot_tag_framebuffer_t *tag;
11569890ff83SToomas Soome extern multiboot_tag_framebuffer_t gfx_fb;
115786759c82SToomas Soome #if defined(EFI)
11589890ff83SToomas Soome
115986759c82SToomas Soome tag = (multiboot_tag_framebuffer_t *)mb_malloc(sizeof (*tag));
11609890ff83SToomas Soome memcpy(tag, &gfx_fb, sizeof (*tag));
11619890ff83SToomas Soome tag->framebuffer_common.mb_type =
11629890ff83SToomas Soome MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
11639890ff83SToomas Soome tag->framebuffer_common.mb_size = sizeof (*tag);
11649890ff83SToomas Soome #else
11659890ff83SToomas Soome extern multiboot_color_t *cmap;
11669890ff83SToomas Soome uint32_t size;
11679890ff83SToomas Soome
11689890ff83SToomas Soome if (gfx_fb.framebuffer_common.framebuffer_type ==
11699890ff83SToomas Soome MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
11709890ff83SToomas Soome uint16_t nc;
11719890ff83SToomas Soome nc = gfx_fb.u.fb1.framebuffer_palette_num_colors;
11729890ff83SToomas Soome size = sizeof (struct multiboot_tag_framebuffer_common)
11739890ff83SToomas Soome + sizeof (nc)
11749890ff83SToomas Soome + nc * sizeof (multiboot_color_t);
11759890ff83SToomas Soome } else {
11769890ff83SToomas Soome size = sizeof (gfx_fb);
11779890ff83SToomas Soome }
11789890ff83SToomas Soome
117986759c82SToomas Soome tag = (multiboot_tag_framebuffer_t *)mb_malloc(size);
11809890ff83SToomas Soome memcpy(tag, &gfx_fb, sizeof (*tag));
11819890ff83SToomas Soome
11829890ff83SToomas Soome tag->framebuffer_common.mb_type =
11839890ff83SToomas Soome MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
11849890ff83SToomas Soome tag->framebuffer_common.mb_size = size;
11859890ff83SToomas Soome
11869890ff83SToomas Soome if (gfx_fb.framebuffer_common.framebuffer_type ==
11879890ff83SToomas Soome MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
118891061836SToomas Soome gfx_fb.u.fb1.framebuffer_palette_num_colors = CMAP_SIZE;
118991061836SToomas Soome
11909890ff83SToomas Soome memcpy(tag->u.fb1.framebuffer_palette, cmap,
119191061836SToomas Soome sizeof (multiboot_color_t) * CMAP_SIZE);
1192f9feecc1SToomas Soome }
11939890ff83SToomas Soome #endif /* EFI */
1194f9feecc1SToomas Soome }
1195f9feecc1SToomas Soome
119686759c82SToomas Soome #if defined(EFI)
1197f9feecc1SToomas Soome /* Leave EFI memmap last as we will also switch off the BS. */
1198f9feecc1SToomas Soome {
1199f9feecc1SToomas Soome multiboot_tag_efi_mmap_t *tag;
1200af8443c4SToomas Soome UINTN key;
1201f9feecc1SToomas Soome EFI_STATUS status;
1202f9feecc1SToomas Soome
1203f9feecc1SToomas Soome tag = (multiboot_tag_efi_mmap_t *)
1204f9feecc1SToomas Soome mb_malloc(sizeof (*tag));
1205f9feecc1SToomas Soome
1206af8443c4SToomas Soome map_size = 0;
1207af8443c4SToomas Soome status = BS->GetMemoryMap(&map_size,
1208f9feecc1SToomas Soome (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1209f9feecc1SToomas Soome &desc_size, &tag->mb_descr_vers);
1210f9feecc1SToomas Soome if (status != EFI_BUFFER_TOO_SMALL) {
1211f9feecc1SToomas Soome error = EINVAL;
1212f9feecc1SToomas Soome goto error;
1213f9feecc1SToomas Soome }
121415ab2c88SToomas Soome map_size = roundup2(map_size, EFI_PAGE_SIZE);
121515ab2c88SToomas Soome
121615ab2c88SToomas Soome i = 2; /* Attempts to ExitBootServices() */
121715ab2c88SToomas Soome while (map_size <= efi_map_size && i > 0) {
121815ab2c88SToomas Soome status = BS->GetMemoryMap(&map_size,
121915ab2c88SToomas Soome (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
122015ab2c88SToomas Soome &desc_size, &tag->mb_descr_vers);
122115ab2c88SToomas Soome if (status == EFI_BUFFER_TOO_SMALL) {
122215ab2c88SToomas Soome /* Still too small? */
122315ab2c88SToomas Soome map_size += EFI_PAGE_SIZE;
122415ab2c88SToomas Soome continue;
122515ab2c88SToomas Soome }
122615ab2c88SToomas Soome if (EFI_ERROR(status)) {
122715ab2c88SToomas Soome error = EINVAL;
122815ab2c88SToomas Soome goto error;
122915ab2c88SToomas Soome }
123015ab2c88SToomas Soome
123115ab2c88SToomas Soome if (keep_bs != 0)
123215ab2c88SToomas Soome break;
123315ab2c88SToomas Soome
123415ab2c88SToomas Soome status = BS->ExitBootServices(IH, key);
1235190f051bSToomas Soome if (status == EFI_SUCCESS) {
1236190f051bSToomas Soome has_boot_services = false;
123715ab2c88SToomas Soome break;
1238190f051bSToomas Soome }
123915ab2c88SToomas Soome i--;
124015ab2c88SToomas Soome }
124115ab2c88SToomas Soome if (status != EFI_SUCCESS) {
1242f9feecc1SToomas Soome error = EINVAL;
1243f9feecc1SToomas Soome goto error;
1244f9feecc1SToomas Soome }
124515ab2c88SToomas Soome
1246f9feecc1SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
1247af8443c4SToomas Soome tag->mb_size = sizeof (*tag) + map_size;
124886759c82SToomas Soome tag->mb_descr_size = (uint32_t)desc_size;
1249f9feecc1SToomas Soome
1250287d0250SJohn Levon map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
1251f9feecc1SToomas Soome
1252af8443c4SToomas Soome last_addr += map_size;
1253f9feecc1SToomas Soome last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
1254f9feecc1SToomas Soome }
12559890ff83SToomas Soome #endif /* EFI */
1256f9feecc1SToomas Soome
125714ee0d29SToomas Soome /*
125814ee0d29SToomas Soome * MB tag list end marker.
125914ee0d29SToomas Soome */
126014ee0d29SToomas Soome {
126114ee0d29SToomas Soome multiboot_tag_t *tag = (multiboot_tag_t *)
126286759c82SToomas Soome mb_malloc(sizeof (*tag));
126314ee0d29SToomas Soome tag->mb_type = MULTIBOOT_TAG_TYPE_END;
126486759c82SToomas Soome tag->mb_size = sizeof (*tag);
126514ee0d29SToomas Soome }
126614ee0d29SToomas Soome
126714ee0d29SToomas Soome mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
126814ee0d29SToomas Soome mbi->mbi_reserved = 0;
126914ee0d29SToomas Soome
127086759c82SToomas Soome #if defined(EFI)
127186759c82SToomas Soome /*
127286759c82SToomas Soome * At this point we have load_addr pointing to kernel load
1273f9feecc1SToomas Soome * address, module list in MBI having physical addresses,
1274f9feecc1SToomas Soome * module list in fp having logical addresses and tmp pointing to
1275f9feecc1SToomas Soome * physical address for MBI.
1276f9feecc1SToomas Soome * Now we must move all pieces to place and start the kernel.
1277f9feecc1SToomas Soome */
1278f9feecc1SToomas Soome head = &relocator->rel_chunk_head;
1279f9feecc1SToomas Soome STAILQ_INIT(head);
1280f9feecc1SToomas Soome
1281f9feecc1SToomas Soome i = 0;
1282f9feecc1SToomas Soome chunk = &relocator->rel_chunklist[i++];
1283f9feecc1SToomas Soome chunk->chunk_vaddr = fp->f_addr;
1284f9feecc1SToomas Soome chunk->chunk_paddr = load_addr;
1285f9feecc1SToomas Soome chunk->chunk_size = fp->f_size;
1286f9feecc1SToomas Soome
1287f9feecc1SToomas Soome STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1288f9feecc1SToomas Soome
1289af8443c4SToomas Soome mp = module;
1290f9feecc1SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
1291f9feecc1SToomas Soome chunk = &relocator->rel_chunklist[i++];
1292f9feecc1SToomas Soome chunk->chunk_vaddr = mfp->f_addr;
1293af8443c4SToomas Soome
1294af8443c4SToomas Soome /*
1295af8443c4SToomas Soome * fix the mb_mod_start and mb_mod_end.
1296af8443c4SToomas Soome */
1297af8443c4SToomas Soome mp->mb_mod_start = efi_physaddr(module, tmp, map,
12985388916eSToomas Soome map_size / desc_size, desc_size, mfp->f_addr,
12995388916eSToomas Soome mp->mb_mod_end);
1300af8443c4SToomas Soome if (mp->mb_mod_start == 0)
130196cf0467SToomas Soome panic("Could not find memory for module");
1302af8443c4SToomas Soome
1303af8443c4SToomas Soome mp->mb_mod_end += mp->mb_mod_start;
1304af8443c4SToomas Soome chunk->chunk_paddr = mp->mb_mod_start;
1305f9feecc1SToomas Soome chunk->chunk_size = mfp->f_size;
1306f9feecc1SToomas Soome STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1307f9feecc1SToomas Soome
1308af8443c4SToomas Soome mp = (multiboot_tag_module_t *)
1309af8443c4SToomas Soome roundup2((uintptr_t)mp + mp->mb_size,
1310f9feecc1SToomas Soome MULTIBOOT_TAG_ALIGN);
1311f9feecc1SToomas Soome }
1312f9feecc1SToomas Soome chunk = &relocator->rel_chunklist[i++];
131383b4671eSToomas Soome chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)(uintptr_t)mbi;
1314af8443c4SToomas Soome chunk->chunk_paddr = efi_physaddr(module, tmp, map,
13155388916eSToomas Soome map_size / desc_size, desc_size, (uintptr_t)mbi,
13165388916eSToomas Soome mbi->mbi_total_size);
1317f9feecc1SToomas Soome chunk->chunk_size = mbi->mbi_total_size;
1318f9feecc1SToomas Soome STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1319f9feecc1SToomas Soome
1320f9feecc1SToomas Soome trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE;
1321f9feecc1SToomas Soome memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE);
1322f9feecc1SToomas Soome
1323f9feecc1SToomas Soome relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE;
1324f9feecc1SToomas Soome memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE);
1325f9feecc1SToomas Soome
1326f9feecc1SToomas Soome relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE;
1327f9feecc1SToomas Soome memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE);
1328f9feecc1SToomas Soome relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8;
1329f9feecc1SToomas Soome
1330f9feecc1SToomas Soome trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr);
1331f9feecc1SToomas Soome #else
133214ee0d29SToomas Soome dev_cleanup();
133314ee0d29SToomas Soome __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
133414ee0d29SToomas Soome (void *)entry_addr, (void *)VTOP(mbi));
13359890ff83SToomas Soome #endif /* EFI */
133614ee0d29SToomas Soome panic("exec returned");
133714ee0d29SToomas Soome
133814ee0d29SToomas Soome error:
1339287d0250SJohn Levon free(cmdline);
1340287d0250SJohn Levon
134186759c82SToomas Soome #if defined(EFI)
1342287d0250SJohn Levon free(relocator);
1343287d0250SJohn Levon
1344f9feecc1SToomas Soome if (mbi != NULL)
134583b4671eSToomas Soome efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
1346f9feecc1SToomas Soome #endif
1347287d0250SJohn Levon
134814ee0d29SToomas Soome return (error);
134914ee0d29SToomas Soome }
1350