mostly include some things that should and remove some things that shouldn't have been included in the handout (yes this does hint at some places that need to be touched for A2)
159 lines
4.6 KiB
C++
159 lines
4.6 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 { return reinterpret_cast<void *>(addr); }
|
|
|
|
void *Memory::getEndAddress() const {
|
|
uint64_t end = addr + len;
|
|
return reinterpret_cast<void *>(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
|