Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc32 / multiboot.c
diff --git a/qemu/roms/openbios/arch/sparc32/multiboot.c b/qemu/roms/openbios/arch/sparc32/multiboot.c
new file mode 100644 (file)
index 0000000..8514ca0
--- /dev/null
@@ -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;
+    unsigned 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;
+}