1
0
Fork 0
mirror of https://github.com/tailix/kernel.git synced 2024-12-04 11:34:42 -05:00
kernel/kernelmq/multiboot.c

166 lines
4.3 KiB
C

#include "multiboot.h"
#include "stdlib.h"
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
struct multiboot_mmap_entry
{
unsigned long long base;
unsigned long long size;
unsigned int type;
unsigned int zero;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_tag
{
unsigned int type;
unsigned int size;
};
struct multiboot_tag_string
{
unsigned int type;
unsigned int size;
char string[0];
};
struct multiboot_tag_module
{
unsigned int type;
unsigned int size;
unsigned int mod_start;
unsigned int mod_end;
char cmdline[0];
};
struct multiboot_tag_mmap
{
unsigned int type;
unsigned int size;
unsigned int entry_size;
unsigned int entry_version;
struct multiboot_mmap_entry entries[0];
};
static unsigned char print_multiboot_tag(struct KernelMQ_Info *kinfo, const struct multiboot_tag *tag);
static unsigned char print_multiboot_tag_cmdline(struct KernelMQ_Info *kinfo, const struct multiboot_tag_string *tag);
static unsigned char print_multiboot_tag_module (struct KernelMQ_Info *kinfo, const struct multiboot_tag_module *tag);
static unsigned char print_multiboot_tag_mmap (struct KernelMQ_Info *kinfo, const struct multiboot_tag_mmap *tag);
unsigned char multiboot_parse(struct KernelMQ_Info *kinfo, unsigned long base)
{
if (!kinfo) {
return 0;
}
// Unaligned address
if (base & 7) {
return 0;
}
for (
struct multiboot_tag *tag = (struct multiboot_tag*)(base + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag*)((unsigned char*)tag + ((tag->size + 7) & ~7))
) {
if (!print_multiboot_tag(kinfo, tag)) {
return 0;
}
}
return 1;
}
unsigned char print_multiboot_tag(struct KernelMQ_Info *kinfo, const struct multiboot_tag *const tag)
{
switch (tag->type)
{
case MULTIBOOT_TAG_TYPE_CMDLINE:
return print_multiboot_tag_cmdline(kinfo, (struct multiboot_tag_string*)tag);
case MULTIBOOT_TAG_TYPE_MODULE:
return print_multiboot_tag_module(kinfo, (struct multiboot_tag_module*)tag);
case MULTIBOOT_TAG_TYPE_MMAP:
return print_multiboot_tag_mmap(kinfo, (struct multiboot_tag_mmap*)tag);
}
return 1;
}
unsigned char print_multiboot_tag_cmdline(struct KernelMQ_Info *kinfo, const struct multiboot_tag_string *const tag)
{
unsigned int slen = kstrlen(tag->string);
if (slen > KERNELMQ_INFO_CMDLINE_SLEN_MAX) {
return 0;
}
kstrncpy(kinfo->cmdline, tag->string, slen);
return 1;
}
unsigned char print_multiboot_tag_module(struct KernelMQ_Info *kinfo, const struct multiboot_tag_module *const tag)
{
if (kinfo->modules_count >= KERNELMQ_INFO_MODULES_MAX) {
return 0;
}
unsigned int cmdline_slen = kstrlen(tag->cmdline);
if (cmdline_slen > KERNELMQ_INFO_CMDLINE_SLEN_MAX) {
return 0;
}
struct KernelMQ_Info_Module *module = &kinfo->modules[kinfo->modules_count];
kstrncpy(module->cmdline, tag->cmdline, cmdline_slen);
module->base = tag->mod_start;
module->limit = tag->mod_end;
module->size = module->limit - module->base + 1;
++kinfo->modules_count;
kinfo->modules_total_size += module->size;
return 1;
}
unsigned char print_multiboot_tag_mmap(struct KernelMQ_Info *kinfo, const struct multiboot_tag_mmap *const tag)
{
for (
const multiboot_memory_map_t *mmap = tag->entries;
(unsigned char*)mmap < (unsigned char*)tag + tag->size;
mmap = (multiboot_memory_map_t*)((unsigned long) mmap + tag->entry_size)
) {
if (kinfo->areas_count >= KERNELMQ_INFO_AREAS_MAX) {
return 0;
}
struct KernelMQ_Info_Area *area = &kinfo->areas[kinfo->areas_count];
area->base = mmap->base;
area->size = mmap->size;
area->limit = area->base + area->size - 1;
area->is_available = mmap->type == MULTIBOOT_MEMORY_AVAILABLE;
++kinfo->areas_count;
}
return 1;
}