aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--fw_cfg.c53
-rw-r--r--include/e820.h2
-rw-r--r--include/multiboot.h66
-rw-r--r--linuxboot.c5
-rw-r--r--main.c2
6 files changed, 125 insertions, 5 deletions
diff --git a/README b/README
index a4f4f0b..360ad7c 100644
--- a/README
+++ b/README
@@ -46,4 +46,4 @@ TODO
====
* SMBIOS tables
-* Multiboot loading
+* Multiboot loading from pflash
diff --git a/fw_cfg.c b/fw_cfg.c
index 79aeb70..684c0f6 100644
--- a/fw_cfg.c
+++ b/fw_cfg.c
@@ -1,9 +1,11 @@
#include "bios.h"
+#include "e820.h"
#include "stdio.h"
#include "ioport.h"
#include "string.h"
#include "fw_cfg.h"
#include "linuxboot.h"
+#include "multiboot.h"
struct fw_cfg_file {
uint32_t size;
@@ -54,6 +56,55 @@ void fw_cfg_file_select(int id)
fw_cfg_select(files[id].select);
}
+/* Multiboot trampoline. QEMU does the ELF parsing. */
+
+static void boot_multiboot_from_fw_cfg(void)
+{
+ void *kernel_addr, *kernel_entry;
+ struct mb_info *mb;
+ struct mb_mmap_entry *mbmem;
+ int i;
+ uint32_t sz;
+
+ fw_cfg_select(FW_CFG_KERNEL_SIZE);
+ sz = fw_cfg_readl_le();
+ if (!sz)
+ panic();
+
+ fw_cfg_select(FW_CFG_KERNEL_ADDR);
+ kernel_addr = (void *) fw_cfg_readl_le();
+ fw_cfg_select(FW_CFG_KERNEL_DATA);
+ fw_cfg_read(kernel_addr, sz);
+
+ fw_cfg_select(FW_CFG_INITRD_SIZE);
+ sz = fw_cfg_readl_le();
+ if (!sz)
+ panic();
+
+ fw_cfg_select(FW_CFG_INITRD_ADDR);
+ mb = (struct mb_info *) fw_cfg_readl_le();
+ fw_cfg_select(FW_CFG_INITRD_DATA);
+ fw_cfg_read(mb, sz);
+
+ mb->mem_lower = 639;
+ mb->mem_upper = (lowmem - 1048576) >> 10;
+
+ mb->mmap_length = 0;
+ for (i = 0; i < e820->nr_map; i++) {
+ mbmem = (struct mb_mmap_entry *) (mb->mmap_addr + mb->mmap_length);
+ mbmem->size = sizeof(e820->map[i]);
+ mbmem->base_addr = e820->map[i].addr;
+ mbmem->length = e820->map[i].size;
+ mbmem->type = e820->map[i].type;
+ mb->mmap_length += sizeof(*mbmem);
+ }
+
+ fw_cfg_select(FW_CFG_KERNEL_ENTRY);
+ kernel_entry = (void *) fw_cfg_readl_le();
+ asm volatile("jmp *%2" : : "a" (0x2badb002), "b"(mb), "c"(kernel_entry));
+ panic();
+}
+
void boot_from_fwcfg(void)
{
struct linuxboot_args args;
@@ -79,7 +130,7 @@ void boot_from_fwcfg(void)
fw_cfg_read(args.header, sizeof(args.header));
if (!parse_bzimage(&args))
- return;
+ boot_multiboot_from_fw_cfg();
/* SETUP_DATA already selected */
if (args.setup_size > sizeof(args.header))
diff --git a/include/e820.h b/include/e820.h
index 085df6a..60483e8 100644
--- a/include/e820.h
+++ b/include/e820.h
@@ -29,6 +29,8 @@ struct e820map {
struct e820entry map[];
};
+extern struct e820map *e820;
+
#define ISA_START_ADDRESS 0xa0000
#define ISA_END_ADDRESS 0x100000
diff --git a/include/multiboot.h b/include/multiboot.h
new file mode 100644
index 0000000..d3d4528
--- /dev/null
+++ b/include/multiboot.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * 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.
+ */
+
+#ifndef MULTIBOOT_H
+#define MULTIBOOT_H
+
+#include <stdint.h>
+
+struct mb_info {
+ uint32_t flags;
+ uint32_t mem_lower;
+ uint32_t mem_upper;
+ uint32_t boot_device;
+ uint32_t cmdline;
+ uint32_t mods_count;
+ uint32_t mods_addr;
+ char syms[16];
+ uint32_t mmap_length;
+ uint32_t mmap_addr;
+ uint32_t drives_length;
+ uint32_t drives_addr;
+ uint32_t config_table;
+ uint32_t boot_loader_name;
+ uint32_t apm_table;
+ uint32_t vbe_control_info;
+ uint32_t vbe_mode_info;
+ uint16_t vbe_mode;
+ uint16_t vbe_interface_seg;
+ uint16_t vbe_interface_off;
+ uint16_t vbe_interface_len;
+} __attribute__((packed));
+
+struct mb_module {
+ uint32_t mod_start;
+ uint32_t mod_end;
+ uint32_t string;
+ uint32_t reserved;
+} __attribute__((packed));
+
+struct mb_mmap_entry {
+ uint32_t size;
+ uint64_t base_addr;
+ uint64_t length;
+ uint32_t type;
+} __attribute__((packed));
+
+#endif
diff --git a/linuxboot.c b/linuxboot.c
index 0e7fe37..65b5936 100644
--- a/linuxboot.c
+++ b/linuxboot.c
@@ -40,8 +40,9 @@ bool parse_bzimage(struct linuxboot_args *args)
if (ldl_p(header+0x202) == 0x53726448)
protocol = lduw_p(header+0x206);
else {
- // if (parse_multiboot(&args)) return;
- protocol = 0;
+ /* assume multiboot. TODO: scan for header */
+ return false;
+ // protocol = 0;
}
if (protocol < 0x200 || !(header[0x211] & 0x01)) {
diff --git a/main.c b/main.c
index b593237..86bd3fd 100644
--- a/main.c
+++ b/main.c
@@ -29,13 +29,13 @@ static void setup_idt(void)
/* Top of memory below 4GB. */
uint32_t lowmem;
+struct e820map *e820;
static void extract_e820(void)
{
int id = fw_cfg_file_id("etc/e820");
uint32_t size;
int nr_map;
- struct e820map *e820;
int i;
if (id == -1)