summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2016-02-16 11:28:33 +0200
committerJoshua M. Clulow <josh@sysmgr.org>2017-04-21 20:09:34 -0700
commit1738dd6ec94e36a9828d13a6e52ac7fb68cb52ed (patch)
tree7f5a6cabbb67f1e367cc65717052aa15f2dfa411 /usr/src
parent660946868929e02041af7b5b1c3e14f547c53f11 (diff)
downloadillumos-gate-1738dd6ec94e36a9828d13a6e52ac7fb68cb52ed.tar.gz
7461 illumos should support multiboot2 protocol
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/tools/mbh_patch/Makefile1
-rw-r--r--usr/src/tools/mbh_patch/mbh_patch.c121
-rw-r--r--usr/src/uts/common/sys/multiboot2.h418
-rw-r--r--usr/src/uts/common/sys/multiboot2_impl.h53
-rw-r--r--usr/src/uts/i86pc/Makefile.files1
-rw-r--r--usr/src/uts/i86pc/Makefile.rules7
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_grub.s102
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_multiboot2.c352
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_startkern.c756
-rw-r--r--usr/src/uts/i86pc/os/ddi_impl.c3
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c149
-rw-r--r--usr/src/uts/i86pc/sys/fastboot_msg.h3
-rw-r--r--usr/src/uts/i86xpv/Makefile.files1
-rw-r--r--usr/src/uts/intel/io/acpica/osl.c26
-rw-r--r--usr/src/uts/intel/sys/bootinfo.h4
15 files changed, 1815 insertions, 182 deletions
diff --git a/usr/src/tools/mbh_patch/Makefile b/usr/src/tools/mbh_patch/Makefile
index 68d2559864..95e8442340 100644
--- a/usr/src/tools/mbh_patch/Makefile
+++ b/usr/src/tools/mbh_patch/Makefile
@@ -23,7 +23,6 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
include ../Makefile.tools
diff --git a/usr/src/tools/mbh_patch/mbh_patch.c b/usr/src/tools/mbh_patch/mbh_patch.c
index 8a5fa4cd31..204009ab4d 100644
--- a/usr/src/tools/mbh_patch/mbh_patch.c
+++ b/usr/src/tools/mbh_patch/mbh_patch.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
@@ -37,7 +35,9 @@
#include <sys/elf_notes.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include "sys/multiboot.h"
+#include "sys/multiboot2.h"
static char *pname;
static char *fname;
@@ -46,7 +46,57 @@ static char *image; /* pointer to the ELF file in memory */
#define ELFSEEK(offset) ((void *)(image + offset))
/*
- * patch the load address / entry address
+ * Find MB2 header tags for entry and patch it.
+ * The first tag is right after header.
+ */
+static int
+patch64_mb2(multiboot2_header_t *mbh2, int file_offset,
+ Elf64_Addr ptload_start, Elf32_Off ptload_offset)
+{
+ multiboot_header_tag_t *tagp = mbh2->mb2_tags;
+ multiboot_header_tag_address_t *mbaddr = NULL;
+ multiboot_header_tag_entry_address_t *mbentry = NULL;
+
+ /*
+ * Loop until we get end TAG or we have both tags.
+ */
+ while (tagp->mbh_type != MULTIBOOT_HEADER_TAG_END &&
+ (mbaddr == NULL || mbentry == NULL)) {
+ switch (tagp->mbh_type) {
+ case MULTIBOOT_HEADER_TAG_ADDRESS:
+ mbaddr = (multiboot_header_tag_address_t *)tagp;
+ break;
+ case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
+ mbentry = (multiboot_header_tag_entry_address_t *)tagp;
+ break;
+ }
+ tagp = (multiboot_header_tag_t *)
+ ((uintptr_t)tagp +
+ P2ROUNDUP(tagp->mbh_size, MULTIBOOT_TAG_ALIGN));
+ }
+
+ if (mbaddr == NULL || mbentry == NULL) {
+ (void) fprintf(stderr, "Missing multiboot2 %s tag\n",
+ (mbaddr == NULL)? "address" : "entry");
+ return (1);
+ }
+
+ /* Patch it. */
+ mbaddr->mbh_load_addr = ptload_start - ptload_offset;
+ mbaddr->mbh_header_addr = mbaddr->mbh_load_addr + file_offset;
+ mbentry->mbh_entry_addr = ptload_start;
+
+#ifdef VERBOSE
+ (void) printf(" ELF64 MB2 header patched\n");
+ (void) printf("\tload_addr now: 0x%x\n", mbaddr->mbh_load_addr);
+ (void) printf("\theader_addr now: 0x%x\n", mbaddr->mbh_header_addr);
+ (void) printf("\tentry_addr now: 0x%x\n", mbentry->mbh_entry_addr);
+#endif
+ return (0);
+}
+
+/*
+ * Patch the load address / entry address for MB1 and MB2 if present.
* Find the physical load address of the 1st PT_LOAD segment.
* Find the amount that e_entry exceeds that amount.
* Now go back and subtract the excess from the p_paddr of the LOAD segment.
@@ -56,8 +106,9 @@ patch64(Elf64_Ehdr *eh)
{
Elf64_Phdr *phdr;
caddr_t phdrs = NULL;
- int ndx, mem;
+ int ndx, mem, mem2;
multiboot_header_t *mbh;
+ multiboot2_header_t *mbh2;
/*
* Verify some ELF basics - this must be an executable with program
@@ -84,7 +135,7 @@ patch64(Elf64_Ehdr *eh)
}
/*
- * Look for multiboot header. It must be 32-bit aligned and
+ * Look for multiboot1 header. It must be 32-bit aligned and
* completely contained in the 1st 8K of the file.
*/
for (mem = 0; mem < 8192 - sizeof (multiboot_header_t); mem += 4) {
@@ -100,6 +151,30 @@ patch64(Elf64_Ehdr *eh)
}
/*
+ * Look for multiboot2 header. It must be 64-bit aligned and
+ * completely contained in the 1st 32K of the file.
+ * We do not require it to be present.
+ */
+ ndx = 0;
+ for (mem2 = 0;
+ mem2 <= MULTIBOOT_SEARCH - sizeof (multiboot2_header_t);
+ mem2 += MULTIBOOT_HEADER_ALIGN) {
+ mbh2 = ELFSEEK(mem2);
+ ndx = mbh2->mb2_header_length;
+ if (mbh2->mb2_magic == MULTIBOOT2_HEADER_MAGIC)
+ break;
+ ndx = 0;
+ }
+
+ if (ndx == 0 || mem2 + ndx > MULTIBOOT_SEARCH) {
+#ifdef VERBOSE
+ (void) fprintf(stderr, "%s: %s: Didn't find multiboot2 "
+ "header\n", pname, fname);
+#endif
+ mbh2 = NULL;
+ }
+
+ /*
* Find the 1:1 mapped PT_LOAD section
*/
for (ndx = 0; ndx < eh->e_phnum; ndx++) {
@@ -135,6 +210,16 @@ patch64(Elf64_Ehdr *eh)
return (1);
}
+ if (mbh2 != NULL && ((mem2 < phdr->p_offset) ||
+ (mem2 >= (phdr->p_offset + phdr->p_filesz)))) {
+#ifdef VERBOSE
+ (void) fprintf(stderr, "%s: %s: multiboot2 header not"
+ " in 1st PT_LOAD\n", pname, fname);
+#endif
+ mem2 = 0;
+ mbh2 = NULL;
+ }
+
/*
* Patch the multiboot header fields to get entire file loaded.
* Grub uses the MB header for 64 bit loading.
@@ -148,6 +233,9 @@ patch64(Elf64_Ehdr *eh)
(void) printf("\tentry_addr now: 0x%x\n", mbh->entry_addr);
(void) printf("\theader_addr now: 0x%x\n", mbh->header_addr);
#endif
+ if (mbh2 != NULL)
+ return (patch64_mb2(mbh2, mem2, phdr->p_paddr,
+ phdr->p_offset));
return (0);
}
@@ -162,9 +250,10 @@ main(int argc, char **argv)
int fd;
uchar_t *ident;
void *hdr = NULL;
+ struct stat sb;
/*
- * we expect one argument -- the elf file
+ * We expect one argument -- the elf file.
*/
if (argc != 2) {
(void) fprintf(stderr, "usage: %s <unix-elf-file>\n", argv[0]);
@@ -184,11 +273,25 @@ main(int argc, char **argv)
return (1);
}
+ if (fstat(fd, &sb) != 0) {
+ (void) fprintf(stderr, "%s: fstat failed: %s\n",
+ pname, strerror(errno));
+ return (1);
+ }
+
+ /* Make sure we have at least MULTIBOOT_SEARCH bytes. */
+ if (sb.st_size < MULTIBOOT_SEARCH) {
+ (void) fprintf(stderr, "%s: %s is too small for a kernel\n",
+ pname, fname);
+ return (1);
+ }
+
/*
- * mmap just the 1st 8K -- since that's where the GRUB
- * multiboot header must be located.
+ * mmap the 1st 32K -- MB1 header is within first 8k and MB2 header
+ * is within 32k.
*/
- image = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ image = mmap(NULL, MULTIBOOT_SEARCH, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
if (image == MAP_FAILED) {
(void) fprintf(stderr, "%s: mmap() of %s failed: %s\n",
pname, fname, strerror(errno));
diff --git a/usr/src/uts/common/sys/multiboot2.h b/usr/src/uts/common/sys/multiboot2.h
new file mode 100644
index 0000000000..556b0217a3
--- /dev/null
+++ b/usr/src/uts/common/sys/multiboot2.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
+ * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ */
+
+/*
+ * This header contains definitions for Multiboot 2 boot protocol, based on
+ * the reference implementation by grub 2.
+ *
+ * At the time this was written (Jan 2017), the Multiboot 2 documentation is in
+ * process of being rewritten and the information in the specification is not
+ * entirely correct. Instead, you must rely on grub 2 source code.
+ *
+ * This header provides essential support for the Multiboot 2 specification
+ * for illumos and makes it possible to pass the needed structures from the
+ * boot loader to the kernel.
+ */
+
+#ifndef _SYS_MULTIBOOT2_H
+#define _SYS_MULTIBOOT2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* How many bytes from the start of the file we search for the header. */
+#define MULTIBOOT_SEARCH 32768
+#define MULTIBOOT_HEADER_ALIGN 8
+
+/* The magic field should contain this. */
+#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
+
+/* This should be in %eax. */
+#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
+
+/* Alignment of multiboot modules. */
+#if defined(__i386) || defined(__amd64)
+#define MULTIBOOT_MOD_ALIGN 0x00001000
+#else
+#error No architecture defined
+#endif
+
+/* Alignment of the multiboot info structure. */
+#define MULTIBOOT_INFO_ALIGN 0x00000008
+
+/* Flags set in the 'flags' member of the multiboot header. */
+
+#define MULTIBOOT_TAG_ALIGN 8
+#define MULTIBOOT_TAG_TYPE_END 0
+#define MULTIBOOT_TAG_TYPE_CMDLINE 1
+#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
+#define MULTIBOOT_TAG_TYPE_MODULE 3
+#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
+#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
+#define MULTIBOOT_TAG_TYPE_MMAP 6
+#define MULTIBOOT_TAG_TYPE_VBE 7
+#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
+#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
+#define MULTIBOOT_TAG_TYPE_APM 10
+#define MULTIBOOT_TAG_TYPE_EFI32 11
+#define MULTIBOOT_TAG_TYPE_EFI64 12
+#define MULTIBOOT_TAG_TYPE_SMBIOS 13
+#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
+#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
+#define MULTIBOOT_TAG_TYPE_NETWORK 16
+#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
+#define MULTIBOOT_TAG_TYPE_EFI_BS 18
+#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
+#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
+#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
+
+#define MULTIBOOT_HEADER_TAG_END 0
+#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
+#define MULTIBOOT_HEADER_TAG_ADDRESS 2
+#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
+#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
+#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
+#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
+#define MULTIBOOT_HEADER_TAG_EFI_BS 7
+#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
+#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
+#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
+
+#define MULTIBOOT_ARCHITECTURE_I386 0
+#define MULTIBOOT_ARCHITECTURE_MIPS32 4
+#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
+
+/* Hints for relocatable kernel load preference */
+#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
+#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
+#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
+
+/* Values for console_flags field in tag multiboot_header_tag_console_flags. */
+#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
+#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
+
+#ifndef _ASM
+
+#include <sys/stdint.h>
+
+#pragma pack(1)
+
+typedef struct multiboot_header_tag {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+} multiboot_header_tag_t;
+
+typedef struct multiboot2_header {
+ /* Must be MULTIBOOT2_MAGIC - see above. */
+ uint32_t mb2_magic;
+
+ /* ISA */
+ uint32_t mb2_architecture;
+
+ /* Total header length. */
+ uint32_t mb2_header_length;
+
+ /* The above fields plus this one must equal 0 mod 2^32. */
+ uint32_t mb2_checksum;
+ multiboot_header_tag_t mb2_tags[];
+} multiboot2_header_t;
+
+typedef struct multiboot_header_tag_information_request {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_requests[];
+} multiboot_header_tag_information_request_t;
+
+typedef struct multiboot_header_tag_address {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_header_addr;
+ uint32_t mbh_load_addr;
+ uint32_t mbh_load_end_addr;
+ uint32_t mbh_bss_end_addr;
+} multiboot_header_tag_address_t;
+
+typedef struct multiboot_header_tag_entry_address {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_entry_addr;
+} multiboot_header_tag_entry_address_t;
+
+typedef struct multiboot_header_tag_console_flags {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_console_flags;
+} multiboot_header_tag_console_flags_t;
+
+typedef struct multiboot_header_tag_framebuffer {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_width;
+ uint32_t mbh_height;
+ uint32_t mbh_depth;
+} multiboot_header_tag_framebuffer_t;
+
+typedef struct multiboot_header_tag_module_align {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+} multiboot_header_tag_module_align_t;
+
+typedef struct multiboot_header_tag_relocatable {
+ uint16_t mbh_type;
+ uint16_t mbh_flags;
+ uint32_t mbh_size;
+ uint32_t mbh_min_addr;
+ uint32_t mbh_max_addr;
+ uint32_t mbh_align;
+ uint32_t mbh_preference;
+} multiboot_header_tag_relocatable_t;
+
+typedef struct multiboot_color {
+ uint8_t mb_red;
+ uint8_t mb_green;
+ uint8_t mb_blue;
+} multiboot_color_t;
+
+typedef struct multiboot_mmap_entry {
+ uint64_t mmap_addr;
+ uint64_t mmap_len;
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
+#define MULTIBOOT_MEMORY_NVS 4
+#define MULTIBOOT_MEMORY_BADRAM 5
+ uint32_t mmap_type;
+ uint32_t mmap_reserved;
+} multiboot_mmap_entry_t;
+
+typedef struct multiboot_tag {
+ uint32_t mb_type;
+ uint32_t mb_size;
+} multiboot_tag_t;
+
+typedef struct multiboot2_info_header {
+ uint32_t mbi_total_size;
+ uint32_t mbi_reserved;
+ multiboot_tag_t mbi_tags[];
+} multiboot2_info_header_t;
+
+typedef struct multiboot_tag_string {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ char mb_string[];
+} multiboot_tag_string_t;
+
+typedef struct multiboot_tag_module {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_mod_start;
+ uint32_t mb_mod_end;
+ char mb_cmdline[];
+} multiboot_tag_module_t;
+
+typedef struct multiboot_tag_basic_meminfo {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_mem_lower;
+ uint32_t mb_mem_upper;
+} multiboot_tag_basic_meminfo_t;
+
+typedef struct multiboot_tag_bootdev {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_biosdev;
+ uint32_t mb_slice;
+ uint32_t mb_part;
+} multiboot_tag_bootdev_t;
+
+typedef struct multiboot_tag_mmap {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_entry_size;
+ uint32_t mb_entry_version;
+ uint8_t mb_entries[];
+} multiboot_tag_mmap_t;
+
+struct multiboot_vbe_info_block {
+ uint8_t vbe_external_specification[512];
+};
+
+struct multiboot_vbe_mode_info_block {
+ uint8_t vbe_external_specification[256];
+};
+
+typedef struct multiboot_tag_vbe {
+ uint32_t mb_type;
+ uint32_t mb_size;
+
+ uint16_t vbe_mode;
+ uint16_t vbe_interface_seg;
+ uint16_t vbe_interface_off;
+ uint16_t vbe_interface_len;
+
+ struct multiboot_vbe_info_block vbe_control_info;
+ struct multiboot_vbe_mode_info_block vbe_mode_info;
+} multiboot_tag_vbe_t;
+
+struct multiboot_tag_framebuffer_common {
+ uint32_t mb_type;
+ uint32_t mb_size;
+
+ uint64_t framebuffer_addr;
+ uint32_t framebuffer_pitch;
+ uint32_t framebuffer_width;
+ uint32_t framebuffer_height;
+ uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
+ uint8_t framebuffer_type;
+ uint16_t mb_reserved;
+};
+
+typedef struct multiboot_tag_framebuffer {
+ struct multiboot_tag_framebuffer_common framebuffer_common;
+
+ union {
+ struct {
+ uint16_t framebuffer_palette_num_colors;
+ multiboot_color_t framebuffer_palette[];
+ } fb1;
+ struct {
+ uint8_t framebuffer_red_field_position;
+ uint8_t framebuffer_red_mask_size;
+ uint8_t framebuffer_green_field_position;
+ uint8_t framebuffer_green_mask_size;
+ uint8_t framebuffer_blue_field_position;
+ uint8_t framebuffer_blue_mask_size;
+ } fb2;
+ } u;
+} multiboot_tag_framebuffer_t;
+
+typedef struct multiboot_tag_elf_sections {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_num;
+ uint32_t mb_entsize;
+ uint32_t mb_shndx;
+ char mb_sections[];
+} multiboot_tag_elf_sections_t;
+
+typedef struct multiboot_tag_apm {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint16_t mb_version;
+ uint16_t mb_cseg;
+ uint32_t mb_offset;
+ uint16_t mb_cseg_16;
+ uint16_t mb_dseg;
+ uint16_t mb_flags;
+ uint16_t mb_cseg_len;
+ uint16_t mb_cseg_16_len;
+ uint16_t mb_dseg_len;
+} multiboot_tag_apm_t;
+
+typedef struct multiboot_tag_efi32 {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_pointer;
+} multiboot_tag_efi32_t;
+
+typedef struct multiboot_tag_efi64 {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint64_t mb_pointer;
+} multiboot_tag_efi64_t;
+
+typedef struct multiboot_tag_smbios {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint8_t mb_major;
+ uint8_t mb_minor;
+ uint8_t mb_reserved[6];
+ uint8_t mb_tables[];
+} multiboot_tag_smbios_t;
+
+typedef struct multiboot_tag_old_acpi {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint8_t mb_rsdp[];
+} multiboot_tag_old_acpi_t;
+
+typedef struct multiboot_tag_new_acpi {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint8_t mb_rsdp[];
+} multiboot_tag_new_acpi_t;
+
+typedef struct multiboot_tag_network {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint8_t mb_dhcpack[];
+} multiboot_tag_network_t;
+
+typedef struct multiboot_tag_efi_mmap {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_descr_size;
+ uint32_t mb_descr_vers;
+ uint8_t mb_efi_mmap[];
+} multiboot_tag_efi_mmap_t;
+
+typedef struct multiboot_tag_efi32_ih {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_pointer;
+} multiboot_tag_efi32_ih_t;
+
+typedef struct multiboot_tag_efi64_ih {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint64_t mb_pointer;
+} multiboot_tag_efi64_ih_t;
+
+typedef struct multiboot_tag_load_base_addr {
+ uint32_t mb_type;
+ uint32_t mb_size;
+ uint32_t mb_load_base_addr;
+} multiboot_tag_load_base_addr_t;
+
+#pragma pack()
+
+#endif /* !_ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SYS_MULTIBOOT2_H */
diff --git a/usr/src/uts/common/sys/multiboot2_impl.h b/usr/src/uts/common/sys/multiboot2_impl.h
new file mode 100644
index 0000000000..d90ed0e8ee
--- /dev/null
+++ b/usr/src/uts/common/sys/multiboot2_impl.h
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ */
+
+#ifndef _SYS_MULTIBOOT2_IMPL_H
+#define _SYS_MULTIBOOT2_IMPL_H
+
+/*
+ * Multiboot 2 protocol implementation for dboot.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/multiboot2.h>
+
+extern void *dboot_multiboot2_find_tag(multiboot2_info_header_t *, uint32_t);
+extern char *dboot_multiboot2_cmdline(multiboot2_info_header_t *);
+extern int dboot_multiboot2_modcount(multiboot2_info_header_t *);
+extern uint32_t dboot_multiboot2_modstart(multiboot2_info_header_t *, int);
+extern uint32_t dboot_multiboot2_modend(multiboot2_info_header_t *, int);
+extern char *dboot_multiboot2_modcmdline(multiboot2_info_header_t *, int);
+extern multiboot_tag_mmap_t *
+ dboot_multiboot2_get_mmap_tagp(multiboot2_info_header_t *);
+extern boolean_t dboot_multiboot2_basicmeminfo(multiboot2_info_header_t *,
+ uint32_t *, uint32_t *);
+extern uint64_t dboot_multiboot2_mmap_get_length(multiboot2_info_header_t *,
+ multiboot_tag_mmap_t *, int);
+extern uint64_t dboot_multiboot2_mmap_get_base(multiboot2_info_header_t *,
+ multiboot_tag_mmap_t *, int);
+extern uint32_t dboot_multiboot2_mmap_get_type(multiboot2_info_header_t *,
+ multiboot_tag_mmap_t *, int);
+extern int dboot_multiboot2_mmap_nentries(multiboot2_info_header_t *,
+ multiboot_tag_mmap_t *);
+extern paddr_t dboot_multiboot2_highest_addr(multiboot2_info_header_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MULTIBOOT2_IMPL_H */
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 7e782f3f61..f3f10e1b6c 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -139,6 +139,7 @@ BOOT_DRIVER_OBJS = \
boot_keyboard_table.o \
boot_vga.o \
boot_mmu.o \
+ dboot_multiboot2.o \
$(FONT_OBJS)
CORE_OBJS += $(BOOT_DRIVER_OBJS)
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index 2d55410f33..a3bf823c69 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -211,6 +211,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/xen/os/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/dboot/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
#
# dboot stuff is always 32 bit, linked to run with phys_addr == virt_addr
#
@@ -422,6 +426,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/os/cpupm/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/boot/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/dboot/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/vm/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/i86pc/dboot/dboot_grub.s b/usr/src/uts/i86pc/dboot/dboot_grub.s
index 92cacc4983..7409c12998 100644
--- a/usr/src/uts/i86pc/dboot/dboot_grub.s
+++ b/usr/src/uts/i86pc/dboot/dboot_grub.s
@@ -1,4 +1,3 @@
-
/*
* CDDL HEADER START
*
@@ -32,6 +31,7 @@ int silence_lint_warnings = 0;
#else /* __lint */
#include <sys/multiboot.h>
+#include <sys/multiboot2.h>
#include <sys/asm_linkage.h>
#include <sys/segments.h>
#include <sys/controlregs.h>
@@ -76,6 +76,103 @@ mb_header:
.long 0 /* height 0 == don't care */
.long 0 /* depth 0 == don't care */
+#if defined(_BOOT_TARGET_i386)
+ /*
+ * The MB2 header must be 8 byte aligned relative to the beginning of
+ * the in-memory ELF object. The 32-bit kernel ELF file has sections
+ * which are 4-byte aligned, and as .align family directives only do
+ * control the alignment inside the section, we need to construct the
+ * image manually, by inserting the padding where needed. The alignment
+ * setup here depends on the first PT_LOAD section of the ELF file, if
+ * this section offset will change, this code must be reviewed.
+ * Similarily, if we add extra tag types into the information request
+ * or add tags into the tag list.
+ */
+ .long 0 /* padding */
+#else
+ .balign MULTIBOOT_HEADER_ALIGN
+#endif
+mb2_header:
+ .long MULTIBOOT2_HEADER_MAGIC
+ .long MULTIBOOT_ARCHITECTURE_I386
+ .long mb2_header_end - mb2_header
+ .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (mb2_header_end - mb2_header))
+
+ /*
+ * Multiboot 2 tags follow. Note, the first tag immediately follows
+ * the header. Subsequent tags must be aligned by MULTIBOOT_TAG_ALIGN.
+ *
+ * MB information request tag.
+ */
+information_request_tag_start:
+ .word MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
+ .word 0
+ .long information_request_tag_end - information_request_tag_start
+ .long MULTIBOOT_TAG_TYPE_CMDLINE
+ .long MULTIBOOT_TAG_TYPE_MODULE
+ .long MULTIBOOT_TAG_TYPE_BOOTDEV
+ .long MULTIBOOT_TAG_TYPE_MMAP
+ .long MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
+information_request_tag_end:
+ .long 0 /* padding */
+
+#if defined (_BOOT_TARGET_amd64)
+ /*
+ * The following values are patched by mbh_patch for the 64-bit kernel,
+ * so we only provide this tag for the 64-bit kernel.
+ */
+ .balign MULTIBOOT_TAG_ALIGN
+address_tag_start:
+ .word MULTIBOOT_HEADER_TAG_ADDRESS
+ .word 0
+ .long address_tag_end - address_tag_start
+ .long mb2_header
+ .globl mb2_load_addr
+mb2_load_addr:
+ .long 0 /* load addr */
+ .long 0 /* load_end_addr */
+ .long 0 /* bss_end_addr */
+address_tag_end:
+ /*
+ * entry address tag
+ */
+ .balign MULTIBOOT_TAG_ALIGN
+entry_address_tag_start:
+ .word MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
+ .word 0
+ .long entry_address_tag_end - entry_address_tag_start
+ .long 0 /* entry addr */
+entry_address_tag_end:
+
+ .balign MULTIBOOT_TAG_ALIGN /* Alignment for the next tag */
+#endif
+ /*
+ * MB console flags tag
+ */
+console_tag_start:
+ .word MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS
+ .word 0
+ .long console_tag_end - console_tag_start
+ .long MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED
+console_tag_end:
+ .long 0 /* padding */
+
+ /*
+ * Tell the bootloader to load the modules page aligned to
+ * the specified alignment.
+ */
+ .word MULTIBOOT_HEADER_TAG_MODULE_ALIGN
+ .word 0
+ .long 8
+
+ /*
+ * Termination tag.
+ */
+ .word MULTIBOOT_HEADER_TAG_END
+ .word 0
+ .long 8
+mb2_header_end:
+
/*
* At entry we are in protected mode, 32 bit execution, paging and
* interrupts are disabled.
@@ -85,7 +182,8 @@ mb_header:
* segment registers all have segments with base 0, limit == 0xffffffff
*/
code_start:
- movl %ebx, mb_info
+ movl %eax, mb_magic
+ movl %ebx, mb_addr
movl $stack_space, %esp /* load my stack pointer */
addl $STACK_SIZE, %esp
diff --git a/usr/src/uts/i86pc/dboot/dboot_multiboot2.c b/usr/src/uts/i86pc/dboot/dboot_multiboot2.c
new file mode 100644
index 0000000000..4e01b0a222
--- /dev/null
+++ b/usr/src/uts/i86pc/dboot/dboot_multiboot2.c
@@ -0,0 +1,352 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ */
+
+/*
+ * dboot module utility functions for multiboot 2 tags processing.
+ */
+
+#include <sys/inttypes.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/multiboot2.h>
+#include <sys/multiboot2_impl.h>
+
+/*
+ * Remove offsetof definition when we have usable sys/stddef.h
+ */
+#if !defined(offsetof)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define offsetof(s, m) __builtin_offsetof(s, m)
+#else
+#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
+#endif
+#endif /* !offsetof */
+
+struct dboot_multiboot2_iterate_ctx;
+
+typedef boolean_t (*dboot_multiboot2_iterate_cb_t)
+ (int, multiboot_tag_t *, struct dboot_multiboot2_iterate_ctx *);
+
+struct dboot_multiboot2_iterate_ctx {
+ dboot_multiboot2_iterate_cb_t dboot_iter_callback;
+ int dboot_iter_index; /* item from set */
+ uint32_t dboot_iter_tag; /* tag to search */
+ multiboot_tag_t *dboot_iter_tagp; /* search result */
+};
+
+/*
+ * Multiboot2 tag list elements are aligned to MULTIBOOT_TAG_ALIGN.
+ * To get the next item from the list, we first add the tag's size
+ * to the start of the current tag. Next, we round up that address to the
+ * nearest MULTIBOOT_TAG_ALIGN address.
+ */
+
+static multiboot_tag_t *
+dboot_multiboot2_first_tag(multiboot2_info_header_t *mbi)
+{
+ return (&mbi->mbi_tags[0]);
+}
+
+static multiboot_tag_t *
+dboot_multiboot2_next_tag(multiboot_tag_t *tag)
+{
+ if (tag == NULL || tag->mb_type == MULTIBOOT_TAG_TYPE_END)
+ return (NULL);
+
+ return ((multiboot_tag_t *)P2ROUNDUP((uintptr_t)tag +
+ tag->mb_size, MULTIBOOT_TAG_ALIGN));
+}
+
+/*
+ * Walk the tag list until we hit the first instance of a given tag or
+ * the end of the list.
+ * MB2_NEXT_TAG() will return NULL on end of list.
+ */
+static void *
+dboot_multiboot2_find_tag_impl(multiboot_tag_t *tagp, uint32_t tag)
+{
+ while (tagp != NULL && tagp->mb_type != tag) {
+ tagp = dboot_multiboot2_next_tag(tagp);
+ }
+ return (tagp);
+}
+
+/*
+ * Walk the entire list to find the first instance of the given tag.
+ */
+void *
+dboot_multiboot2_find_tag(multiboot2_info_header_t *mbi, uint32_t tag)
+{
+ multiboot_tag_t *tagp = dboot_multiboot2_first_tag(mbi);
+
+ return (dboot_multiboot2_find_tag_impl(tagp, tag));
+}
+
+/*
+ * dboot_multiboot2_iterate()
+ *
+ * While most tags in tag list are unique, the modules are specified
+ * one module per tag and therefore we need an mechanism to process
+ * tags in set.
+ *
+ * Arguments:
+ * mbi: multiboot info header
+ * data: callback context.
+ *
+ * Return value:
+ * Processed item count.
+ * Callback returning B_TRUE will terminate the iteration.
+ */
+static int
+dboot_multiboot2_iterate(multiboot2_info_header_t *mbi,
+ struct dboot_multiboot2_iterate_ctx *ctx)
+{
+ dboot_multiboot2_iterate_cb_t callback = ctx->dboot_iter_callback;
+ multiboot_tag_t *tagp;
+ uint32_t tag = ctx->dboot_iter_tag;
+ int index = 0;
+
+ tagp = dboot_multiboot2_find_tag(mbi, tag);
+ while (tagp != NULL) {
+ if (callback != NULL) {
+ if (callback(index, tagp, ctx) == B_TRUE) {
+ return (index + 1);
+ }
+ }
+ tagp = dboot_multiboot2_next_tag(tagp);
+ tagp = dboot_multiboot2_find_tag_impl(tagp, tag);
+ index++;
+ }
+ return (index);
+}
+
+char *
+dboot_multiboot2_cmdline(multiboot2_info_header_t *mbi)
+{
+ multiboot_tag_string_t *tag;
+
+ tag = dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_CMDLINE);
+
+ if (tag != NULL)
+ return (&tag->mb_string[0]);
+ else
+ return (NULL);
+}
+
+/*
+ * Simple callback to index item in set.
+ * Terminates iteration if the indexed item is found.
+ */
+static boolean_t
+dboot_multiboot2_iterate_callback(int index, multiboot_tag_t *tagp,
+ struct dboot_multiboot2_iterate_ctx *ctx)
+{
+ if (index == ctx->dboot_iter_index) {
+ ctx->dboot_iter_tagp = tagp;
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+int
+dboot_multiboot2_modcount(multiboot2_info_header_t *mbi)
+{
+ struct dboot_multiboot2_iterate_ctx ctx = {
+ .dboot_iter_callback = NULL,
+ .dboot_iter_index = 0,
+ .dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
+ .dboot_iter_tagp = NULL
+ };
+
+ return (dboot_multiboot2_iterate(mbi, &ctx));
+}
+
+uint32_t
+dboot_multiboot2_modstart(multiboot2_info_header_t *mbi, int index)
+{
+ multiboot_tag_module_t *tagp;
+ struct dboot_multiboot2_iterate_ctx ctx = {
+ .dboot_iter_callback = dboot_multiboot2_iterate_callback,
+ .dboot_iter_index = index,
+ .dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
+ .dboot_iter_tagp = NULL
+ };
+
+ if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
+ tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
+
+ if (tagp != NULL)
+ return (tagp->mb_mod_start);
+ }
+ return (0);
+}
+
+uint32_t
+dboot_multiboot2_modend(multiboot2_info_header_t *mbi, int index)
+{
+ multiboot_tag_module_t *tagp;
+ struct dboot_multiboot2_iterate_ctx ctx = {
+ .dboot_iter_callback = dboot_multiboot2_iterate_callback,
+ .dboot_iter_index = index,
+ .dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
+ .dboot_iter_tagp = NULL
+ };
+
+ if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
+ tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
+
+ if (tagp != NULL)
+ return (tagp->mb_mod_end);
+ }
+ return (0);
+}
+
+char *
+dboot_multiboot2_modcmdline(multiboot2_info_header_t *mbi, int index)
+{
+ multiboot_tag_module_t *tagp;
+ struct dboot_multiboot2_iterate_ctx ctx = {
+ .dboot_iter_callback = dboot_multiboot2_iterate_callback,
+ .dboot_iter_index = index,
+ .dboot_iter_tag = MULTIBOOT_TAG_TYPE_MODULE,
+ .dboot_iter_tagp = NULL
+ };
+
+ if (dboot_multiboot2_iterate(mbi, &ctx) != 0) {
+ tagp = (multiboot_tag_module_t *)ctx.dboot_iter_tagp;
+
+ if (tagp != NULL)
+ return (&tagp->mb_cmdline[0]);
+ }
+ return (NULL);
+}
+
+multiboot_tag_mmap_t *
+dboot_multiboot2_get_mmap_tagp(multiboot2_info_header_t *mbi)
+{
+ return (dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_MMAP));
+}
+
+boolean_t
+dboot_multiboot2_basicmeminfo(multiboot2_info_header_t *mbi,
+ uint32_t *lower, uint32_t *upper)
+{
+ multiboot_tag_basic_meminfo_t *mip;
+
+ mip = dboot_multiboot2_find_tag(mbi, MULTIBOOT_TAG_TYPE_BASIC_MEMINFO);
+ if (mip != NULL) {
+ *lower = mip->mb_mem_lower;
+ *upper = mip->mb_mem_upper;
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Return the type of mmap entry referenced by index.
+ */
+uint32_t
+dboot_multiboot2_mmap_get_type(multiboot2_info_header_t *mbi,
+ multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
+{
+ multiboot_mmap_entry_t *mapentp;
+
+ if (mb2_mmap_tagp == NULL)
+ mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
+
+ if (mb2_mmap_tagp == NULL)
+ return (0);
+
+ if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
+ return (0);
+
+ mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
+ index * mb2_mmap_tagp->mb_entry_size);
+ return (mapentp->mmap_type);
+}
+
+/*
+ * Return the length of mmap entry referenced by index.
+ */
+uint64_t
+dboot_multiboot2_mmap_get_length(multiboot2_info_header_t *mbi,
+ multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
+{
+ multiboot_mmap_entry_t *mapentp;
+
+ if (mb2_mmap_tagp == NULL)
+ mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
+
+ if (mb2_mmap_tagp == NULL)
+ return (0);
+
+ if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
+ return (0);
+
+ mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
+ index * mb2_mmap_tagp->mb_entry_size);
+ return (mapentp->mmap_len);
+}
+
+/*
+ * Return the address from mmap entry referenced by index.
+ */
+uint64_t
+dboot_multiboot2_mmap_get_base(multiboot2_info_header_t *mbi,
+ multiboot_tag_mmap_t *mb2_mmap_tagp, int index)
+{
+ multiboot_mmap_entry_t *mapentp;
+
+ if (mb2_mmap_tagp == NULL)
+ mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
+
+ if (mb2_mmap_tagp == NULL)
+ return (0);
+
+ if (dboot_multiboot2_mmap_nentries(mbi, mb2_mmap_tagp) < index)
+ return (0);
+
+ mapentp = (multiboot_mmap_entry_t *)(mb2_mmap_tagp->mb_entries +
+ index * mb2_mmap_tagp->mb_entry_size);
+ return (mapentp->mmap_addr);
+}
+
+/*
+ * Count and return the number of mmap entries provided by the tag.
+ */
+int
+dboot_multiboot2_mmap_nentries(multiboot2_info_header_t *mbi,
+ multiboot_tag_mmap_t *mb2_mmap_tagp)
+{
+ if (mb2_mmap_tagp == NULL)
+ mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mbi);
+
+ if (mb2_mmap_tagp != NULL) {
+ return ((mb2_mmap_tagp->mb_size -
+ offsetof(multiboot_tag_mmap_t, mb_entries)) /
+ mb2_mmap_tagp->mb_entry_size);
+ }
+ return (0);
+}
+
+/*
+ * Return the highest address used by info header.
+ */
+paddr_t
+dboot_multiboot2_highest_addr(multiboot2_info_header_t *mbi)
+{
+ return ((paddr_t)(uintptr_t)mbi + mbi->mbi_total_size);
+}
diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c
index 7fc43e27bd..d7a9026bd5 100644
--- a/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c
@@ -33,6 +33,9 @@
#include <sys/systm.h>
#include <sys/mach_mmu.h>
#include <sys/multiboot.h>
+#include <sys/multiboot2.h>
+#include <sys/multiboot2_impl.h>
+#include <sys/sysmacros.h>
#include <sys/sha1.h>
#include <util/string.h>
#include <util/strtolctype.h>
@@ -46,6 +49,7 @@ pfn_t *mfn_to_pfn_mapping;
#else /* !__xpv */
extern multiboot_header_t mb_header;
+extern uint32_t mb2_load_addr;
extern int have_cpuid(void);
#endif /* !__xpv */
@@ -123,7 +127,15 @@ start_info_t *xen_info;
/*
* If on the metal, then we have a multiboot loader.
*/
+uint32_t mb_magic; /* magic from boot loader */
+uint32_t mb_addr; /* multiboot info package from loader */
+int multiboot_version;
multiboot_info_t *mb_info;
+multiboot2_info_header_t *mb2_info;
+multiboot_tag_mmap_t *mb2_mmap_tagp;
+int num_entries; /* mmap entry count */
+boolean_t num_entries_set; /* is mmap entry count set */
+uintptr_t load_addr;
#endif /* __xpv */
@@ -172,6 +184,30 @@ uint_t rsvdmemlists_used = 0;
struct boot_modules modules[MAX_BOOT_MODULES];
uint_t modules_used = 0;
+#ifdef __xpv
+/*
+ * Xen strips the size field out of the mb_memory_map_t, see struct e820entry
+ * definition in Xen source.
+ */
+typedef struct {
+ uint32_t base_addr_low;
+ uint32_t base_addr_high;
+ uint32_t length_low;
+ uint32_t length_high;
+ uint32_t type;
+} mmap_t;
+
+/*
+ * There is 512KB of scratch area after the boot stack page.
+ * We'll use that for everything except the kernel nucleus pages which are too
+ * big to fit there and are allocated last anyway.
+ */
+#define MAXMAPS 100
+static mmap_t map_buffer[MAXMAPS];
+#else
+typedef mb_memory_map_t mmap_t;
+#endif
+
/*
* Debugging macros
*/
@@ -607,29 +643,182 @@ exclude_from_pci(uint64_t start, uint64_t end)
}
/*
- * Xen strips the size field out of the mb_memory_map_t, see struct e820entry
- * definition in Xen source.
+ * During memory allocation, find the highest address not used yet.
*/
-#ifdef __xpv
-typedef struct {
- uint32_t base_addr_low;
- uint32_t base_addr_high;
- uint32_t length_low;
- uint32_t length_high;
- uint32_t type;
-} mmap_t;
+static void
+check_higher(paddr_t a)
+{
+ if (a < next_avail_addr)
+ return;
+ next_avail_addr = RNDUP(a + 1, MMU_PAGESIZE);
+ DBG(next_avail_addr);
+}
+
+static int
+dboot_loader_mmap_entries(void)
+{
+#if !defined(__xpv)
+ if (num_entries_set == B_TRUE)
+ return (num_entries);
+
+ switch (multiboot_version) {
+ case 1:
+ DBG(mb_info->flags);
+ if (mb_info->flags & 0x40) {
+ mb_memory_map_t *mmap;
+
+ DBG(mb_info->mmap_addr);
+ DBG(mb_info->mmap_length);
+ check_higher(mb_info->mmap_addr + mb_info->mmap_length);
+
+ for (mmap = (mb_memory_map_t *)mb_info->mmap_addr;
+ (uint32_t)mmap < mb_info->mmap_addr +
+ mb_info->mmap_length;
+ mmap = (mb_memory_map_t *)((uint32_t)mmap +
+ mmap->size + sizeof (mmap->size)))
+ ++num_entries;
+
+ num_entries_set = B_TRUE;
+ }
+ break;
+ case 2:
+ num_entries_set = B_TRUE;
+ num_entries = dboot_multiboot2_mmap_nentries(mb2_info,
+ mb2_mmap_tagp);
+ break;
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (num_entries);
#else
-typedef mb_memory_map_t mmap_t;
+ return (MAXMAPS);
+#endif
+}
+
+static uint32_t
+dboot_loader_mmap_get_type(int index)
+{
+#if !defined(__xpv)
+ mb_memory_map_t *mp, *mpend;
+ int i;
+
+ switch (multiboot_version) {
+ case 1:
+ mp = (mb_memory_map_t *)mb_info->mmap_addr;
+ mpend = (mb_memory_map_t *)
+ (mb_info->mmap_addr + mb_info->mmap_length);
+
+ for (i = 0; mp < mpend && i != index; i++)
+ mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
+ sizeof (mp->size));
+ if (mp >= mpend) {
+ dboot_panic("dboot_loader_mmap_get_type(): index "
+ "out of bounds: %d\n", index);
+ }
+ return (mp->type);
+
+ case 2:
+ return (dboot_multiboot2_mmap_get_type(mb2_info,
+ mb2_mmap_tagp, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+#else
+ return (map_buffer[index].type);
+#endif
+}
+
+static uint64_t
+dboot_loader_mmap_get_base(int index)
+{
+#if !defined(__xpv)
+ mb_memory_map_t *mp, *mpend;
+ int i;
+
+ switch (multiboot_version) {
+ case 1:
+ mp = (mb_memory_map_t *)mb_info->mmap_addr;
+ mpend = (mb_memory_map_t *)
+ (mb_info->mmap_addr + mb_info->mmap_length);
+
+ for (i = 0; mp < mpend && i != index; i++)
+ mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
+ sizeof (mp->size));
+ if (mp >= mpend) {
+ dboot_panic("dboot_loader_mmap_get_base(): index "
+ "out of bounds: %d\n", index);
+ }
+ return (((uint64_t)mp->base_addr_high << 32) +
+ (uint64_t)mp->base_addr_low);
+
+ case 2:
+ return (dboot_multiboot2_mmap_get_base(mb2_info,
+ mb2_mmap_tagp, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+#else
+ return (((uint64_t)map_buffer[index].base_addr_high << 32) +
+ (uint64_t)map_buffer[index].base_addr_low);
#endif
+}
+
+static uint64_t
+dboot_loader_mmap_get_length(int index)
+{
+#if !defined(__xpv)
+ mb_memory_map_t *mp, *mpend;
+ int i;
+
+ switch (multiboot_version) {
+ case 1:
+ mp = (mb_memory_map_t *)mb_info->mmap_addr;
+ mpend = (mb_memory_map_t *)
+ (mb_info->mmap_addr + mb_info->mmap_length);
+
+ for (i = 0; mp < mpend && i != index; i++)
+ mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
+ sizeof (mp->size));
+ if (mp >= mpend) {
+ dboot_panic("dboot_loader_mmap_get_length(): index "
+ "out of bounds: %d\n", index);
+ }
+ return (((uint64_t)mp->length_high << 32) +
+ (uint64_t)mp->length_low);
+
+ case 2:
+ return (dboot_multiboot2_mmap_get_length(mb2_info,
+ mb2_mmap_tagp, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+#else
+ return (((uint64_t)map_buffer[index].length_high << 32) +
+ (uint64_t)map_buffer[index].length_low);
+#endif
+}
static void
-build_pcimemlists(mmap_t *mem, int num)
+build_pcimemlists(void)
{
- mmap_t *mmap;
uint64_t page_offset = MMU_PAGEOFFSET; /* needs to be 64 bits */
uint64_t start;
uint64_t end;
- int i;
+ int i, num;
/*
* initialize
@@ -638,18 +827,18 @@ build_pcimemlists(mmap_t *mem, int num)
pcimemlists[0].size = pci_hi_limit - pci_lo_limit;
pcimemlists_used = 1;
+ num = dboot_loader_mmap_entries();
/*
* Fill in PCI memlists.
*/
- for (mmap = mem, i = 0; i < num; ++i, ++mmap) {
- start = ((uint64_t)mmap->base_addr_high << 32) +
- mmap->base_addr_low;
- end = start + ((uint64_t)mmap->length_high << 32) +
- mmap->length_low;
+ for (i = 0; i < num; ++i) {
+ start = dboot_loader_mmap_get_base(i);
+ end = start + dboot_loader_mmap_get_length(i);
if (prom_debug)
dboot_printf("\ttype: %d %" PRIx64 "..%"
- PRIx64 "\n", mmap->type, start, end);
+ PRIx64 "\n", dboot_loader_mmap_get_type(i),
+ start, end);
/*
* page align start and end
@@ -688,13 +877,7 @@ build_pcimemlists(mmap_t *mem, int num)
#if defined(__xpv)
/*
* Initialize memory allocator stuff from hypervisor-supplied start info.
- *
- * There is 512KB of scratch area after the boot stack page.
- * We'll use that for everything except the kernel nucleus pages which are too
- * big to fit there and are allocated last anyway.
*/
-#define MAXMAPS 100
-static mmap_t map_buffer[MAXMAPS];
static void
init_mem_alloc(void)
{
@@ -774,12 +957,122 @@ init_mem_alloc(void)
set_xen_guest_handle(map.buffer, map_buffer);
if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
dboot_panic("getting XENMEM_machine_memory_map failed");
- build_pcimemlists(map_buffer, map.nr_entries);
+ build_pcimemlists();
}
}
#else /* !__xpv */
+/* Stub in this version. */
+static void
+dboot_multiboot1_xboot_consinfo(void)
+{
+}
+
+/* Stub in this version. */
+static void
+dboot_multiboot2_xboot_consinfo(void)
+{
+}
+
+static int
+dboot_multiboot_modcount(void)
+{
+ switch (multiboot_version) {
+ case 1:
+ return (mb_info->mods_count);
+
+ case 2:
+ return (dboot_multiboot2_modcount(mb2_info));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+}
+
+static uint32_t
+dboot_multiboot_modstart(int index)
+{
+ switch (multiboot_version) {
+ case 1:
+ return (((mb_module_t *)mb_info->mods_addr)[index].mod_start);
+
+ case 2:
+ return (dboot_multiboot2_modstart(mb2_info, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+}
+
+static uint32_t
+dboot_multiboot_modend(int index)
+{
+ switch (multiboot_version) {
+ case 1:
+ return (((mb_module_t *)mb_info->mods_addr)[index].mod_end);
+
+ case 2:
+ return (dboot_multiboot2_modend(mb2_info, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+}
+
+static char *
+dboot_multiboot_modcmdline(int index)
+{
+ switch (multiboot_version) {
+ case 1:
+ return ((char *)((mb_module_t *)
+ mb_info->mods_addr)[index].mod_name);
+
+ case 2:
+ return (dboot_multiboot2_modcmdline(mb2_info, index));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (0);
+}
+
+static boolean_t
+dboot_multiboot_basicmeminfo(uint32_t *lower, uint32_t *upper)
+{
+ boolean_t rv = B_FALSE;
+
+ switch (multiboot_version) {
+ case 1:
+ if (mb_info->flags & 0x01) {
+ *lower = mb_info->mem_lower;
+ *upper = mb_info->mem_upper;
+ rv = B_TRUE;
+ }
+ break;
+
+ case 2:
+ return (dboot_multiboot2_basicmeminfo(mb2_info, lower, upper));
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+ return (rv);
+}
+
static uint8_t
dboot_a2h(char v)
{
@@ -899,21 +1192,23 @@ check_images(void)
* hashes which are checked prior to transferring control to the kernel.
*/
static void
-process_module(mb_module_t *mod)
+process_module(int midx)
{
- int midx = modules_used++;
+ uint32_t mod_start = dboot_multiboot_modstart(midx);
+ uint32_t mod_end = dboot_multiboot_modend(midx);
+ char *cmdline = dboot_multiboot_modcmdline(midx);
char *p, *q;
+ check_higher(mod_end);
if (prom_debug) {
dboot_printf("\tmodule #%d: '%s' at 0x%lx, end 0x%lx\n",
- midx, (char *)(mod->mod_name),
- (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
+ midx, cmdline, (ulong_t)mod_start, (ulong_t)mod_end);
}
- if (mod->mod_start > mod->mod_end) {
+ if (mod_start > mod_end) {
dboot_panic("module #%d: module start address 0x%lx greater "
"than end address 0x%lx", midx,
- (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
+ (ulong_t)mod_start, (ulong_t)mod_end);
}
/*
@@ -934,18 +1229,18 @@ process_module(mb_module_t *mod)
* correct number of bytes in each module, achieving exactly this.
*/
- modules[midx].bm_addr = mod->mod_start;
- modules[midx].bm_size = mod->mod_end - mod->mod_start;
- modules[midx].bm_name = mod->mod_name;
+ modules[midx].bm_addr = mod_start;
+ modules[midx].bm_size = mod_end - mod_start;
+ modules[midx].bm_name = (native_ptr_t)(uintptr_t)cmdline;
modules[midx].bm_hash = NULL;
modules[midx].bm_type = BMT_FILE;
- if (mod->mod_name == NULL) {
+ if (cmdline == NULL) {
modules[midx].bm_name = (native_ptr_t)(uintptr_t)noname;
return;
}
- p = (char *)(uintptr_t)mod->mod_name;
+ p = cmdline;
modules[midx].bm_name =
(native_ptr_t)(uintptr_t)strsep(&p, " \t\f\n\r");
@@ -1056,89 +1351,69 @@ assign_module_hashes(void)
}
/*
- * During memory allocation, find the highest address not used yet.
- */
-static void
-check_higher(paddr_t a)
-{
- if (a < next_avail_addr)
- return;
- next_avail_addr = RNDUP(a + 1, MMU_PAGESIZE);
- DBG(next_avail_addr);
-}
-
-/*
* Walk through the module information finding the last used address.
* The first available address will become the top level page table.
- *
- * We then build the phys_install memlist from the multiboot information.
*/
static void
-init_mem_alloc(void)
+dboot_process_modules(void)
{
- mb_memory_map_t *mmap;
- mb_module_t *mod;
- uint64_t start;
- uint64_t end;
- uint64_t page_offset = MMU_PAGEOFFSET; /* needs to be 64 bits */
+ int i, modcount;
extern char _end[];
- int i;
-
- DBG_MSG("Entered init_mem_alloc()\n");
- DBG((uintptr_t)mb_info);
- if (mb_info->mods_count > MAX_BOOT_MODULES) {
+ DBG_MSG("\nFinding Modules\n");
+ modcount = dboot_multiboot_modcount();
+ if (modcount > MAX_BOOT_MODULES) {
dboot_panic("Too many modules (%d) -- the maximum is %d.",
- mb_info->mods_count, MAX_BOOT_MODULES);
+ modcount, MAX_BOOT_MODULES);
}
/*
* search the modules to find the last used address
* we'll build the module list while we're walking through here
*/
- DBG_MSG("\nFinding Modules\n");
check_higher((paddr_t)(uintptr_t)&_end);
- for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
- i < mb_info->mods_count;
- ++mod, ++i) {
- process_module(mod);
- check_higher(mod->mod_end);
+ for (i = 0; i < modcount; ++i) {
+ process_module(i);
+ modules_used++;
}
bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
DBG(bi->bi_modules);
- bi->bi_module_cnt = mb_info->mods_count;
+ bi->bi_module_cnt = modcount;
DBG(bi->bi_module_cnt);
fixup_modules();
assign_module_hashes();
check_images();
+}
+
+/*
+ * We then build the phys_install memlist from the multiboot information.
+ */
+static void
+dboot_process_mmap(void)
+{
+ uint64_t start;
+ uint64_t end;
+ uint64_t page_offset = MMU_PAGEOFFSET; /* needs to be 64 bits */
+ uint32_t lower, upper;
+ int i, mmap_entries;
/*
* Walk through the memory map from multiboot and build our memlist
* structures. Note these will have native format pointers.
*/
DBG_MSG("\nFinding Memory Map\n");
- DBG(mb_info->flags);
+ num_entries = 0;
+ num_entries_set = B_FALSE;
max_mem = 0;
- if (mb_info->flags & 0x40) {
- int cnt = 0;
-
- DBG(mb_info->mmap_addr);
- DBG(mb_info->mmap_length);
- check_higher(mb_info->mmap_addr + mb_info->mmap_length);
-
- for (mmap = (mb_memory_map_t *)mb_info->mmap_addr;
- (uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length;
- mmap = (mb_memory_map_t *)((uint32_t)mmap + mmap->size
- + sizeof (mmap->size))) {
- ++cnt;
- start = ((uint64_t)mmap->base_addr_high << 32) +
- mmap->base_addr_low;
- end = start + ((uint64_t)mmap->length_high << 32) +
- mmap->length_low;
+ if ((mmap_entries = dboot_loader_mmap_entries()) > 0) {
+ for (i = 0; i < mmap_entries; i++) {
+ uint32_t type = dboot_loader_mmap_get_type(i);
+ start = dboot_loader_mmap_get_base(i);
+ end = start + dboot_loader_mmap_get_length(i);
if (prom_debug)
dboot_printf("\ttype: %d %" PRIx64 "..%"
- PRIx64 "\n", mmap->type, start, end);
+ PRIx64 "\n", type, start, end);
/*
* page align start and end
@@ -1151,7 +1426,7 @@ init_mem_alloc(void)
/*
* only type 1 is usable RAM
*/
- switch (mmap->type) {
+ switch (type) {
case 1:
if (end > max_mem)
max_mem = end;
@@ -1173,22 +1448,21 @@ init_mem_alloc(void)
continue;
}
}
- build_pcimemlists((mb_memory_map_t *)mb_info->mmap_addr, cnt);
- } else if (mb_info->flags & 0x01) {
- DBG(mb_info->mem_lower);
+ build_pcimemlists();
+ } else if (dboot_multiboot_basicmeminfo(&lower, &upper)) {
+ DBG(lower);
memlists[memlists_used].addr = 0;
- memlists[memlists_used].size = mb_info->mem_lower * 1024;
+ memlists[memlists_used].size = lower * 1024;
++memlists_used;
- DBG(mb_info->mem_upper);
+ DBG(upper);
memlists[memlists_used].addr = 1024 * 1024;
- memlists[memlists_used].size = mb_info->mem_upper * 1024;
+ memlists[memlists_used].size = upper * 1024;
++memlists_used;
/*
* Old platform - assume I/O space at the end of memory.
*/
- pcimemlists[0].addr =
- (mb_info->mem_upper * 1024) + (1024 * 1024);
+ pcimemlists[0].addr = (upper * 1024) + (1024 * 1024);
pcimemlists[0].size = pci_hi_limit - pcimemlists[0].addr;
pcimemlists[0].next = 0;
pcimemlists[0].prev = 0;
@@ -1198,8 +1472,6 @@ init_mem_alloc(void)
dboot_panic("No memory info from boot loader!!!");
}
- check_higher(bi->bi_cmdline);
-
/*
* finish processing the physinstall list
*/
@@ -1210,6 +1482,102 @@ init_mem_alloc(void)
*/
build_rsvdmemlists();
}
+
+/*
+ * The highest address is used as the starting point for dboot's simple
+ * memory allocator.
+ *
+ * Finding the highest address in case of Multiboot 1 protocol is
+ * quite painful in the sense that some information provided by
+ * the multiboot info structure points to BIOS data, and some to RAM.
+ *
+ * The module list was processed and checked already by dboot_process_modules(),
+ * so we will check the command line string and the memory map.
+ *
+ * This list of to be checked items is based on our current knowledge of
+ * allocations made by grub1 and will need to be reviewed if there
+ * are updates about the information provided by Multiboot 1.
+ *
+ * In the case of the Multiboot 2, our life is much simpler, as the MB2
+ * information tag list is one contiguous chunk of memory.
+ */
+static paddr_t
+dboot_multiboot1_highest_addr(void)
+{
+ paddr_t addr = NULL;
+ char *cmdl = (char *)mb_info->cmdline;
+
+ if (mb_info->flags & MB_INFO_CMDLINE)
+ addr = ((paddr_t)((uintptr_t)cmdl + strlen(cmdl) + 1));
+
+ if (mb_info->flags & MB_INFO_MEM_MAP)
+ addr = MAX(addr,
+ ((paddr_t)(mb_info->mmap_addr + mb_info->mmap_length)));
+ return (addr);
+}
+
+static void
+dboot_multiboot_highest_addr(void)
+{
+ paddr_t addr;
+
+ switch (multiboot_version) {
+ case 1:
+ addr = dboot_multiboot1_highest_addr();
+ if (addr != NULL)
+ check_higher(addr);
+ break;
+ case 2:
+ addr = dboot_multiboot2_highest_addr(mb2_info);
+ if (addr != NULL)
+ check_higher(addr);
+ break;
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+}
+
+/*
+ * Walk the boot loader provided information and find the highest free address.
+ */
+static void
+init_mem_alloc(void)
+{
+ DBG_MSG("Entered init_mem_alloc()\n");
+ dboot_process_modules();
+ dboot_process_mmap();
+ dboot_multiboot_highest_addr();
+}
+
+static void
+dboot_multiboot_get_fwtables(void)
+{
+ multiboot_tag_new_acpi_t *nacpitagp;
+ multiboot_tag_old_acpi_t *oacpitagp;
+
+ /* no fw tables from multiboot 1 */
+ if (multiboot_version != 2)
+ return;
+
+ nacpitagp = (multiboot_tag_new_acpi_t *)
+ dboot_multiboot2_find_tag(mb2_info,
+ MULTIBOOT_TAG_TYPE_ACPI_NEW);
+ oacpitagp = (multiboot_tag_old_acpi_t *)
+ dboot_multiboot2_find_tag(mb2_info,
+ MULTIBOOT_TAG_TYPE_ACPI_OLD);
+
+ if (nacpitagp != NULL) {
+ bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
+ &nacpitagp->mb_rsdp[0];
+ } else if (oacpitagp != NULL) {
+ bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
+ &oacpitagp->mb_rsdp[0];
+ } else {
+ bi->bi_acpi_rsdp = NULL;
+ }
+}
#endif /* !__xpv */
/*
@@ -1397,6 +1765,135 @@ kernel$ /platform/i86pc/kernel/$ISADIR/unix\n\
module$ /platform/i86pc/$ISADIR/boot_archive\n\
See http://illumos.org/msg/SUNOS-8000-AK for details.\n"
+static void
+dboot_init_xboot_consinfo(void)
+{
+ uintptr_t addr;
+ /*
+ * boot info must be 16 byte aligned for 64 bit kernel ABI
+ */
+ addr = (uintptr_t)boot_info;
+ addr = (addr + 0xf) & ~0xf;
+ bi = (struct xboot_info *)addr;
+
+#if !defined(__xpv)
+ switch (multiboot_version) {
+ case 1:
+ dboot_multiboot1_xboot_consinfo();
+ break;
+ case 2:
+ dboot_multiboot2_xboot_consinfo();
+ break;
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+#endif
+}
+
+/*
+ * Set up basic data from the boot loader.
+ * The load_addr is part of AOUT kludge setup in dboot_grub.s, to support
+ * 32-bit dboot code setup used to set up and start 64-bit kernel.
+ * AOUT kludge does allow 32-bit boot loader, such as grub1, to load and
+ * start 64-bit illumos kernel.
+ */
+static void
+dboot_loader_init(void)
+{
+#if !defined(__xpv)
+ mb_info = NULL;
+ mb2_info = NULL;
+
+ switch (mb_magic) {
+ case MB_BOOTLOADER_MAGIC:
+ multiboot_version = 1;
+ mb_info = (multiboot_info_t *)(uintptr_t)mb_addr;
+#if defined(_BOOT_TARGET_amd64)
+ load_addr = mb_header.load_addr;
+#endif
+ break;
+
+ case MULTIBOOT2_BOOTLOADER_MAGIC:
+ multiboot_version = 2;
+ mb2_info = (multiboot2_info_header_t *)(uintptr_t)mb_addr;
+ mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mb2_info);
+#if defined(_BOOT_TARGET_amd64)
+ load_addr = mb2_load_addr;
+#endif
+ break;
+
+ default:
+ dboot_panic("Unknown bootloader magic: 0x%x\n", mb_magic);
+ break;
+ }
+#endif /* !defined(__xpv) */
+}
+
+/* Extract the kernel command line from [multi]boot information. */
+static char *
+dboot_loader_cmdline(void)
+{
+ char *line = NULL;
+
+#if defined(__xpv)
+ line = (char *)xen_info->cmd_line;
+#else /* __xpv */
+
+ switch (multiboot_version) {
+ case 1:
+ if (mb_info->flags & MB_INFO_CMDLINE)
+ line = (char *)mb_info->cmdline;
+ break;
+
+ case 2:
+ line = dboot_multiboot2_cmdline(mb2_info);
+ break;
+
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+
+#endif /* __xpv */
+
+ /*
+ * Make sure we have valid pointer so the string operations
+ * will not crash us.
+ */
+ if (line == NULL)
+ line = "";
+
+ return (line);
+}
+
+static char *
+dboot_loader_name(void)
+{
+#if defined(__xpv)
+ return (NULL);
+#else /* __xpv */
+ multiboot_tag_string_t *tag;
+
+ switch (multiboot_version) {
+ case 1:
+ return ((char *)mb_info->boot_loader_name);
+
+ case 2:
+ tag = dboot_multiboot2_find_tag(mb2_info,
+ MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME);
+ return (tag->mb_string);
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
+
+ return (NULL);
+#endif /* __xpv */
+}
/*
* startup_kernel has a pretty simple job. It builds pagetables which reflect
* 1:1 mappings for all memory in use. It then also adds mappings for
@@ -1409,19 +1906,18 @@ void
startup_kernel(void)
{
char *cmdline;
- uintptr_t addr;
+ char *bootloader;
#if defined(__xpv)
physdev_set_iopl_t set_iopl;
#endif /* __xpv */
+ dboot_loader_init();
/*
* At this point we are executing in a 32 bit real mode.
*/
-#if defined(__xpv)
- cmdline = (char *)xen_info->cmd_line;
-#else /* __xpv */
- cmdline = (char *)mb_info->cmdline;
-#endif /* __xpv */
+
+ bootloader = dboot_loader_name();
+ cmdline = dboot_loader_cmdline();
prom_debug = (strstr(cmdline, "prom_debug") != NULL);
map_debug = (strstr(cmdline, "map_debug") != NULL);
@@ -1437,23 +1933,37 @@ startup_kernel(void)
}
#endif /* __xpv */
+ dboot_init_xboot_consinfo();
+ bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
+
+#if !defined(__xpv)
+ dboot_multiboot_get_fwtables();
+#endif
bcons_init(cmdline);
- DBG_MSG("\n\nSolaris prekernel set: ");
+ DBG_MSG("\n\nillumos prekernel set: ");
DBG_MSG(cmdline);
DBG_MSG("\n");
+ if (bootloader != NULL && prom_debug) {
+ dboot_printf("Kernel loaded by: %s\n", bootloader);
+#if !defined(__xpv)
+ dboot_printf("Using multiboot %d boot protocol.\n",
+ multiboot_version);
+#endif
+ }
+
if (strstr(cmdline, "multiboot") != NULL) {
dboot_panic(NO_MULTIBOOT);
}
- /*
- * boot info must be 16 byte aligned for 64 bit kernel ABI
- */
- addr = (uintptr_t)boot_info;
- addr = (addr + 0xf) & ~0xf;
- bi = (struct xboot_info *)addr;
DBG((uintptr_t)bi);
- bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
+#if !defined(__xpv)
+ DBG((uintptr_t)mb_info);
+ DBG((uintptr_t)mb2_info);
+ if (mb2_info != NULL)
+ DBG(mb2_info->mbi_total_size);
+ DBG(bi->bi_acpi_rsdp);
+#endif
/*
* Need correct target_kernel_text value
@@ -1668,7 +2178,8 @@ startup_kernel(void)
ktext_phys = (uintptr_t)do_mem_alloc(ksize, FOUR_MEG);
if (ktext_phys == 0)
dboot_panic("failed to allocate aligned kernel memory");
- if (dboot_elfload64(mb_header.load_addr) != 0)
+ DBG(load_addr);
+ if (dboot_elfload64(load_addr) != 0)
dboot_panic("failed to parse kernel ELF image, rebooting");
#endif
@@ -1716,7 +2227,20 @@ startup_kernel(void)
DBG(bi->bi_next_paddr);
bi->bi_next_vaddr = (uintptr_t)next_avail_addr;
DBG(bi->bi_next_vaddr);
- bi->bi_mb_info = (uintptr_t)mb_info;
+ bi->bi_mb_version = multiboot_version;
+
+ switch (multiboot_version) {
+ case 1:
+ bi->bi_mb_info = (uintptr_t)mb_info;
+ break;
+ case 2:
+ bi->bi_mb_info = (uintptr_t)mb2_info;
+ break;
+ default:
+ dboot_panic("Unknown multiboot version: %d\n",
+ multiboot_version);
+ break;
+ }
bi->bi_top_page_table = (uintptr_t)top_page_table;
#endif /* __xpv */
diff --git a/usr/src/uts/i86pc/os/ddi_impl.c b/usr/src/uts/i86pc/os/ddi_impl.c
index 84b41cfdad..fa07371303 100644
--- a/usr/src/uts/i86pc/os/ddi_impl.c
+++ b/usr/src/uts/i86pc/os/ddi_impl.c
@@ -1903,6 +1903,9 @@ get_boot_properties(void)
copy_boot_str(bop_staging_area, property_val, 50);
(void) ndi_prop_update_string(DDI_DEV_T_NONE, devi,
property_name, property_val);
+ } else if (strcmp(name, "acpi-root-tab") == 0) {
+ (void) ndi_prop_update_int64(DDI_DEV_T_NONE, devi,
+ property_name, *((int64_t *)bop_staging_area));
} else if (strcmp(name, "stdout") == 0) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi,
property_name, *((int *)bop_staging_area));
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index 2a1c65d4b6..b2a500ed9a 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -40,6 +40,8 @@
#include <sys/bootsvcs.h>
#include <sys/bootinfo.h>
#include <sys/multiboot.h>
+#include <sys/multiboot2.h>
+#include <sys/multiboot2_impl.h>
#include <sys/bootvfs.h>
#include <sys/bootprops.h>
#include <sys/varargs.h>
@@ -132,7 +134,7 @@ shared_info_t *HYPERVISOR_shared_info;
static ulong_t total_bop_alloc_scratch = 0;
static ulong_t total_bop_alloc_kernel = 0;
-static void build_firmware_properties(void);
+static void build_firmware_properties(struct xboot_info *);
static int early_allocation = 1;
@@ -1130,7 +1132,8 @@ build_panic_cmdline(const char *cmd, int cmdlen)
#ifndef __xpv
/*
- * Construct boot command line for Fast Reboot
+ * Construct boot command line for Fast Reboot. The saved_cmdline
+ * is also reported by "eeprom bootcmd".
*/
static void
build_fastboot_cmdline(struct xboot_info *xbp)
@@ -1228,9 +1231,6 @@ build_boot_properties(struct xboot_info *xbp)
static int stdout_val = 0;
uchar_t boot_device;
char str[3];
- multiboot_info_t *mbi;
- int netboot;
- struct sol_netinfo *sip;
#endif
/*
@@ -1277,6 +1277,19 @@ build_boot_properties(struct xboot_info *xbp)
fastreboot_disable(FBNS_BOOTMOD);
}
+#ifndef __xpv
+ /*
+ * Disable fast reboot if we're using the Multiboot 2 boot protocol,
+ * since we don't currently support MB2 info and module relocation.
+ * Note that fast reboot will have already been disabled if multiple
+ * modules are present, since the current implementation assumes that
+ * we only have a single module, the boot_archive.
+ */
+ if (xbp->bi_mb_version != 1) {
+ fastreboot_disable(FBNS_MULTIBOOT2);
+ }
+#endif
+
DBG_MSG("Parsing command line for boot properties\n");
value = xbp->bi_cmdline;
@@ -1472,46 +1485,79 @@ build_boot_properties(struct xboot_info *xbp)
#ifndef __xpv
/*
- * set the BIOS boot device from GRUB
- */
- netboot = 0;
- mbi = xbp->bi_mb_info;
-
- /*
* Build boot command line for Fast Reboot
*/
build_fastboot_cmdline(xbp);
- /*
- * Save various boot information for Fast Reboot
- */
- save_boot_info(xbp);
-
- if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
- boot_device = mbi->boot_device >> 24;
- if (boot_device == 0x20)
- netboot++;
- str[0] = (boot_device >> 4) + '0';
- str[1] = (boot_device & 0xf) + '0';
- str[2] = 0;
- bsetprops("bios-boot-device", str);
- } else {
- netboot = 1;
- }
+ if (xbp->bi_mb_version == 1) {
+ multiboot_info_t *mbi = xbp->bi_mb_info;
+ int netboot;
+ struct sol_netinfo *sip;
- /*
- * In the netboot case, drives_info is overloaded with the dhcp ack.
- * This is not multiboot compliant and requires special pxegrub!
- */
- if (netboot && mbi->drives_length != 0) {
- sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
- if (sip->sn_infotype == SN_TYPE_BOOTP)
+ /*
+ * set the BIOS boot device from GRUB
+ */
+ netboot = 0;
+
+ /*
+ * Save various boot information for Fast Reboot
+ */
+ save_boot_info(xbp);
+
+ if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
+ boot_device = mbi->boot_device >> 24;
+ if (boot_device == 0x20)
+ netboot++;
+ str[0] = (boot_device >> 4) + '0';
+ str[1] = (boot_device & 0xf) + '0';
+ str[2] = 0;
+ bsetprops("bios-boot-device", str);
+ } else {
+ netboot = 1;
+ }
+
+ /*
+ * In the netboot case, drives_info is overloaded with the
+ * dhcp ack. This is not multiboot compliant and requires
+ * special pxegrub!
+ */
+ if (netboot && mbi->drives_length != 0) {
+ sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
+ if (sip->sn_infotype == SN_TYPE_BOOTP)
+ bsetprop("bootp-response",
+ sizeof ("bootp-response"),
+ (void *)(uintptr_t)mbi->drives_addr,
+ mbi->drives_length);
+ else if (sip->sn_infotype == SN_TYPE_RARP)
+ setup_rarp_props(sip);
+ }
+ } else {
+ multiboot2_info_header_t *mbi = xbp->bi_mb_info;
+ multiboot_tag_bootdev_t *bootdev = NULL;
+ multiboot_tag_network_t *netdev = NULL;
+
+ if (mbi != NULL) {
+ bootdev = dboot_multiboot2_find_tag(mbi,
+ MULTIBOOT_TAG_TYPE_BOOTDEV);
+ netdev = dboot_multiboot2_find_tag(mbi,
+ MULTIBOOT_TAG_TYPE_NETWORK);
+ }
+ if (bootdev != NULL) {
+ DBG(bootdev->mb_biosdev);
+ boot_device = bootdev->mb_biosdev;
+ str[0] = (boot_device >> 4) + '0';
+ str[1] = (boot_device & 0xf) + '0';
+ str[2] = 0;
+ bsetprops("bios-boot-device", str);
+ }
+ if (netdev != NULL) {
bsetprop("bootp-response", sizeof ("bootp-response"),
- (void *)(uintptr_t)mbi->drives_addr,
- mbi->drives_length);
- else if (sip->sn_infotype == SN_TYPE_RARP)
- setup_rarp_props(sip);
+ (void *)(uintptr_t)netdev->mb_dhcpack,
+ netdev->mb_size -
+ sizeof (multiboot_tag_network_t));
+ }
}
+
bsetprop("stdout", strlen("stdout"),
&stdout_val, sizeof (stdout_val));
#endif /* __xpv */
@@ -1530,7 +1576,7 @@ build_boot_properties(struct xboot_info *xbp)
/*
* Build firmware-provided system properties
*/
- build_firmware_properties();
+ build_firmware_properties(xbp);
/*
* XXPV
@@ -2019,9 +2065,26 @@ static ACPI_TABLE_RSDP *
find_rsdp()
{
ACPI_TABLE_RSDP *rsdp;
+ uint64_t rsdp_val = 0;
uint16_t *ebda_seg;
paddr_t ebda_addr;
+ /* check for "acpi-root-tab" property */
+ if (do_bsys_getproplen(NULL, "acpi-root-tab") == sizeof (uint64_t)) {
+ (void) do_bsys_getprop(NULL, "acpi-root-tab", &rsdp_val);
+ if (rsdp_val != 0) {
+ rsdp = scan_rsdp(rsdp_val, rsdp_val + sizeof (*rsdp));
+ if (rsdp != NULL) {
+ if (kbm_debug) {
+ bop_printf(NULL,
+ "Using RSDP from bootloader: "
+ "0x%p\n", (void *)rsdp);
+ }
+ return (rsdp);
+ }
+ }
+ }
+
/*
* Get the EBDA segment and scan the first 1K
*/
@@ -2536,12 +2599,18 @@ enumerate_xen_cpus()
}
#endif /* __xpv */
+/*ARGSUSED*/
static void
-build_firmware_properties(void)
+build_firmware_properties(struct xboot_info *xbp)
{
ACPI_TABLE_HEADER *tp = NULL;
#ifndef __xpv
+ if (xbp->bi_acpi_rsdp) {
+ bsetprop64("acpi-root-tab",
+ (uint64_t)(uintptr_t)xbp->bi_acpi_rsdp);
+ }
+
if ((tp = find_fw_table(ACPI_SIG_MSCT)) != NULL)
msct_ptr = process_msct((ACPI_TABLE_MSCT *)tp);
else
diff --git a/usr/src/uts/i86pc/sys/fastboot_msg.h b/usr/src/uts/i86pc/sys/fastboot_msg.h
index 9a1c9bd878..5643d65b29 100644
--- a/usr/src/uts/i86pc/sys/fastboot_msg.h
+++ b/usr/src/uts/i86pc/sys/fastboot_msg.h
@@ -42,17 +42,20 @@
#define fastboot_nosup_msg_end(id)
#endif /* fastboot_nosup_msg_end */
+/* BEGIN CSTYLED */
fastboot_nosup_msg(FBNS_DEFAULT, "")
fastboot_nosup_msg(FBNS_SUSPEND, " after suspend/resume")
fastboot_nosup_msg(FBNS_FMAHWERR, " due to FMA recovery from hardware error")
fastboot_nosup_msg(FBNS_HOTPLUG, " after DR operations")
fastboot_nosup_msg(FBNS_BOOTMOD, " due to presence of boot-time modules")
+fastboot_nosup_msg(FBNS_MULTIBOOT2, " due to multiboot2 boot protocol")
/*
* Should ALWAYS be the last one.
* No fastboot_nosup_msg() after that line.
*/
fastboot_nosup_msg_end(FBNS_END)
+/* END CSTYLED */
#undef fastboot_nosup_msg
#undef fastboot_nosup_msg_end
diff --git a/usr/src/uts/i86xpv/Makefile.files b/usr/src/uts/i86xpv/Makefile.files
index 1da8a3813c..8fdda3652d 100644
--- a/usr/src/uts/i86xpv/Makefile.files
+++ b/usr/src/uts/i86xpv/Makefile.files
@@ -119,6 +119,7 @@ BOOT_DRIVER_OBJS = \
boot_mmu.o \
boot_vga.o \
boot_xconsole.o \
+ dboot_multiboot2.o \
$(FONT_OBJS)
CORE_OBJS += $(BOOT_DRIVER_OBJS)
diff --git a/usr/src/uts/intel/io/acpica/osl.c b/usr/src/uts/intel/io/acpica/osl.c
index 5bc1b855fd..5c32604088 100644
--- a/usr/src/uts/intel/io/acpica/osl.c
+++ b/usr/src/uts/intel/io/acpica/osl.c
@@ -229,7 +229,7 @@ AcpiOsGetRootPointer()
* The boot code process the table and put the physical address
* in the acpi-root-tab property.
*/
- Address = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
+ Address = ddi_prop_get_int64(DDI_DEV_T_ANY, ddi_root_node(),
DDI_PROP_DONTPASS, "acpi-root-tab", NULL);
if ((Address == NULL) && ACPI_FAILURE(AcpiFindRootPointer(&Address)))
@@ -241,7 +241,7 @@ AcpiOsGetRootPointer()
/*ARGSUSED*/
ACPI_STATUS
AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *InitVal,
- ACPI_STRING *NewVal)
+ ACPI_STRING *NewVal)
{
*NewVal = 0;
@@ -260,7 +260,7 @@ acpica_strncpy(char *dest, const char *src, int len)
ACPI_STATUS
AcpiOsTableOverride(ACPI_TABLE_HEADER *ExistingTable,
- ACPI_TABLE_HEADER **NewTable)
+ ACPI_TABLE_HEADER **NewTable)
{
char signature[5];
char oemid[7];
@@ -418,7 +418,7 @@ acpi_sema_v(acpi_sema_t *sp, unsigned count)
ACPI_STATUS
AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
-ACPI_HANDLE *OutHandle)
+ ACPI_HANDLE *OutHandle)
{
acpi_sema_t *sp;
@@ -622,7 +622,7 @@ AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
/*ARGSUSED*/
ACPI_STATUS
AcpiOsGetPhysicalAddress(void *LogicalAddress,
- ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
+ ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
{
/* UNIMPLEMENTED: not invoked by ACPI CA code */
@@ -653,8 +653,8 @@ static int acpi_intr_hooked = 0;
ACPI_STATUS
AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
- ACPI_OSD_HANDLER ServiceRoutine,
- void *Context)
+ ACPI_OSD_HANDLER ServiceRoutine,
+ void *Context)
{
_NOTE(ARGUNUSED(InterruptNumber))
@@ -687,7 +687,7 @@ AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
ACPI_STATUS
AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber,
- ACPI_OSD_HANDLER ServiceRoutine)
+ ACPI_OSD_HANDLER ServiceRoutine)
{
_NOTE(ARGUNUSED(ServiceRoutine))
@@ -931,7 +931,7 @@ osl_rw_memory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value,
ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,
- UINT64 *Value, UINT32 Width)
+ UINT64 *Value, UINT32 Width)
{
osl_rw_memory(Address, Value, Width, 0);
return (AE_OK);
@@ -939,7 +939,7 @@ AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,
ACPI_STATUS
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,
- UINT64 Value, UINT32 Width)
+ UINT64 Value, UINT32 Width)
{
osl_rw_memory(Address, &Value, Width, 1);
return (AE_OK);
@@ -948,7 +948,7 @@ AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,
ACPI_STATUS
AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Reg,
- UINT64 *Value, UINT32 Width)
+ UINT64 *Value, UINT32 Width)
{
switch (Width) {
@@ -980,7 +980,7 @@ int acpica_write_pci_config_ok = 1;
ACPI_STATUS
AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Reg,
- UINT64 Value, UINT32 Width)
+ UINT64 Value, UINT32 Width)
{
if (!acpica_write_pci_config_ok) {
@@ -1034,7 +1034,7 @@ AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Reg,
*/
void
AcpiOsDerivePciId(ACPI_HANDLE rhandle, ACPI_HANDLE chandle,
- ACPI_PCI_ID **PciId)
+ ACPI_PCI_ID **PciId)
{
ACPI_HANDLE handle;
dev_info_t *dip;
diff --git a/usr/src/uts/intel/sys/bootinfo.h b/usr/src/uts/intel/sys/bootinfo.h
index 3adce64fc4..9e205e342f 100644
--- a/usr/src/uts/intel/sys/bootinfo.h
+++ b/usr/src/uts/intel/sys/bootinfo.h
@@ -107,7 +107,9 @@ struct xboot_info {
native_ptr_t bi_xen_start_info;
native_ptr_t bi_shared_info; /* VA for shared_info */
#else
- native_ptr_t bi_mb_info;
+ native_ptr_t bi_mb_info; /* multiboot 1 or 2 info */
+ int bi_mb_version; /* multiboot version */
+ native_ptr_t bi_acpi_rsdp;
#endif
};
#pragma pack()