Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160420010
D28497.id83404.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D28497.id83404.diff
View Options
Index: stand/efi/loader/arch/amd64/Makefile.inc
===================================================================
--- stand/efi/loader/arch/amd64/Makefile.inc
+++ stand/efi/loader/arch/amd64/Makefile.inc
@@ -4,6 +4,7 @@
start.S \
elf64_freebsd.c \
trap.c \
+ multiboot2.c \
exc.S
.PATH: ${BOOTSRC}/i386/libi386
Index: stand/efi/loader/arch/amd64/amd64_tramp.S
===================================================================
--- stand/efi/loader/arch/amd64/amd64_tramp.S
+++ stand/efi/loader/arch/amd64/amd64_tramp.S
@@ -30,6 +30,9 @@
#include <machine/asmacros.h>
+#define ASM_FILE
+#include "multiboot2.h"
+
.text
.globl amd64_tramp
@@ -58,6 +61,15 @@
ALIGN_TEXT
amd64_tramp_end:
+/* void multiboot2_exec(uint64_t entry, uint64_t multiboot_info, uint64_t stack) */
+ .globl multiboot2_exec
+multiboot2_exec:
+ movq %rdx,%rsp
+ pushq %rdi
+ movq %rsi,%rbx
+ movq $MULTIBOOT2_BOOTLOADER_MAGIC,%rax
+ ret
+
.data
.globl amd64_tramp_size
amd64_tramp_size:
Index: stand/efi/loader/arch/amd64/elf64_freebsd.c
===================================================================
--- stand/efi/loader/arch/amd64/elf64_freebsd.c
+++ stand/efi/loader/arch/amd64/elf64_freebsd.c
@@ -69,7 +69,12 @@
.l_exec = elf64_obj_exec,
};
+extern struct file_format multiboot2;
+extern struct file_format multiboot2_obj;
+
struct file_format *file_formats[] = {
+ &multiboot2,
+ &multiboot2_obj,
&amd64_elf,
&amd64_elf_obj,
NULL
Index: stand/efi/loader/arch/amd64/multiboot2.h
===================================================================
--- /dev/null
+++ stand/efi/loader/arch/amd64/multiboot2.h
@@ -0,0 +1,416 @@
+/* multiboot2.h - Multiboot 2 header file. */
+/* 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.
+ */
+
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+/* 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. */
+#define MULTIBOOT_MOD_ALIGN 0x00001000
+
+/* 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_EFI64 9
+#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
+
+#define MULTIBOOT2_ARCHITECTURE_I386 0
+#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
+#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
+
+#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
+#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
+#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
+
+#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
+#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
+
+#ifndef ASM_FILE
+
+typedef unsigned char multiboot_uint8_t;
+typedef unsigned short multiboot_uint16_t;
+typedef unsigned int multiboot_uint32_t;
+typedef unsigned long long multiboot_uint64_t;
+
+struct multiboot_header
+{
+ /* Must be MULTIBOOT_MAGIC - see above. */
+ multiboot_uint32_t magic;
+
+ /* ISA */
+ multiboot_uint32_t architecture;
+
+ /* Total header length. */
+ multiboot_uint32_t header_length;
+
+ /* The above fields plus this one must equal 0 mod 2^32. */
+ multiboot_uint32_t checksum;
+};
+
+struct multiboot_header_tag
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+};
+
+struct multiboot_header_tag_information_request
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t requests[0];
+};
+
+struct multiboot_header_tag_address
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t header_addr;
+ multiboot_uint32_t load_addr;
+ multiboot_uint32_t load_end_addr;
+ multiboot_uint32_t bss_end_addr;
+};
+
+struct multiboot_header_tag_entry_address
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t entry_addr;
+};
+
+struct multiboot_header_tag_console_flags
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t console_flags;
+};
+
+struct multiboot_header_tag_framebuffer
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t width;
+ multiboot_uint32_t height;
+ multiboot_uint32_t depth;
+};
+
+struct multiboot_header_tag_module_align
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+};
+
+struct multiboot_header_tag_relocatable
+{
+ multiboot_uint16_t type;
+ multiboot_uint16_t flags;
+ multiboot_uint32_t size;
+ multiboot_uint32_t min_addr;
+ multiboot_uint32_t max_addr;
+ multiboot_uint32_t align;
+ multiboot_uint32_t preference;
+};
+
+struct multiboot_color
+{
+ multiboot_uint8_t red;
+ multiboot_uint8_t green;
+ multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+ multiboot_uint64_t addr;
+ multiboot_uint64_t 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
+ multiboot_uint32_t type;
+ multiboot_uint32_t zero;
+};
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_tag
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+};
+
+struct multiboot_tag_string
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ char string[0];
+};
+
+struct multiboot_tag_module
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t mod_start;
+ multiboot_uint32_t mod_end;
+ char cmdline[0];
+};
+
+struct multiboot_tag_basic_meminfo
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t mem_lower;
+ multiboot_uint32_t mem_upper;
+};
+
+struct multiboot_tag_bootdev
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t biosdev;
+ multiboot_uint32_t slice;
+ multiboot_uint32_t part;
+};
+
+struct multiboot_tag_mmap
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t entry_size;
+ multiboot_uint32_t entry_version;
+ struct multiboot_mmap_entry entries[0];
+};
+
+struct multiboot_vbe_info_block
+{
+ multiboot_uint8_t external_specification[512];
+};
+
+struct multiboot_vbe_mode_info_block
+{
+ multiboot_uint8_t external_specification[256];
+};
+
+struct multiboot_tag_vbe
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+
+ multiboot_uint16_t vbe_mode;
+ multiboot_uint16_t vbe_interface_seg;
+ multiboot_uint16_t vbe_interface_off;
+ multiboot_uint16_t vbe_interface_len;
+
+ struct multiboot_vbe_info_block vbe_control_info;
+ struct multiboot_vbe_mode_info_block vbe_mode_info;
+};
+
+struct multiboot_tag_framebuffer_common
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+
+ multiboot_uint64_t framebuffer_addr;
+ multiboot_uint32_t framebuffer_pitch;
+ multiboot_uint32_t framebuffer_width;
+ multiboot_uint32_t framebuffer_height;
+ multiboot_uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
+ multiboot_uint8_t framebuffer_type;
+ multiboot_uint16_t reserved;
+};
+
+struct multiboot_tag_framebuffer
+{
+ struct multiboot_tag_framebuffer_common common;
+
+ union
+ {
+ struct
+ {
+ multiboot_uint16_t framebuffer_palette_num_colors;
+ struct multiboot_color framebuffer_palette[0];
+ };
+ struct
+ {
+ multiboot_uint8_t framebuffer_red_field_position;
+ multiboot_uint8_t framebuffer_red_mask_size;
+ multiboot_uint8_t framebuffer_green_field_position;
+ multiboot_uint8_t framebuffer_green_mask_size;
+ multiboot_uint8_t framebuffer_blue_field_position;
+ multiboot_uint8_t framebuffer_blue_mask_size;
+ };
+ };
+};
+
+struct multiboot_tag_elf_sections
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t num;
+ multiboot_uint32_t entsize;
+ multiboot_uint32_t shndx;
+ char sections[0];
+};
+
+struct multiboot_tag_apm
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint16_t version;
+ multiboot_uint16_t cseg;
+ multiboot_uint32_t offset;
+ multiboot_uint16_t cseg_16;
+ multiboot_uint16_t dseg;
+ multiboot_uint16_t flags;
+ multiboot_uint16_t cseg_len;
+ multiboot_uint16_t cseg_16_len;
+ multiboot_uint16_t dseg_len;
+};
+
+struct multiboot_tag_efi32
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t pointer;
+};
+
+struct multiboot_tag_efi64
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint64_t pointer;
+};
+
+struct multiboot_tag_smbios
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint8_t major;
+ multiboot_uint8_t minor;
+ multiboot_uint8_t reserved[6];
+ multiboot_uint8_t tables[0];
+};
+
+struct multiboot_tag_old_acpi
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint8_t rsdp[0];
+};
+
+struct multiboot_tag_new_acpi
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint8_t rsdp[0];
+};
+
+struct multiboot_tag_network
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint8_t dhcpack[0];
+};
+
+struct multiboot_tag_efi_mmap
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t descr_size;
+ multiboot_uint32_t descr_vers;
+ multiboot_uint8_t efi_mmap[0];
+};
+
+struct multiboot_tag_efi32_ih
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t pointer;
+};
+
+struct multiboot_tag_efi64_ih
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint64_t pointer;
+};
+
+struct multiboot_tag_load_base_addr
+{
+ multiboot_uint32_t type;
+ multiboot_uint32_t size;
+ multiboot_uint32_t load_base_addr;
+};
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! MULTIBOOT_HEADER */
Index: stand/efi/loader/arch/amd64/multiboot2.c
===================================================================
--- /dev/null
+++ stand/efi/loader/arch/amd64/multiboot2.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2021 Roger Pau Monné <royger@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This multiboot2 implementation only implements a subset of the full
+ * multiboot2 specification in order to be able to boot Xen and a
+ * FreeBSD Dom0. Trying to use it to boot other multiboot2 compliant
+ * kernels will most surely fail.
+ *
+ * The full multiboot specification can be found here:
+ * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stdint.h>
+#define _MACHINE_ELF_WANT_32BIT
+#include <machine/elf.h>
+#include <machine/metadata.h>
+#include <string.h>
+#include <stand.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "bootstrap.h"
+#include "multiboot2.h"
+#include "loader_efi.h"
+
+extern int elf32_loadfile_raw(char *filename, uint64_t dest,
+ struct preloaded_file **result, int multiboot);
+extern int elf64_load_modmetadata(struct preloaded_file *fp, uint64_t dest);
+extern int elf64_obj_loadfile(char *filename, uint64_t dest,
+ struct preloaded_file **result);
+extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp,
+ bool exit_bs);
+
+extern void multiboot2_exec(void *entry, uint64_t multiboot_info,
+ uint64_t stack);
+
+static int
+loadfile(char *filename, uint64_t dest, struct preloaded_file **result)
+{
+ unsigned int i;
+ int error, fd;
+ void *header_search = NULL;
+ void *multiboot = NULL;
+ ssize_t search_size;
+ struct multiboot_header *header;
+ char *cmdline;
+ uint32_t entry_addr;
+
+ /*
+ * Read MULTIBOOT_SEARCH size in order to search for the
+ * multiboot magic header.
+ */
+ if (filename == NULL)
+ return (EFTYPE);
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return (errno);
+ header_search = malloc(MULTIBOOT_SEARCH);
+ if (header_search == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ search_size = read(fd, header_search, MULTIBOOT_SEARCH);
+
+ for (i = 0; i < search_size; i += MULTIBOOT_HEADER_ALIGN) {
+ header = header_search + i;
+ if (header->magic == MULTIBOOT2_HEADER_MAGIC)
+ break;
+ }
+
+ if (i >= MULTIBOOT_SEARCH) {
+ error = EFTYPE;
+ goto out;
+ }
+
+ /* Valid multiboot header has been found, validate checksum */
+ if (header->magic + header->architecture + header->header_length +
+ header->checksum != 0) {
+ printf("Multiboot checksum failed, magic: %#x architecture: %#x"
+ "header_length %#x checksum: %#x\n",
+ header->magic, header->architecture, header->header_length,
+ header->checksum);
+ error = EFTYPE;
+ goto out;
+ }
+
+ if (header->architecture != MULTIBOOT2_ARCHITECTURE_I386) {
+ printf("Unsupported architecture: %#x\n",
+ header->architecture);
+ error = EFTYPE;
+ goto out;
+ }
+
+ multiboot = malloc(header->header_length - sizeof(*header));
+ error = lseek(fd, i + sizeof(*header), SEEK_SET);
+ if (error != i + sizeof(*header)) {
+ printf("Unable to set file pointer to header location: %d\n",
+ error);
+ goto out;
+ }
+ search_size = read(fd, multiboot,
+ header->header_length - sizeof(*header));
+
+ entry_addr = 0;
+ for (i = 0; i < search_size; ) {
+ struct multiboot_header_tag *tag;
+ struct multiboot_header_tag_entry_address *entry;
+ struct multiboot_header_tag_console_flags *console;
+ struct multiboot_header_tag_information_request *req;
+ unsigned int j;
+
+ tag = (struct multiboot_header_tag *)(multiboot + i);
+
+ switch(tag->type) {
+ case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
+ req =
+ (struct multiboot_header_tag_information_request *)tag;
+ for (j = 0;
+ j < (tag->size - sizeof(*tag)) / sizeof(uint32_t);
+ j++) {
+ switch (req->requests[j]) {
+ case MULTIBOOT_TAG_TYPE_MMAP:
+ case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
+ /* Only applicable to BIOS. */
+ break;
+
+ default:
+ if (req->flags &
+ MULTIBOOT_HEADER_TAG_OPTIONAL)
+ break;
+
+ printf(
+ "Unknown non-optional information request %u\n",
+ req->requests[j]);
+ error = EINVAL;
+ goto out;
+ }
+ }
+ break;
+
+ case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
+ /* We will align modules by default already. */
+ case MULTIBOOT_HEADER_TAG_EFI_BS:
+ /* Never shut down BS. */
+ case MULTIBOOT_HEADER_TAG_END:
+ break;
+
+ case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64:
+ entry =
+ (struct multiboot_header_tag_entry_address *)tag;
+ entry_addr = entry->entry_addr;
+ break;
+
+ default:
+ if (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
+ break;
+ printf("Unknown header tag %#x not optional\n",
+ tag->type);
+ error = EINVAL;
+ goto out;
+ }
+
+ i += roundup2(tag->size, MULTIBOOT_TAG_ALIGN);
+ if (tag->type == MULTIBOOT_HEADER_TAG_END)
+ break;
+ }
+
+ if (entry_addr == 0) {
+ printf("No EFI64 entry address provided\n");
+ error = EINVAL;
+ goto out;
+ }
+
+ error = elf32_loadfile_raw(filename, dest, result, 1);
+ if (error != 0) {
+ printf(
+ "elf32_loadfile_raw failed: %d unable to load multiboot kernel\n",
+ error);
+ goto out;
+ }
+
+ file_addmetadata(*result, MODINFOMD_NOCOPY | MODINFOMD_MULTIEFI64,
+ sizeof(entry_addr), &entry_addr);
+
+ /*
+ * f_addr is already aligned to PAGE_SIZE, make sure
+ * f_size it's also aligned so when the modules are loaded
+ * they are aligned to PAGE_SIZE.
+ */
+ (*result)->f_size = roundup((*result)->f_size, PAGE_SIZE);
+
+out:
+ if (header_search != NULL)
+ free(header_search);
+ if (multiboot != NULL)
+ free(multiboot);
+ close(fd);
+ return (error);
+}
+
+static unsigned int add_string(void *buf, unsigned int type, const char *str)
+{
+ struct multiboot_tag *tag;
+
+ tag = buf;
+ tag->type = type;
+ tag->size = sizeof(*tag) + strlen(str) + 1;
+ strcpy(buf + sizeof(*tag), str);
+ return (roundup2(tag->size, MULTIBOOT_TAG_ALIGN));
+}
+
+static unsigned int add_efi(void *buf)
+{
+ struct multiboot_tag *bs;
+ struct multiboot_tag_efi64 *efi64;
+ struct multiboot_tag_efi64_ih *ih;
+ unsigned int len;
+
+ len = 0;
+ bs = buf;
+ bs->type = MULTIBOOT_TAG_TYPE_EFI_BS;
+ bs->size = sizeof(*bs);
+ len += roundup2(bs->size, MULTIBOOT_TAG_ALIGN);
+
+ efi64 = buf + len;
+ efi64->type = MULTIBOOT_TAG_TYPE_EFI64;
+ efi64->size = sizeof(*efi64);
+ efi64->pointer = (uintptr_t)ST;
+ len += roundup2(efi64->size, MULTIBOOT_TAG_ALIGN);
+
+ ih = buf + len;
+ ih->type = MULTIBOOT_TAG_TYPE_EFI64_IH;
+ ih->size = sizeof(*ih);
+ ih->pointer = (uintptr_t)IH;
+
+ return (len + roundup2(ih->size, MULTIBOOT_TAG_ALIGN));
+}
+
+static unsigned int add_module(void *buf, vm_offset_t start, vm_offset_t end,
+ const char *cmdline)
+{
+ struct multiboot_tag_module *mod;
+
+ mod = buf;
+ mod->type = MULTIBOOT_TAG_TYPE_MODULE;
+ mod->size = sizeof(*mod);
+ mod->mod_start = start;
+ mod->mod_end = end;
+ if (cmdline != NULL)
+ {
+ strcpy(buf + sizeof(*mod), cmdline);
+ mod->size += strlen(cmdline) + 1;
+ }
+
+ return (roundup2(mod->size, MULTIBOOT_TAG_ALIGN));
+}
+
+static unsigned int add_end(void *buf)
+{
+ struct multiboot_tag *tag;
+
+ tag = buf;
+ tag->type = MULTIBOOT_TAG_TYPE_END;
+ tag->size = sizeof(*tag);
+
+ return (roundup2(tag->size, MULTIBOOT_TAG_ALIGN));
+}
+
+static int
+exec(struct preloaded_file *fp)
+{
+ EFI_PHYSICAL_ADDRESS addr = 0;
+ EFI_PHYSICAL_ADDRESS stack = 0;
+ EFI_STATUS status;
+ void *multiboot_space;
+ vm_offset_t modulep, kernend, kern_base,
+ payload_base;
+ char *cmdline = NULL;
+ size_t len;
+ int error;
+ uint32_t *total_size, *entry_addr;
+ struct file_metadata *md;
+ struct xen_header header;
+
+
+ CTASSERT(sizeof(header) <= PAGE_SIZE);
+
+ if ((md = file_findmetadata(fp,
+ MODINFOMD_NOCOPY | MODINFOMD_MULTIEFI64)) == NULL) {
+ printf("Missing Multiboot2 EFI64 entry point\n");
+ return(EFTYPE);
+ }
+
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(PAGE_SIZE), &addr);
+ if (EFI_ERROR(status)) {
+ printf("Failed to allocate pages for multiboot2 header: %lu\n",
+ EFI_ERROR_CODE(status));
+ error = ENOMEM;
+ goto error;
+ }
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(128 * 1024), &stack);
+ if (EFI_ERROR(status)) {
+ printf("Failed to allocate pages for Xen stack: %lu\n",
+ EFI_ERROR_CODE(status));
+ error = ENOMEM;
+ goto error;
+ }
+
+ /*
+ * Scratch space to build the multiboot2 header. Reserve the start of
+ * the space to place the header with the size, which we don't know
+ * yet.
+ */
+ multiboot_space = (void *)(uintptr_t)(addr + sizeof(uint32_t) * 2);
+
+ /*
+ * Don't pass the memory size found by the bootloader, the memory
+ * available to Dom0 will be lower than that.
+ */
+ unsetenv("smbios.memory.enabled");
+
+ /* Set the Xen command line. */
+ if (fp->f_args == NULL) {
+ /* Add the Xen command line if it is set. */
+ cmdline = getenv("xen_cmdline");
+ if (cmdline != NULL) {
+ fp->f_args = strdup(cmdline);
+ if (fp->f_args == NULL) {
+ error = ENOMEM;
+ goto error;
+ }
+ }
+ }
+ if (fp->f_args != NULL) {
+ len = strlen(fp->f_name) + 1 + strlen(fp->f_args) + 1;
+ cmdline = malloc(len);
+ if (cmdline == NULL) {
+ error = ENOMEM;
+ goto error;
+ }
+ snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
+ multiboot_space += add_string(multiboot_space,
+ MULTIBOOT_TAG_TYPE_CMDLINE, cmdline);
+ free(cmdline);
+ }
+
+ multiboot_space += add_string(multiboot_space,
+ MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME, "FreeBSD Loader");
+ multiboot_space += add_efi(multiboot_space);
+
+ /*
+ * Prepare the multiboot module list, Xen assumes the first
+ * module is the Dom0 kernel, and the second one is the initramfs.
+ * This is not optimal for FreeBSD, that doesn't have a initramfs
+ * but instead loads modules dynamically and creates the metadata
+ * info on-the-fly.
+ *
+ * As expected, the first multiboot module is going to be the
+ * FreeBSD kernel loaded as a raw file. The second module is going
+ * to contain the metadata info and the loaded modules.
+ *
+ * There's a small header prefixed in the second module that contains
+ * some information required to calculate the relocated address of
+ * modulep based on the original offset of modulep from the start of
+ * the module address. Note other fields might be added to this header
+ * if required.
+ *
+ * Native layout:
+ * fp->f_addr + fp->f_size
+ * +---------+----------------+------------+
+ * | | | |
+ * | Kernel | Modules | Metadata |
+ * | | | |
+ * +---------+----------------+------------+
+ * fp->f_addr modulep kernend
+ *
+ * Xen dom0 layout:
+ * fp->f_addr fp->f_addr + fp->f_size
+ * +---------+------------+----------------+------------+
+ * | | | | |
+ * | Kernel | xen_header | Modules | Metadata |
+ * | | | | |
+ * +---------+------------+----------------+------------+
+ * modulep kernend
+ * \________/\__________________________________________/
+ * module 0 module 1
+ */
+
+ fp = file_findfile(NULL, "elf kernel");
+ if (fp == NULL) {
+ printf("No FreeBSD kernel provided, aborting\n");
+ error = EINVAL;
+ goto error;
+ }
+
+ error = bi_load(fp->f_args, &modulep, &kernend, false);
+ if (error != 0)
+ goto error;
+
+ /*
+ * Note that the Xen kernel requires to be started with BootServices
+ * enabled, and hence we cannot use efi_copy_finish to relocate the
+ * loaded data from the staging area to the expected loaded addresses.
+ * This is fine because the Xen kernel is relocatable, so it can boot
+ * fine straight from the staging area. We use efi_translate to get the
+ * staging addresses where the kernels and metadata are currently
+ * loaded.
+ */
+ kern_base = (uintptr_t)efi_translate(fp->f_addr);
+ payload_base = kern_base + fp->f_size - PAGE_SIZE;
+ multiboot_space += add_module(multiboot_space, kern_base, payload_base,
+ NULL);
+ multiboot_space += add_module(multiboot_space, payload_base,
+ (uintptr_t)efi_translate(kernend), "header");
+
+ header.flags = XENHEADER_HAS_MODULEP_OFFSET;
+ header.modulep_offset = modulep - (fp->f_addr + fp->f_size - PAGE_SIZE);
+ archsw.arch_copyin(&header, fp->f_addr + fp->f_size - PAGE_SIZE,
+ sizeof(header));
+
+ multiboot_space += add_end(multiboot_space);
+ total_size = (uint32_t *)(uintptr_t)(addr);
+ *total_size = (uintptr_t)multiboot_space - addr;
+
+ if (*total_size > PAGE_SIZE)
+ panic("Multiboot header exceeds fixed size");
+
+ entry_addr = (uint32_t *)&(md->md_data);
+
+ efi_time_fini();
+ dev_cleanup();
+ multiboot2_exec(efi_translate(*entry_addr), addr, stack + 128 * 1024);
+
+ panic("exec returned");
+
+error:
+ if (addr)
+ BS->FreePages(addr, EFI_SIZE_TO_PAGES(PAGE_SIZE));
+ if (stack)
+ BS->FreePages(stack, EFI_SIZE_TO_PAGES(128 * 1024));
+ return (error);
+}
+
+static int
+obj_loadfile(char *filename, uint64_t dest, struct preloaded_file **result)
+{
+ struct preloaded_file *mfp, *kfp, *rfp;
+ struct kernel_module *kmp;
+ int error;
+
+ /* See if there's a multiboot kernel loaded */
+ mfp = file_findfile(NULL, "elf multiboot kernel");
+ if (mfp == NULL)
+ return (EFTYPE);
+
+ /*
+ * We have a multiboot kernel loaded, see if there's a FreeBSD
+ * kernel loaded also.
+ */
+ kfp = file_findfile(NULL, "elf kernel");
+ if (kfp == NULL) {
+ /*
+ * No kernel loaded, this must be it. The kernel has to
+ * be loaded as a raw file, it will be processed by
+ * Xen and correctly loaded as an ELF file.
+ */
+ rfp = file_loadraw(filename, "elf kernel", 0);
+ if (rfp == NULL) {
+ printf(
+ "Unable to load %s as a multiboot payload kernel\n",
+ filename);
+ return (EINVAL);
+ }
+
+ /* Load kernel metadata... */
+ setenv("kernelname", filename, 1);
+ error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
+ if (error) {
+ printf("Unable to load kernel %s metadata error: %d\n",
+ rfp->f_name, error);
+ return (EINVAL);
+ }
+
+
+ /*
+ * Reserve one page at the end of the kernel to place some
+ * metadata in order to cope for Xen relocating the modules and
+ * the metadata information.
+ */
+ rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
+ rfp->f_size += PAGE_SIZE;
+ *result = rfp;
+ } else {
+ /* The rest should be loaded as regular modules */
+ error = elf64_obj_loadfile(filename, dest, result);
+ if (error != 0) {
+ printf("Unable to load %s as an object file, error: %d",
+ filename, error);
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+obj_exec(struct preloaded_file *fp)
+{
+
+ return (EFTYPE);
+}
+
+struct file_format multiboot2 = { loadfile, exec };
+struct file_format multiboot2_obj = { obj_loadfile, obj_exec };
Index: sys/sys/linker.h
===================================================================
--- sys/sys/linker.h
+++ sys/sys/linker.h
@@ -215,6 +215,7 @@
#define MODINFOMD_SSYM 0x0003 /* start of symbols */
#define MODINFOMD_ESYM 0x0004 /* end of symbols */
#define MODINFOMD_DYNAMIC 0x0005 /* _DYNAMIC pointer */
+#define MODINFOMD_MULTIEFI64 0x0006 /* EFI64 multiboot entry addr */
/* These values are MD on PowerPC */
#if !defined(__powerpc__)
#define MODINFOMD_ENVP 0x0006 /* envp[] */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jun 25, 7:27 AM (21 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34311246
Default Alt Text
D28497.id83404.diff (29 KB)
Attached To
Mode
D28497: stand/multiboot2: add support for booting a Xen dom0 in UEFI mode
Attached
Detach File
Event Timeline
Log In to Comment