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++
168 lines
5.2 KiB
C++
#include "boot/multiboot/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
|