Better platform separation along with Windows implementation (Linux refactorings still untested)
This commit is contained in:
@@ -40,5 +40,8 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
|
|||||||
$<$<CONFIG:RelWithDebInfo>:DEBUG>
|
$<$<CONFIG:RelWithDebInfo>:DEBUG>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(Boost_USE_STATIC_LIBS on)
|
||||||
|
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||||
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|||||||
+1
-2
@@ -17,18 +17,17 @@ include_directories(
|
|||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
Platform.h
|
Platform.h
|
||||||
UEFI.h
|
UEFI.h
|
||||||
|
UEFI.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(SOURCE_FILES ${SOURCE_FILES}
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
Platform_Windows.cpp
|
Platform_Windows.cpp
|
||||||
UEFI_Windows.cpp
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
set(SOURCE_FILES ${SOURCE_FILES}
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
Platform_Linux.cpp
|
Platform_Linux.cpp
|
||||||
UEFI_Linux.cpp
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
source_group("" FILES ${SOURCE_FILES})
|
source_group("" FILES ${SOURCE_FILES})
|
||||||
|
|||||||
@@ -2,10 +2,15 @@
|
|||||||
#define Platform_h__
|
#define Platform_h__
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
#include <boost/locale.hpp>
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void Initialize();
|
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();
|
void Reboot();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,32 @@ void Platform::Initialize()
|
|||||||
// TODO: root permission check here
|
// 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()
|
void Platform::Reboot()
|
||||||
{
|
{
|
||||||
sync();
|
sync();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include <sstream>
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
const LPCWSTR EFI_GLOBAL_GUID = L"{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}";
|
||||||
|
|
||||||
void SetPrivilege(HANDLE hToken, LPCWSTR lpszPrivilege, bool bEnablePrivilege)
|
void SetPrivilege(HANDLE hToken, LPCWSTR lpszPrivilege, bool bEnablePrivilege)
|
||||||
{
|
{
|
||||||
LUID luid;
|
LUID luid;
|
||||||
@@ -44,6 +45,45 @@ void Platform::Initialize()
|
|||||||
SetPrivilege(hToken, SE_SHUTDOWN_NAME, true);
|
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()
|
void Platform::Reboot()
|
||||||
{
|
{
|
||||||
if (InitiateSystemShutdown(nullptr, nullptr, 0, false, true) == 0) {
|
if (InitiateSystemShutdown(nullptr, nullptr, 0, false, true) == 0) {
|
||||||
|
|||||||
@@ -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
@@ -1,9 +1,14 @@
|
|||||||
|
#ifndef UEFI_h__
|
||||||
|
#define UEFI_h__
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <memory>
|
#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);
|
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);
|
void WriteBootOrder(const std::vector<BootOption>& bootOrder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ReadDescription(std::uint16_t id);
|
std::string readDescription(std::uint16_t id);
|
||||||
std::string VarNameFromID(std::uint16_t id);
|
std::string optionVarFromID(std::uint16_t id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+1
-1
@@ -14,7 +14,7 @@ std::pair<T*, std::size_t> ReadVariable(const std::string& name)
|
|||||||
std::uint32_t attributes;
|
std::uint32_t attributes;
|
||||||
if (efi_get_variable(EFI_GLOBAL_GUID, name.c_str(), &data, &size, &attributes) != 0) {
|
if (efi_get_variable(EFI_GLOBAL_GUID, name.c_str(), &data, &size, &attributes) != 0) {
|
||||||
std::stringstream message;
|
std::stringstream message;
|
||||||
message << "Failed to read EFI variable: " << name;
|
message << "Failed to read EFI variable \"" << name << "\"";
|
||||||
throw std::runtime_error(message.str());
|
throw std::runtime_error(message.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
#include "UEFI.h"
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user