mirror of
https://github.com/Metabolix/HackBGRT.git
synced 2025-12-06 17:15:42 -08:00
Implement rebooting to UEFI setup
This commit is contained in:
2
Makefile
2
Makefile
@@ -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_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)
|
||||
CFLAGS += '-DGIT_DESCRIBE=L"$(GIT_DESCRIBE)"'
|
||||
ZIPDIR = HackBGRT-$(GIT_DESCRIBE:v%=%)
|
||||
|
||||
176
src/Efi.cs
Normal file
176
src/Efi.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
37
src/Setup.cs
37
src/Setup.cs
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Win32;
|
||||
|
||||
/**
|
||||
* HackBGRT Setup.
|
||||
@@ -203,7 +202,7 @@ public class Setup: SetupHelper {
|
||||
* Check Secure Boot status and inform the user.
|
||||
*/
|
||||
public static void HandleSecureBoot() {
|
||||
int secureBoot = EfiGetSecureBootStatus();
|
||||
int secureBoot = Efi.GetSecureBootStatus();
|
||||
if (secureBoot == 0) {
|
||||
Console.WriteLine("Secure Boot is disabled, good!");
|
||||
} else {
|
||||
@@ -215,12 +214,29 @@ public class Setup: SetupHelper {
|
||||
Console.WriteLine("It's very important to disable Secure Boot before installing.");
|
||||
Console.WriteLine("Otherwise your machine may become unbootable.");
|
||||
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(" C = Cancel");
|
||||
var k = Console.ReadKey().Key;
|
||||
Console.WriteLine();
|
||||
if (k == ConsoleKey.I) {
|
||||
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 {
|
||||
Console.WriteLine("Aborting because of Secure Boot.");
|
||||
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 BootLoaderInfo MsLoader, MsLoaderBackup, NewLoader, NewLoaderSource;
|
||||
protected string EfiArch;
|
||||
|
||||
@@ -91,6 +91,7 @@ public class SetupHelper {
|
||||
Environment.ExitCode = p.ExitCode;
|
||||
return;
|
||||
}
|
||||
Efi.EnablePrivilege();
|
||||
} catch {
|
||||
Console.WriteLine("This installer needs to be run as administrator!");
|
||||
Console.WriteLine("Press any key to quit.");
|
||||
|
||||
Reference in New Issue
Block a user