├── .gitignore ├── Include ├── UEFI++ │ ├── MemoryMap.hpp │ ├── MemoryMap.inl │ ├── TextInputStream.hpp │ ├── TextInputStream.inl │ ├── TextOutputStream.hpp │ └── TextOutputStream.inl └── UEFI │ ├── BootServices.hpp │ ├── CRC32.hpp │ ├── CRC32.inl │ ├── ConfigurationTable.hpp │ ├── ConsoleColor.hpp │ ├── Detail │ └── BitFlags.hpp │ ├── FileProtocol.hpp │ ├── GUID.hpp │ ├── GUID.inl │ ├── Handle.hpp │ ├── MemoryAttribute.hpp │ ├── MemoryType.hpp │ ├── NonCopyable.hpp │ ├── Revision.hpp │ ├── RuntimeServices.hpp │ ├── Signature.hpp │ ├── SignedTable.hpp │ ├── SimpleFileSystemProtocol.hpp │ ├── SimpleTextInputProtocol.hpp │ ├── SimpleTextOutputProtocol.hpp │ ├── Status.hpp │ ├── SystemTable.hpp │ ├── Table.hpp │ ├── TableHeader.hpp │ └── TaskPriorityLevel.hpp └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /Include/UEFI++/MemoryMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | struct MemoryMap 6 | { 7 | /// The size in bytes. 8 | std::size_t size; 9 | 10 | /// Size in bytes of each descriptor. 11 | /// The firmware is allowed to have extra information at the end of the descriptor, 12 | /// but it's backwards compatible. 13 | std::size_t sizeOfEntry; 14 | 15 | /// The current key. This is used by the firmware to determine if the map is current or not. 16 | /// Use this when calling exitBootServices(). 17 | std::size_t currentKey; 18 | 19 | /// Pointer to an array of memory descriptors. 20 | /// Note: use operator[] to access these. They might not have the size of the structure. 21 | BootServices::MemoryDescriptor* descriptors; 22 | 23 | /// Number of descriptors in the array. 24 | std::size_t getNumberOfEntries() const noexcept 25 | { 26 | return size / sizeOfEntry; 27 | } 28 | 29 | /// Accesses a memory region in the map. 30 | /// @param i The index of the region. 31 | /// @return The descriptor at that point. 32 | const BootServices::MemoryDescriptor& operator[](std::size_t i) const noexcept 33 | { 34 | return *reinterpret_cast(reinterpret_cast(descriptors) + (i * sizeOfEntry)); 35 | } 36 | }; 37 | 38 | /// This function will retrieve the memory map. It determines how much memory is needed, 39 | /// asks UEFI to allocate a buffer, 40 | /// @param bootServices The boot services table. 41 | /// @return The memory map at the current time. 42 | /// @return The map will have size 0 if it fails. 43 | MemoryMap getMemoryMap(BootServices& bootServices); 44 | } 45 | -------------------------------------------------------------------------------- /Include/UEFI++/MemoryMap.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | MemoryMap getMemoryMap(BootServices& bootServices) 6 | { 7 | // Get the memory map. 8 | BootServices::MemoryDescriptor* memoryMap = nullptr; 9 | 10 | std::size_t mapSize = 0, key, descriptorSize; 11 | std::uint32_t descriptorVersion; 12 | 13 | // Try getting the memory map. 14 | // No point in checking the status, since we know it will fail, because size is 0. 15 | bootServices.getMemoryMap(mapSize, memoryMap, key, descriptorSize, descriptorVersion); 16 | 17 | // Allocating from the pool (might) add some extra descriptors. 18 | // TODO: is this extra enough? 19 | mapSize += 4 * descriptorSize; 20 | 21 | // Now we know the needed size in mapSize. 22 | const auto status = bootServices.allocatePool(MemoryType::LoaderData, mapSize, reinterpret_cast(&memoryMap)); 23 | 24 | // This could fail if there's not enough memory left. 25 | if (status != Status::Success) 26 | return{ }; 27 | 28 | // This cannot fail: we have allocated more than enough memory, and the buffer is not nullptr. 29 | bootServices.getMemoryMap(mapSize, memoryMap, key, descriptorSize, descriptorVersion); 30 | 31 | return{ mapSize, descriptorSize, key, memoryMap }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Include/UEFI++/TextInputStream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// This class provides utility functions from reading and writing to the console. 8 | struct TextInputStream 9 | { 10 | using Key = SimpleTextInputProtocol::Key; 11 | 12 | void setInput(SimpleTextInputProtocol& txIn); 13 | 14 | Key readKeySync(); 15 | 16 | SimpleTextInputProtocol* in; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /Include/UEFI++/TextInputStream.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | void TextInputStream::setInput(SimpleTextInputProtocol& txIn) 6 | { 7 | in = &txIn; 8 | } 9 | 10 | auto TextInputStream::readKeySync() -> Key 11 | { 12 | Key key; 13 | 14 | // TODO: something else than an infinite loop? What if input fails because of device errors? 15 | while(in->readKeyStroke(key) != Status::Success); 16 | 17 | return key; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Include/UEFI++/TextOutputStream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace UEFI 7 | { 8 | /// For UEFI newlines are in Carriage Return + Line Feed (Windows) format. 9 | constexpr auto newLine = u"\r\n"; 10 | 11 | using TextColor = SimpleTextOutputProtocol::Attribute; 12 | 13 | /// Note: this "default color" isn't specified in the standard, but OVMF and mTextOutputStreamt computers use this as the default. 14 | constexpr TextColor defaultColor = { ForegroundColor::LightGray, BackgroundColor::Black }; 15 | 16 | struct TextOutputStream 17 | { 18 | // Since static constructors require runtime support, it's better for users to just call initialize(). 19 | [[gnu::ms_abi]] 20 | void initialize(); 21 | 22 | [[gnu::ms_abi]] 23 | void setOutput(SimpleTextOutputProtocol& txOut); 24 | 25 | [[gnu::ms_abi]] 26 | void reset(bool extendedVerification); 27 | 28 | [[gnu::ms_abi]] 29 | void clear(); 30 | 31 | [[gnu::ms_abi]] 32 | void setNumberBase(std::uint8_t b); 33 | 34 | SimpleTextOutputProtocol* out; 35 | 36 | bool boolAlpha; 37 | std::uint8_t base; 38 | 39 | char _padding[6]; 40 | }; 41 | 42 | [[gnu::ms_abi]] 43 | TextOutputStream& operator<<(TextOutputStream& to, const char16_t* msg); 44 | 45 | [[gnu::ms_abi]] 46 | TextOutputStream& operator<<(TextOutputStream& to, char16_t* msg); 47 | 48 | /// Prints a number in the specified base to `stream`. 49 | /// Base should be above 2, and no bigger than 36 (otherwise it would start running out of letters). 50 | [[gnu::ms_abi]] 51 | void printNumber(TextOutputStream& stream, std::uint64_t number); 52 | 53 | [[gnu::ms_abi]] 54 | TextOutputStream& operator<<(TextOutputStream& to, TextColor color); 55 | 56 | [[gnu::ms_abi]] 57 | TextOutputStream& operator<<(TextOutputStream& os, bool value); 58 | 59 | [[gnu::ms_abi]] 60 | TextOutputStream& operator<<(TextOutputStream& to, std::uint64_t n); 61 | 62 | [[gnu::ms_abi]] 63 | inline TextOutputStream& operator<<(TextOutputStream& to, std::uint16_t n) 64 | { 65 | return to << static_cast(n); 66 | } 67 | 68 | [[gnu::ms_abi]] 69 | TextOutputStream& operator<<(TextOutputStream& to, Status status); 70 | 71 | [[gnu::ms_abi]] 72 | TextOutputStream& operator<<(TextOutputStream& to, const unsigned char* msg); 73 | 74 | [[gnu::ms_abi]] 75 | TextOutputStream& operator<<(TextOutputStream& to, unsigned char* msg); 76 | 77 | [[gnu::ms_abi]] 78 | TextOutputStream& operator<<(TextOutputStream& to, const char* msg); 79 | 80 | [[gnu::ms_abi]] 81 | TextOutputStream& operator<<(TextOutputStream& to, char* msg); 82 | } 83 | -------------------------------------------------------------------------------- /Include/UEFI++/TextOutputStream.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | void TextOutputStream::initialize() 8 | { 9 | boolAlpha = true; 10 | base = 10; 11 | } 12 | 13 | void TextOutputStream::setOutput(SimpleTextOutputProtocol& txOut) 14 | { 15 | out = &txOut; 16 | } 17 | 18 | void TextOutputStream::reset(bool extendedVerification) 19 | { 20 | out->reset(extendedVerification); 21 | } 22 | 23 | void TextOutputStream::clear() 24 | { 25 | out->clearScreen(); 26 | } 27 | 28 | void TextOutputStream::setNumberBase(std::uint8_t b) 29 | { 30 | base = b; 31 | } 32 | 33 | 34 | TextOutputStream& operator<<(TextOutputStream& to, const char16_t* msg) 35 | { 36 | to.out->outputString(msg); 37 | return to; 38 | } 39 | 40 | TextOutputStream& operator<<(TextOutputStream& to, char16_t* msg) 41 | { 42 | return to << static_cast(msg); 43 | } 44 | 45 | void printNumber(TextOutputStream& stream, std::uint64_t number) 46 | { 47 | auto base = stream.base; 48 | 49 | if (base < 2 || base > 36) 50 | return; 51 | 52 | // A 64 bit number can be up to 2^64, which means up to log2(2^64) = 64 digits in base 2. 53 | // In bigger bases then it is smaller. 54 | static char16_t buf[65]; 55 | 56 | // Add some prefixes for various bases. 57 | switch (base) 58 | { 59 | case 2: 60 | stream << u"0b"; 61 | break; 62 | 63 | case 8: 64 | stream << u"0"; 65 | break; 66 | 67 | case 16: 68 | stream << u"0x"; 69 | break; 70 | 71 | default: 72 | break; 73 | } 74 | 75 | int k = 0; 76 | 77 | if(number == 0) 78 | { 79 | buf[0] = '0'; 80 | k = 1; 81 | } 82 | 83 | while (number) 84 | { 85 | std::uint8_t value = (number % base); 86 | 87 | // If it's a digit. 88 | if (value <= 9) 89 | buf[k++] = '0' + value; 90 | // Loop around to letters. 91 | else 92 | buf[k++] = 'A' + (value - 10); 93 | 94 | // Remove a digit. 95 | number /= base; 96 | } 97 | 98 | // TODO: is there no better solution than reversing? 99 | for (int i = 0; i < k / 2; ++i) 100 | std::swap(buf[i], buf[k - i - 1]); 101 | 102 | // Add a null terminator. 103 | buf[k] = 0; 104 | 105 | stream << buf; 106 | } 107 | 108 | TextOutputStream& operator<<(TextOutputStream& to, TextColor color) 109 | { 110 | to.out->setAttribute(color); 111 | return to; 112 | } 113 | 114 | TextOutputStream& operator<<(TextOutputStream& os, bool value) 115 | { 116 | if (os.boolAlpha) 117 | return os << (value ? u"true" : u"false"); 118 | else 119 | return os << (value ? u"1" : u"0"); 120 | } 121 | 122 | TextOutputStream& operator<<(TextOutputStream& to, std::uint64_t n) 123 | { 124 | printNumber(to, n); 125 | return to; 126 | } 127 | 128 | TextOutputStream& operator<<(TextOutputStream& to, Status status) 129 | { 130 | std::uint64_t code = static_cast(status); 131 | 132 | // Clear the high bit. 133 | code &= ~(1ull << 63); 134 | 135 | auto copy = to.base; 136 | 137 | to.setNumberBase(10); 138 | to << code; 139 | to.setNumberBase(copy); 140 | 141 | return to; 142 | } 143 | 144 | TextOutputStream& operator<<(TextOutputStream& to, const unsigned char* msg) 145 | { 146 | // TODO: bounds checking for buffer 147 | static char16_t buffer[512]; 148 | 149 | auto ptr = buffer; 150 | 151 | while (*msg != 0) 152 | *ptr++ = *msg++; 153 | 154 | *ptr = 0; 155 | 156 | return to << buffer; 157 | } 158 | 159 | TextOutputStream& operator<<(TextOutputStream& to, unsigned char* msg) 160 | { 161 | return to << static_cast(msg); 162 | } 163 | 164 | TextOutputStream& operator<<(TextOutputStream& to, const char* msg) 165 | { 166 | return to << reinterpret_cast(msg); 167 | } 168 | 169 | TextOutputStream& operator<<(TextOutputStream& to, char* msg) 170 | { 171 | return to << reinterpret_cast(msg); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Include/UEFI/BootServices.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SignedTable.hpp" 4 | #include "Status.hpp" 5 | #include "GUID.hpp" 6 | #include "Handle.hpp" 7 | #include "Detail/BitFlags.hpp" 8 | 9 | #include "TaskPriorityLevel.hpp" 10 | #include "MemoryAttribute.hpp" 11 | #include "MemoryType.hpp" 12 | 13 | namespace UEFI 14 | { 15 | class BootServices : public SignedTable<0x56524553544f4f42> 16 | { 17 | public: 18 | /// TaskPriorityServices 19 | /// @{ 20 | /// Raises a task’s priority level and returns its previous level. 21 | /// @param newTpl The new level to raise to. 22 | /// @return The old level. 23 | TPL raiseTPL(TPL newTpl) 24 | { 25 | return _raiseTpl(newTpl); 26 | } 27 | 28 | void restoreTPL(TPL oldTpl) 29 | { 30 | _restoreTpl(oldTpl); 31 | } 32 | /// @} 33 | 34 | 35 | // Memory Services 36 | 37 | enum class AllocateType 38 | { 39 | /// Any available range of pages that satisfies the request. 40 | AnyPages, 41 | /// Any available range of pages whose uppermost address is less than or equal to the address pointed to by the input. 42 | MaxAddress, 43 | /// Allocate pages at the address pointed to by the input. 44 | Address, 45 | 46 | MaxAllocateType 47 | }; 48 | 49 | using PhysicalAddress = std::uint64_t; 50 | using VirtualAddress = std::uint64_t; 51 | 52 | /// Allocates memory pages from the system. 53 | /// @return Success The requested pages were allocated. 54 | /// @return OutOfResources The pages could not be allocated. 55 | /// @return InvalidParameter Type is not a valid enum value. 56 | /// @return InvalidParameter MemoryType is in the range MaxMemoryType ... 0x6FFFFFFF. 57 | /// @return InvalidParameter MemoryType is PersistentMemory. 58 | /// @return NotFound The requested pages could not be found 59 | Status allocatePages(AllocateType type, MemoryType memType, std::size_t pages, PhysicalAddress& memory) 60 | { 61 | return _allocatePages(type, memType, pages, memory); 62 | } 63 | 64 | Status freePages(PhysicalAddress memory, std::size_t pages) 65 | { 66 | return _freePages(memory, pages); 67 | } 68 | 69 | /// Describes a region of memory. 70 | /// Note: firmware is free to have memory descriptors of different sizes. This structure can and will have extra 71 | /// variables at the end. Therefore, you should remember to check and use descriptorSize. 72 | struct MemoryDescriptor 73 | { 74 | /// The type of memory in this block. 75 | MemoryType type; 76 | 77 | /// This variable would have been added automatically by the compiler. It's here just to show there is a gap. 78 | std::uint32_t _pad; 79 | 80 | /// The start of this memory range. 81 | PhysicalAddress physicalStart; 82 | 83 | /// This should / will always be 0 or some garbage value during startup. UEFI either uses identity mapping 84 | /// or disables paging (on 32 bit) on startup. 85 | VirtualAddress virtualStart; 86 | 87 | /// How many 4 KiB pages does this block contain. 88 | std::uint64_t numberOfPages; 89 | 90 | /// Attributes describe what settings the block CAN be configured for, not necessarily the current settings. 91 | MemoryAttribute attribute; 92 | }; 93 | 94 | static_assert(sizeof(MemoryDescriptor) == 40); 95 | 96 | /// Returns the current memory map. 97 | /// @param[in,out] mapSize The size, in bytes, of the memoryMap buffer. 98 | /// On output, it is the size of the buffer returned by the firmware if the buffer was large enough, 99 | /// or the size of the buffer needed to contain the map if the buffer was too small. 100 | /// @param[in,out] memoryMap An array of MemoryDescriptors in which the firmware places the current memory map. 101 | /// @param[out] mapKey The location in which firmware returns the key for the current memory map. 102 | /// @param[out] descriptorSize The size, in bytes, of a MemoryDescriptor. 103 | /// @param[out] descriptorVersion The version number associated with the MemoryDescriptor. 104 | /// @return Success The memory map was returned in the buffer. 105 | /// @return BufferTooSmall The buffer was too small. The current buffer size needed to hold the memory map is returned in mapSize. 106 | /// @return InvalidParameter The buffer is nullptr. 107 | Status getMemoryMap(std::size_t& mapSize, MemoryDescriptor* memoryMap, std::size_t& mapKey, std::size_t& descriptorSize, std::uint32_t& descriptorVersion) 108 | { 109 | return _getMemoryMap(mapSize, memoryMap, mapKey, descriptorSize, descriptorVersion); 110 | } 111 | 112 | /// Allocates pool memory. 113 | /// @param poolType The type of pool to allocate. 114 | /// @param size How many bytes to allocate from the pool. 115 | /// @param[out] buffer Pointer to a pointer to the allocated buffer. 116 | /// @return Success The requested number of bytes was allocated. 117 | /// @return OutOfResources The pool requested could not be allocated. 118 | /// @return InvalidParameter The type is in the range MaxMemoryType .. 0x6FFFFFFF. 119 | /// @return InvalidParameter The type is PersistentMemory . 120 | /// @return InvalidParameter The buffer is nullptr. 121 | Status allocatePool(MemoryType poolType, std::size_t size, void** buffer) 122 | { 123 | return _allocatePool(poolType, size, buffer); 124 | } 125 | 126 | /// Returns pool memory to the system. 127 | Status freePool(void* buffer) 128 | { 129 | return _freePool(buffer); 130 | } 131 | 132 | // 133 | // Event & Timer Services 134 | // 135 | // EFI_CREATE_EVENT CreateEvent; 136 | // EFI_SET_TIMER SetTimer; 137 | // EFI_WAIT_FOR_EVENT WaitForEvent; 138 | // EFI_SIGNAL_EVENT SignalEvent; 139 | // EFI_CLOSE_EVENT CloseEvent; 140 | // EFI_CHECK_EVENT CheckEvent; 141 | 142 | // 143 | // Protocol Handler Services 144 | // 145 | // EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; 146 | // EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; 147 | // EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; 148 | 149 | /// Queries a handle to determine if it supports a specified protocol. 150 | /// @param[out] interface Pointer to the interface, or nullptr if handle does not support the interface. 151 | //[[deprecated("As of UEFI 1.10 you should use openProtocol()")]] 152 | Status handleProtocol(Handle handle, const GUID& protocol, void** interface) 153 | { 154 | return _handleProtocol(handle, protocol, interface); 155 | } 156 | 157 | // EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; 158 | // EFI_LOCATE_HANDLE LocateHandle; 159 | // EFI_LOCATE_DEVICE_PATH LocateDevicePath; 160 | // EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; 161 | 162 | // 163 | // Image Services 164 | // 165 | // EFI_IMAGE_LOAD LoadImage; 166 | // EFI_IMAGE_START StartImage; 167 | // EFI_EXIT Exit; 168 | // EFI_IMAGE_UNLOAD UnloadImage; 169 | /// Terminates all boot services. 170 | Status exitBootServices(Handle imageHandle, std::size_t mapKey) 171 | { 172 | return _exitBootServices(imageHandle, mapKey); 173 | } 174 | 175 | // 176 | // Miscellaneous Services 177 | // 178 | // EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; 179 | // EFI_STALL Stall; 180 | // EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; 181 | 182 | // --> These only exist in UEFI 1.1+ 183 | 184 | // 185 | // DriverSupport Services 186 | // 187 | // EFI_CONNECT_CONTROLLER ConnectController; 188 | // EFI_DISCONNECT_CONTROLLER DisconnectController; 189 | 190 | // 191 | // Open and Close Protocol Services 192 | // 193 | 194 | enum class OpenProtocolAttributes 195 | { 196 | ByHandleProtocol = 1, 197 | GetProtocol = 2, 198 | TestProtocol = 4, 199 | ByChildController = 8, 200 | ByDriver = 16, 201 | Exclusive = 32 202 | }; 203 | 204 | /// Queries a handle to determine if it supports a specified protocol. 205 | /// If the protocol is supported by the handle, it opens the protocol on behalf of the calling agent. 206 | Status openProtocol(Handle handle, const GUID& protocolGuid, void** interface, Handle agent, Handle controller, OpenProtocolAttributes attributes) 207 | { 208 | return _openProtocol(handle, protocolGuid, interface, agent, controller, attributes); 209 | } 210 | 211 | // EFI_CLOSE_PROTOCOL CloseProtocol; 212 | // EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; 213 | 214 | // 215 | // Library Services 216 | // 217 | // EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; 218 | enum class LocateSearchType 219 | { 220 | AllHandles, 221 | ByRegisterNotify, 222 | ByProtocol 223 | }; 224 | 225 | Status locateHandleBuffer(LocateSearchType searchType, const GUID* protocol, const void* searchKey, std::size_t& nrOfHandles, Handle*& buffer) 226 | { 227 | return _locateHandleBuffer(searchType, protocol, searchKey, nrOfHandles, buffer); 228 | } 229 | 230 | // EFI_LOCATE_PROTOCOL LocateProtocol; 231 | 232 | // EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; 233 | // EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; 234 | 235 | // 236 | // 32-bit CRC Services 237 | // 238 | // EFI_CALCULATE_CRC32 CalculateCrc32; 239 | 240 | // 241 | // Miscellaneous Services 242 | 243 | /// Copies the contents of one buffer to another buffer. 244 | void copyMem(void* destination, const void* source, std::size_t length) 245 | { 246 | return _copyMem(destination, source, length); 247 | } 248 | 249 | /// Fills a buffer with a specified value. 250 | /// @param buffer Pointer to the buffer to fill. 251 | /// @param size Number of bytes in buffer to fill. 252 | /// @param value Value to fill buffer with. 253 | void setMem(void* buffer, std::size_t size, std::uint8_t value) 254 | { 255 | return _setMem(buffer, size, value); 256 | } 257 | 258 | // UEFI 2.0+ 259 | // EFI_CREATE_EVENT_EX CreateEventEx; 260 | 261 | private: 262 | // Function pointers 263 | 264 | TPL (*_raiseTpl)(TPL); 265 | void (*_restoreTpl)(TPL); 266 | 267 | 268 | Status (*_allocatePages)(AllocateType, MemoryType, std::size_t, PhysicalAddress&); 269 | Status (*_freePages)(PhysicalAddress, std::size_t); 270 | 271 | Status (*_getMemoryMap)(std::size_t&, MemoryDescriptor*, std::size_t&, std::size_t&, std::uint32_t&); 272 | 273 | Status (*_allocatePool)(MemoryType, std::size_t, void**); 274 | Status (*_freePool)(void*); 275 | 276 | [[maybe_unused]] void* buf2[9]; 277 | 278 | Status (*_handleProtocol)(Handle, const GUID&, void**); 279 | [[maybe_unused]] void* _reserved; 280 | 281 | [[maybe_unused]] void* bufX[8]; 282 | 283 | Status (*_exitBootServices)(Handle, std::size_t); 284 | 285 | [[maybe_unused]] void* buf3[5]; 286 | 287 | Status (*_openProtocol)(Handle, const GUID&, void**, Handle, Handle, OpenProtocolAttributes); 288 | 289 | [[maybe_unused]] void* buf4[3]; 290 | 291 | Status (*_locateHandleBuffer)(LocateSearchType searchType, const GUID* protocol, const void* searchKey, std::size_t& nrOfHandles, Handle*& buffer); 292 | 293 | [[maybe_unused]] void* buf5[4]; 294 | 295 | void (*_copyMem)(void*, const void*, std::size_t); 296 | void (*_setMem)(void*, std::size_t, std::uint8_t); 297 | 298 | [[maybe_unused]] void* buf6[1]; 299 | }; 300 | 301 | UEFI_BIT_FLAGS(BootServices::OpenProtocolAttributes); 302 | } 303 | -------------------------------------------------------------------------------- /Include/UEFI/CRC32.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace UEFI 7 | { 8 | /// UEFI uses a standard CCITT32 CRC algorithm with a seed polynomial value of 0x04C11DB7 for its CRC calculations. 9 | using CRC32 = std::uint32_t; 10 | 11 | // The following functions are defined in the CRC32.inl file. Include it in your sources. 12 | 13 | struct Table; 14 | 15 | /// Verifies an UEFI table's integrity. 16 | /// @param table The table to check. 17 | /// @return True if the table's specified CRC value matches the table's specified CRC. 18 | bool doesCRC32Match(Table& table) noexcept; 19 | 20 | /// Calculates the CRC32 of an UEFI table. 21 | /// @param table The table to calculate. 22 | /// @return The CRC of the table. 23 | CRC32 calculateCRC32(Table& table) noexcept; 24 | 25 | /// Algorithm to calculate CCITT32 for a UEFI structure. 26 | /// @param data Pointer to the start of the structure. 27 | /// @param size The size in bytes of the structure. 28 | /// @return The calculated CRC32. 29 | CRC32 calculateCRC32(const void* data, std::size_t size) noexcept; 30 | } 31 | -------------------------------------------------------------------------------- /Include/UEFI/CRC32.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | bool doesCRC32Match(Table& table) noexcept 6 | { 7 | return table.header.crc32 == calculateCRC32(table); 8 | } 9 | 10 | CRC32 calculateCRC32(Table& table) noexcept 11 | { 12 | // CRC must be set to 0 before calculating. 13 | const auto copyCRC = table.header.crc32; 14 | 15 | table.header.crc32 = 0; 16 | 17 | const auto result = calculateCRC32(&table, table.header.size); 18 | 19 | // Reset the original CRC. 20 | table.header.crc32 = copyCRC; 21 | 22 | return result; 23 | } 24 | 25 | // Original: http://stackoverflow.com/a/26051190 26 | // Adapted the original to C++ and turned table generator into a constexpr function. 27 | CRC32 calculateCRC32(const void* data, std::size_t size) noexcept 28 | { 29 | constexpr static struct CRC32Table 30 | { 31 | std::uint32_t data[256] { }; 32 | 33 | constexpr CRC32Table() 34 | { 35 | // 0xEDB88320 is 0x04C11DB7 but with changed endianess. 36 | constexpr std::uint32_t polynomial = 0xEDB88320; 37 | 38 | for(std::uint32_t i = 0; i < 256; ++i) 39 | { 40 | std::uint32_t remainder = i; 41 | 42 | for (std::uint32_t bit = 8; bit > 0; --bit) 43 | if (remainder & 1) 44 | remainder = (remainder >> 1) ^ polynomial; 45 | else 46 | remainder = (remainder >> 1); 47 | 48 | data[i] = remainder; 49 | } 50 | } 51 | 52 | std::uint32_t operator[](std::uint8_t i) const 53 | { 54 | return data[i]; 55 | } 56 | 57 | } crcTable; 58 | 59 | CRC32 crc = 0xFF'FF'FF'FF; 60 | 61 | // Pointer to go through the data. 62 | auto ptr = reinterpret_cast(data); 63 | 64 | for(std::size_t i = 0; i < size; ++i, ++ptr) 65 | crc = crcTable[*ptr ^ (crc & 0xFF)] ^ (crc >> 8); 66 | 67 | return ~crc; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Include/UEFI/ConfigurationTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | struct ConfigurationTable 6 | { 7 | 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /Include/UEFI/ConsoleColor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// Colors accepted for the console text (foreground). 8 | enum class ForegroundColor : std::uint8_t 9 | { 10 | Black = 0, 11 | Blue = 1, 12 | Green = 2, 13 | Cyan = 3, 14 | Red = 4, 15 | Magenta = 5, 16 | Brown = 6, 17 | LightGray = 7, 18 | DarkGray = 8, 19 | LightBlue = 9, 20 | LightGreen = 10, 21 | LightCyan = 11, 22 | LightRed = 12, 23 | LightMagenta = 13, 24 | Yellow = 14, 25 | White = 15 26 | }; 27 | 28 | /// Colors accepted for the console background. 29 | enum class BackgroundColor : std::uint8_t 30 | { 31 | Black = 0, 32 | Blue = 1, 33 | Green = 2, 34 | Cyan = 3, 35 | Red = 4, 36 | Magenta = 5, 37 | Brown = 6, 38 | LightGray = 7 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /Include/UEFI/Detail/BitFlags.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// Generates bit operators for a given enum. 8 | /// @hideinitializer 9 | #define UEFI_BIT_FLAGS(E) \ 10 | inline constexpr auto operator|(E lhs, E rhs) \ 11 | { \ 12 | return static_cast(static_cast(lhs) | static_cast(rhs));\ 13 | } \ 14 | inline auto operator|=(E& lhs, E rhs) \ 15 | { \ 16 | reinterpret_cast(lhs) |= static_cast(rhs);\ 17 | return lhs; \ 18 | } \ 19 | inline constexpr auto operator&(E lhs, E rhs) \ 20 | { \ 21 | return static_cast(static_cast(lhs) & static_cast(rhs));\ 22 | } \ 23 | inline auto operator&=(E& lhs, E rhs) \ 24 | { \ 25 | reinterpret_cast(lhs) &= static_cast(rhs);\ 26 | return lhs; \ 27 | } \ 28 | inline constexpr auto operator~(E lhs) \ 29 | { \ 30 | return static_cast(~static_cast(lhs));\ 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Include/UEFI/FileProtocol.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "NonCopyable.hpp" 5 | #include "GUID.hpp" 6 | 7 | #include "Detail/BitFlags.hpp" 8 | 9 | namespace UEFI 10 | { 11 | template 12 | struct FileSystemInfo 13 | { 14 | static constexpr GUID guid = {0x09576e93,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}; 15 | 16 | std::uint64_t size; 17 | bool readOnly; 18 | std::uint64_t volumeSize, freeSpace; 19 | std::uint32_t blockSize; 20 | 21 | /// This field might not be large enough. Try with different sizes. 22 | char16_t volumeLabel[labelSize]; 23 | }; 24 | 25 | template 26 | struct FileSystemVolumeLabel 27 | { 28 | static constexpr GUID guid = {0xdb47d7d3,0xfe81,0x11d3,{0x9a,0x35,0x00,0x90,0x27,0x3f,0xC1,0x4d}}; 29 | 30 | char16_t volumeLabel[labelSize]; 31 | }; 32 | 33 | enum class OpenMode : std::uint64_t 34 | { 35 | Create = 0x8000000000000000, 36 | Read = 1, 37 | Write = 2 38 | }; 39 | 40 | UEFI_BIT_FLAGS(OpenMode); 41 | 42 | enum class FileAttributes : std::uint64_t 43 | { 44 | None = 0, 45 | ReadOnly = 1, 46 | Hidden = 2, 47 | System = 4, 48 | Reserved = 8, 49 | Directory = 0x10, 50 | Archive = 0x20, 51 | ValidAttr = 0x37 52 | }; 53 | 54 | UEFI_BIT_FLAGS(FileAttributes); 55 | 56 | /// Provides file based access to supported file systems. 57 | class FileProtocol : private NonCopyable 58 | { 59 | public: 60 | std::uint64_t revision; 61 | 62 | 63 | /// @return Success The file was opened. 64 | /// @return NotFound The specified file could not be found on the device. 65 | /// @return NoMedia The device has no medium. 66 | /// @return MediaChanged The device has a different medium in it or the medium is no longer supported. 67 | /// @return DeviceError The device reported an error. 68 | /// @return VolumeCorrupted The file system structures are corrupted. 69 | /// @return WriteProtected An attempt was made to create a file, or open a file for write when the media is write-protected. 70 | /// @return AccessDenied The service denied access to the file. 71 | /// @return OutOfResources Not enough resources were available to open the file. 72 | /// @return VolumeFull The volume is full. 73 | Status open(FileProtocol*& newHandle, const char16_t* fileName, OpenMode openMode, FileAttributes attributes) 74 | { 75 | return (this->*_open)(newHandle, fileName, openMode, attributes); 76 | } 77 | 78 | Status close() 79 | { 80 | return (this->*_close)(); 81 | } 82 | 83 | // EFI_FILE_DELETE Delete; 84 | 85 | Status read(std::size_t& bufferSize, void* buffer) 86 | { 87 | return (this->*_read)(bufferSize, buffer); 88 | } 89 | 90 | Status write(std::size_t& bufferSize, const void* buffer) 91 | { 92 | return (this->*_write)(bufferSize, buffer); 93 | } 94 | 95 | Status getPosition(std::uint64_t& position) 96 | { 97 | return (this->*_getPosition)(position); 98 | } 99 | 100 | Status setPosition(std::uint64_t position) 101 | { 102 | return (this->*_setPosition)(position); 103 | } 104 | 105 | Status getInfo(const GUID& infoType, std::size_t& bufferSize, void* buffer) 106 | { 107 | return (this->*_getInfo)(infoType, bufferSize, buffer); 108 | } 109 | 110 | // EFI_FILE_SET_INFO SetInfo; 111 | // EFI_FILE_FLUSH Flush; 112 | 113 | private: 114 | using _fp = FileProtocol; 115 | 116 | decltype(&_fp::open) _open; 117 | decltype(&_fp::close) _close; 118 | 119 | [[maybe_unused]] void* buf1[1]; 120 | 121 | decltype(&_fp::read) _read; 122 | decltype(&_fp::write) _write; 123 | 124 | decltype(&_fp::getPosition) _getPosition; 125 | decltype(&_fp::setPosition) _setPosition; 126 | 127 | decltype(&_fp::getInfo) _getInfo; 128 | }; 129 | 130 | class FileProtocol2 : public FileProtocol 131 | { 132 | public: 133 | // EFI_FILE_OPEN_EX OpenEx; 134 | // EFI_FILE_READ_EX ReadEx; 135 | // EFI_FILE_WRITE_EX WriteEx; 136 | // EFI_FILE_FLUSH_EX FlushEx; 137 | 138 | private: 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /Include/UEFI/GUID.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// Unique reference number used as an identifier for various protocols or for partition tables. 8 | /// See https://en.wikipedia.org/wiki/Globally_unique_identifier 9 | union GUID 10 | { 11 | /// Constructs a new GUID from some values (usually taken from the standard). 12 | constexpr GUID(std::uint32_t d1, std::uint16_t d2, std::uint16_t d3, const std::uint8_t (&d4)[8]) 13 | : a{ d1, d2, d3, { /* Constexpr constructor must initialize all members. */ } } 14 | { 15 | // Can't use memset(). 16 | for (std::uint8_t i = 0; i < 8; ++i) 17 | a.data4[i] = d4[i]; 18 | } 19 | 20 | // This is how they are given in the standard. 21 | struct SeparateParts 22 | { 23 | std::uint32_t data1; 24 | std::uint16_t data2, data3; 25 | std::uint8_t data4[8]; 26 | } a; 27 | 28 | // Used when comparing GUIDs. 29 | struct MergedGUID 30 | { 31 | std::uint64_t data1, data2; 32 | } b; 33 | }; 34 | 35 | static_assert(sizeof(GUID) == 16, "GUIDs are supposed to be 128 bit big."); 36 | 37 | bool operator==(const GUID& lhs, const GUID& rhs); 38 | } 39 | -------------------------------------------------------------------------------- /Include/UEFI/GUID.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | bool operator==(const GUID& lhs, const GUID& rhs) 6 | { 7 | return lhs.b.data1 == rhs.b.data2; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Include/UEFI/Handle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | /// Represents an opaque handle, usually allocated by the UEFI boot loader. 6 | using Handle = struct { } *; 7 | } 8 | -------------------------------------------------------------------------------- /Include/UEFI/MemoryAttribute.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Detail/BitFlags.hpp" 4 | 5 | namespace UEFI 6 | { 7 | /// Attributes of the memory region that describe the bit mask of capabilities for that memory region. 8 | enum class MemoryAttribute : std::uint64_t 9 | { 10 | /// Cacheability attributes 11 | /// @{ 12 | Uncacheable = 0x1, 13 | WriteCombining = 0x2, 14 | /// Writes that hit in the cache will also be written to main memory. 15 | WriteThrough = 0x4, 16 | /// Reads and writes that hit in the cache do not propagate to main memory. 17 | /// Dirty data is written back to main memory when a new cache line is allocated. 18 | WriteBack = 0x8, 19 | /// Not cacheable, exported, and supports the "fetch and add" semaphore mechanism. 20 | UncacheableExported = 0x10, 21 | /// @} 22 | 23 | /// Physical memory protection attributes 24 | /// @{ 25 | /// This is typically used as a cacheability attribute today. 26 | /// The memory region supports being configured as cacheable with a "write protected" policy. 27 | /// Reads come from cache lines when possible, and read misses cause cache fills. 28 | /// Writes are propagated to the system bus and cause corresponding cache lines on all processors on the bus to be invalidated. 29 | WriteProtected = 0x1000, 30 | /// Read-protected by system hardware. 31 | ReadProtected = 0x2000, 32 | /// Protected by system hardware from executing code. 33 | ExecuteProtected = 0x4000, 34 | /// @} 35 | 36 | /// Runtime memory attributes 37 | /// @{ 38 | /// The memory region refers to persistent memory. 39 | NonVolatile = 0x8000, 40 | /// The memory region needs to be given a virtual mapping by the operating system when setVirtualAddressMap() is called. 41 | /// @see setVirtualAddressMap() 42 | Runtime = 0x8000000000000000, 43 | /// @} 44 | 45 | /// Reliability attributes 46 | /// @{ 47 | /// The memory region provides higher reliability relative to other memory in the system. 48 | /// If all memory has the same reliability, then this bit is not used. 49 | MoreReliable = 0x10000 50 | /// @} 51 | }; 52 | 53 | UEFI_BIT_FLAGS(MemoryAttribute); 54 | } 55 | -------------------------------------------------------------------------------- /Include/UEFI/MemoryType.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// The type of memory to allocate. 8 | /// Normal allocations (that is, allocations by any UEFI application) are of type LoaderData. 9 | /// Values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use. 10 | /// Values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI OS loaders. 11 | enum class MemoryType : std::uint32_t 12 | { 13 | /// Memory reserved by the firmware / hardware, such as by SMM or ACPI. 14 | /// Not usable by applications or drivers. 15 | ReservedMemory = 0, 16 | 17 | /// The code portions of a loaded UEFI application. 18 | LoaderCode = 1, 19 | /// The data portions of a loaded UEFI application and the default data allocation type 20 | /// used by a UEFI application to allocate pool memory. 21 | LoaderData = 2, 22 | 23 | /// Boot services memory 24 | /// After calling exitBootServices(), this memory is free to use. 25 | 26 | /// The code portions of a loaded UEFI Boot Service Driver. 27 | BootServicesCode = 3, 28 | ///The data portions of a loaded UEFI Boot Service Driver, and the default data allocation type 29 | /// used by a UEFI Boot Service Driver to allocate pool memory. 30 | BootServicesData = 4, 31 | 32 | /// The code portions of a loaded UEFI Runtime Driver. 33 | RuntimeServicesCode = 5, 34 | /// The data portions of a loaded UEFI Runtime Driver and the default data allocation type used by a UEFI Runtime Driver to allocate pool memory. 35 | RuntimeServicesData = 6, 36 | 37 | /// Free (unallocated) memory. 38 | ConventionalMemory = 7, 39 | /// Memory in which errors have been detected. 40 | UnusableMemory = 8, 41 | 42 | /// Memory that holds the ACPI tables. 43 | /// After the OS reads the ACPI tables, this memory can be reclaimed. 44 | ACPIReclaimMemory = 9, 45 | /// Address space reserved for use by the ACPI firmware. 46 | ACPIMemoryNVS = 10, 47 | 48 | /// Used by system firmware to request that a memory-mapped IO region be mapped by the OS to a virtual address, 49 | /// so it can be accessed by EFI runtime services. 50 | MemoryMappedIO = 11, 51 | /// System memory-mapped IO region that is used to translate memory cycles to IO cycles by the processor. 52 | MemoryMappedIOPortSpace = 12, 53 | 54 | /// Address space reserved by the firmware for code that is part of the processor. 55 | PalCode = 13, 56 | 57 | /// A memory region that operates as ConventionalMemory. 58 | /// However, it happens to also support byte-addressable non-volatility. 59 | PersistentMemory = 14, 60 | 61 | MaxMemoryType = 15 62 | }; 63 | 64 | /// Checks if the given memory type is OEM allocated memory. 65 | /// @param type The given type to check. 66 | /// @return Whether the given type is OEM-reserved or not. 67 | constexpr bool isMemoryTypeOEM(MemoryType type) noexcept 68 | { 69 | auto value = static_cast(type); 70 | return (0x70000000 <= value) && (value <= 0x7FFFFFFF); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Include/UEFI/NonCopyable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | /// Classes that inherit from this will not be copyable. 6 | class NonCopyable 7 | { 8 | NonCopyable(NonCopyable&) = delete; 9 | NonCopyable& operator=(NonCopyable&) = delete; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /Include/UEFI/Revision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | /// This structures describes a revision of some structure or software. 6 | /// For UEFI tables, the revision corresponds to the specification's version. 7 | struct Revision 8 | { 9 | std::uint16_t minor; 10 | std::uint16_t major; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /Include/UEFI/RuntimeServices.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace UEFI 4 | { 5 | struct RuntimeServices 6 | { 7 | 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /Include/UEFI/Signature.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// 64-bit value to identify tables. 8 | struct Signature 9 | { 10 | constexpr Signature(std::uint64_t signature) 11 | : value{ signature } 12 | { 13 | } 14 | 15 | constexpr operator std::uint64_t() const 16 | { 17 | return value; 18 | } 19 | 20 | std::uint64_t value; 21 | }; 22 | 23 | constexpr bool operator==(Signature lhs, Signature rhs) 24 | { 25 | return lhs.value == rhs.value; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Include/UEFI/SignedTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Table.hpp" 4 | 5 | namespace UEFI 6 | { 7 | /// This template struct is used to for UEFI tables that have signatures assigned by the UEFI standard. 8 | /// @tparam sgn The signature of this table. 9 | template 10 | struct SignedTable : Table 11 | { 12 | /// The signature of this table, as specified by the standard. 13 | constexpr static Signature signature{ sgn }; 14 | 15 | /// Call this function to ensure a table instance matches its signature. 16 | /// @return True if the signature of this table instance matches the expected type signature. 17 | bool checkSignature() noexcept 18 | { 19 | return header.signature == signature; 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /Include/UEFI/SimpleFileSystemProtocol.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FileProtocol.hpp" 4 | 5 | namespace UEFI 6 | { 7 | /// The firmware automatically creates handles for any block device that supports the following file system formats: 8 | /// - FAT12 9 | /// - FAT16 10 | /// - FAT32 11 | class SimpleFileSystemProtocol : private NonCopyable 12 | { 13 | public: 14 | static constexpr GUID guid = {0x0964e5b22,0x6459,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}; 15 | 16 | std::uint64_t revision; 17 | 18 | Status openVolume(FileProtocol*& root) 19 | { 20 | return (this->*_openVolume)(root); 21 | } 22 | 23 | private: 24 | using _sfsp = SimpleFileSystemProtocol; 25 | decltype(&_sfsp::openVolume) _openVolume; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /Include/UEFI/SimpleTextInputProtocol.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "NonCopyable.hpp" 6 | #include "GUID.hpp" 7 | #include "Status.hpp" 8 | 9 | namespace UEFI 10 | { 11 | class SimpleTextInputProtocol : private NonCopyable 12 | { 13 | public: 14 | static constexpr GUID guid = {0x387477c1,0x69c7,0x11d2, {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}; 15 | 16 | 17 | struct Key 18 | { 19 | std::uint16_t scanCode; 20 | 21 | /// The character that represents this key. 22 | /// 0 if not a printable character. 23 | char16_t unicodeChar; 24 | }; 25 | 26 | /// Resets the input device hardware. 27 | /// Clears the contents of any input queues and puts the input stream in a known empty state. 28 | /// @param extendedVerification If true the driver may perform a more exhaustive verification of the device. 29 | /// @return Success: The device was reset. 30 | /// @return DeviceError: The device is not functioning correctly and could not be reset. 31 | [[gnu::ms_abi]] 32 | Status reset(bool extendedVerification) 33 | { 34 | return (this->*_reset)(extendedVerification); 35 | } 36 | 37 | /// Reads a keystroke from the input queue, if any. 38 | /// @param[out] key The structure to read keystroke data into. 39 | /// @return Sucess: The keystroke information was returned. 40 | /// @return NotReady: There was no keystroke data available. 41 | /// @return DeviceError: The keystroke information was not returned due to hardware errors. 42 | [[gnu::ms_abi]] 43 | Status readKeyStroke(Key& key) 44 | { 45 | return (this->*_readKeyStroke)(key); 46 | } 47 | 48 | private: 49 | using _sti = SimpleTextInputProtocol; 50 | decltype(&_sti::reset) _reset; 51 | decltype(&_sti::readKeyStroke) _readKeyStroke; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /Include/UEFI/SimpleTextOutputProtocol.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "NonCopyable.hpp" 6 | #include "GUID.hpp" 7 | #include "Status.hpp" 8 | 9 | namespace UEFI 10 | { 11 | // You can find these in the ConsoleColor header. 12 | enum class ForegroundColor : std::uint8_t; 13 | enum class BackgroundColor : std::uint8_t; 14 | 15 | class SimpleTextOutputProtocol : private NonCopyable 16 | { 17 | public: 18 | static constexpr GUID guid = {0x387477c2,0x69c7,0x11d2, {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}; 19 | 20 | /// Represents the console's current color settings. 21 | struct Attribute 22 | { 23 | ForegroundColor foreground : 4; 24 | 25 | // This should only be 3 bits wide, but we need to ensure the compiler sets the extra bit to 0. 26 | BackgroundColor background : 4; 27 | }; 28 | 29 | /// Resets the text output device hardware. 30 | /// The cursor position is set to (0, 0). 31 | /// The screen is cleared to the default background color for the output device. 32 | /// @param extendedVerification If set, the device may run exhaustive error checks. 33 | /// @return Success The text output device was reset. 34 | /// @return DeviceError The text output device is not functioning correctly and could not be reset. 35 | [[gnu::ms_abi]] 36 | Status reset(bool extendedVerification) 37 | { 38 | return (this->*_reset)(extendedVerification); 39 | } 40 | 41 | /// Writes a string to the output device. 42 | /// @param string The null-terminated string to print. 43 | /// @return Success The string was output to the device. 44 | /// @return DeviceError The device reported an error while attempting to output the text. 45 | /// @return Unsupported The output device’s mode is not currently in a defined text mode. 46 | /// @return WarnUnknownGlyph This warning code indicates that some of the characters in the string could not be rendered and were skipped. 47 | [[gnu::ms_abi]] 48 | Status outputString(const char16_t* string) 49 | { 50 | return (this->*_outputString)(string); 51 | } 52 | 53 | // TODO: document these functions 54 | [[gnu::ms_abi]] 55 | Status testString(const char16_t* string) 56 | { 57 | return (this->*_testString)(string); 58 | } 59 | 60 | [[gnu::ms_abi]] 61 | Status queryMode(std::size_t modeNumber, std::size_t& columns, std::size_t& rows) 62 | { 63 | return (this->*_queryMode)(modeNumber, columns, rows); 64 | } 65 | 66 | /// Sets the output device to a specified mode. 67 | /// On success the device is in the geometry for the requested mode, 68 | /// and the device has been cleared to the current background color with the cursor at (0,0). 69 | /// @return Success The requested text mode was set. 70 | /// @return DeviceError The device had an error and could not complete the request. 71 | /// @return Unsupported The mode number was not valid. 72 | [[gnu::ms_abi]] 73 | Status setMode(std::size_t modeNumber) 74 | { 75 | return (this->*_setMode)(modeNumber); 76 | } 77 | 78 | /// Sets the background and foreground colors for the OutputString() and ClearScreen() functions. 79 | /// @param att The attribute to set (foreground and background color). 80 | /// @return Success The requested attributes were set. 81 | /// @return DeviceError The device had an error and could not complete the request. 82 | [[gnu::ms_abi]] 83 | Status setAttribute(Attribute att) 84 | { 85 | return (this->*_setAttribute)(att); 86 | } 87 | 88 | /// Clears the output device display to the currently selected background color. 89 | /// @return Success The operation completed successfully. 90 | /// @return DeviceError The device had an error and could not complete the request. 91 | /// @return Unsupported The output device is not in a valid text mode. 92 | [[gnu::ms_abi]] 93 | Status clearScreen() 94 | { 95 | return (this->*_clearScreen)(); 96 | } 97 | 98 | private: 99 | // Function pointers. 100 | using _stp = SimpleTextOutputProtocol; 101 | decltype(&_stp::reset) _reset; 102 | decltype(&_stp::outputString) _outputString; 103 | decltype(&_stp::testString) _testString; 104 | decltype(&_stp::queryMode) _queryMode; 105 | decltype(&_stp::setMode) _setMode; 106 | decltype(&_stp::setAttribute) _setAttribute; 107 | decltype(&_stp::clearScreen) _clearScreen; 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /Include/UEFI/Status.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// Sets the high-order bit of a number. 8 | constexpr std::uint64_t makeErrorCode(std::uint64_t value) 9 | { 10 | return value | (1ull << 63); 11 | } 12 | 13 | /// UEFI interfaces return a Status code for success, errors, and warnings, respectively. 14 | /// Taken from "Appendix D Status Codes" of the UEFI specification. 15 | // TODO: add more 16 | enum class Status : std::uint64_t 17 | { 18 | /// The operation completed successfully. 19 | Success = 0, 20 | /// The image failed to load. 21 | LoadError = makeErrorCode(1), 22 | /// A parameter was incorrect. 23 | InvalidParameter = makeErrorCode(2), 24 | /// The operation is not supported. 25 | Unsupported = makeErrorCode(3), 26 | /// The buffer was not the proper size for the request. 27 | BadBufferSize = makeErrorCode(4), 28 | /// The buffer is not large enough to hold the requested data. 29 | /// The required buffer size is returned in the appropriate parameter when this error occurs. 30 | BufferTooSmall = makeErrorCode(5), 31 | /// The item was not found. 32 | NotFound = makeErrorCode(14), 33 | /// The function was not performed due to a security violation. 34 | SecurityViolation = makeErrorCode(26), 35 | }; 36 | 37 | /// Error codes have the high-order bit set. 38 | constexpr bool isErrorCode(Status code) 39 | { 40 | return ((static_cast(code) >> 63) & 1); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Include/UEFI/SystemTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "SignedTable.hpp" 7 | #include "Handle.hpp" 8 | #include "RuntimeServices.hpp" 9 | #include "BootServices.hpp" 10 | #include "ConfigurationTable.hpp" 11 | 12 | namespace UEFI 13 | { 14 | class SimpleTextInputProtocol; 15 | class SimpleTextOutputProtocol; 16 | 17 | /// The UEFI System Table contains pointers to the runtime and boot services tables. 18 | /// After a call to ExitBootServices(), only the header, firmware, firmware, runtimeServices, numberOfTableEntries, and configurationTable are still vaild. 19 | struct SystemTable : public SignedTable<0x5453595320494249> 20 | { 21 | /// Information about the UEFI firmware. 22 | struct 23 | { 24 | /// A null-terminated string with the name of the vendor of the firmware. 25 | const char16_t* vendor; 26 | /// The version of the firmware. 27 | Revision revision; 28 | } firmware; 29 | 30 | Handle consoleInHandle; 31 | SimpleTextInputProtocol* conIn; 32 | 33 | Handle consoleOutHandle; 34 | SimpleTextOutputProtocol* conOut; 35 | 36 | Handle standardErrorHandle; 37 | SimpleTextOutputProtocol* stdErr; 38 | 39 | RuntimeServices* runtimeServices; 40 | BootServices* bootServices; 41 | 42 | std::size_t numberOfTableEntries; 43 | ConfigurationTable* configurationTable; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /Include/UEFI/Table.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TableHeader.hpp" 4 | 5 | namespace UEFI 6 | { 7 | /// An UEFI table. It's recommended to inherit from this class if you plan to create your own table. 8 | struct Table 9 | { 10 | TableHeader header; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /Include/UEFI/TableHeader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CRC32.hpp" 4 | #include "Signature.hpp" 5 | #include "Revision.hpp" 6 | 7 | namespace UEFI 8 | { 9 | struct TableHeader 10 | { 11 | /// A 64-bit signature that identifies the type of table that follows. 12 | Signature signature; 13 | 14 | /// The revision of the EFI Specification to which this table conforms. 15 | Revision revision; 16 | 17 | /// The size, in bytes, of the entire table including this structure. 18 | std::uint32_t size; 19 | 20 | /// The 32-bit CRC for the entire table. 21 | /// This value is computed by setting this field to 0, and computing the 32-bit CRC for the whole table. 22 | CRC32 crc32; 23 | 24 | /// Reserved field that must be set to 0. 25 | std::uint32_t reserved; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /Include/UEFI/TaskPriorityLevel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace UEFI 6 | { 7 | /// Task Priority Level. 8 | /// By raising the task priority level to higher levels some notifications are masked until the task priority level is restored. 9 | /// Device drivers will typically use Callback or Notify for their notification functions. 10 | /// Good coding practice dictates that all code should execute at its lowest possible TPL level. 11 | enum class TPL : std::size_t 12 | { 13 | /// Application is where all normal execution occurs. 14 | Application = 4, 15 | /// Typically used for application level notification functions. 16 | Callback = 8, 17 | /// Synchronous blocking I/O functions execute at Notify. 18 | Notify = 16, 19 | 20 | /// Do not use, intended only for the firmware. 21 | HighLevel = 31 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UEFI++ 2 | ## An object-oriented wrapper for UEFI 3 | 4 | **Note**: **I am no longer maintaining this project, instead 5 | I am working on [an equivalent library][wrap] for the [Rust][rust] programming language.** 6 | 7 | [wrap]: https://github.com/GabrielMajeri/uefi-rs 8 | [rust]: https://www.rust-lang.org/en-US/ 9 | 10 | This project is a C++ wrapper for the UEFI specification, intended for people who write UEFI applications (OS loaders, shells, etc.) 11 | 12 | This wrapper supports both 32 and 64 bit UEFI architectures. 13 | 14 | The project is composed of two parts: 15 | - The headers in the `UEFI` folder, which contain the base structures from the UEFI specification. 16 | - The headers in the `UEFI++` folder, which contain some classes to make UEFI easier to use. 17 | 18 | **The current version is based on Version 2.6 of the UEFI specification, available [here](http://www.uefi.org/specifications).** 19 | 20 | # Example 21 | Here's some code that uses the old, C-style API of the specification: 22 | 23 | ```c 24 | systemTable->ConOut->OutputString(systemTable->ConOut, L"Hello UEFI!"); 25 | ``` 26 | 27 | Here's some code that uses the new C++ API: 28 | 29 | ```c++ 30 | systemTable.consoleOut.outputString(u"Hello UEFI!"); 31 | ``` 32 | 33 | And here's one that's even more modern: 34 | 35 | ```c++ 36 | // Set the stream's output. 37 | out.setOutput(*systemTable.consoleOut); 38 | 39 | out << "Hello UEFI!"; 40 | ``` 41 | 42 | Performance difference? Zero. Zero cost abstractions make this possible. 43 | 44 | # Features 45 | - Uses modern C++14 features (constexpr, static_assert, strongly typed enums). 46 | - Mainly intended for UEFI applications, not tested for UEFI drivers. 47 | - Relies on some C/C++ headers, but does not require a hosted standard library. 48 | 49 | # Required software 50 | * C++14 compatible compiler (Clang, GCC). 51 | * A C++14 standard library (including the C headers). This wrapper only uses non-hosted functions from the standard lib, therefore it doesn't require a runtime. Some of the required headers: 52 | - ``: for cross-architecture integer types. 53 | - ``: for size_t. 54 | - ``: for some template metaprogramming and static assertions. 55 | - ``: for some utility functions (e.g. std::swap()). 56 | 57 | * *(Optional)* QEmu with OVMF to be able to test UEFI apps in a virtual machine. 58 | * *(Optional)* Doxygen to generate documentation. 59 | 60 | # License 61 | The files included in this repository are licensed under the 62 | [Mozilla Public License, Version 2.0](https://www.mozilla.org/en-US/MPL/2.0/). 63 | 64 | This means you are free to use the header files, even in a proprietary program, 65 | as long as they are unmodified. You must open source any modifications to the 66 | headers you use. 67 | 68 | See the license for more information. 69 | 70 | # Contributions 71 | Anyone is welcome to contribute to this project. 72 | 73 | Please try to adhere to modern C++ coding style & guidelines and avoid C-style hacks. Use the **Issues** tab to submit bugs or feature requests, or submit improved code as **Pull requests**. 74 | --------------------------------------------------------------------------------