Package: qemu-kvm
Version: 0.14.0+dfsg-1~tls
Severity: normal

Hi,

I've included Alexander Graf as CC in this mail since he is the author
of the original multiboot support. Hi Alexander.

Attached is an update for the multiboot2 patch. It adds supports for
MULTIBOOT_ARCHITECTURE_X86_64 and switches to 64bit mode before
calling such a kernel. The patch is still incomplete, as in doesn't
support all of the specs, but it is getting there. Now it is only a
matter of adding the relevant tags to the C code though.


Missing tags that should be there:

MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME
MULTIBOOT_TAG_TYPE_MODULE
MULTIBOOT_TAG_TYPE_ELF_SECTIONS

Tags that might be good to also support:

MULTIBOOT_TAG_TYPE_VBE
MULTIBOOT_TAG_TYPE_FRAMEBUFFER
MULTIBOOT_TAG_TYPE_APM
MULTIBOOT_TAG_TYPE_ACPI_NEW
MULTIBOOT_TAG_TYPE_NETWORK


Also attached a mini kernel for 64bit based on the 32bit example
kernel from the multiboot2 specs.

MfG
        Goswin

Attachment: multiboot2-kernel64.tar.gz
Description: GNU Zip compressed data

Description: multiboot2 support
 This patch adds support for the new multiboot2 format. It supports a
 single kernel (no modules yet) and sets the cmdline, basic_meminfo
 and mmap tags in the boot info. This is sufficient to boot the
 example kernel for multiboot2. It also adds support for true 64bit
 kernels, calling the kernels entry point in 64bit mode.
Author: Goswin von Brederlow <[email protected]>
Bug-Debian: http://bugs.debian.org/621529
Last-Update: 2011-04-18

---

Index: qemu-kvm-0.14.0+dfsg/Makefile.target
===================================================================
--- qemu-kvm-0.14.0+dfsg.orig/Makefile.target   2011-04-08 14:18:18.000000000 
+0200
+++ qemu-kvm-0.14.0+dfsg/Makefile.target        2011-04-08 14:18:18.000000000 
+0200
@@ -228,7 +228,7 @@
 obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += extboot.o
-obj-i386-y += debugcon.o multiboot.o
+obj-i386-y += debugcon.o multiboot.o multiboot2.o
 obj-i386-y += pc_piix.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 obj-i386-y += testdev.o
Index: qemu-kvm-0.14.0+dfsg/pc-bios/optionrom/Makefile
===================================================================
--- qemu-kvm-0.14.0+dfsg.orig/pc-bios/optionrom/Makefile        2011-04-08 
14:18:18.000000000 +0200
+++ qemu-kvm-0.14.0+dfsg/pc-bios/optionrom/Makefile     2011-04-08 
14:18:18.000000000 +0200
@@ -14,7 +14,7 @@
 CFLAGS += $(call cc-option, $(CFLAGS), -fno-stack-protector)
 QEMU_CFLAGS = $(CFLAGS)
 
-build-all: multiboot.bin linuxboot.bin
+build-all: multiboot.bin multiboot2.bin linuxboot.bin
 
 build-all: extboot.bin vapic.bin
 
