#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: multiboot2.c,v 1.8 2021/10/07 12:52:27 msaitoh Exp $");
#include "opt_multiboot.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cdefs_elf.h>
#include <sys/boot_flag.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/optstr.h>
#include <sys/ksyms.h>
#include <sys/common_ansi.h>
#include <sys/intr.h>
#include <x86/efi.h>
#include <machine/bootinfo.h>
#include <arch/i386/include/multiboot2.h>
#ifdef _LOCORE64
typedef uint64_t locore_vaddr_t;
typedef Elf64_Shdr locore_Elf_Shdr;
typedef Elf64_Word locore_Elf_Word;
typedef Elf64_Addr locore_Elf_Addr;
#else
typedef vaddr_t locore_vaddr_t;
typedef Elf_Shdr locore_Elf_Shdr;
typedef Elf_Word locore_Elf_Word;
typedef Elf_Addr locore_Elf_Addr;
#endif
#if !defined(MULTIBOOT)
# error "MULTIBOOT not defined; this cannot happen."
#endif
#define BS_PRINT(efisystbl, wstring) \
efi_systbl->st_coutif->ei_outputstring(efi_systbl->st_coutif, \
(efi_char *)__UNCONST(wstring))
struct multiboot_symbols {
uint32_t s_symstart;
uint32_t s_symsize;
uint32_t s_strstart;
uint32_t s_strsize;
};
void multiboot2_copy_syms(struct multiboot_tag_elf_sections *,
struct multiboot_symbols *,
bool *, int **, void *, vaddr_t);
void multiboot2_pre_reloc(char *);
void multiboot2_post_reloc(void);
void multiboot2_print_info(void);
bool multiboot2_ksyms_addsyms_elf(void);
extern int biosbasemem;
extern int biosextmem;
#ifdef __i386__
extern int biosmem_implicit;
#endif
extern int boothowto;
extern struct bootinfo bootinfo;
extern int end;
extern int * esym;
extern char start;
char multiboot_info[16384] = "\0\0\0\0";
bool multiboot2_enabled = false;
bool has_syms = false;
struct multiboot_symbols Multiboot_Symbols;
#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
static void
efi_exit_bs(struct efi_systbl *efi_systbl, void *efi_ih)
{
struct efi_bs *efi_bs;
struct efi_md *desc;
uintn bufsize, key, size;
uint32_t vers;
if (efi_systbl == NULL)
panic("EFI system table is NULL");
if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG)
panic("EFI system table signature is wrong");
efi_bs = efi_systbl->st_bs;
if (efi_bs == NULL)
panic("EFI BS is NULL");
if (efi_bs->bs_hdr.th_sig != EFI_BS_SIG)
panic("EFI BS signature is wrong");
if (efi_ih == NULL)
panic("EFI IH is NULL");
bufsize = 16384;
if (efi_bs->bs_allocatepool(EFI_MD_TYPE_DATA,
bufsize, (void **)&desc) != 0)
panic("EFI AllocatePool failed");
if (efi_bs->bs_getmemorymap(&bufsize, desc, &key, &size, &vers) == 0)
goto exit_bs;
(void)efi_bs->bs_freepool((void *)desc);
if (efi_bs->bs_allocatepool(EFI_MD_TYPE_DATA,
bufsize, (void **)&desc) != 0)
panic("EFI AllocatePool failed");
if (efi_bs->bs_getmemorymap(&bufsize, desc, &key, &size, &vers) != 0)
panic("EFI GetMemoryMap failed");
exit_bs:
if (efi_bs->bs_exitbootservices(efi_ih, key) != 0)
panic("EFI ExitBootServices failed");
return;
}
void
multiboot2_copy_syms(struct multiboot_tag_elf_sections *mbt_elf,
struct multiboot_symbols *ms,
bool *has_symsp, int **esymp, void *endp,
vaddr_t kernbase)
{
int i;
locore_Elf_Shdr *symtabp, *strtabp;
locore_Elf_Word symsize, strsize;
locore_Elf_Addr symaddr, straddr;
locore_Elf_Addr symstart, strstart;
locore_Elf_Addr cp1src, cp1dst;
locore_Elf_Word cp1size;
locore_Elf_Addr cp2src, cp2dst;
locore_Elf_Word cp2size;
symtabp = strtabp = NULL;
for (i = 0; i < mbt_elf->num && symtabp == NULL &&
strtabp == NULL; i++) {
locore_Elf_Shdr *shdrp;
shdrp = &((locore_Elf_Shdr *)mbt_elf->sections)[i];
if ((shdrp->sh_type == SHT_SYMTAB) &&
shdrp->sh_link != SHN_UNDEF) {
locore_Elf_Shdr *shdrp2;
shdrp2 = &((locore_Elf_Shdr *)mbt_elf->sections)
[shdrp->sh_link];
if (shdrp2->sh_type == SHT_STRTAB) {
symtabp = (locore_Elf_Shdr *)shdrp;
strtabp = (locore_Elf_Shdr *)shdrp2;
}
}
}
if (symtabp == NULL || strtabp == NULL)
return;
symaddr = symtabp->sh_addr;
straddr = strtabp->sh_addr;
symsize = symtabp->sh_size;
strsize = strtabp->sh_size;
if ((void *)(uintptr_t)symaddr < endp &&
(void *)(uintptr_t)straddr < endp) {
cp1src = symaddr; cp1size = symsize;
cp2src = straddr; cp2size = strsize;
} else if ((void *)(uintptr_t)symaddr > endp &&
(void *)(uintptr_t)straddr < endp) {
cp1src = symaddr; cp1size = symsize;
cp2src = straddr; cp2size = strsize;
} else if ((void *)(uintptr_t)symaddr < endp &&
(void *)(uintptr_t)straddr > endp) {
cp1src = straddr; cp1size = strsize;
cp2src = symaddr; cp2size = symsize;
} else {
if (symaddr < straddr) {
cp1src = symaddr; cp1size = symsize;
cp2src = straddr; cp2size = strsize;
} else {
cp1src = straddr; cp1size = strsize;
cp2src = symaddr; cp2size = symsize;
}
}
cp1dst = (locore_Elf_Addr)(uintptr_t)endp;
cp2dst = (locore_Elf_Addr)(uintptr_t)endp + cp1size;
(void)memcpy((void *)(uintptr_t)cp1dst,
(void *)(uintptr_t)cp1src, cp1size);
(void)memcpy((void *)(uintptr_t)cp2dst,
(void *)(uintptr_t)cp2src, cp2size);
symstart = (cp1src == symaddr) ? cp1dst : cp2dst;
strstart = (cp1src == straddr) ? cp1dst : cp2dst;
ms->s_symstart = symstart + kernbase;
ms->s_symsize = symsize;
ms->s_strstart = strstart + kernbase;
ms->s_strsize = strsize;
*has_symsp = true;
*esymp = (int *)((uintptr_t)endp + symsize + strsize + kernbase);
}
void
multiboot2_pre_reloc(char *mbi)
{
uint32_t mbi_size;
void *mbidest = RELOC(void *, multiboot_info);
char *cp;
struct multiboot_tag_module *mbt;
struct multiboot_tag_elf_sections *mbt_elf = NULL;
struct efi_systbl *efi_systbl = NULL;
void *efi_ih = NULL;
bool has_bs = false;
mbi_size = *(uint32_t *)mbi;
if (mbi_size < sizeof(multiboot_info))
memcpy(mbidest, mbi, mbi_size);
else
panic("multiboot_info too big");
*RELOC(bool *, &multiboot2_enabled) = true;
for (cp = mbi + (2 * sizeof(uint32_t));
cp - mbi < mbi_size;
cp += roundup(mbt->size, MULTIBOOT_INFO_ALIGN)) {
mbt = (struct multiboot_tag_module *)cp;
switch (mbt->type) {
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
mbt_elf = (struct multiboot_tag_elf_sections *)mbt;
break;
#ifdef __LP64__
case MULTIBOOT_TAG_TYPE_EFI64:
efi_systbl = (struct efi_systbl *)
((struct multiboot_tag_efi64 *)mbt)->pointer;
break;
case MULTIBOOT_TAG_TYPE_EFI64_IH:
efi_ih = (void *)
((struct multiboot_tag_efi64_ih *)mbt)->pointer;
break;
#else
case MULTIBOOT_TAG_TYPE_EFI32:
efi_systbl = (struct efi_systbl *)
((struct multiboot_tag_efi32 *)mbt)->pointer;
break;
case MULTIBOOT_TAG_TYPE_EFI32_IH:
efi_ih = (void *)
((struct multiboot_tag_efi32_ih *)mbt)->pointer;
break;
#endif
case MULTIBOOT_TAG_TYPE_EFI_BS:
#if notyet
has_bs = true;
#endif
break;
default:
break;
}
}
if (has_bs)
efi_exit_bs(efi_systbl, efi_ih);
if (mbt_elf)
multiboot2_copy_syms(mbt_elf,
RELOC(struct multiboot_symbols *, &Multiboot_Symbols),
RELOC(bool *, &has_syms),
RELOC(int **, &esym),
RELOC(void *, &end),
KERNBASE);
return;
}
static struct btinfo_common *
bootinfo_init(int type, int len)
{
int i;
struct bootinfo *bip = (struct bootinfo *)&bootinfo;
vaddr_t data;
data = (vaddr_t)&bip->bi_data;
for (i = 0; i < bip->bi_nentries; i++) {
struct btinfo_common *tmp;
tmp = (struct btinfo_common *)data;
data += tmp->len;
}
if (data + len < (vaddr_t)&bip->bi_data + sizeof(bip->bi_data)) {
struct btinfo_common *item = (struct btinfo_common *)data;
item->type = type;
item->len = len;
bip->bi_nentries++;
return item;
} else {
return NULL;
}
}
static void
bootinfo_add(struct btinfo_common *item, int type, int len)
{
struct btinfo_common *bip = bootinfo_init(type, len);
if (bip == NULL)
return;
memcpy(&bip[1], &item[1], len - sizeof(*item));
}
static void
mbi_cmdline(struct multiboot_tag_string *mbt)
{
char *cmdline = mbt->string;
struct btinfo_console bic;
struct btinfo_rootdevice bir;
char *cl;
if (optstr_get(cmdline, "console", bic.devname, sizeof(bic.devname))) {
if (strncmp(bic.devname, "com", sizeof(bic.devname)) == 0) {
char opt[10];
if (optstr_get(cmdline, "console_speed",
opt, sizeof(opt)))
bic.speed = strtoul(opt, NULL, 10);
else
bic.speed = 0;
if (optstr_get(cmdline, "console_addr",
opt, sizeof(opt))) {
if (opt[0] == '0' && opt[1] == 'x')
bic.addr = strtoul(opt + 2, NULL, 16);
else
bic.addr = strtoul(opt, NULL, 10);
} else {
bic.addr = 0;
}
bootinfo_add((struct btinfo_common *)&bic,
BTINFO_CONSOLE, sizeof(bic));
}
if (strncmp(bic.devname, "pc", sizeof(bic.devname)) == 0)
bootinfo_add((struct btinfo_common *)&bic,
BTINFO_CONSOLE, sizeof(bic));
}
if (optstr_get(cmdline, "root", bir.devname, sizeof(bir.devname)))
bootinfo_add((struct btinfo_common *)&bir, BTINFO_ROOTDEVICE,
sizeof(bir));
cl = cmdline;
while (*cl != '\0' && *cl != ' ')
cl++;
while (*cl == ' ')
cl++;
if (*cl == '-') {
int howto = 0;
cl++;
while (*cl != '\0' && *cl != ' ') {
BOOT_FLAG(*cl, howto);
cl++;
}
if (*cl == ' ')
cl++;
boothowto = howto;
}
return;
}
static void
mbi_modules(char *mbi, uint32_t mbi_size, int module_count)
{
char *cp;
struct multiboot_tag_module *mbt;
size_t bim_len;
struct bi_modulelist_entry *bie;
struct btinfo_modulelist *bim;
bim_len = sizeof(*bim) + (module_count * sizeof(*bie));
bim = (struct btinfo_modulelist *)bootinfo_init(BTINFO_MODULELIST,
bim_len);
if (bim == NULL)
return;
bim->num = module_count;
bim->endpa = end;
bie = (struct bi_modulelist_entry *)(bim + 1);
for (cp = mbi + (2 * sizeof(uint32_t));
cp - mbi < mbi_size;
cp += roundup(mbt->size, MULTIBOOT_INFO_ALIGN)) {
mbt = (struct multiboot_tag_module *)cp;
if (mbt->type != MULTIBOOT_TAG_TYPE_MODULE)
continue;
strncpy(bie->path, mbt->cmdline, sizeof(bie->path));
bie->type = BI_MODULE_ELF;
bie->len = mbt->mod_end - mbt->mod_start;
bie->base = mbt->mod_start;
bie++;
}
}
static void
mbi_basic_meminfo(struct multiboot_tag_basic_meminfo *mbt)
{
if (biosbasemem == 0) {
biosbasemem = mbt->mem_lower;
#ifdef __i386__
biosmem_implicit = 1;
#endif
}
if (biosextmem == 0) {
biosextmem = mbt->mem_upper;
#ifdef __i386__
biosmem_implicit = 1;
#endif
}
return;
}
static void
mbi_bootdev(struct multiboot_tag_bootdev *mbt)
{
struct btinfo_bootdisk bid;
bid.labelsector = -1;
bid.biosdev = mbt->biosdev;
bid.partition = mbt->slice;
bootinfo_add((struct btinfo_common *)&bid,
BTINFO_BOOTDISK, sizeof(bid));
}
static void
mbi_mmap(struct multiboot_tag_mmap *mbt)
{
struct btinfo_memmap *bim;
int num;
char *cp;
if (mbt->entry_version != 0)
return;
num = 0;
for (cp = (char *)(mbt + 1);
cp - (char *)mbt < mbt->size;
cp += mbt->entry_size) {
num++;
}
bim = (struct btinfo_memmap *)bootinfo_init(BTINFO_MEMMAP,
sizeof(num) + num * sizeof(struct bi_memmap_entry));
if (bim == NULL)
return;
bim->num = 0;
for (cp = (char *)(mbt + 1);
cp - (char *)mbt < mbt->size;
cp += mbt->entry_size) {
struct multiboot_mmap_entry *mbe;
struct bi_memmap_entry *bie;
mbe = (struct multiboot_mmap_entry *)cp;
bie = &bim->entry[bim->num];
bie->addr = mbe->addr;
bie->size = mbe->len;
switch (mbe->type) {
case MULTIBOOT_MEMORY_AVAILABLE:
bie->type = BIM_Memory;
break;
case MULTIBOOT_MEMORY_RESERVED:
bie->type = BIM_Reserved;
break;
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
bie->type = BIM_ACPI;
break;
case MULTIBOOT_MEMORY_NVS:
bie->type = BIM_NVS;
break;
case MULTIBOOT_MEMORY_BADRAM:
default:
bie->type = BIM_Unusable;
break;
}
bim->num++;
}
KASSERT(bim->num == num);
}
static void
mbi_vbe(struct multiboot_tag_vbe *mbt, struct btinfo_framebuffer *bif)
{
bif->vbemode = mbt->vbe_mode;
return;
}
static void
mbi_framebuffer(struct multiboot_tag_framebuffer *mbt,
struct btinfo_framebuffer *bif)
{
bif->physaddr = mbt->common.framebuffer_addr;
bif->width = mbt->common.framebuffer_width;
bif->height = mbt->common.framebuffer_height;
bif->depth = mbt->common.framebuffer_bpp;
bif->stride = mbt->common.framebuffer_pitch;
return;
}
static void
mbi_efi32(struct multiboot_tag_efi32 *mbt)
{
struct btinfo_efi bie;
bie.systblpa = mbt->pointer;
bie.flags = BI_EFI_32BIT;
bootinfo_add((struct btinfo_common *)&bie, BTINFO_EFI, sizeof(bie));
}
static void
mbi_efi64(struct multiboot_tag_efi64 *mbt)
{
struct btinfo_efi bie;
bie.systblpa = mbt->pointer;
bootinfo_add((struct btinfo_common *)&bie, BTINFO_EFI, sizeof(bie));
}
static void
mbi_efi_mmap(struct multiboot_tag_efi_mmap *mbt)
{
struct btinfo_efimemmap *bie;
size_t bie_len;
if (mbt->descr_vers != 0)
return;
bie_len = sizeof(*bie) + mbt->size - sizeof(*mbt);
bie = (struct btinfo_efimemmap *)bootinfo_init(BTINFO_EFIMEMMAP,
bie_len);
if (bie == NULL)
return;
bie->num = (mbt->size - sizeof(*mbt)) / mbt->descr_size;
bie->version = mbt->descr_vers;
bie->size = mbt->descr_size;
memcpy(bie->memmap, mbt + 1, mbt->size - sizeof(*mbt));
}
void
multiboot2_post_reloc(void)
{
uint32_t mbi_size;
struct multiboot_tag *mbt;
char *mbi = multiboot_info;
char *cp;
int module_count = 0;
struct btinfo_framebuffer fbinfo;
bool has_fbinfo = false;
if (multiboot2_enabled == false)
goto out;
mbi_size = *(uint32_t *)multiboot_info;
if (mbi_size < 2 * sizeof(uint32_t))
goto out;
bootinfo.bi_nentries = 0;
memset(&fbinfo, 0, sizeof(fbinfo));
for (cp = mbi + (2 * sizeof(uint32_t));
cp - mbi < mbi_size;
cp += roundup(mbt->size, MULTIBOOT_INFO_ALIGN)) {
mbt = (struct multiboot_tag *)cp;
switch (mbt->type) {
case MULTIBOOT_TAG_TYPE_CMDLINE:
mbi_cmdline((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
break;
case MULTIBOOT_TAG_TYPE_MMAP:
mbi_mmap((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_MODULE:
module_count++;
break;
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
mbi_basic_meminfo((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_BOOTDEV:
mbi_bootdev((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_VBE:
mbi_vbe((void *)mbt, &fbinfo);
break;
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
mbi_framebuffer((void *)mbt, &fbinfo);
has_fbinfo = true;
break;
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
case MULTIBOOT_TAG_TYPE_APM:
break;
case MULTIBOOT_TAG_TYPE_EFI32:
mbi_efi32((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_EFI64:
mbi_efi64((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_SMBIOS:
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
case MULTIBOOT_TAG_TYPE_NETWORK:
break;
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
mbi_efi_mmap((void *)mbt);
break;
case MULTIBOOT_TAG_TYPE_EFI_BS:
case MULTIBOOT_TAG_TYPE_EFI32_IH:
case MULTIBOOT_TAG_TYPE_EFI64_IH:
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
case MULTIBOOT_TAG_TYPE_END:
default:
break;
}
}
if (has_fbinfo)
bootinfo_add((struct btinfo_common *)&fbinfo,
BTINFO_FRAMEBUFFER, sizeof(fbinfo));
if (module_count > 0)
mbi_modules(mbi, mbi_size, module_count);
out:
return;
}
#ifdef DEBUG
static void
mbi_hexdump(char *addr, size_t len)
{
int i,j;
for (i = 0; i < len; i += 16) {
printf(" %p ", addr + i);
for (j = 0; j < 16 && i + j < len; j++) {
char *cp = addr + i + j;
printf("%s%s%x",
(i+j) % 4 ? "" : " ",
(unsigned char)*cp < 0x10 ? "0" : "",
(unsigned char)*cp);
}
printf("\n");
}
return;
}
#endif
static const char *
mbi_tag_name(uint32_t type)
{
const char *tag_name;
switch (type) {
case MULTIBOOT_TAG_TYPE_END:
tag_name = "";
break;
case MULTIBOOT_TAG_TYPE_CMDLINE:
tag_name = "command line"; break;
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
tag_name = "boot loader name"; break;
case MULTIBOOT_TAG_TYPE_MODULE:
tag_name = "module"; break;
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
tag_name = "basic meminfo"; break;
case MULTIBOOT_TAG_TYPE_BOOTDEV:
tag_name = "boot device"; break;
case MULTIBOOT_TAG_TYPE_MMAP:
tag_name = "memory map"; break;
case MULTIBOOT_TAG_TYPE_VBE:
tag_name = "VESA BIOS Extensions"; break;
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
tag_name = "framebuffer"; break;
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
tag_name = "ELF sections"; break;
case MULTIBOOT_TAG_TYPE_APM:
tag_name = "APM"; break;
case MULTIBOOT_TAG_TYPE_EFI32:
tag_name = "EFI system table"; break;
case MULTIBOOT_TAG_TYPE_EFI64:
tag_name = "EFI system table"; break;
case MULTIBOOT_TAG_TYPE_SMBIOS:
tag_name = "SMBIOS"; break;
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
tag_name = "ACPI 2"; break;
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
tag_name = "ACPI 3"; break;
case MULTIBOOT_TAG_TYPE_NETWORK:
tag_name = "network"; break;
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
tag_name = "EFI memory map"; break;
case MULTIBOOT_TAG_TYPE_EFI_BS:
tag_name = "EFI boot services available"; break;
case MULTIBOOT_TAG_TYPE_EFI32_IH:
tag_name = "EFI ImageHandle"; break;
case MULTIBOOT_TAG_TYPE_EFI64_IH:
tag_name = "EFI ImaheHandle"; break;
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
tag_name = "load base"; break;
default:
tag_name = ""; break;
}
return tag_name;
}
void
multiboot2_print_info(void)
{
struct multiboot_tag *mbt;
char *cp;
uint32_t total_size;
uint32_t reserved;
#ifdef DEBUG
int i = 0;
#endif
if (multiboot2_enabled == false)
goto out;
total_size = *(uint32_t *)multiboot_info;
reserved = *(uint32_t *)multiboot_info + 1;
mbt = (struct multiboot_tag *)(uint32_t *)multiboot_info + 2;
for (cp = multiboot_info + sizeof(total_size) + sizeof(reserved);
cp - multiboot_info < total_size;
cp = cp + roundup(mbt->size, MULTIBOOT_TAG_ALIGN)) {
const char *tag_name;
mbt = (struct multiboot_tag *)cp;
tag_name = mbi_tag_name(mbt->type);
#ifdef DEBUG
printf("multiboot2: tag[%d].type = %d(%s), .size = %d ",
i++, mbt->type, tag_name, mbt->size);
#else
if (*tag_name == '\0')
break;
printf("multiboot2: %s ", mbi_tag_name(mbt->type));
#endif
switch (mbt->type) {
case MULTIBOOT_TAG_TYPE_CMDLINE:
printf("%s\n",
((struct multiboot_tag_string *)mbt)->string);
break;
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
printf("%s\n",
((struct multiboot_tag_string *)mbt)->string);
break;
case MULTIBOOT_TAG_TYPE_MODULE:
printf("0x%08x - 0x%08x %s\n",
((struct multiboot_tag_module *)mbt)->mod_start,
((struct multiboot_tag_module *)mbt)->mod_end,
((struct multiboot_tag_module *)mbt)->cmdline);
break;
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: {
struct multiboot_tag_basic_meminfo *meminfo;
meminfo = (struct multiboot_tag_basic_meminfo *)mbt;
printf("ower = %uKB, upper = %uKB\n",
meminfo->mem_lower, meminfo->mem_upper);
break;
}
case MULTIBOOT_TAG_TYPE_BOOTDEV:
printf ("biosdev = 0x%x, slice = %d, part = %d\n",
((struct multiboot_tag_bootdev *)mbt)->biosdev,
((struct multiboot_tag_bootdev *)mbt)->slice,
((struct multiboot_tag_bootdev *)mbt)->part);
break;
case MULTIBOOT_TAG_TYPE_MMAP: {
struct multiboot_tag_mmap *memmap;
multiboot_memory_map_t *mmap;
uint32_t entry_size;
uint32_t entry_version;
memmap = (struct multiboot_tag_mmap *)mbt;
entry_size = memmap->entry_size;
entry_version = memmap->entry_version;
printf ("entry version = %d\n", entry_version);
if (entry_version != 0)
break;
for (mmap = ((struct multiboot_tag_mmap *)mbt)->entries;
(char *)mmap - (char *)mbt < mbt->size;
mmap = (void *)((char *)mmap + entry_size))
printf(" 0x%016"PRIx64" @ 0x%016"PRIx64" "
"type 0x%x\n",
(uint64_t)mmap->len, (uint64_t)mmap->addr,
mmap->type);
break;
}
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: {
struct multiboot_tag_framebuffer *fb = (void *)mbt;
printf ("%dx%dx%d @ 0x%"PRIx64"\n",
fb->common.framebuffer_width,
fb->common.framebuffer_height,
fb->common.framebuffer_bpp,
(uint64_t)fb->common.framebuffer_addr);
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
}
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
printf("num = %d, entsize = %d, shndx = %d\n",
((struct multiboot_tag_elf_sections *)mbt)->num,
((struct multiboot_tag_elf_sections *)mbt)->entsize,
((struct multiboot_tag_elf_sections *)mbt)->shndx);
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_APM:
printf("version = %d, cseg = 0x%x, offset = 0x%x, "
"cseg_16 = 0x%x, dseg = 0x%x, flags = 0x%x, "
"cseg_len = %d, cseg_16_len = %d, "
"dseg_len = %d\n",
((struct multiboot_tag_apm *)mbt)->version,
((struct multiboot_tag_apm *)mbt)->cseg,
((struct multiboot_tag_apm *)mbt)->offset,
((struct multiboot_tag_apm *)mbt)->cseg_16,
((struct multiboot_tag_apm *)mbt)->dseg,
((struct multiboot_tag_apm *)mbt)->flags,
((struct multiboot_tag_apm *)mbt)->cseg_len,
((struct multiboot_tag_apm *)mbt)->cseg_16_len,
((struct multiboot_tag_apm *)mbt)->dseg_len);
break;
case MULTIBOOT_TAG_TYPE_EFI32:
printf("0x%x\n",
((struct multiboot_tag_efi32 *)mbt)->pointer);
break;
case MULTIBOOT_TAG_TYPE_EFI64:
printf("0x%"PRIx64"\n", (uint64_t)
((struct multiboot_tag_efi64 *)mbt)->pointer);
break;
case MULTIBOOT_TAG_TYPE_SMBIOS:
printf("major = %d, minor = %d\n",
((struct multiboot_tag_smbios *)mbt)->major,
((struct multiboot_tag_smbios *)mbt)->minor);
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
printf("\n");
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
printf("\n");
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_NETWORK:
printf("\n");
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
printf("\n");
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
case MULTIBOOT_TAG_TYPE_EFI_BS:
printf("\n");
break;
case MULTIBOOT_TAG_TYPE_EFI32_IH:
printf("0x%"PRIx32"\n",
((struct multiboot_tag_efi32_ih *)mbt)->pointer);
break;
case MULTIBOOT_TAG_TYPE_EFI64_IH:
printf("0x%"PRIx64"\n", (uint64_t)
((struct multiboot_tag_efi64_ih *)mbt)->pointer);
break;
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: {
struct multiboot_tag_load_base_addr *ld = (void *)mbt;
printf("0x%x\n", ld->load_base_addr);
break;
}
case MULTIBOOT_TAG_TYPE_END:
printf("\n");
break;
default:
printf("\n");
#ifdef DEBUG
mbi_hexdump((char *)mbt, mbt->size);
#endif
break;
}
}
out:
return;
}
bool
multiboot2_ksyms_addsyms_elf(void)
{
struct multiboot_symbols *ms = &Multiboot_Symbols;
vaddr_t symstart = (vaddr_t)ms->s_symstart;
vaddr_t strstart = (vaddr_t)ms->s_strstart;
Elf_Ehdr ehdr;
if (!multiboot2_enabled || !has_syms)
return false;
KASSERT(esym != 0);
#ifdef __LP64__
symstart &= 0xffffffff;
symstart |= ((vaddr_t)KERNBASE_HI << 32);
strstart &= 0xffffffff;
strstart |= ((vaddr_t)KERNBASE_HI << 32);
#endif
memset(&ehdr, 0, sizeof(ehdr));
memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
ehdr.e_ident[EI_CLASS] = ELFCLASS;
ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
ehdr.e_ident[EI_ABIVERSION] = 0;
ehdr.e_type = ET_EXEC;
#ifdef __amd64__
ehdr.e_machine = EM_X86_64;
#elif __i386__
ehdr.e_machine = EM_386;
#else
#error "Unknown ELF machine type"
#endif
ehdr.e_version = 1;
ehdr.e_entry = (Elf_Addr)&start;
ehdr.e_ehsize = sizeof(ehdr);
ksyms_addsyms_explicit((void *)&ehdr,
(void *)symstart, ms->s_symsize,
(void *)strstart, ms->s_strsize);
return true;
}