#ifndef __EFIGUARD_GUID_H__
#define __EFIGUARD_GUID_H__

#include <Guid/GlobalVariable.h>

#ifdef __cplusplus
extern "C" {
#endif

//
// EfiGuard Bootkit Protocol GUID
//
#define EFI_EFIGUARD_DRIVER_PROTOCOL_GUID \
	{ \
	0x51e4785b, 0xb1e4, 0x4fda, { 0xaf, 0x5f, 0x94, 0x2e, 0xc0, 0x15, 0xf1, 0x7 } \
	}

//
// Type of Driver Signature Enforcement bypass to use
//
typedef enum _EFIGUARD_DSE_BYPASS_TYPE {
	//
	// Do not disable DSE.
	//
	DSE_DISABLE_NONE = 0,

	//
	// Prevent DSE initialization at boot by patching SepInitializeCodeIntegrity.
	// DSE will remain disabled until system reboot.
	//
	// Note: This can be trivially detected. If this is not a problem for you,
	// this is the most convenient option.
	//
	DSE_DISABLE_AT_BOOT = 1,

	//
	// Hook the EFI SetVariable() runtime service to provide a stealth method for writing
	// to any kernel address. This is therefore not a true DSE bypass but simply a backdoor.
	// The most obvious use however is to set g_CiOptions/g_CiEnabled to 0 to load any driver.
	//
	// This is the default DSE bypass setting.
	//
	DSE_DISABLE_SETVARIABLE_HOOK = 2
} EFIGUARD_DSE_BYPASS_TYPE;


//
// Kernel read/write backdoor struct, used in combination with DSE bypass type DSE_DISABLE_SETVARIABLE_HOOK.
// For scalar values, use one of the Byte through Qword fields, set its size in Size, and set IsMemCopy to FALSE.
// For writes, the field that was used to supply the data will contain the original value on return.
//
// To perform a memcpy, set UserBuffer to a pointer-aligned buffer, Size to the size of the buffer, and IsMemCopy to TRUE.
// There is no SEH in UEFI for buffer probing, so it is the caller's responsibility that the address is valid and correctly aligned.
// No backup of the original buffer will be made because this would require memory allocation at runtime. If you wish to obtain
// the contents of the current data at KernelAddress, call the backdoor twice with the first call having IsReadOperation = TRUE.
//
// If IsReadOperation is TRUE, no writes to kernel memory will be performed. Instead either
// (1) one of the Byte through Qword fields (depending on size) will contain the value at KernelAddress, or
// (2) the memcpy performed will be in the opposite direction, i.e. from KernelAddress to UserBuffer.
//
#define EFIGUARD_BACKDOOR_VARIABLE_NAME						L"roodkcaBdrauGifE" // "EfiGuardBackdoor" // TODO: randomize?
#define EFIGUARD_BACKDOOR_VARIABLE_GUID						&gEfiGlobalVariableGuid
#define EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES				(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)
#define EFIGUARD_BACKDOOR_VARIABLE_DATASIZE					sizeof(EFIGUARD_BACKDOOR_DATA)

#define EFIGUARD_BACKDOOR_COOKIE_VALUE						(0xDEADC0DE)

typedef struct _EFIGUARD_BACKDOOR_DATA {

	UINTN CookieValue; // Currently must be EFIGUARD_BACKDOOR_COOKIE_VALUE
	VOID* KernelAddress;

	union {
		struct {
			UINT64 Byte : 8;
			UINT64 Word : 16;
			UINT64 Dword : 32;
			UINT64 Spare : 8;
		} s;

		UINT64 Qword;
		VOID* UserBuffer;
	} u;

	UINT32 Size;
	BOOLEAN ReadOnly;
} EFIGUARD_BACKDOOR_DATA;


//
// Main driver configuration data. This can be optionally sent to the driver using the Configure() pointer in the protocol.
//
typedef struct _EFIGUARD_CONFIGURATION_DATA {
	//
	// Type of Driver Signature Enforcement bypass to use.
	// Default: DSE_DISABLE_SETVARIABLE_HOOK
	//
	EFIGUARD_DSE_BYPASS_TYPE DseBypassMethod;

	//
	// Whether to wait for a keypress at the end of each patch stage, regardless of success or failure.
	// Recommended for debugging purposes only.
	// Default: FALSE
	//
	BOOLEAN WaitForKeyPress;
} EFIGUARD_CONFIGURATION_DATA;


//
// Sends configuration data to the driver.
//
typedef
EFI_STATUS
(EFIAPI*
EFIGUARD_CONFIGURE)(
	IN CONST EFIGUARD_CONFIGURATION_DATA* ConfigurationData
	);


//
// The EfiGuard bootkit driver protocol.
//
typedef struct _EFIGUARD_DRIVER_PROTOCOL {
	EFIGUARD_CONFIGURE Configure;
} EFIGUARD_DRIVER_PROTOCOL;


extern EFI_GUID gEfiGuardDriverProtocolGuid;

#ifdef __cplusplus
}
#endif

#endif