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.
		
		
		
		
		
			
		
			
				
	
	
		
			231 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			231 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
| /*! \file
 | |
|  *  \brief \ref Multiboot Interface
 | |
|  */
 | |
| #pragma once
 | |
| #include "../../compiler/fix.h"
 | |
| #include "../../debug/assert.h"
 | |
| #include "../../types.h"
 | |
| 
 | |
| /*! \brief Interface for Multiboot
 | |
|  *
 | |
|  * Due to historical reasons, a normal BIOS allows you to do quite an egg dance
 | |
|  * until you finally reach the actual kernel (especially with only 512 bytes
 | |
|  * available in the master boot record...).
 | |
|  * Fortunately, there are [boot loaders](https://wiki.osdev.org/Bootloader) that
 | |
|  * (partly) do this ungrateful job for you:
 | |
|  * They load your kernel into memory, switch (the bootstrap processor) to
 | |
|  * protected mode (32 bit) and jump to the entry point of our kernel -- saving
 | |
|  * you a lot of boring (or enlightening?) work: reading ancient systems
 | |
|  * documentation. One of the most famous representatives is the [Grand Unified
 | |
|  * Bootloader (GRUB)](https://www.gnu.org/software/grub/), which is also the
 | |
|  * reference implementation of the [Multiboot Specification]{@ref multiboot}.
 | |
|  *
 | |
|  * A Multiboot compliant boot loader will prepare the system according to your
 | |
|  * needs and can hand you a lot of useful information (e.g. references to
 | |
|  * initial ramdisks).
 | |
|  *
 | |
|  * However, you have to inform the loader that you are also compliant to the
 | |
|  * specification, and (if required) instruct the loader to adjust specific
 | |
|  * settings (e.g. the graphics mode).
 | |
|  *
 | |
|  * For this purpose you have to configure the beginning of the kernel (the first
 | |
|  * 8192 bytes of the kernel binary) accordingly (see `compiler/section.ld`) --
 | |
|  * this is were the boot loader will search for a magic header and parse the
 | |
|  * subsequent entries containing the desired system configuration.
 | |
|  * In StuBS these flags are set in `boot/multiboot/config.inc` and the header
 | |
|  * structure is generated in `boot/multiboot/header.asm`.
 | |
|  *
 | |
|  * The first step in your \ref startup_bsp() "kernel entry function" is saving
 | |
|  * the pointer to the struct with the information from the boot loader
 | |
|  * (transferred via register `ebx`) -- and \ref Multiboot provides you the
 | |
|  * interface to comfortably access its contents!
 | |
|  */
 | |
