/**
* @file multiboot2.cpp
* @brief multiboot2 解析实现
* @author Zone.N (Zone.Niuzh@hotmail.com)
* @version 1.0
* @date 2021-09-18
* @copyright MIT LICENSE
* https://github.com/Simple-XX/SimpleKernel
* @par change log:
*
* Date | Author | Description
* |
---|
2021-09-18 | digmouse233 | 迁移到 doxygen
* |
*/
#include "assert.h"
#include "stdio.h"
//#include "common.h"
#include "multiboot2.h"
#include "boot_info.h"
//#include "resource.h"
//#include "pmm.h"
/// @todo 优化
void MULTIBOOT2::multiboot2_iter(bool (*_fun)(const iter_data_t *, void *),
void *_data) {
uintptr_t addr = BOOT_INFO::boot_info_addr;
// 下一字节开始为 tag 信息
iter_data_t *tag = (iter_data_t *)(addr + 8);
for (; tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (iter_data_t *)((uint8_t *)tag + COMMON::ALIGN(tag->size, 8))) {
if (_fun(tag, _data) == true) {
return;
}
}
return;
}
bool MULTIBOOT2::multiboot2_init(void) {
uintptr_t addr = BOOT_INFO::boot_info_addr;
// 判断魔数是否正确
assert(BOOT_INFO::multiboot2_magic == MULTIBOOT2_BOOTLOADER_MAGIC);
assert((reinterpret_cast(addr) & 7) == 0);
// addr+0 保存大小
BOOT_INFO::boot_info_size = *(uint32_t *)addr;
return true;
}
// 读取 grub2 传递的物理内存信息,保存到 e820map_t 结构体中
// 一般而言是这样的
// 地址(长度) 类型
// 0x00(0x9F000) 0x1
// 0x9F000(0x1000) 0x2
// 0xE8000(0x18000) 0x2
// 0x100000(0x7EF0000) 0x1
// 0x7FF0000(0x10000) 0x3
// 0xFFFC0000(0x40000) 0x2
bool MULTIBOOT2::get_memory(const iter_data_t *_iter_data, void *_data) {
if (_iter_data->type != MULTIBOOT2::MULTIBOOT_TAG_TYPE_MMAP) {
return false;
}
resource_t *resource = (resource_t *)_data;
resource->type = resource_t::MEM;
resource->name = (char *)"available phy memory";
resource->mem.addr = 0x0;
resource->mem.len = 0;
MULTIBOOT2::multiboot_mmap_entry_t *mmap =
((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data)->entries;
for (; (uint8_t *)mmap < (uint8_t *)_iter_data + _iter_data->size;
mmap = (MULTIBOOT2::multiboot_mmap_entry_t
*)((uint8_t *)mmap +
((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data)
->entry_size)) {
// 如果是可用内存或地址小于 1M
// 这里将 0~1M 的空间全部算为可用,在 c++ 库可用后进行优化
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE ||
mmap->addr < 1 * COMMON::MB) {
// 长度+
resource->mem.len += mmap->len;
}
}
return true;
}
namespace BOOT_INFO {
// 地址
uintptr_t boot_info_addr;
// 长度
size_t boot_info_size;
// 魔数
uint32_t multiboot2_magic;
bool init(void) {
auto res = MULTIBOOT2::multiboot2_init();
info("BOOT_INFO init.\n");
return res;
}
resource_t get_memory(void) {
resource_t resource;
MULTIBOOT2::multiboot2_iter(MULTIBOOT2::get_memory, &resource);
return resource;
}
};