summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/amd64/multiboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/arch/amd64/multiboot.c')
-rw-r--r--qemu/roms/openbios/arch/amd64/multiboot.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/qemu/roms/openbios/arch/amd64/multiboot.c b/qemu/roms/openbios/arch/amd64/multiboot.c
new file mode 100644
index 000000000..4271bd52b
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/multiboot.c
@@ -0,0 +1,125 @@
+/* Support for Multiboot */
+
+#include "config.h"
+#include "asm/io.h"
+#include "libopenbios/sys_info.h"
+#include "multiboot.h"
+
+#define printf printk
+#ifdef CONFIG_DEBUG_BOOT
+#define debug printk
+#else
+#define debug(x...)
+#endif
+
+struct mbheader {
+ unsigned int magic, flags, checksum;
+};
+const struct mbheader multiboot_header
+ __attribute__((section (".hdr"))) =
+{
+ MULTIBOOT_HEADER_MAGIC,
+ MULTIBOOT_HEADER_FLAGS,
+ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+};
+
+/* Multiboot information structure, provided by loader to us */
+
+struct multiboot_mmap {
+ unsigned entry_size;
+ unsigned base_lo, base_hi;
+ unsigned size_lo, size_hi;
+ unsigned type;
+};
+
+#define MULTIBOOT_MEM_VALID 0x01
+#define MULTIBOOT_BOOT_DEV_VALID 0x02
+#define MULTIBOOT_CMDLINE_VALID 0x04
+#define MULTIBOOT_MODS_VALID 0x08
+#define MULTIBOOT_AOUT_SYMS_VALID 0x10
+#define MULTIBOOT_ELF_SYMS_VALID 0x20
+#define MULTIBOOT_MMAP_VALID 0x40
+
+void collect_multiboot_info(struct sys_info *info);
+void collect_multiboot_info(struct sys_info *info)
+{
+ struct multiboot_info *mbinfo;
+ struct multiboot_mmap *mbmem;
+ unsigned mbcount, mbaddr;
+ int i;
+ struct memrange *mmap;
+ int mmap_count;
+ module_t *mod;
+
+ if (info->boot_type != 0x2BADB002)
+ return;
+
+ debug("Using Multiboot information at %#lx\n", info->boot_data);
+
+ mbinfo = phys_to_virt(info->boot_data);
+
+ if (mbinfo->mods_count != 1) {
+ printf("Multiboot: no dictionary\n");
+ return;
+ }
+
+ mod = (module_t *) mbinfo->mods_addr;
+ info->dict_start=(unsigned long *)mod->mod_start;
+ info->dict_end=(unsigned long *)mod->mod_end;
+
+ if (mbinfo->flags & MULTIBOOT_MMAP_VALID) {
+ /* convert mmap records */
+ mbmem = phys_to_virt(mbinfo->mmap_addr);
+ mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4);
+ mmap = malloc(mbcount * sizeof(struct memrange));
+ mmap_count = 0;
+ mbaddr = mbinfo->mmap_addr;
+ for (i = 0; i < mbcount; i++) {
+ mbmem = phys_to_virt(mbaddr);
+ debug("%08x%08x %08x%08x (%d)\n",
+ mbmem->base_hi,
+ mbmem->base_lo,
+ mbmem->size_hi,
+ mbmem->size_lo,
+ mbmem->type);
+ if (mbmem->type == 1) { /* Only normal RAM */
+ mmap[mmap_count].base = mbmem->base_lo
+ + (((unsigned long long) mbmem->base_hi) << 32);
+ mmap[mmap_count].size = mbmem->size_lo
+ + (((unsigned long long) mbmem->size_hi) << 32);
+ mmap_count++;
+ }
+ mbaddr += mbmem->entry_size + 4;
+ if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length)
+ break;
+ }
+ /* simple sanity check - there should be at least 2 RAM segments
+ * (base 640k and extended) */
+ if (mmap_count >= 2)
+ goto got_it;
+
+ printf("Multiboot mmap is broken\n");
+ free(mmap);
+ /* fall back to mem_lower/mem_upper */
+ }
+
+ if (mbinfo->flags & MULTIBOOT_MEM_VALID) {
+ /* use mem_lower and mem_upper */
+ mmap_count = 2;
+ mmap = malloc(2 * sizeof(*mmap));
+ mmap[0].base = 0;
+ mmap[0].size = mbinfo->mem_lower << 10;
+ mmap[1].base = 1 << 20; /* 1MB */
+ mmap[1].size = mbinfo->mem_upper << 10;
+ goto got_it;
+ }
+
+ printf("Can't get memory information from Multiboot\n");
+ return;
+
+got_it:
+ info->memrange = mmap;
+ info->n_memranges = mmap_count;
+
+ return;
+}