Index: qemu-kvm-0.14.0+dfsg/pc-bios/optionrom/multiboot2.S
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ qemu-kvm-0.14.0+dfsg/pc-bios/optionrom/multiboot2.S 2011-04-18 
18:49:45.000000000 +0200
@@ -0,0 +1,313 @@
+/*
+ * 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 <[email protected]>
+ *
+ * Adaption to Multiboot2 specs:
+ * Copyright Goswin von Brederlow, 2011
+ *   Authors: Goswin von Brederlow <[email protected]>
+ *
+ */
+
+#include "optionrom.h"
+
+#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 */
+.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
Index: qemu-kvm-0.14.0+dfsg/hw/multiboot2.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ qemu-kvm-0.14.0+dfsg/hw/multiboot2.c        2011-04-18 18:45:00.000000000 
+0200
@@ -0,0 +1,641 @@
+/*
+ * 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 "hw.h"
+#include "fw_cfg.h"
+#include "multiboot2.h"
+#include "loader.h"
+#include "elf.h"
+#include "sysemu.h"
+
+/* Show multiboot debug output */
+#define DEBUG_MULTIBOOT
+
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## 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
+
+/**********************************************************************
+ * multiboot2.h                                                       *
+ **********************************************************************/
+/*  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_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
+
+#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;
+  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];
+};
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! MULTIBOOT_HEADER */
+
+
+/**********************************************************************
+ * multiboot2 loader based on multiboot.c                             *
+ * Copyright 2011 Goswin von Brederlow <[email protected]>            *
+ **********************************************************************/
+
+typedef struct {
+    /* buffers holding kernel and boot info tags */
+    void *mb_buf;
+    void *mb_tags;
+    /* address in target */
+    target_phys_addr_t 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;
+
+    mb_debug("mb_add_cmline: len = %d '%s'\n", len, cmdline);
+
+    new_size += sizeof(struct multiboot_tag_string) + len;
+    new_size = (new_size + 7) & ~7;
+
+    /* allocate space for cmdline tag */
+    s->mb_tags = qemu_realloc(s->mb_tags, new_size);
+    tag = (struct multiboot_tag_string *)(s->mb_tags + s->mb_tags_size);
+    s->mb_tags_size = new_size;
+
+    /* Fill tag */
+    tag->type = MULTIBOOT_TAG_TYPE_CMDLINE;
+    tag->size = sizeof(struct multiboot_tag_string) + len;
+    pstrcpy((char*)tag->string, len, cmdline);
+}
+
+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;
+
+    /* allocate space for basic_meminfo tag */
+    s->mb_tags = qemu_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;
+
+    /* Fill tag */
+    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(void *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;
+    int i, is_multiboot = 0;
+    uint32_t architecture = 0;
+    uint32_t header_length = 0;
+    struct multiboot_header_tag *current_tag, *last_tag;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+
+    /* Ok, let's see if it is a multiboot image.
+       The header is in the first 32k. */
+    for (i = 0; (i < 32768 - 15) && (i < kernel_file_size - 15) ; i += 4) {
+        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; /* no multiboot */
+
+    switch(architecture) {
+    case MULTIBOOT_ARCHITECTURE_I386:
+       // Start in 32bit mode
+       mb_debug("qemu: architecture i386\n");
+       fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_64BIT, 0);
+       break;
+    case MULTIBOOT_ARCHITECTURE_X86_64:
+       // Start in 64bit mode
+       mb_debug("qemu: architecture x86_64\n");
+       fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_64BIT, 1);
+       break;
+    default:
+        fprintf(stderr, "qemu: multiboot2 architecture must be i386 or 
x86_64.\n");
+       exit(1);
+    }
+
+    mb_debug("qemu: I believe we found a multiboot2 image!\n");
+    mb_debug("header_length = %#x\n", header_length);
+
+    /* Zero out multiboot infos */
+    memset(&mbs, 0, sizeof(mbs));
+
+    current_tag = (struct multiboot_header_tag *)(header + i + sizeof(struct 
multiboot_header));
+    last_tag = (struct multiboot_header_tag *)(header + header_length);
+    /* FIXME: scan header tags */
+
+    /* Add size field to multiboot info */
+    mbs.mb_tags = qemu_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, (ram_size / 1024) - 1024);
+
+    /* Load kernel */
+    /* FIXME: only elf support for now */
+    {
+       uint64_t elf_entry;
+        uint64_t elf_low, elf_high;
+        int kernel_size;
+        fclose(f);
+
+        if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
+           mb_debug("qemu: 64bit elf, I hope you know what you are doing\n");
+        }
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_low, &elf_high, 0, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = elf_low;
+        mb_kernel_size = elf_high - elf_low;
+        mh_entry_addr = elf_entry;
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != 
mb_kernel_size) {
+            fprintf(stderr, "Error while fetching elf kernel from rom\n");
+            exit(1);
+        }
+
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry 
%#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("qemu: kernel_entry = %#zx\n", (size_t)mh_entry_addr);
+    mb_debug("      kernel_addr  = %#zx\n", (size_t)mh_load_addr);
+    mb_debug("      kernel_size  = %#zx\n", (size_t)mbs.mb_buf_size);
+    unsigned char *p = mbs.mb_buf;
+    for(i = 0; i < 0xff; ++i, ++p) {
+       if (i % 16 == 0) mb_debug("\n0x%02x:", i);
+       mb_debug(" %02x", *p);
+    }
+    mb_debug("\n");
+    mb_debug("      initrd_addr  = %#zx\n", (size_t)MULTIBOOT_MEM);
+    mb_debug("      initrd_size  = %#zx\n", (size_t)mbs.mb_tags_size);
+    p = mbs.mb_tags;
+    for(i = 0; i < mbs.mb_tags_size; ++i, ++p) {
+       if (i % 16 == 0) mb_debug("\n0x%02x:", i);
+       mb_debug(" %02x", *p);
+    }
+    mb_debug("\n");
+
+    /* Add extra space for dynamic tags */
+    mbs.mb_tags_size += 4096;
+    mbs.mb_tags = qemu_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 */
+}
Index: qemu-kvm-0.14.0+dfsg/hw/pc.c
===================================================================
--- qemu-kvm-0.14.0+dfsg.orig/hw/pc.c   2011-04-08 14:18:18.000000000 +0200
+++ qemu-kvm-0.14.0+dfsg/hw/pc.c        2011-04-08 14:18:18.000000000 +0200
@@ -35,6 +35,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "multiboot.h"
+#include "multiboot2.h"
 #include "mc146818rtc.h"
 #include "msix.h"
 #include "sysbus.h"
@@ -680,6 +681,9 @@
         if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
                            kernel_cmdline, kernel_size, header))
             return;
+        if (load_multiboot2(fw_cfg, f, kernel_filename, initrd_filename,
+                           kernel_cmdline, kernel_size, header))
+            return;
        protocol = 0;
     }
 
Index: qemu-kvm-0.14.0+dfsg/hw/multiboot2.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ qemu-kvm-0.14.0+dfsg/hw/multiboot2.h        2011-04-08 14:18:18.000000000 
+0200
@@ -0,0 +1,12 @@
+#ifndef QEMU_MULTIBOOT2_H
+#define QEMU_MULTIBOOT2_H
+
+int load_multiboot2(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header);
+
+#endif
--- qemu-kvm-0.14.0+dfsg.orig/hw/fw_cfg.h
+++ qemu-kvm-0.14.0+dfsg/hw/fw_cfg.h
@@ -27,8 +27,9 @@
 #define FW_CFG_SETUP_SIZE       0x17
 #define FW_CFG_SETUP_DATA       0x18
 #define FW_CFG_FILE_DIR         0x19
+#define FW_CFG_KERNEL_64BIT     0x20
 
-#define FW_CFG_FILE_FIRST       0x20
+#define FW_CFG_FILE_FIRST       0x23
 #define FW_CFG_FILE_SLOTS       0x10
 #define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST+FW_CFG_FILE_SLOTS)
 

Reply via email to