├── .gitignore ├── efireboot.pro ├── reboot-linux.c ├── wincommon.h ├── reboot.h ├── reboot-windows.c ├── efi.h ├── efireboot-gui.pro ├── efireboot-cli.pro ├── main.c ├── efirebootgui.cpp ├── efi-linux.c ├── wincommon.c └── efi-windows.c /.gitignore: -------------------------------------------------------------------------------- 1 | efireboot.pro.user 2 | -------------------------------------------------------------------------------- /efireboot.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = efireboot-cli \ 3 | efireboot-gui 4 | 5 | efireboot-cli.file = efireboot-cli.pro 6 | efireboot-gui.file = efireboot-gui.pro 7 | -------------------------------------------------------------------------------- /reboot-linux.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void reboot_init() { 5 | 6 | } 7 | 8 | void do_reboot() { 9 | // reboot(RB_AUTOBOOT); 10 | system("reboot"); 11 | } 12 | -------------------------------------------------------------------------------- /wincommon.h: -------------------------------------------------------------------------------- 1 | #ifndef WINERROR_H 2 | #define WINERROR_H 3 | 4 | const wchar_t* GetWChar(const char* c); 5 | void PrintError(DWORD errorCode); 6 | void ObtainPrivileges(LPCTSTR privilege); 7 | 8 | #endif // WINERROR_H 9 | -------------------------------------------------------------------------------- /reboot.h: -------------------------------------------------------------------------------- 1 | #ifndef REBOOT_H 2 | #define REBOOT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void do_reboot(); 8 | void reboot_init(); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | #endif // REBOOT_H 14 | -------------------------------------------------------------------------------- /reboot-windows.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "wincommon.h" 3 | 4 | void reboot_init() { 5 | ObtainPrivileges(SE_SHUTDOWN_NAME); 6 | } 7 | 8 | void do_reboot() { 9 | int res = ExitWindowsEx(EWX_REBOOT, 0); 10 | if (res == 0) { 11 | PrintError(GetLastError()); 12 | exit(GetLastError()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /efi.h: -------------------------------------------------------------------------------- 1 | #ifndef EFI_H 2 | #define EFI_H 3 | #ifdef __cplusplus 4 | #include 5 | extern "C" { 6 | #else 7 | #include 8 | #endif 9 | 10 | char* boot_entry_name(uint16_t id); 11 | int boot_entry_list(uint16_t **list); 12 | int set_boot_next(uint16_t num); 13 | void efi_init(); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | #endif // EFI_H 19 | -------------------------------------------------------------------------------- /efireboot-gui.pro: -------------------------------------------------------------------------------- 1 | QT += core gui widgets 2 | TARGET = efireboot-gui 3 | TEMPLATE = app 4 | SOURCES += efirebootgui.cpp 5 | HEADERS += efi.h \ 6 | reboot.h 7 | 8 | unix: { 9 | LIBS += -lefivar 10 | SOURCES += efi-linux.c \ 11 | reboot-linux.c 12 | } 13 | 14 | win32: { 15 | SOURCES += efi-windows.c \ 16 | reboot-windows.c \ 17 | wincommon.c 18 | LIBS = "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" 19 | HEADERS += wincommon.h 20 | } 21 | -------------------------------------------------------------------------------- /efireboot-cli.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | CONFIG -= app_bundle 4 | CONFIG -= qt 5 | unix: { 6 | LIBS += -lefivar 7 | SOURCES += efi-linux.c \ 8 | reboot-linux.c 9 | } 10 | 11 | win32: { 12 | SOURCES += efi-windows.c \ 13 | reboot-windows.c \ 14 | wincommon.c 15 | LIBS = "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" 16 | HEADERS += wincommon.h 17 | } 18 | 19 | SOURCES += main.c 20 | 21 | HEADERS += \ 22 | efi.h \ 23 | reboot.h 24 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "efi.h" 4 | #include "reboot.h" 5 | 6 | int main() 7 | { 8 | uint16_t *data; 9 | int l, i, c; 10 | data = NULL; 11 | efi_init(); // Perform all tasks needed to access EFI functions 12 | reboot_init(); // Perform all tasks needed to access Reboot functions 13 | l = boot_entry_list(&data); 14 | for (i = 0; i < l; i++) { 15 | printf("%d: %s\n", i, boot_entry_name(data[i])); 16 | } 17 | printf("Input your choice: "); 18 | scanf("%d", &c); 19 | if (c < 0 || c >= l) { 20 | printf("ERROR: Invalid choice\n"); 21 | exit(-1); 22 | } 23 | set_boot_next(data[c]); 24 | printf("Set next boot target to: %s\n", boot_entry_name(data[c])); 25 | do_reboot(); 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /efirebootgui.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "efi.h" 6 | #include "reboot.h" 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | QApplication a(argc, argv); 12 | QDialog w; 13 | w.setWindowTitle("Reboot into:"); 14 | QVBoxLayout layout; 15 | efi_init(); 16 | reboot_init(); 17 | uint16_t *data; 18 | int l = boot_entry_list(&data); 19 | for (int i = 0; i < l; i++) { 20 | QPushButton *button = new QPushButton(QString(boot_entry_name(data[i]))); 21 | layout.addWidget(button); 22 | button->connect(button, &QPushButton::clicked, [=]() { 23 | set_boot_next(data[i]); 24 | do_reboot(); 25 | }); 26 | } 27 | w.setLayout(&layout); 28 | w.show(); 29 | return a.exec(); 30 | } 31 | -------------------------------------------------------------------------------- /efi-linux.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define EFI_GLOBAL_VARIABLE \ 6 | EFI_GUID( 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C) 7 | 8 | void efi_init() { 9 | 10 | } 11 | 12 | int read_efi_variable(const char* name, uint16_t** data) { 13 | uint16_t *res = NULL; 14 | efi_guid_t guid = EFI_GLOBAL_VARIABLE; 15 | uint32_t attributes = 0; 16 | size_t data_size = 0; 17 | 18 | int rc; 19 | rc = efi_get_variable(guid, name, (uint8_t **)&res, &data_size, &attributes); 20 | if (rc < 0) exit(rc); 21 | *data = res; 22 | return data_size / 2; 23 | } 24 | 25 | int set_efi_variable(const char* name, uint16_t num) { 26 | printf("Setting variable\n"); 27 | num &= 0xFFFF; 28 | return efi_set_variable( 29 | EFI_GLOBAL_VARIABLE, 30 | name, 31 | (uint8_t *) &num, 32 | sizeof(num), 33 | EFI_VARIABLE_NON_VOLATILE | 34 | EFI_VARIABLE_BOOTSERVICE_ACCESS | 35 | EFI_VARIABLE_RUNTIME_ACCESS); 36 | } 37 | 38 | char* boot_entry_name(uint16_t id) { 39 | char buffer[8]; 40 | sprintf(buffer, "Boot%04x", id); 41 | uint16_t *data = NULL; 42 | int length = read_efi_variable(buffer, &data); 43 | char* name = (char *) malloc(64*sizeof(char)); 44 | int i = 0; 45 | for (i = 3; i < length; i++) { 46 | if (data[i] == 0) break; 47 | name[i-3] = data[i]; 48 | } 49 | name[i-3] = 0; 50 | return name; 51 | } 52 | 53 | int boot_entry_list(uint16_t **list) { 54 | uint16_t *data = NULL; 55 | int length = read_efi_variable("BootOrder", &data); 56 | *list = data; 57 | return length; 58 | } 59 | 60 | int set_boot_next(uint16_t num) { 61 | return set_efi_variable("BootNext", num); 62 | } 63 | -------------------------------------------------------------------------------- /wincommon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void PrintError(DWORD errorCode) { 5 | LPVOID lpMsgBuf; 6 | 7 | FormatMessage( 8 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 9 | FORMAT_MESSAGE_FROM_SYSTEM | 10 | FORMAT_MESSAGE_IGNORE_INSERTS, 11 | NULL, 12 | errorCode, 13 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 14 | (LPTSTR)&lpMsgBuf, 15 | 0, 16 | NULL); 17 | 18 | printf("Error code was: %ld\n", errorCode); 19 | printf("Error message was: %ws", lpMsgBuf); 20 | LocalFree(lpMsgBuf); 21 | } 22 | 23 | const wchar_t* GetWChar(const char* c) { 24 | const size_t cSize = strlen(c) + 1; 25 | wchar_t* wc = (wchar_t *)malloc(sizeof(wchar_t)*cSize); 26 | //mbstowcs(wc, c, cSize); 27 | size_t result; 28 | mbstowcs_s(&result, wc, cSize, c, cSize); 29 | return wc; 30 | } 31 | 32 | void ObtainPrivileges(LPCTSTR privilege) { 33 | HANDLE hToken; 34 | TOKEN_PRIVILEGES tkp; 35 | BOOL res; 36 | DWORD error; 37 | // Obtain required privileges 38 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 39 | printf("OpenProcessToken failed!\n"); 40 | PrintError(GetLastError()); 41 | exit(GetLastError()); 42 | } 43 | 44 | res = LookupPrivilegeValue(NULL, privilege, &tkp.Privileges[0].Luid); 45 | if (!res) { 46 | printf("LookupPrivilegeValue failed!\n"); 47 | PrintError(GetLastError()); 48 | exit(GetLastError()); 49 | } 50 | tkp.PrivilegeCount = 1; 51 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 52 | AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 53 | 54 | error = GetLastError(); 55 | if (error != ERROR_SUCCESS) { 56 | printf("AdjustTokenPrivileges failed\n"); 57 | PrintError(error); 58 | exit(error); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /efi-windows.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "wincommon.h" 5 | 6 | #define _CRT_SECURE_NO_WARNINGS 1 7 | const char* EFI_GLOBAL_VARIABLE = "{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}"; 8 | 9 | #ifdef UNICODE 10 | #define ___T(str) GetWChar(str) 11 | #else 12 | #define ___T(str) str 13 | #endif 14 | 15 | void efi_init() { 16 | // Determine if running UEFI. If no -> then exit 17 | FIRMWARE_TYPE fwtype; 18 | DWORD dwRet; 19 | GetFirmwareType(&fwtype); 20 | if (fwtype != FirmwareTypeUefi) { 21 | printf("You are not running UEFI!\n"); 22 | exit(-1); 23 | } 24 | 25 | ObtainPrivileges(SE_SYSTEM_ENVIRONMENT_NAME); 26 | 27 | // Perform check if UEFI variables are present. 28 | // If not, we get ERROR_INVALID_FUNCTION on this. 29 | // If yes, we get ERROR_NOACCESS because we are accessing not-existing variable. 30 | // Any other errors are unexpected. 31 | dwRet = 0; 32 | if (GetFirmwareEnvironmentVariable(___T(""), ___T("{00000000-0000-0000-0000-000000000000}"), NULL, 0) == 0) { 33 | if (GetLastError() == ERROR_INVALID_FUNCTION) { 34 | printf("Cannot access UEFI (are you running BIOS?)\n"); 35 | exit(-1); 36 | } 37 | else if (GetLastError() == ERROR_NOACCESS) { 38 | // Expected 39 | } 40 | else { 41 | PrintError(GetLastError()); 42 | exit(GetLastError()); 43 | } 44 | } 45 | } 46 | 47 | int read_efi_variable(const char* name, uint16_t** data) { 48 | // Windows does not allocate memory for it so we have to do it 49 | uint16_t* res = (uint16_t *)malloc(sizeof(uint16_t)* 1024); 50 | int data_size = GetFirmwareEnvironmentVariable( 51 | ___T(name), 52 | ___T(EFI_GLOBAL_VARIABLE), 53 | res, 54 | sizeof(uint16_t)* 1024); 55 | if (data_size) { 56 | *data = res; 57 | return data_size / 2; 58 | } 59 | else { 60 | PrintError(GetLastError()); 61 | exit(GetLastError()); 62 | } 63 | } 64 | 65 | int set_efi_variable(const char* name, uint16_t num) { 66 | int res = SetFirmwareEnvironmentVariable( 67 | ___T(name), 68 | ___T(EFI_GLOBAL_VARIABLE), 69 | (PVOID)&num, 70 | sizeof(uint16_t)); 71 | if (res) { 72 | return res; 73 | } 74 | else { 75 | PrintError(GetLastError()); 76 | exit(GetLastError()); 77 | } 78 | } 79 | 80 | int set_boot_next(uint16_t num) { 81 | return set_efi_variable("BootNext", num); 82 | } 83 | 84 | int boot_entry_list(uint16_t** list) { 85 | uint16_t *data = NULL; 86 | int length = read_efi_variable("BootOrder", &data); 87 | *list = data; 88 | return length; 89 | } 90 | 91 | char* boot_entry_name(uint16_t id) { 92 | char buffer[9]; 93 | uint16_t *data = NULL; 94 | int length, i; 95 | char* name = (char *)malloc(64 * sizeof(char)); 96 | sprintf_s(buffer, 9, "Boot%04x", id); 97 | length = read_efi_variable(buffer, &data); 98 | for (i = 3; i < length; i++) { 99 | if (data[i] == 0) break; 100 | name[i - 3] = data[i]; 101 | } 102 | name[i - 3] = 0; 103 | return name; 104 | } 105 | --------------------------------------------------------------------------------