mirror of
https://github.com/Metabolix/HackBGRT.git
synced 2026-09-25 21:41:22 -07:00
Implement rebooting to UEFI setup
This commit is contained in:
@@ -9,7 +9,7 @@ GNUEFI_LIB = /usr/$(CC_PREFIX)/lib
|
|||||||
|
|
||||||
FILES_C = src/main.c src/util.c src/types.c src/config.c
|
FILES_C = src/main.c src/util.c src/types.c src/config.c
|
||||||
FILES_H = $(wildcard src/*.h)
|
FILES_H = $(wildcard src/*.h)
|
||||||
FILES_CS = src/Setup.cs src/SetupHelper.cs src/Esp.cs
|
FILES_CS = src/Setup.cs src/SetupHelper.cs src/Esp.cs src/Efi.cs
|
||||||
GIT_DESCRIBE = $(firstword $(shell git describe --tags) unknown)
|
GIT_DESCRIBE = $(firstword $(shell git describe --tags) unknown)
|
||||||
CFLAGS += '-DGIT_DESCRIBE=L"$(GIT_DESCRIBE)"'
|
CFLAGS += '-DGIT_DESCRIBE=L"$(GIT_DESCRIBE)"'
|
||||||
ZIPDIR = HackBGRT-$(GIT_DESCRIBE:v%=%)
|
ZIPDIR = HackBGRT-$(GIT_DESCRIBE:v%=%)
|
||||||
|
|||||||
+176
@@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods for handling EFI variables.
|
||||||
|
*/
|
||||||
|
public class Efi {
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern UInt32 GetFirmwareEnvironmentVariableEx(string lpName, string lpGuid, [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer, UInt32 nSize, out UInt32 pdwAttributes);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern UInt32 SetFirmwareEnvironmentVariableEx(string lpName, string lpGuid, [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer, UInt32 nSize, UInt32 pdwAttributes);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
|
||||||
|
private static extern bool AdjustTokenPrivileges(IntPtr htoken, bool disable, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", ExactSpelling = true)]
|
||||||
|
private static extern IntPtr GetCurrentProcess();
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
|
||||||
|
private static extern bool OpenProcessToken(IntPtr h, int acc, out IntPtr phtok);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
private static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern bool CloseHandle(IntPtr hObject);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
private struct TokPriv1Luid {
|
||||||
|
public int Count;
|
||||||
|
public long Luid;
|
||||||
|
public int Attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about an EFI variable.
|
||||||
|
*/
|
||||||
|
public class Variable {
|
||||||
|
public string name, guid;
|
||||||
|
public UInt32 attributes;
|
||||||
|
public byte[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string EFI_GLOBAL_GUID = "{8be4df61-93ca-11d2-aa0d-00e098032b8c}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the privilege to access EFI variables.
|
||||||
|
*/
|
||||||
|
public static void EnablePrivilege() {
|
||||||
|
const int SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||||
|
const int TOKEN_QUERY = 0x00000008;
|
||||||
|
const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
|
||||||
|
const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege";
|
||||||
|
IntPtr htoken = IntPtr.Zero;
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out htoken)) {
|
||||||
|
throw new Exception("EnablePrivilege: OpenProcessToken failed: " + Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TokPriv1Luid tp;
|
||||||
|
tp.Count = 1;
|
||||||
|
tp.Luid = 0;
|
||||||
|
tp.Attr = SE_PRIVILEGE_ENABLED;
|
||||||
|
if (!LookupPrivilegeValue(null, SE_SYSTEM_ENVIRONMENT_NAME, ref tp.Luid)) {
|
||||||
|
throw new Exception("EnablePrivilege: LookupPrivilegeValue failed: " + Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
if (!AdjustTokenPrivileges(htoken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero)) {
|
||||||
|
throw new Exception("EnablePrivilege: AdjustTokenPrivileges failed: " + Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
CloseHandle(htoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an EFI variable.
|
||||||
|
*
|
||||||
|
* @param name Name of the EFI variable.
|
||||||
|
* @param guid GUID of the EFI variable.
|
||||||
|
* @return Information about the EFI variable.
|
||||||
|
*/
|
||||||
|
private static Variable GetVariable(string name, string guid = EFI_GLOBAL_GUID) {
|
||||||
|
Variable result = new Variable();
|
||||||
|
result.name = name;
|
||||||
|
result.guid = guid;
|
||||||
|
result.data = null;
|
||||||
|
result.attributes = 0;
|
||||||
|
for (UInt32 i = 4096; i <= 1024*1024; i *= 2) {
|
||||||
|
byte[] buf = new byte[i];
|
||||||
|
UInt32 len = GetFirmwareEnvironmentVariableEx(name, guid, buf, (UInt32) buf.Length, out result.attributes);
|
||||||
|
if (len == buf.Length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (len > 0 || Marshal.GetLastWin32Error() == 0) {
|
||||||
|
result.data = new byte[len];
|
||||||
|
Array.Copy(buf, 0, result.data, 0, len);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
switch (len != 0 ? 0 : Marshal.GetLastWin32Error()) {
|
||||||
|
case 203:
|
||||||
|
// Not found.
|
||||||
|
return result;
|
||||||
|
case 87:
|
||||||
|
throw new Exception("GetVariable: Invalid parameter");
|
||||||
|
case 1314:
|
||||||
|
throw new Exception("GetVariable: Privilege not held");
|
||||||
|
default:
|
||||||
|
throw new Exception("GetVariable: error " + Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("GetFirmwareEnvironmentVariable: too big data");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an EFI variable.
|
||||||
|
*
|
||||||
|
* @param v Information of the variable.
|
||||||
|
*/
|
||||||
|
private static void SetVariable(Variable v) {
|
||||||
|
UInt32 r = SetFirmwareEnvironmentVariableEx(v.name, v.guid, v.data, (UInt32) v.data.Length, v.attributes);
|
||||||
|
if (r == 0) {
|
||||||
|
switch (Marshal.GetLastWin32Error()) {
|
||||||
|
case 87:
|
||||||
|
throw new Exception("GetVariable: Invalid parameter");
|
||||||
|
case 1314:
|
||||||
|
throw new Exception("GetVariable: Privilege not held");
|
||||||
|
default:
|
||||||
|
throw new Exception("GetVariable: error " + Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if Secure Boot is enabled.
|
||||||
|
*
|
||||||
|
* @return 0 for disabled, 1 for enabled, other for unknown.
|
||||||
|
*/
|
||||||
|
public static int GetSecureBootStatus() {
|
||||||
|
// GetVariable("SecureBoot") reports always 1 (on Lenovo E335).
|
||||||
|
// Windows registry seems to work better, though.
|
||||||
|
try {
|
||||||
|
return (int) Registry.GetValue(
|
||||||
|
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State",
|
||||||
|
"UEFISecureBootEnabled",
|
||||||
|
-1
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if it's possible to reboot to EFI setup.
|
||||||
|
*
|
||||||
|
* @return True, if it's possible to reboot to EFI setup.
|
||||||
|
*/
|
||||||
|
public static bool CanBootToFW() {
|
||||||
|
try {
|
||||||
|
Variable tmp = GetVariable("OsIndicationsSupported");
|
||||||
|
return tmp.data != null && (tmp.data[0] & 1) != 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark that the next reboot should go to EFI setup.
|
||||||
|
*/
|
||||||
|
public static void SetBootToFW() {
|
||||||
|
Variable tmp = GetVariable("OsIndications");
|
||||||
|
tmp.data[0] |= 1;
|
||||||
|
SetVariable(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
-19
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HackBGRT Setup.
|
* HackBGRT Setup.
|
||||||
@@ -203,7 +202,7 @@ public class Setup: SetupHelper {
|
|||||||
* Check Secure Boot status and inform the user.
|
* Check Secure Boot status and inform the user.
|
||||||
*/
|
*/
|
||||||
public static void HandleSecureBoot() {
|
public static void HandleSecureBoot() {
|
||||||
int secureBoot = EfiGetSecureBootStatus();
|
int secureBoot = Efi.GetSecureBootStatus();
|
||||||
if (secureBoot == 0) {
|
if (secureBoot == 0) {
|
||||||
Console.WriteLine("Secure Boot is disabled, good!");
|
Console.WriteLine("Secure Boot is disabled, good!");
|
||||||
} else {
|
} else {
|
||||||
@@ -215,12 +214,29 @@ public class Setup: SetupHelper {
|
|||||||
Console.WriteLine("It's very important to disable Secure Boot before installing.");
|
Console.WriteLine("It's very important to disable Secure Boot before installing.");
|
||||||
Console.WriteLine("Otherwise your machine may become unbootable.");
|
Console.WriteLine("Otherwise your machine may become unbootable.");
|
||||||
Console.WriteLine("Choose action (press a key):");
|
Console.WriteLine("Choose action (press a key):");
|
||||||
|
bool canBootToFW = Efi.CanBootToFW();
|
||||||
|
if (canBootToFW) {
|
||||||
|
Console.WriteLine(" S = Enter EFI Setup to disable Secure Boot manually; requires reboot!");
|
||||||
|
}
|
||||||
Console.WriteLine(" I = Install anyway; THIS MAY BE DANGEROUS!");
|
Console.WriteLine(" I = Install anyway; THIS MAY BE DANGEROUS!");
|
||||||
Console.WriteLine(" C = Cancel");
|
Console.WriteLine(" C = Cancel");
|
||||||
var k = Console.ReadKey().Key;
|
var k = Console.ReadKey().Key;
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
if (k == ConsoleKey.I) {
|
if (k == ConsoleKey.I) {
|
||||||
Console.WriteLine("Continuing. THIS MAY BE DANGEROUS!");
|
Console.WriteLine("Continuing. THIS MAY BE DANGEROUS!");
|
||||||
|
} else if (canBootToFW && k == ConsoleKey.S) {
|
||||||
|
Efi.SetBootToFW();
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Reboot your computer. You will then automatically enter the UEFI setup.");
|
||||||
|
Console.WriteLine("Find and disable Secure Boot, then save and exit, then run this installer.");
|
||||||
|
Console.WriteLine("Press R to reboot now, other key to exit.");
|
||||||
|
var k2 = Console.ReadKey().Key;
|
||||||
|
Console.WriteLine();
|
||||||
|
if (k2 == ConsoleKey.R) {
|
||||||
|
StartProcess("shutdown", "-f -r -t 1");
|
||||||
|
}
|
||||||
|
Environment.Exit(0);
|
||||||
|
throw new ExitSetup(0);
|
||||||
} else {
|
} else {
|
||||||
Console.WriteLine("Aborting because of Secure Boot.");
|
Console.WriteLine("Aborting because of Secure Boot.");
|
||||||
throw new ExitSetup(1);
|
throw new ExitSetup(1);
|
||||||
@@ -228,23 +244,6 @@ public class Setup: SetupHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if Secure Boot is enabled.
|
|
||||||
*
|
|
||||||
* @return 0 for disabled, 1 for enabled, other for unknown.
|
|
||||||
*/
|
|
||||||
public static int EfiGetSecureBootStatus() {
|
|
||||||
try {
|
|
||||||
return (int) Registry.GetValue(
|
|
||||||
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State",
|
|
||||||
"UEFISecureBootEnabled",
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
} catch (Exception) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string Source, Destination, Config, Splash;
|
protected string Source, Destination, Config, Splash;
|
||||||
protected BootLoaderInfo MsLoader, MsLoaderBackup, NewLoader, NewLoaderSource;
|
protected BootLoaderInfo MsLoader, MsLoaderBackup, NewLoader, NewLoaderSource;
|
||||||
protected string EfiArch;
|
protected string EfiArch;
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ public class SetupHelper {
|
|||||||
Environment.ExitCode = p.ExitCode;
|
Environment.ExitCode = p.ExitCode;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Efi.EnablePrivilege();
|
||||||
} catch {
|
} catch {
|
||||||
Console.WriteLine("This installer needs to be run as administrator!");
|
Console.WriteLine("This installer needs to be run as administrator!");
|
||||||
Console.WriteLine("Press any key to quit.");
|
Console.WriteLine("Press any key to quit.");
|
||||||
|
|||||||
Reference in New Issue
Block a user