diff options
author | Toomas Soome <tsoome@me.com> | 2016-02-16 11:28:33 +0200 |
---|---|---|
committer | Joshua M. Clulow <josh@sysmgr.org> | 2017-04-21 20:09:34 -0700 |
commit | 1738dd6ec94e36a9828d13a6e52ac7fb68cb52ed (patch) | |
tree | 7f5a6cabbb67f1e367cc65717052aa15f2dfa411 /usr/src | |
parent | 660946868929e02041af7b5b1c3e14f547c53f11 (diff) | |
download | illumos-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/Makefile | 1 | ||||
-rw-r--r-- | usr/src/tools/mbh_patch/mbh_patch.c | 121 | ||||
-rw-r--r-- | usr/src/uts/common/sys/multiboot2.h | 418 | ||||
-rw-r--r-- | usr/src/uts/common/sys/multiboot2_impl.h | 53 | ||||
-rw-r--r-- | usr/src/uts/i86pc/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/uts/i86pc/Makefile.rules | 7 | ||||
-rw-r--r-- | usr/src/uts/i86pc/dboot/dboot_grub.s | 102 | ||||
-rw-r--r-- | usr/src/uts/i86pc/dboot/dboot_multiboot2.c | 352 | ||||
-rw-r--r-- | usr/src/uts/i86pc/dboot/dboot_startkern.c | 756 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/ddi_impl.c | 3 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/fakebop.c | 149 | ||||
-rw-r--r-- | usr/src/uts/i86pc/sys/fastboot_msg.h | 3 | ||||
-rw-r--r-- | usr/src/uts/i86xpv/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/uts/intel/io/acpica/osl.c | 26 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/bootinfo.h | 4 |
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() |