303 lines
6.6 KiB
C++
303 lines
6.6 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,
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
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
|