Better platform separation along with Windows implementation (Linux refactorings still untested)

This commit is contained in:
2016-11-11 19:30:55 +01:00
parent 938117c92b
commit a9c383ee77
9 changed files with 171 additions and 8 deletions
+3
View File
@@ -40,5 +40,8 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:RelWithDebInfo>:DEBUG>
)
set(Boost_USE_STATIC_LIBS on)
add_definitions(-DBOOST_ALL_NO_LIB)
include_directories(${PROJECT_SOURCE_DIR}/src)
add_subdirectory(src)
+1 -2
View File
@@ -17,18 +17,17 @@ include_directories(
set(SOURCE_FILES
Platform.h
UEFI.h
UEFI.cpp
main.cpp
)
if(WIN32)
set(SOURCE_FILES ${SOURCE_FILES}
Platform_Windows.cpp
UEFI_Windows.cpp
)
endif()
if(UNIX)
set(SOURCE_FILES ${SOURCE_FILES}
Platform_Linux.cpp
UEFI_Linux.cpp
)
endif()
source_group("" FILES ${SOURCE_FILES})
+5
View File
@@ -2,10 +2,15 @@
#define Platform_h__
#include <stdexcept>
#include <sstream>
#include <boost/locale.hpp>
namespace Platform {
void Initialize();
bool UEFICheck();
std::pair<std::uint8_t*, std::size_t> UEFIReadVariable(const std::string& name);
void UEFIWriteVariable(const std::string& name, void* buffer, std::size_t size);
void Reboot();
}
+26
View File
@@ -7,6 +7,32 @@ void Platform::Initialize()
// TODO: root permission check here
}
bool Platform::UEFICheck()
{
return efi_variables_supported();
}
std::pair<std::uint8_t*, std::size_t> Platform::UEFIReadVariable(const std::string& name)
{
std::uint8_t* data = nullptr;
std::size_t size;
std::uint32_t attributes;
if (efi_get_variable(EFI_GLOBAL_GUID, name.c_str(), &data, &size, &attributes) != 0) {
std::stringstream message;
message << "Failed to read UEFI variable \"" << name << "\"";
throw std::runtime_error(message.str());
}
return std::make_pair(data, size);
}
void Platform::UEFIWriteVariable(const std::string& name, void* buffer, std::size_t size)
{
if (efi_set_variable(EFI_GLOBAL_GUID, name.c_str(), static_cast<std::uint8_t*>(buffer), size, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 0600) != 0) {
throw std::runtime_error("Failed to write UEFI variable: BootNext");
}
}
void Platform::Reboot()
{
sync();
+41 -1
View File
@@ -1,7 +1,8 @@
#include "Platform.h"
#include <sstream>
#include <Windows.h>
const LPCWSTR EFI_GLOBAL_GUID = L"{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}";
void SetPrivilege(HANDLE hToken, LPCWSTR lpszPrivilege, bool bEnablePrivilege)
{
LUID luid;
@@ -44,6 +45,45 @@ void Platform::Initialize()
SetPrivilege(hToken, SE_SHUTDOWN_NAME, true);
}
bool Platform::UEFICheck()
{
FIRMWARE_TYPE firmwareType;
if (GetFirmwareType(&firmwareType) == 0) {
std::stringstream message;
message << "GetFirmwareType failed: " << GetLastError();
throw std::runtime_error(message.str());
}
return firmwareType == FirmwareTypeUefi;
}
std::pair<std::uint8_t*, std::size_t> Platform::UEFIReadVariable(const std::string& name)
{
auto nameUTF16 = boost::locale::conv::utf_to_utf<char16_t, char>(name);
const std::size_t bufferSize = 2048;
std::uint8_t* data = new std::uint8_t[bufferSize];
std::size_t size = GetFirmwareEnvironmentVariableW(reinterpret_cast<LPCWSTR>(nameUTF16.c_str()), EFI_GLOBAL_GUID, data, sizeof(std::uint8_t) * bufferSize);
if (size == 0) {
std::stringstream message;
message << "Failed to read UEFI variable \"" << name << "\": " << GetLastError();
throw std::runtime_error(message.str());
}
return std::make_pair(data, size);
}
void Platform::UEFIWriteVariable(const std::string& name, void* buffer, std::size_t size)
{
auto nameUTF16 = boost::locale::conv::utf_to_utf<char16_t, char>(name);
bool result = SetFirmwareEnvironmentVariableW(reinterpret_cast<LPCWSTR>(nameUTF16.c_str()), EFI_GLOBAL_GUID, buffer, size);
if (!result) {
std::stringstream message;
message << "Failed to write UEFI variable \"" << name << "\": " << GetLastError();
throw std::runtime_error(message.str());
}
}
void Platform::Reboot()
{
if (InitiateSystemShutdown(nullptr, nullptr, 0, false, true) == 0) {
+86
View File
@@ -0,0 +1,86 @@
#include "UEFI.h"
UEFI::UEFI()
{
if (!Platform::UEFICheck()) {
throw std::runtime_error("System is not UEFI!");
}
}
UEFI::BootOption UEFI::ReadBootCurrent()
{
auto data = Platform::UEFIReadVariable("BootCurrent");
UEFI::BootOption option;
option.ID = *reinterpret_cast<std::uint16_t*>(data.first);
option.Description = readDescription(option.ID);
std::free(data.first);
return option;
}
UEFI::BootOption UEFI::ReadBootNext()
{
auto data = Platform::UEFIReadVariable("BootNext");
UEFI::BootOption option;
option.ID = *reinterpret_cast<std::uint16_t*>(data.first);
option.Description = readDescription(option.ID);
std::free(data.first);
return option;
}
void UEFI::WriteBootNext(const UEFI::BootOption& option)
{
auto data = const_cast<std::uint16_t*>(&option.ID);
Platform::UEFIWriteVariable("BootNext", data, sizeof(std::uint16_t));
}
std::vector<UEFI::BootOption> UEFI::ReadBootOrder()
{
auto data = Platform::UEFIReadVariable("BootOrder");
int numOptions = data.second / sizeof(std::uint16_t);
std::vector<UEFI::BootOption> bootOrder(numOptions);
for (int i = 0; i < numOptions; ++i) {
auto& option = bootOrder[i];
option.ID = *(reinterpret_cast<std::uint16_t*>(data.first) + i);
option.Description = readDescription(option.ID);
}
std::free(data.first);
return bootOrder;
}
void UEFI::WriteBootOrder(const std::vector<UEFI::BootOption>& order)
{
std::vector<std::uint16_t> data(order.size());
for (int i = 0; i < order.size(); ++i) {
data[i] = order[i].ID;
}
Platform::UEFIWriteVariable("BootOrder", data.data(), sizeof(std::uint16_t) * data.size());
}
std::string UEFI::readDescription(std::uint16_t id)
{
auto data = Platform::UEFIReadVariable(optionVarFromID(id));
char16_t* descUTF16 = reinterpret_cast<char16_t*>(data.first + EFI_LOAD_OPTION_DESCRIPTION_OFFSET);
std::string descUTF8 = boost::locale::conv::utf_to_utf<char, char16_t>(descUTF16);
std::free(data.first);
return descUTF8;
}
std::string UEFI::optionVarFromID(std::uint16_t id)
{
char entry[9] = "Boot####";
std::snprintf(entry, 9, "Boot%04X", id);
return std::string(entry);
}
+8 -2
View File
@@ -1,9 +1,14 @@
#ifndef UEFI_h__
#define UEFI_h__
#include <cstdint>
#include <limits>
#include <string>
#include <vector>
#include <stdexcept>
#include <memory>
#include <boost/locale.hpp>
#include "Platform.h"
const std::size_t EFI_LOAD_OPTION_DESCRIPTION_OFFSET = sizeof(std::uint32_t) + sizeof(std::uint16_t);
@@ -25,7 +30,8 @@ public:
void WriteBootOrder(const std::vector<BootOption>& bootOrder);
private:
std::string ReadDescription(std::uint16_t id);
std::string VarNameFromID(std::uint16_t id);
std::string readDescription(std::uint16_t id);
std::string optionVarFromID(std::uint16_t id);
};
#endif
+1 -1
View File
@@ -14,7 +14,7 @@ std::pair<T*, std::size_t> ReadVariable(const std::string& name)
std::uint32_t attributes;
if (efi_get_variable(EFI_GLOBAL_GUID, name.c_str(), &data, &size, &attributes) != 0) {
std::stringstream message;
message << "Failed to read EFI variable: " << name;
message << "Failed to read EFI variable \"" << name << "\"";
throw std::runtime_error(message.str());
}
-2
View File
@@ -1,2 +0,0 @@
#include "UEFI.h"