PrOSess/kernel/include/init/multiboot2.h

342 lines
8.5 KiB
C++

#pragma once
#include "util/number.h"
#include "util/function.h"
#include "memory/pointer.h"
namespace multiboot {
inline constexpr uint32_t magic = 0x36d76289;
inline constexpr uint32_t alignment = 8;
enum class tag_type : uint32_t {
end = 0,
cmdline = 1,
boot_loader_name = 2,
module = 3,
basic_meminfo = 4,
bootdev = 5,
mmap = 6,
vbe = 7,
framebuffer = 8,
elf_sections = 9,
apm = 10,
efi32 = 14,
efi64 = 15,
smbios = 16,
acpi_old = 17,
acpi_new = 18,
network = 19,
efi_mmap = 20,
efi_bs = 21,
efi32_ih = 22,
efi64_ih = 23,
load_base_addr = 24,
};
inline constexpr const char* get_tag_name(tag_type type) {
switch (type) {
case tag_type::end: return "end";
case tag_type::cmdline: return "cmdline";
case tag_type::boot_loader_name: return "boot_loader_name";
case tag_type::module: return "module";
case tag_type::basic_meminfo: return "basic_meminfo";
case tag_type::bootdev: return "bootdev";
case tag_type::mmap: return "mmap";
case tag_type::vbe: return "vbe";
case tag_type::framebuffer: return "framebuffer";
case tag_type::elf_sections: return "elf_sections";
case tag_type::apm: return "apm";
case tag_type::efi32: return "efi32";
case tag_type::efi64: return "efi64";
case tag_type::smbios: return "smbios";
case tag_type::acpi_old: return "acpi_old";
case tag_type::acpi_new: return "acpi_new";
case tag_type::network: return "network";
case tag_type::efi_mmap: return "efi_mmap";
case tag_type::efi_bs: return "efi_bs";
case tag_type::efi32_ih: return "efi32_ih";
case tag_type::efi64_ih: return "efi64_ih";
case tag_type::load_base_addr: return "load_base_addr";
}
return "";
}
enum class framebuffer_type : uint8_t {
indexed = 0,
rgb = 1,
ega_text = 2,
};
enum class mem_type : uint32_t {
available = 1,
reserved = 2,
acpi_reclaimable = 3,
nvs = 4,
badram = 5,
};
inline constexpr const char* get_mem_type_name(mem_type type) {
switch (type) {
case mem_type::available: return "available";
case mem_type::reserved: return "reserved";
case mem_type::acpi_reclaimable: return "acpi_reclaimable";
case mem_type::nvs: return "nvs";
case mem_type::badram: return "badram";
default: return "unknown";
}
}
struct color {
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct mem_entry {
uint64_t addr;
uint64_t len;
mem_type type;
uint32_t zero;
};
struct tag {
tag_type type;
uint32_t size;
};
struct tag_string {
tag_type type;
uint32_t size;
char string[0];
};
struct tag_module {
tag_type type;
uint32_t size;
uint32_t mod_start;
uint32_t mod_end;
char cmdline[0];
};
struct tag_basic_meminfo {
tag_type type;
uint32_t size;
uint32_t mem_lower;
uint32_t mem_upper;
};
struct tag_bootdev {
tag_type type;
uint32_t size;
uint32_t biosdev;
uint32_t slice;
uint32_t part;
};
struct tag_mmap {
tag_type type;
uint32_t size;
uint32_t entry_size;
uint32_t entry_version;
mem_entry entries[0];
};
struct vbe_info_block {
uint8_t external_specification[512];
};
struct vbe_mode_info_block {
uint8_t external_specification[256];
};
struct tag_vbe {
tag_type type;
uint32_t size;
uint16_t vbe_mode;
uint16_t vbe_interface_seg;
uint16_t vbe_interface_off;
uint16_t vbe_interface_len;
vbe_info_block vbe_control_info;
vbe_mode_info_block vbe_mode_info;
};
struct tag_framebuffer {
tag_type type;
uint32_t size;
uint64_t framebuffer_addr;
uint32_t framebuffer_pitch;
uint32_t framebuffer_width;
uint32_t framebuffer_height;
uint8_t framebuffer_bpp;
framebuffer_type framebuffer_type;
uint16_t reserved;
union {
struct {
uint16_t framebuffer_palette_num_colors;
color framebuffer_palette[0];
};
struct {
uint8_t framebuffer_red_field_position;
uint8_t framebuffer_red_mask_size;
uint8_t framebuffer_green_field_position;
uint8_t framebuffer_green_mask_size;
uint8_t framebuffer_blue_field_position;
uint8_t framebuffer_blue_mask_size;
};
};
};
struct tag_elf_sections {
tag_type type;
uint32_t size;
uint32_t num;
uint32_t entsize;
uint32_t shndx;
char sections[0];
};
struct tag_apm {
tag_type type;
uint32_t size;
uint16_t version;
uint16_t cseg;
uint32_t offset;
uint16_t cseg_16;
uint16_t dseg;
uint16_t flags;
uint16_t cseg_len;
uint16_t cseg_16_len;
uint16_t dseg_len;
};
struct tag_efi32 {
tag_type type;
uint32_t size;
uint32_t pointer;
};
struct tag_efi64 {
tag_type type;
uint32_t size;
uint64_t pointer;
};
struct tag_smbios {
tag_type type;
uint32_t size;
uint8_t major;
uint8_t minor;
uint8_t reserved[6];
uint8_t tables[0];
};
struct tag_old_acpi {
tag_type type;
uint32_t size;
uint8_t rsdp[0];
};
struct tag_new_acpi {
tag_type type;
uint32_t size;
uint8_t rsdp[0];
};
struct tag_network {
tag_type type;
uint32_t size;
uint8_t dhcpack[0];
};
struct tag_efi_mmap {
tag_type type;
uint32_t size;
uint32_t descr_size;
uint32_t descr_vers;
uint8_t efi_mmap[0];
};
struct tag_efi32_ih {
tag_type type;
uint32_t size;
uint32_t pointer;
};
struct tag_efi64_ih {
tag_type type;
uint32_t size;
uint64_t pointer;
};
struct tag_load_base_addr {
tag_type type;
uint32_t size;
uint32_t load_base_addr;
};
struct info {
uint32_t total_size;
uint32_t reserved;
};
inline info* get_multiboot_info() {
auto addr = read_symbol("__multiboot_info");
uint32_t phys = *paddr_t{addr}.access<volatile uint32_t>();
return paddr_t{phys}.access<info>();
}
template<typename Fn>
void visit(const tag* t, Fn&& fn) {
#define MB_DISPATCH(tag_enum, TagType) \
case tag_type::tag_enum: \
if constexpr (requires { fn(static_cast<const TagType*>(nullptr)); }) \
fn(reinterpret_cast<const TagType*>(t)); \
break;
switch (t->type) {
MB_DISPATCH(cmdline, tag_string)
MB_DISPATCH(boot_loader_name, tag_string)
MB_DISPATCH(module, tag_module)
MB_DISPATCH(basic_meminfo, tag_basic_meminfo)
MB_DISPATCH(bootdev, tag_bootdev)
MB_DISPATCH(mmap, tag_mmap)
MB_DISPATCH(vbe, tag_vbe)
MB_DISPATCH(framebuffer, tag_framebuffer)
MB_DISPATCH(elf_sections, tag_elf_sections)
MB_DISPATCH(apm, tag_apm)
MB_DISPATCH(efi32, tag_efi32)
MB_DISPATCH(efi64, tag_efi64)
MB_DISPATCH(smbios, tag_smbios)
MB_DISPATCH(acpi_old, tag_old_acpi)
MB_DISPATCH(acpi_new, tag_new_acpi)
MB_DISPATCH(network, tag_network)
MB_DISPATCH(efi_mmap, tag_efi_mmap)
MB_DISPATCH(efi32_ih, tag_efi32_ih)
MB_DISPATCH(efi64_ih, tag_efi64_ih)
MB_DISPATCH(load_base_addr, tag_load_base_addr)
default: break;
}
#undef MB_DISPATCH
}
template<typename Fn>
void visit_all(const info* mb, Fn&& fn) {
auto ptr = reinterpret_cast<const uint8_t*>(mb) + sizeof(info);
const auto end = reinterpret_cast<const uint8_t*>(mb) + mb->total_size;
while (ptr < end) {
auto t = reinterpret_cast<const tag*>(ptr);
if (t->type == tag_type::end) break;
visit(t, fn);
ptr += (t->size + alignment - 1) & ~(alignment - 1);
}
}
template<typename Fn>
void visit_all(Fn&& fn) {
visit_all(get_multiboot_info(), fn);
}
} // namespace multiboot