---
i386/i386at/model_dep.c | 178 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index 70fb70cc..6b14e908 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -475,10 +475,186 @@ finalise_mb1_boot_info(void)
}
}
+static const char* const mb2_alloc_mem_failed =
+ "Cannot allocate memory for multiboot2 conversion\n";
+
+/* Rebuild multiboot1 'boot_info' from the multiboot2 data structure. */
static void
finalise_mb2_boot_info(const struct multiboot2_raw_info *mb2_info)
{
- panic("Multiboot2 not implemented yet");
+ const uint32_t tags_len =
+ (mb2_info->total_size - offsetof(struct multiboot2_raw_info, content));
+ uint32_t mod_count = 0;
+ uint32_t offset = 0;
+
+ boot_info.flags = 0;
+
+ while (offset < tags_len)
+ {
+ const struct multiboot2_tag *tag =
+ (const struct multiboot2_tag *)&mb2_info->content[offset];
+
+ if (tag->type == MULTIBOOT2_TAG_TYPE_MODULE)
+ mod_count++;
+
+ offset += MULTIBOOT2_NEXT_TAG_OFFSET(tag->size);
+ }
+
+ if (mod_count)
+ {
+ size_t mod_sz = (mod_count * sizeof(struct multiboot_raw_module));
+ vm_offset_t addr;
+
+ if (! init_alloc_aligned(round_page(mod_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+
+ boot_info.mods_addr = addr;
+ boot_info.flags |= MULTIBOOT_MODS;
+ }
+
+ /* Initialise to zero in all cases and increment below as each
+ module is added. */
+ boot_info.mods_count = 0;
+
+ offset = 0;
+
+ while (offset < tags_len)
+ {
+ const struct multiboot2_tag *tag =
+ (const struct multiboot2_tag *)&mb2_info->content[offset];
+
+ switch (tag->type)
+ {
+ case MULTIBOOT2_TAG_TYPE_MMAP:
+ {
+ const struct multiboot2_tag_mmap *mmap_tag =
+ (const struct multiboot2_tag_mmap *)tag;
+
+ const uint8_t *mb2_entries = (const uint8_t *)mmap_tag->entries;
+ const uint8_t *mb2_entries_end =
+ mb2_entries + tag->size - offsetof(struct multiboot2_tag_mmap,
entries);
+ size_t buf_sz = ((mb2_entries_end - mb2_entries)
+ / mmap_tag->entry_size
+ * sizeof(struct multiboot_raw_mmap_entry));
+ vm_offset_t addr;
+
+ if (! init_alloc_aligned(round_page(buf_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+
+ struct multiboot_raw_mmap_entry* mb1_entry =
+ (struct multiboot_raw_mmap_entry *)phystokv(addr);
+
+ while (mb2_entries < mb2_entries_end)
+ {
+ const multiboot2_memory_map_t *mb2_entry =
+ (const multiboot2_memory_map_t *)mb2_entries;
+
+ mb1_entry->size = (sizeof(*mb1_entry) -
sizeof(mb1_entry->size));
+ mb1_entry->base_addr = mb2_entry->addr;
+ mb1_entry->length = mb2_entry->len;
+ mb1_entry->type = mb2_entry->type;
+
+ mb2_entries += mmap_tag->entry_size;
+ mb1_entry++;
+ }
+
+ boot_info.mmap_addr = addr;
+ boot_info.mmap_length = buf_sz;
+ boot_info.flags |= MULTIBOOT_MEM_MAP;
+ }
+ break;
+
+ case MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO:
+ {
+ const struct multiboot2_tag_basic_meminfo *bi_tag =
+ (const struct multiboot2_tag_basic_meminfo *)tag;
+
+ boot_info.mem_lower = bi_tag->mem_lower;
+ boot_info.mem_upper = bi_tag->mem_upper;
+ boot_info.flags |= MULTIBOOT_MEMORY;
+ }
+ break;
+
+ case MULTIBOOT2_TAG_TYPE_CMDLINE:
+ {
+ const struct multiboot2_tag_string *cl_tag =
+ (const struct multiboot2_tag_string *)tag;
+
+ const size_t cl_sz = (cl_tag->size - sizeof(struct multiboot2_tag));
+ vm_offset_t addr;
+
+ if (! init_alloc_aligned(round_page(cl_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+
+ memcpy((void*)phystokv(addr), cl_tag->string, cl_sz);
+ boot_info.cmdline = addr;
+ boot_info.flags |= MULTIBOOT_CMDLINE;
+ }
+ break;
+
+ case MULTIBOOT2_TAG_TYPE_ELF_SECTIONS:
+ {
+ const struct multiboot2_tag_elf_sections *elf_tag =
+ (const struct multiboot2_tag_elf_sections *)tag;
+
+ const size_t sections_sz =
+ (elf_tag->size
+ - offsetof(struct multiboot2_tag_elf_sections, sections));
+ vm_offset_t addr;
+
+ if (! init_alloc_aligned(round_page(sections_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+
+ memcpy((void*)phystokv(addr), elf_tag->sections, sections_sz);
+ boot_info.shdr_num = elf_tag->num;
+ boot_info.shdr_size = elf_tag->entsize;
+ boot_info.shdr_addr = addr;
+ boot_info.shdr_strndx = elf_tag->shndx;
+ boot_info.flags |= MULTIBOOT_ELF_SHDR;
+ }
+ break;
+
+ case MULTIBOOT2_TAG_TYPE_MODULE:
+ {
+ const struct multiboot2_tag_module *mod_tag =
+ (const struct multiboot2_tag_module *)tag;
+
+ struct multiboot_raw_module * module =
+ (struct multiboot_raw_module *)phystokv(boot_info.mods_addr) +
+ boot_info.mods_count;
+
+ vm_offset_t addr;
+ vm_size_t mod_sz = (mod_tag->mod_end - mod_tag->mod_start);
+ if (! init_alloc_aligned(round_page(mod_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+ memcpy((void*) phystokv(addr), (void*)
phystokv(mod_tag->mod_start), mod_sz);
+ module->mod_start = addr;
+ module->mod_end = (addr + mod_sz);
+
+ size_t cl_sz = (mod_tag->size - offsetof(struct
multiboot2_tag_module, cmdline));
+
+ if (! init_alloc_aligned(round_page(cl_sz), &addr))
+ panic(mb2_alloc_mem_failed);
+
+ memcpy((void*)phystokv(addr), &mod_tag->cmdline, cl_sz);
+ module->string = addr;
+
+ boot_info.flags |= MULTIBOOT_MODS;
+ boot_info.mods_count++;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ offset += MULTIBOOT2_NEXT_TAG_OFFSET(tag->size);
+ }
+
+ if (boot_info.flags & MULTIBOOT_CMDLINE)
+ kernel_cmdline = (char*)phystokv(boot_info.cmdline);
+
+ mbinfo_register_boot_data(&boot_info);
}
#endif /* MACH_HYP */
--
2.47.3