You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.2 KiB
C++

#include "./data.h"
/*! \brief Multiboot Information Structure according to Specification
* \see [Multiboot Specification]{@ref multiboot}
*/
struct multiboot_info {
/*! \brief Helper Structure
*/
struct Array {
uint32_t size; ///< Length
uint32_t addr; ///< Begin (physical address)
} __attribute__((packed));
enum Flag : uint32_t {
Memory = 1 << 0, ///< is there basic lower/upper memory information?
BootDev = 1 << 1, ///< is there a boot device set?
CmdLine = 1 << 2, ///< is the command-line defined?
Modules = 1 << 3, ///< are there modules to do something with?
/* These next two are mutually exclusive */
SymbolTable = 1 << 4, ///< is there an a.out symbol table loaded?
SectionHeader = 1 << 5, ///< is there an ELF section header table?
MemoryMap = 1 << 6, ///< is there a full memory map?
DriveInfo = 1 << 7, ///< Is there drive info?
ConfigTable = 1 << 8, ///< Is there a config table?
BootLoaderName = 1 << 9, ///< Is there a boot loader name?
ApmTable = 1 << 10, ///< Is there a APM table?
// Is there video information?
VbeInfo = 1 << 11, ///< Vesa bios extension
FramebufferInfo = 1 << 12 ///< Framebuffer
} flags;
/*! \brief Available memory retrieved from BIOS
*/
struct {
uint32_t lower; ///< Amount of memory below 1 MiB in kilobytes
uint32_t upper; ///< Amount of memory above 1 MiB in kilobytes
} mem __attribute__((packed));
uint32_t boot_device; ///< "root" partition
uint32_t cmdline; ///< Kernel command line
Array mods; ///< List of boot modules
union {
/*! \brief Symbol table for kernel in a.out format
*/
struct {
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
} aout_symbol_table __attribute__((packed));
/*! \brief Section header table for kernel in ELF
*/
struct {
uint32_t num; ///< Number of entries
uint32_t size; ///< Size per entry
uint32_t addr; ///< Start of the header table
uint32_t shndx; ///< String table index
} elf_section_header_table __attribute__((packed));
};
struct Array mmap; ///< Memory Map
struct Array drives; ///< Drive Information
uint32_t config_table; ///< ROM configuration table
uint32_t boot_loader_name; ///< Boot Loader Name
uint32_t apm_table; ///< APM table
struct Multiboot::VBE vbe; ///< VBE Information
struct Multiboot::Framebuffer framebuffer; ///< Framebuffer information
/*! \brief Check if setting is available
* \param flag Flag to check
* \return `true` if available
*/
bool has(enum Flag flag) const { return (flags & flag) != 0; }
} __attribute__((packed));
assert_size(multiboot_info, 116);
/*! \brief The pointer to the multiboot structures will be assigned in the
* assembler startup code (multiboot.inc)
*/
struct multiboot_info *multiboot_addr = 0;
namespace Multiboot {
Module *getModule(unsigned i) {
if (multiboot_addr != nullptr &&
multiboot_addr->has(multiboot_info::Flag::Modules) &&
i < multiboot_addr->mods.size) {
return i + reinterpret_cast<Module *>(
static_cast<uintptr_t>(multiboot_addr->mods.addr));
} else {
return nullptr;
}
}
unsigned getModuleCount() { return multiboot_addr->mods.size; }
void *Memory::getStartAddress() const {
if (sizeof(void *) == 4 && (addr >> 32) != 0) {
return reinterpret_cast<void *>(addr & 0xffffffff);
} else {
return reinterpret_cast<void *>(static_cast<uintptr_t>(addr));
}
}
void *Memory::getEndAddress() const {
uint64_t end = addr + len;
if (sizeof(void *) == 4 && (end >> 32) != 0) {
return reinterpret_cast<void *>(addr & 0xffffffff);
} else {
return reinterpret_cast<void *>(static_cast<uintptr_t>(end));
}
}
bool Memory::isAvailable() const { return type == AVAILABLE; }
Memory *Memory::getNext() const {
if (multiboot_addr != nullptr &&
multiboot_addr->has(multiboot_info::Flag::MemoryMap)) {
uintptr_t next = reinterpret_cast<uintptr_t>(this) + size + sizeof(size);
if (next < multiboot_addr->mmap.addr + multiboot_addr->mmap.size) {
return reinterpret_cast<Memory *>(next);
}
}
return nullptr;
}
Memory *getMemoryMap() {
if (multiboot_addr != nullptr &&
multiboot_addr->has(multiboot_info::Flag::MemoryMap) &&
multiboot_addr->mmap.size > 0) {
return reinterpret_cast<Memory *>(
static_cast<uintptr_t>(multiboot_addr->mmap.addr));
} else {
return nullptr;
}
}
char *getCommandLine() {
return reinterpret_cast<char *>(
static_cast<uintptr_t>(multiboot_addr->cmdline));
}
char *getBootLoader() {
return reinterpret_cast<char *>(
static_cast<uintptr_t>(multiboot_addr->boot_loader_name));
}
VBE *getVesaBiosExtensionInfo() {
if (multiboot_addr != nullptr &&
multiboot_addr->has(multiboot_info::Flag::VbeInfo)) {
return &(multiboot_addr->vbe);
} else {
return nullptr;
}
}
Framebuffer *getFramebufferInfo() {
if (multiboot_addr != nullptr &&
multiboot_addr->has(multiboot_info::Flag::FramebufferInfo)) {
return &(multiboot_addr->framebuffer);
} else {
return nullptr;
}
}
} // namespace Multiboot