| namespace Multiboot {
 | |
| /*! \brief Boot Module
 | |
|  * (also known as `initrd` = initial Ramdisk)
 | |
|  *
 | |
|  * \see [1.7 Boot modules]{@ref multiboot}
 | |
|  * \see [3.3 Boot information format]{@ref multiboot}
 | |
|  */
 | |
| class Module {
 | |
|   uint32_t start;                 ///< Start address
 | |
|   uint32_t end;                   ///< End address (excluded)
 | |
|   uint32_t cmdline;               ///< commandline parameter
 | |
|   uint32_t pad [[maybe_unused]];  ///< alignment; must be 0
 | |
| 
 | |
|  public:
 | |
|   /*! \brief Get start of this boot module
 | |
|    * \return Pointer to begin of modules physical address
 | |
|    */
 | |
|   void* getStartAddress() const {
 | |
|     return reinterpret_cast<void*>(static_cast<uintptr_t>(start));
 | |
|   }
 | |
| 
 | |
|   /*! \brief Get end of this boot module
 | |
|    * \return Pointer beyond the modules physical address
 | |
|    */
 | |
|   void* getEndAddress() const {
 | |
|     return reinterpret_cast<void*>(static_cast<uintptr_t>(end));
 | |
|   }
 | |
| 
 | |
|   /*! \brief Get the size of this boot module
 | |
|    * \return Module size in bytes (difference of end and start address)
 | |
|    */
 | |
|   size_t getSize() const { return static_cast<size_t>(end - start); }
 | |
| 
 | |
|   /*! \brief Get the command line for this module
 | |
|    * \return pointer to zero terminated string
 | |
|    */
 | |
|   char* getCommandLine() const {
 | |
|     return reinterpret_cast<char*>(static_cast<uintptr_t>(cmdline));
 | |
|   }
 | |
| } __attribute__((packed));
 | |
| assert_size(Module, 16);
 | |
| 
 | |
| /*! \brief Retrieve a certain boot module
 | |
|  * \param i boot module number
 | |
|  * \return Pointer to structure with boot module information
 | |
|  */
 | |
| Module* getModule(unsigned i);
 | |
| 
 | |
| /*! \brief Get the number of modules
 | |
|  * \return Pointer to structure with boot module information
 | |
|  */
 | |
| unsigned getModuleCount();
 | |
| 
 | |
| /*! \brief Get the kernel command line
 | |
|  * \return pointer to zero terminated string
 | |
|  */
 | |
| char* getCommandLine();
 | |
| 
 | |
| /*! \brief Get the name of the boot loader
 | |
|  * \return pointer to zero terminated string
 | |
|  */
 | |
| char* getBootLoader();
 | |
| 
 | |
| /*! \brief Memory Map
 | |
|  *
 | |
|  * The boot loader queries the BIOS for a memory map and stores its result in
 | |
|  * (something like) a linked list. However, this list may not be complete,
 | |
|  * can have contradictory entries and does not take the location of your kernel
 | |
|  * or any boot modules into account.
 | |
|  * (Anyways, it is still the best memory map you will have in StuBS...)
 | |
|  *
 | |
|  * \note Needs to be enabled explicitly by setting the `MULTIBOOT_MEMORY_INFO`
 | |
|  * flag in the multiboot header (see `boot/multiboot/config.inc`)!
 | |
|  *
 | |
|  * \see [Detecting Memory](https://wiki.osdev.org/Detecting_Memory_(x86))
 | |
|  */
 | |
| class Memory {
 | |
|   uint32_t size;  ///< Size of this entry (can exceed size of the class, rest
 | |
|                   ///< will be padding bits)
 | |
|   uint64_t addr;  ///< Begin of memory area
 | |
|   uint64_t len;   ///< length of the memory area
 | |
| 
 | |
|   /*! \brief Usage Type
 | |
|    */
 | |
|   enum Type : uint32_t {
 | |
|     AVAILABLE = 1,  ///< Memory is available and usable in kernel
 | |
|     RESERVED = 2,   ///< Memory is reserved (without further explanation)
 | |
|     ACPI = 3,       ///< Memory may be reclaimed by ACPI
 | |
|     NVS = 4,        ///< Memory is non volatile storage for ACPI
 | |
|     BADRAM = 5      ///< Area contains bad memory
 | |
|   } type;
 | |
| 
 | |
|  public:
 | |
|   /*! \brief Get start of this memory area
 | |
|    * \return Pointer to begin of the physical address of the memory area
 | |
|    */
 | |
|   void* getStartAddress() const;
 | |
| 
 | |
|   /*! \brief Get end of this memory area
 | |
|    * \return Pointer beyond the physical address of this memory area
 | |
|    */
 | |
|   void* getEndAddress() const;
 | |
| 
 | |
|   /*! \brief Is the memory marked as usable
 | |
|    * \return `true` if available, `false` if not usable.
 | |
|    */
 | |
|   bool isAvailable() const;
 | |
| 
 | |
|   /*! \brief Get the next memory area
 | |
|    * \return pointer to the next memory area entry
 | |
|    */
 | |
|   Memory* getNext() const;
 | |
| } __attribute__((packed));
 | |
| assert_size(Memory, 24);
 | |
| 
 | |
| /*! \brief Retrieve the first entry of the memory map
 | |
|  */
 | |
| Memory* getMemoryMap();
 | |
| 
 | |
| /*! \brief Video mode: Vesa BIOS Extension
 | |
|  *
 | |
|  * \see [VESA BIOS Extension (VBE) Core Functions (Version 3)](vbe3.pdf)
 | |
|  */
 | |
| struct VBE {
 | |
|   uint32_t control_info;   ///< Pointer to VBE control information
 | |
|   uint32_t mode_info;      ///< Pointer to VBE mode information
 | |
|   uint16_t mode;           ///< Selected video mode (as defined in the standard)
 | |
|   uint16_t interface_seg;  ///< Protected mode interface (unused)
 | |
|   uint16_t interface_off;  ///< Protected mode interface (unused)
 | |
|   uint16_t interface_len;  ///< Protected mode interface (unused)
 | |
| } __attribute__((packed));
 | |
| assert_size(VBE, 16);
 | |
| 
 | |
| /*! \brief Get pointer to Vesa BIOS Extension information
 | |
|  *
 | |
|  * \note Only available if the `MULTIBOOT_VIDEO_MODE` flag was explicitly set
 | |
|  *       in the multiboot header (see `boot/multiboot/config.inc`)!
 | |
|  */
 | |
| VBE* getVesaBiosExtensionInfo();
 | |
| 
 | |
| /*! \brief Video mode: Framebuffer
 | |
|  *
 | |
|  * This beautiful structure contains everything required for using the graphic
 | |
|  * framebuffer in a very handy manner -- however, it may not be well supported
 | |
|  * by current boot loaders...
 | |
|  * These information can be retrieved from \ref VBE as well, though you then
 | |
|  * have to parse these huge structures containing a lot of useless stuff.
 | |
|  */
 | |
| struct Framebuffer {
 | |
|   uint64_t address;  ///< Physical address of the framebuffer
 | |
|   uint32_t pitch;    ///< Number of bytes per row
 | |
|   uint32_t width;    ///< Width of framebuffer
 | |
|   uint32_t height;   ///< Height of framebuffer
 | |
|   uint8_t bpp;       ///< Bits per pixel
 | |
|   enum Type : uint8_t {
 | |
|     INDEXED = 0,  ///< Using a custom color palette
 | |
|     RGB = 1,      ///< Standard red-green-blue
 | |
|     EGA_TEXT = 2  ///< Enhanced Graphics Adapter color palette
 | |
|   } type;
 | |
|   union {
 | |
|     /*! \brief For INDEXED type
 | |
|      */
 | |
|     struct {
 | |
|       uint32_t palette_addr;        ///< Address of an array with RGB values
 | |
|       uint16_t palette_num_colors;  ///< Number of colors (in array above)
 | |
|     } __attribute__((packed));
 | |
| 
 | |
|     /*! \brief For RGB type
 | |
|      */
 | |
|     struct {
 | |
|       uint8_t offset_red;    ///< Offset of red value
 | |
|       uint8_t bits_red;      ///< Bits used in red value
 | |
|       uint8_t offset_green;  ///< Offset of green value
 | |
|       uint8_t bits_green;    ///< Bits used in green value
 | |
|       uint8_t offset_blue;   ///< Offset of blue value
 | |
|       uint8_t bits_blue;     ///< Bits used in blue value
 | |
|     } __attribute__((packed));
 | |
|   } __attribute__((packed));
 | |
| } __attribute__((packed));
 | |
| assert_size(Framebuffer, 28);
 | |
| 
 | |
| /*! \brief Get pointer to framebuffer information
 | |
|  *
 | |
|  * \note Only available if the `MULTIBOOT_VIDEO_MODE` flag was explicitly set
 | |
|  *       in the multiboot header (see `boot/multiboot/config.inc`)!
 | |
|  */
 | |
| Framebuffer* getFramebufferInfo();
 | |
| }  // namespace Multiboot
 |