I have sent an email now asking him if he wants to sign off on it, in which case I will add him as well.
Jens Den tis 6 feb. 2024 16:50Daniel P. Berrangé <berra...@redhat.com> skrev: > On Tue, Feb 06, 2024 at 02:52:31PM +0100, Jens Nyberg wrote: > > This is the first very rough version of what is supposed to be support > for > > multiboot2. This is a continuation of work that was started years ago but > > never saw fruition for reasons unknown. > > Since you've picked up work orignially started by someone else, > there's a little complexity wrt the Signed-off-by. > > As a general rule we would expect to see a 'Signed-off-by' by > the person whose work you continued. Unfortunately it looks > like they didn't add their S-o-B when attaching their proposed > patch to > > > https://bugs.debian.org/cgi-bin/bugreport.cgi?att=2;bug=621529;filename=multiboot2.patch;msg=15 > > Did you try to contact Goswin von Brederlow <goswin-...@web.de> > to see if their email addr is still active, and ask if they're > willing to add their Signed-off-by, for their part in developing > this patch ? > > It isn't a 100% blocker to not have their S-o-B, it just means > you have to be comfortable with the fact that you're effectively > signing off work done by them. The fact that their added this > patch to the Debian bug tracker with the explicit intention it > get incorporated into QEMU is positive. > > It is still worth emailing them to see if we can get the easy > answer directly. > > > This is submitted as an RFC only for now. It would be nice if someone > would > > be willing to guide me into further improving this code > > > > Any ideas on how to properly test this would also be nice! > > > > Signed-off-by: Jens Nyberg <jens.nyb...@gmail.com> > > --- > > hw/i386/meson.build | 1 + > > hw/i386/multiboot2.c | 552 +++++++++++++++++++ > > hw/i386/multiboot2.h | 16 + > > hw/i386/x86.c | 8 + > > include/standard-headers/linux/qemu_fw_cfg.h | 2 + > > pc-bios/optionrom/Makefile | 2 +- > > pc-bios/optionrom/multiboot2.S | 324 +++++++++++ > > pc-bios/optionrom/optionrom.h | 1 + > > 8 files changed, 905 insertions(+), 1 deletion(-) > > create mode 100644 hw/i386/multiboot2.c > > create mode 100644 hw/i386/multiboot2.h > > create mode 100644 pc-bios/optionrom/multiboot2.S > > > > diff --git a/hw/i386/meson.build b/hw/i386/meson.build > > index 369c6bf823..3ccf9d7398 100644 > > --- a/hw/i386/meson.build > > +++ b/hw/i386/meson.build > > @@ -4,6 +4,7 @@ i386_ss.add(files( > > 'kvmvapic.c', > > 'e820_memory_layout.c', > > 'multiboot.c', > > + 'multiboot2.c', > > 'x86.c', > > )) > > > > diff --git a/hw/i386/multiboot2.c b/hw/i386/multiboot2.c > > new file mode 100644 > > index 0000000000..6d1c07cc40 > > --- /dev/null > > +++ b/hw/i386/multiboot2.c > > @@ -0,0 +1,552 @@ > > +/* > > + * QEMU PC System Emulator > > + * > > + * Copyright (c) 2003-2004 Fabrice Bellard > > + * > > + * 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 > > + * THE AUTHORS OR COPYRIGHT HOLDERS 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. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qemu/option.h" > > +#include "cpu.h" > > +#include "hw/nvram/fw_cfg.h" > > +#include "multiboot2.h" > > +#include "hw/loader.h" > > +#include "elf.h" > > +#include "sysemu/sysemu.h" > > +#include "qemu/error-report.h" > > + > > +/* Show multiboot debug output */ > > +/* #define DEBUG_MULTIBOOT2 */ > > + > > +#ifdef DEBUG_MULTIBOOT2 > > +#define mb_debug(a...) error_report(a) > > +#else > > +#define mb_debug(a...) > > +#endif > > + > > +#define MULTIBOOT_MEM 0x8000 > > + > > +#if MULTIBOOT_MEM > 0xf0000 > > +#error multiboot struct needs to fit in 16 bit real mode > > +#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. */ > > +#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_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_ARCHITECTURE_I386 0 > > +#define MULTIBOOT_ARCHITECTURE_X86_64 1 > > +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 > > +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 > > + > > +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 > > +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 > > + > > +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; > > + multiboot_uint32_t width; > > + multiboot_uint32_t height; > > + multiboot_uint32_t depth; > > +}; > > + > > +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; > > +} __attribute__((packed)); > > + > > +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]; > > +}; > > + > > +typedef struct { > > + /* buffers holding kernel and boot info tags */ > > + void *mb_buf; > > + void *mb_tags; > > + /* address in target */ > > + hwaddr mb_buf_phys; > > + /* size of mb_buf in bytes */ > > + unsigned mb_buf_size; > > + /* size of tags in bytes */ > > + unsigned mb_tags_size; > > +} MultibootState; > > + > > +static void mb_add_cmdline(MultibootState *s, const char *cmdline) > > +{ > > + int len = strlen(cmdline) + 1; > > + struct multiboot_tag_string *tag; > > + unsigned new_size = s->mb_tags_size; > > + > > + new_size += sizeof(struct multiboot_tag_string) + len; > > + new_size = (new_size + 7) & ~7; > > + > > + s->mb_tags = g_realloc(s->mb_tags, new_size); > > + tag = (struct multiboot_tag_string *)(s->mb_tags + s->mb_tags_size); > > + s->mb_tags_size = new_size; > > + > > + tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; > > + tag->size = sizeof(struct multiboot_tag_string) + len; > > + > > + strncpy((char *)tag->string, cmdline, len); > > +} > > + > > +static void mb_add_basic_meminfo(MultibootState *s, > > + uint32_t mem_lower, > > + uint32_t mem_upper) > > +{ > > + struct multiboot_tag_basic_meminfo *tag; > > + unsigned new_size = s->mb_tags_size; > > + > > + new_size += sizeof(struct multiboot_tag_basic_meminfo); > > + new_size = (new_size + 7) & ~7; > > + > > + s->mb_tags = g_realloc(s->mb_tags, new_size); > > + tag = (struct multiboot_tag_basic_meminfo *)(s->mb_tags + > s->mb_tags_size); > > + s->mb_tags_size = new_size; > > + > > + tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; > > + tag->size = sizeof(struct multiboot_tag_basic_meminfo); > > + tag->mem_lower = mem_lower; > > + tag->mem_upper = mem_upper; > > +} > > + > > +int load_multiboot2(X86MachineState *x86ms, > > + FWCfgState *fw_cfg, > > + FILE *f, > > + const char *kernel_filename, > > + const char *initrd_filename, > > + const char *kernel_cmdline, > > + int kernel_file_size, > > + uint8_t *header) > > +{ > > + MultibootState mbs; > > + uint32_t architecture = 0; > > + uint32_t header_length = 0; > > + uint32_t mh_entry_addr; > > + uint32_t mh_load_addr; > > + uint32_t mb_kernel_size; > > + int is_multiboot = 0; > > + int i; > > + > > + /* The header is in the first 32k with alignment 8. */ > > + for (i = 0; (i < 32768 - 15) && (i < kernel_file_size - 15); i += > 8) { > > + if (ldl_p(header + i) == MULTIBOOT2_HEADER_MAGIC) { > > + uint32_t checksum = ldl_p(header + i + 12); > > + architecture = ldl_p(header + i + 4); > > + header_length = ldl_p(header + i + 8); > > + checksum += MULTIBOOT2_HEADER_MAGIC; > > + checksum += architecture; > > + checksum += header_length; > > + > > + if (!checksum) { > > + is_multiboot = 1; > > + break; > > + } > > + } > > + } > > + > > + if (!is_multiboot) { > > + return 0; > > + } > > + > > + switch (architecture) { > > + case MULTIBOOT_ARCHITECTURE_I386: > > + mb_debug("architecture i386\n"); > > + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_64BIT, 0); > > + break; > > + case MULTIBOOT_ARCHITECTURE_X86_64: > > + mb_debug("architecture x86_64\n"); > > + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_64BIT, 1); > > + break; > > + default: > > + error_report("multiboot2 architecture must be i386 or x86_64."); > > + exit(1); > > + } > > + > > + mb_debug("I believe we found a multiboot2 image!\n"); > > + memset(&mbs, 0, sizeof(mbs)); > > + > > + /* Add size field to multiboot info */ > > + mbs.mb_tags = g_malloc(8); > > + mbs.mb_tags_size = 8; > > + > > + /* Commandline support */ > > + char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2]; > > + > > + snprintf(kcmdline, sizeof(kcmdline), "%s %s", > > + kernel_filename, kernel_cmdline); > > + mb_add_cmdline(&mbs, kcmdline); > > + > > + /* Basic memory info */ > > + mb_add_basic_meminfo(&mbs, 640, (x86ms->above_4g_mem_size / 1024) - > 1024); > > + > > + /* Load kernel */ > > + /* FIXME: only elf support for now */ > > + { > > + uint64_t elf_entry; > > + uint64_t elf_low, elf_high; > > + int kernel_size; > > + int size; > > + > > + fclose(f); > > + > > + if (((struct elf64_hdr *)header)->e_machine == EM_X86_64) { > > + mb_debug("64bit elf, I hope you know what you are doing\n"); > > + } > > + > > + kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, > &elf_entry, > > + &elf_low, &elf_high, NULL, 0, > I386_ELF_MACHINE, > > + 0, 0); > > + > > + if (kernel_size < 0) { > > + error_report("Error while loading elf kernel"); > > + exit(1); > > + } > > + > > + mh_load_addr = elf_low; > > + mb_kernel_size = elf_high - elf_low; > > + mh_entry_addr = elf_entry; > > + mbs.mb_buf = g_malloc(mb_kernel_size); > > + size = rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size); > > + > > + if (size != mb_kernel_size) { > > + error_report("Error while fetching elf kernel from rom"); > > + exit(1); > > + } > > + > > + mb_debug("loading multiboot-elf kernel (0x%x bytes)" > > + " with entry 0x%zx\n", > > + mb_kernel_size, (size_t)mh_entry_addr); > > + } > > + > > + /* Align to next page */ > > + /* FIXME: honor align header tag */ > > + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size); > > + > > + /* FIXME: load modules */ > > + /* FIXME: add other tags */ > > + > > + /* The multiboot2 bootrom will add the mmap and end tags. */ > > + > > + /* Set size of multiboot infos */ > > + multiboot_uint64_t *size = mbs.mb_tags; > > + *size = mbs.mb_tags_size; > > + > > + /* Display infos */ > > + mb_debug("kernel_entry = 0x%zx\n", (size_t)mh_entry_addr); > > + mb_debug("kernel_addr = 0x%zx\n", (size_t)mh_load_addr); > > + mb_debug("kernel_size = 0x%zx\n", (size_t)mbs.mb_buf_size); > > + mb_debug("initrd_addr = 0x%zx\n", (size_t)MULTIBOOT_MEM); > > + mb_debug("initrd_size = 0x%zx\n", (size_t)mbs.mb_tags_size); > > + > > + /* Add extra space for dynamic tags */ > > + mbs.mb_tags_size += 4096; > > + mbs.mb_tags = g_realloc(mbs.mb_tags, mbs.mb_tags_size); > > + > > + /* Pass variables to option rom */ > > + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr); > > + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); > > + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size); > > + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, > > + mbs.mb_buf, mbs.mb_buf_size); > > + > > + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, MULTIBOOT_MEM); > > + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, mbs.mb_tags_size); > > + fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mbs.mb_tags, > > + mbs.mb_tags_size); > > + > > + option_rom[nb_option_roms].name = "multiboot2.bin"; > > + option_rom[nb_option_roms].bootindex = 0; > > + nb_option_roms++; > > + > > + return 1; /* yes, we are multiboot */ > > +} > > diff --git a/hw/i386/multiboot2.h b/hw/i386/multiboot2.h > > new file mode 100644 > > index 0000000000..d98d4723c7 > > --- /dev/null > > +++ b/hw/i386/multiboot2.h > > @@ -0,0 +1,16 @@ > > +#ifndef QEMU_MULTIBOOT2_H > > +#define QEMU_MULTIBOOT2_H > > + > > +#include "hw/nvram/fw_cfg.h" > > +#include "hw/i386/x86.h" > > + > > +int load_multiboot2(X86MachineState *x86ms, > > + FWCfgState *fw_cfg, > > + FILE *f, > > + const char *kernel_filename, > > + const char *initrd_filename, > > + const char *kernel_cmdline, > > + int kernel_file_size, > > + uint8_t *header); > > + > > +#endif > > diff --git a/hw/i386/x86.c b/hw/i386/x86.c > > index 2b6291ad8d..f40f0ad8ec 100644 > > --- a/hw/i386/x86.c > > +++ b/hw/i386/x86.c > > @@ -53,6 +53,7 @@ > > #include "hw/nmi.h" > > #include "hw/loader.h" > > #include "multiboot.h" > > +#include "multiboot2.h" > > #include "elf.h" > > #include "standard-headers/asm-x86/bootparam.h" > > #include CONFIG_DEVICES > > @@ -845,6 +846,13 @@ void x86_load_linux(X86MachineState *x86ms, > > kernel_cmdline, kernel_size, header)) { > > return; > > } > > + /* > > + * Check multiboot2 kernel. > > + */ > > + if (load_multiboot2(x86ms, fw_cfg, f, kernel_filename, > initrd_filename, > > + kernel_cmdline, kernel_size, header)) { > > + return; > > + } > > /* > > * Check if the file is an uncompressed kernel file (ELF) and > load it, > > * saving the PVH entry point used by the x86/HVM direct boot > ABI. > > diff --git a/include/standard-headers/linux/qemu_fw_cfg.h > b/include/standard-headers/linux/qemu_fw_cfg.h > > index cb93f6678d..f9b877e14d 100644 > > --- a/include/standard-headers/linux/qemu_fw_cfg.h > > +++ b/include/standard-headers/linux/qemu_fw_cfg.h > > @@ -37,6 +37,8 @@ > > #define FW_CFG_FILE_FIRST 0x20 > > #define FW_CFG_FILE_SLOTS_MIN 0x10 > > > > +#define FW_CFG_KERNEL_64BIT 0x21 > > + > > #define FW_CFG_WRITE_CHANNEL 0x4000 > > #define FW_CFG_ARCH_LOCAL 0x8000 > > #define FW_CFG_ENTRY_MASK (~(FW_CFG_WRITE_CHANNEL | > FW_CFG_ARCH_LOCAL)) > > diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile > > index 30d07026c7..21094232e0 100644 > > --- a/pc-bios/optionrom/Makefile > > +++ b/pc-bios/optionrom/Makefile > > @@ -2,7 +2,7 @@ include config.mak > > SRC_DIR := $(TOPSRC_DIR)/pc-bios/optionrom > > VPATH = $(SRC_DIR) > > > > -all: multiboot.bin multiboot_dma.bin linuxboot.bin linuxboot_dma.bin > kvmvapic.bin pvh.bin > > +all: multiboot.bin multiboot_dma.bin multiboot2.bin linuxboot.bin > linuxboot_dma.bin kvmvapic.bin pvh.bin > > # Dummy command so that make thinks it has done something > > @true > > > > diff --git a/pc-bios/optionrom/multiboot2.S > b/pc-bios/optionrom/multiboot2.S > > new file mode 100644 > > index 0000000000..a27c2a1f3c > > --- /dev/null > > +++ b/pc-bios/optionrom/multiboot2.S > > @@ -0,0 +1,324 @@ > > +/* > > + * Multiboot2 Option ROM > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License > > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > > + * > > + * Original Multiboot Option ROM: > > + * Copyright Novell Inc, 2009 > > + * Authors: Alexander Graf <ag...@suse.de> > > + * > > + * Adaption to Multiboot2 specs: > > + * Copyright Goswin von Brederlow, 2011 > > + * Authors: Goswin von Brederlow <goswin-...@web.de> > > + * > > + * Cleaned up and merged by: > > + * Copyright Jens Nyberg, 2024 > > + * Authors: Jens Nyberg <jens.nyb...@gmail.com> > > + * > > + */ > > + > > +#include "optionrom.h" > > + > > +#define BOOT_ROM_PRODUCT "multiboot2 loader" > > + > > +#define MULTIBOOT_MAGIC 0x36d76289 > > + > > +#define GS_PROT_JUMP 0 > > +#define GS_GDT_DESC 8 > > + > > +/* Memory layout (page tables only for 64 bit): > > + * 0x2000 L4 page table > > + * 0x3000 L3 page table > > + * 0x4000 L2 page table > > + * ... > > + * 0x7000 L2 page table > > + * 0x8000 bootinfo tags > > + */ > > + > > +#define PGTABLE 0x2000 > > + > > +BOOT_ROM_START > > + > > +run_multiboot: > > + > > + cli > > + cld > > + > > + mov %cs, %eax > > + shl $0x4, %eax > > + mov %eax, %ebp /* used below to jump to 64bit */ > > + > > + /* set up a long jump descriptor that is PC relative */ > > + > > + /* move stack memory to %gs */ > > + mov %ss, %ecx > > + shl $0x4, %ecx > > + mov %esp, %ebx > > + add %ebx, %ecx > > + sub $0x20, %ecx > > + sub $0x30, %esp > > + shr $0x4, %ecx > > + mov %cx, %gs > > + > > + /* now push the indirect jump decriptor there */ > > + mov (prot_jump), %ebx > > + add %eax, %ebx > > + movl %ebx, %gs:GS_PROT_JUMP > > + mov $8, %bx > > + movw %bx, %gs:GS_PROT_JUMP + 4 > > + > > + /* fix the gdt descriptor to be PC relative */ > > + movw (gdt_desc), %bx > > + movw %bx, %gs:GS_GDT_DESC > > + movl (gdt_desc+2), %ebx > > + add %eax, %ebx > > + movl %ebx, %gs:GS_GDT_DESC + 2 > > + > > + xor %eax, %eax > > + mov %eax, %es > > + > > + /* Read the bootinfo struct into RAM */ > > + read_fw_blob(FW_CFG_INITRD) > > + > > + /* FS = bootinfo_struct */ > > + read_fw FW_CFG_INITRD_ADDR > > + shr $4, %eax > > + mov %ax, %fs > > + mov %ax, %es /* for int 0x15 */ > > + > > + /* %fs:%edi = bootinfo size = offset of mmap tag */ > > + movl %fs:0, %edi > > + > > +#define MULTIBOOT_TAG_TYPE_MMAP 6 > > + /* Create mmap tag */ > > + movl $6, %fs:0(%edi) /* type mmap */ > > + movl $24, %fs:8(%edi) /* entry_size */ > > + movl $0, %fs:12(%edi) /* entry_version */ > > + > > + /* Initialize multiboot mmap structs using int 0x15(e820) */ > > + xor %ebx, %ebx > > + /* mmap starts at byte 16 */ > > + addl $16, %edi > > + > > +mmap_loop: > > + /* entry size (mmap struct) & max buffer size (int15) */ > > + movl $20, %ecx > > + /* e820 */ > > + movl $0x0000e820, %eax > > + /* 'SMAP' magic */ > > + movl $0x534d4150, %edx > > + int $0x15 > > + > > +mmap_check_entry: > > + /* last entry? then we're done */ > > + jb mmap_done > > + and %bx, %bx > > + jz mmap_done > > + /* valid entry, so let's loop on */ > > + > > +mmap_next_entry: > > + /* Advance %edi by sizeof(struct multiboot_mmap_entry) = 24 */ > > + addl $24, %edi > > + jmp mmap_loop > > + > > +mmap_done: > > + addl $24, %edi /* advance past entry */ > > + /* Create end tag */ > > + movl $0, %fs:0(%edi) /* type */ > > + movl $8, %fs:4(%edi) /* size */ > > + leal 8(%edi), %ebx /* size of all tags */ > > + > > + /* set mmap tag size */ > > + mov %edi, %eax /* save offset after mmap */ > > + mov %fs:0, %edi /* offset of mmap tag */ > > + sub %edi, %eax /* size of mmap tag */ > > + movl %eax, %fs:4(%edi) /* size */ > > + > > + /* Store size of all tags */ > > + movl %ebx, %fs:0 > > + > > +real_to_prot: > > + /* Load the GDT before going into protected mode */ > > +lgdt: > > + data32 lgdt %gs:GS_GDT_DESC > > + > > + /* get us to protected mode now */ > > + movl $1, %eax > > + movl %eax, %cr0 > > + > > + /* the LJMP sets CS for us and gets us to 32-bit */ > > +ljmp32: > > + data32 ljmp *%gs:GS_PROT_JUMP > > + > > +prot_mode: > > +.code32 > > + /* initialize all other segments */ > > + movl $0x10, %eax > > + movl %eax, %ss > > + movl %eax, %ds > > + movl %eax, %es > > + movl %eax, %fs > > + movl %eax, %gs > > + > > + /* Read the kernel and modules into RAM */ > > + read_fw_blob(FW_CFG_KERNEL) > > + > > + /* 32bit or 64bit mode? */ > > + read_fw FW_CFG_KERNEL_64BIT > > + cmpl $0, %eax > > + jne ljmp64 > > + > > + /* Jump off to the kernel */ > > + read_fw FW_CFG_KERNEL_ENTRY > > + mov %eax, %ecx > > + > > + /* EBX contains a pointer to the bootinfo struct */ > > + read_fw FW_CFG_INITRD_ADDR > > + movl %eax, %ebx > > + > > + /* EAX has to contain the magic */ > > + movl $MULTIBOOT_MAGIC, %eax > > +ljmp2: > > + /* Jump to kernel in 32bit mode */ > > + jmp *%ecx > > + > > +/******************************************************************/ > > +/* Set up 64bit mode */ > > +/******************************************************************/ > > +ljmp64: > > + /* Enable PAE */ > > + movl %cr4, %eax > > + btsl $5, %eax > > + movl %eax, %cr4 > > + > > + /* > > + * Build early 4G boot pagetable > > + */ > > + /* Initialize Page tables to 0 */ > > + leal PGTABLE, %edi > > + xorl %eax, %eax > > + movl $((4096*6)/4), %ecx > > + rep stosl > > + > > + /* Build Level 4 */ > > + leal PGTABLE + 0, %edi > > + leal 0x1007 (%edi), %eax > > + movl %eax, 0(%edi) > > + > > + /* Build Level 3 */ > > + leal PGTABLE + 0x1000, %edi > > + leal 0x1007(%edi), %eax > > + movl $4, %ecx > > +1: movl %eax, 0x00(%edi) > > + addl $0x00001000, %eax > > + addl $8, %edi > > + decl %ecx > > + jnz 1b > > + > > + /* Build Level 2 */ > > + leal PGTABLE + 0x2000, %edi > > + movl $0x00000183, %eax > > + movl $2048, %ecx > > +1: movl %eax, 0(%edi) > > + addl $0x00200000, %eax > > + addl $8, %edi > > + decl %ecx > > + jnz 1b > > + > > + /* Load Level 4 page table (page 128) */ > > + leal PGTABLE, %eax > > + movl %eax, %cr3 > > + > > + /* Enable long mode */ > > + movl $0xc0000080, %ecx > > + rdmsr > > + btsl $8, %eax > > + wrmsr > > + > > + /* enable paging to activate long mode */ > > + movl %cr0, %eax > > + btsl $1, %eax /* protected mode */ > > + btsl $31, %eax /* paging */ > > + movl %eax, %cr0 > > + > > + /* Jump off to the kernel */ > > + read_fw FW_CFG_KERNEL_ENTRY > > + movl %eax, %ebx > > + > > + /* pointer to the bootinfo struct */ > > + read_fw FW_CFG_INITRD_ADDR > > + movl %eax, %ecx > > + > > + /* jump to 64bit mode */ > > + pushl $0x28 > > + leal startup_64(%ebp), %eax > > + pushl %eax > > + lret > > + > > + .code64 > > +startup_64: > > +_startup_64: > > + /* EDI has to contain the magic, ESI the boot info */ > > + movl %ebx, %eax /* kernel entry address */ > > + movl %ecx, %esi /* pointer to boot info */ > > + movl $MULTIBOOT_MAGIC, %edi > > + jmp *%rax > > + > > +color: /* collor me silly */ > > + addl $0x1,0xb8000 > > + jmp color > > + > > +/******************************************************************/ > > + > > + > > +/* Variables */ > > +.align 4, 0 > > +prot_jump: .long prot_mode > > + .short 8 > > + > > +.align 4, 0 > > +gdt: > > + /* 0x00: null segment */ > > +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 > > + > > + /* 0x08: code segment */ > > + /* base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k */ > > +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 > > + > > + /* 0x10: data segment */ > > + /* base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k */ > > +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 > > + > > + /* 0x18: code segment */ > > + /* base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, > 1b */ > > +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00 > > + > > + /* 0x20: data segment */ > > + /* base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b */ > > +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 > > + > > + /* 0x28: code segment */ > > + /* base=0, limit=0xfffff, type=64bit code exec/read, DPL=0, 4k */ > > +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xaf, 0x00 > > + > > + /* 0x30: ts descriptor */ > > +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x80, 0x00 > > + /* 0x38: ts continued */ > > +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 > > + > > +gdt_desc: > > +.short (8 * 8) - 1 > > +.long gdt > > + > > +BOOT_ROM_END > > diff --git a/pc-bios/optionrom/optionrom.h > b/pc-bios/optionrom/optionrom.h > > index 7bcdf0eeb2..6f758c58be 100644 > > --- a/pc-bios/optionrom/optionrom.h > > +++ b/pc-bios/optionrom/optionrom.h > > @@ -33,6 +33,7 @@ > > #define FW_CFG_SETUP_ADDR 0x16 > > #define FW_CFG_SETUP_SIZE 0x17 > > #define FW_CFG_SETUP_DATA 0x18 > > +#define FW_CFG_KERNEL_64BIT 0x21 > > > > #define BIOS_CFG_IOPORT_CFG 0x510 > > #define BIOS_CFG_IOPORT_DATA 0x511 > > -- > > 2.43.0 > > > > > > With regards, > Daniel > -- > |: https://berrange.com -o- > https://www.flickr.com/photos/dberrange :| > |: https://libvirt.org -o- > https://fstop138.berrange.com :| > |: https://entangle-photo.org -o- > https://www.instagram.com/dberrange :| > >