| // Multiboot interface support. |
| // |
| // Copyright (C) 2015 Vladimir Serbinenko <phcoder@gmail.com> |
| // |
| // This file may be distributed under the terms of the GNU LGPLv3 license. |
| |
| #include "config.h" // CONFIG_* |
| #include "malloc.h" // free |
| #include "output.h" // dprintf |
| #include "romfile.h" // romfile_add |
| #include "std/multiboot.h" // MULTIBOOT_* |
| #include "string.h" // memset |
| #include "util.h" // multiboot_init |
| |
| struct mbfs_romfile_s { |
| struct romfile_s file; |
| void *data; |
| }; |
| |
| static int |
| extract_filename(char *dest, char *src, size_t lim) |
| { |
| char *ptr; |
| for (ptr = src; *ptr; ptr++) { |
| if (!(ptr == src || ptr[-1] == ' ' || ptr[-1] == '\t')) |
| continue; |
| /* memcmp stops early if it encounters \0 as it doesn't match name=. */ |
| if (memcmp(ptr, "name=", 5) == 0) { |
| int i; |
| char *optr = dest; |
| for (i = 0, ptr += 5; *ptr && *ptr != ' ' && i < lim; i++) { |
| *optr++ = *ptr++; |
| } |
| *optr++ = '\0'; |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| // Copy a file to memory |
| static int |
| mbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen) |
| { |
| struct mbfs_romfile_s *cfile; |
| cfile = container_of(file, struct mbfs_romfile_s, file); |
| u32 size = cfile->file.size; |
| void *src = cfile->data; |
| |
| // Not compressed. |
| dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst); |
| if (size > maxlen) { |
| warn_noalloc(); |
| return -1; |
| } |
| iomemcpy(dst, src, size); |
| return size; |
| } |
| |
| u32 __VISIBLE entry_elf_eax, entry_elf_ebx; |
| |
| void |
| multiboot_init(void) |
| { |
| struct multiboot_info *mbi; |
| if (!CONFIG_MULTIBOOT) |
| return; |
| dprintf(1, "multiboot: eax=%x, ebx=%x\n", entry_elf_eax, entry_elf_ebx); |
| if (entry_elf_eax != MULTIBOOT_BOOTLOADER_MAGIC) |
| return; |
| mbi = (void *)entry_elf_ebx; |
| dprintf(1, "mbptr=%p\n", mbi); |
| dprintf(1, "flags=0x%x, mods=0x%x, mods_c=%d\n", mbi->flags, mbi->mods_addr, |
| mbi->mods_count); |
| if (!(mbi->flags & MULTIBOOT_INFO_MODS)) |
| return; |
| int i; |
| struct multiboot_mod_list *mod = (void *)mbi->mods_addr; |
| for (i = 0; i < mbi->mods_count; i++) { |
| struct mbfs_romfile_s *cfile; |
| u8 *copy; |
| u32 len; |
| if (!mod[i].cmdline) |
| continue; |
| len = mod[i].mod_end - mod[i].mod_start; |
| cfile = malloc_tmp(sizeof(*cfile)); |
| if (!cfile) { |
| warn_noalloc(); |
| return; |
| } |
| memset(cfile, 0, sizeof(*cfile)); |
| dprintf(1, "module %s, size 0x%x\n", (char *)mod[i].cmdline, len); |
| if (!extract_filename(cfile->file.name, (char *)mod[i].cmdline, |
| sizeof(cfile->file.name))) { |
| free(cfile); |
| continue; |
| } |
| dprintf(1, "assigned file name <%s>\n", cfile->file.name); |
| cfile->file.size = len; |
| copy = malloc_tmp(len); |
| if (!copy) { |
| warn_noalloc(); |
| free(cfile); |
| return; |
| } |
| memcpy(copy, (void *)mod[i].mod_start, len); |
| cfile->file.copy = mbfs_copyfile; |
| cfile->data = copy; |
| romfile_add(&cfile->file); |
| } |
| } |