#pragma once #include <cstdint> #include <type_traits> #include <bit> #include <string> #include "byteswap.h" #ifdef _WIN32 #include <windows.h> #endif // real win32 handles will never use the upper bits unless something goes really wrong #define CHECK_GUEST_HANDLE(HANDLE) (((HANDLE) & 0x80000000) == 0x80000000) #define GUEST_HANDLE(HANDLE) ((HANDLE) | 0x80000000) #define HOST_HANDLE(HANDLE) ((HANDLE) & ~0x80000000) // Return true to free the associated memory typedef bool(*TypeDestructor_t)(void*); template<typename T> bool DestroyObject(void* obj) { static_cast<T*>(obj)->~T(); return true; } template<typename T> struct be { T value; be() : value(0) { } be(const T v) { set(v); } static T byteswap(T value) { if constexpr (std::is_same_v<T, double>) { const uint64_t swapped = ByteSwap(*reinterpret_cast<uint64_t*>(&value)); return *reinterpret_cast<const T*>(&swapped); } else if constexpr (std::is_same_v<T, float>) { const uint32_t swapped = ByteSwap(*reinterpret_cast<uint32_t*>(&value)); return *reinterpret_cast<const T*>(&swapped); } else if constexpr (std::is_enum_v<T>) { const std::underlying_type_t<T> swapped = ByteSwap(*reinterpret_cast<std::underlying_type_t<T>*>(&value)); return *reinterpret_cast<const T*>(&swapped); } else { return ByteSwap(value); } } void set(const T v) { value = byteswap(v); } T get() const { return byteswap(value); } be& operator| (T value) { set(get() | value); return *this; } be& operator& (T value) { set(get() & value); return *this; } operator T() const { return get(); } be& operator=(T v) { set(v); return *this; } }; extern "C" void* MmGetHostAddress(uint32_t ptr); template<typename T> struct xpointer { be<uint32_t> ptr; xpointer() : ptr(0) { } xpointer(T* p) : ptr(p != nullptr ? (reinterpret_cast<size_t>(p) - reinterpret_cast<size_t>(MmGetHostAddress(0))) : 0) { } T* get() const { if (!ptr.value) { return nullptr; } return reinterpret_cast<T*>(MmGetHostAddress(ptr)); } operator T* () const { return get(); } T* operator->() const { return get(); } }; template<typename TGuest> struct HostObject { typedef TGuest guest_type; }; struct _XLIST_ENTRY; typedef _XLIST_ENTRY XLIST_ENTRY; typedef xpointer<XLIST_ENTRY> PXLIST_ENTRY; typedef struct _IMAGE_CE_RUNTIME_FUNCTION { uint32_t BeginAddress; union { uint32_t Data; struct { uint32_t PrologLength : 8; uint32_t FunctionLength : 22; uint32_t ThirtyTwoBit : 1; uint32_t ExceptionFlag : 1; }; }; } IMAGE_CE_RUNTIME_FUNCTION; static_assert(sizeof(IMAGE_CE_RUNTIME_FUNCTION) == 8); typedef struct _XLIST_ENTRY { be<uint32_t> Flink; be<uint32_t> Blink; } XLIST_ENTRY; typedef struct _XDISPATCHER_HEADER { union { struct { uint8_t Type; union { uint8_t Abandoned; uint8_t Absolute; uint8_t NpxIrql; uint8_t Signalling; }; union { uint8_t Size; uint8_t Hand; }; union { uint8_t Inserted; uint8_t DebugActive; uint8_t DpcActive; }; }; be<uint32_t> Lock; }; be<uint32_t> SignalState; XLIST_ENTRY WaitListHead; } XDISPATCHER_HEADER, * XPDISPATCHER_HEADER; // These variables are never accessed in guest code, we can safely use them in little endian typedef struct _XRTL_CRITICAL_SECTION { XDISPATCHER_HEADER Header; int32_t LockCount; int32_t RecursionCount; uint32_t OwningThread; } XRTL_CRITICAL_SECTION; typedef struct _XANSI_STRING { be<uint16_t> Length; be<uint16_t> MaximumLength; xpointer<char> Buffer; } XANSI_STRING; typedef struct _XOBJECT_ATTRIBUTES { be<uint32_t> RootDirectory; xpointer<XANSI_STRING> Name; xpointer<void> Attributes; } XOBJECT_ATTRIBUTES; typedef XDISPATCHER_HEADER XKEVENT; typedef struct _XIO_STATUS_BLOCK { union { be<uint32_t> Status; be<uint32_t> Pointer; }; be<uint32_t> Information; } XIO_STATUS_BLOCK; typedef struct _XOVERLAPPED { be<uint32_t> Internal; be<uint32_t> InternalHigh; be<uint32_t> Offset; be<uint32_t> OffsetHigh; be<uint32_t> hEvent; } XOVERLAPPED; // this name is so dumb typedef struct _XXOVERLAPPED { union { struct { be<uint32_t> Error; be<uint32_t> Length; }; struct { uint32_t InternalLow; uint32_t InternalHigh; }; }; uint32_t InternalContext; be<uint32_t> hEvent; be<uint32_t> pCompletionRoutine; be<uint32_t> dwCompletionContext; be<uint32_t> dwExtendedError; } XXOVERLAPPED, *PXXOVERLAPPED; static_assert(sizeof(_XXOVERLAPPED) == 0x1C); // https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-memorystatus typedef struct _XMEMORYSTATUS { be<uint32_t> dwLength; be<uint32_t> dwMemoryLoad; be<uint32_t> dwTotalPhys; be<uint32_t> dwAvailPhys; be<uint32_t> dwTotalPageFile; be<uint32_t> dwAvailPageFile; be<uint32_t> dwTotalVirtual; be<uint32_t> dwAvailVirtual; } XMEMORYSTATUS, * XLPMEMORYSTATUS; typedef struct _XVIDEO_MODE { be<uint32_t> DisplayWidth; be<uint32_t> DisplayHeight; be<uint32_t> IsInterlaced; be<uint32_t> IsWidescreen; be<uint32_t> IsHighDefinition; be<uint32_t> RefreshRate; be<uint32_t> VideoStandard; be<uint32_t> Unknown4A; be<uint32_t> Unknown01; be<uint32_t> reserved[3]; } XVIDEO_MODE; typedef struct _XKSEMAPHORE { XDISPATCHER_HEADER Header; be<uint32_t> Limit; } XKSEMAPHORE; typedef struct _XUSER_SIGNIN_INFO { be<uint64_t> xuid; be<uint32_t> dwField08; be<uint32_t> SigninState; be<uint32_t> dwField10; be<uint32_t> dwField14; char Name[16]; } XUSER_SIGNIN_INFO; typedef struct _XTIME_FIELDS { be<uint16_t> Year; be<uint16_t> Month; be<uint16_t> Day; be<uint16_t> Hour; be<uint16_t> Minute; be<uint16_t> Second; be<uint16_t> Milliseconds; be<uint16_t> Weekday; } XTIME_FIELDS, * PXTIME_FIELDS; // Content types #define XCONTENTTYPE_SAVEDATA 1 #define XCONTENTTYPE_DLC 2 #define XCONTENTTYPE_RESERVED 3 #define XCONTENT_NEW 1 #define XCONTENT_EXISTING 2 #define XCONTENT_MAX_DISPLAYNAME 128 #define XCONTENT_MAX_FILENAME 42 #define XCONTENTDEVICE_MAX_NAME 27 typedef struct _XCONTENT_DATA { be<uint32_t> DeviceID; be<uint32_t> dwContentType; be<uint16_t> szDisplayName[XCONTENT_MAX_DISPLAYNAME]; char szFileName[XCONTENT_MAX_FILENAME]; } XCONTENT_DATA, * PXCONTENT_DATA; typedef struct _XHOSTCONTENT_DATA : _XCONTENT_DATA { // This is a host exclusive type so we don't care what goes on std::string szRoot{}; } XHOSTCONTENT_DATA, *PXHOSTCONTENT_DATA; #define XCONTENTDEVICETYPE_HDD 1 #define XCONTENTDEVICETYPE_MU 2 typedef struct _XDEVICE_DATA { be<uint32_t> DeviceID; be<uint32_t> DeviceType; be<uint64_t> ulDeviceBytes; be<uint64_t> ulDeviceFreeBytes; be<uint16_t> wszName[XCONTENTDEVICE_MAX_NAME]; } XDEVICE_DATA, *PXDEVICE_DATA; // Direct reflection of XInput structures #define XAMINPUT_DEVTYPE_GAMEPAD 0x01 #define XAMINPUT_DEVSUBTYPE_GAMEPAD 0x01 #define XAMINPUT_GAMEPAD_DPAD_UP 0x0001 #define XAMINPUT_GAMEPAD_DPAD_DOWN 0x0002 #define XAMINPUT_GAMEPAD_DPAD_LEFT 0x0004 #define XAMINPUT_GAMEPAD_DPAD_RIGHT 0x0008 #define XAMINPUT_GAMEPAD_START 0x0010 #define XAMINPUT_GAMEPAD_BACK 0x0020 #define XAMINPUT_GAMEPAD_LEFT_THUMB 0x0040 #define XAMINPUT_GAMEPAD_RIGHT_THUMB 0x0080 #define XAMINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 #define XAMINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 #define XAMINPUT_GAMEPAD_A 0x1000 #define XAMINPUT_GAMEPAD_B 0x2000 #define XAMINPUT_GAMEPAD_X 0x4000 #define XAMINPUT_GAMEPAD_Y 0x8000 typedef struct _XAMINPUT_GAMEPAD { uint16_t wButtons; uint8_t bLeftTrigger; uint8_t bRightTrigger; int16_t sThumbLX; int16_t sThumbLY; int16_t sThumbRX; int16_t sThumbRY; } XAMINPUT_GAMEPAD, *PXAMINPUT_GAMEPAD; typedef struct _XAMINPUT_VIBRATION { uint16_t wLeftMotorSpeed; uint16_t wRightMotorSpeed; } XAMINPUT_VIBRATION, * PXAMINPUT_VIBRATION; typedef struct _XAMINPUT_CAPABILITIES { uint8_t Type; uint8_t SubType; uint16_t Flags; XAMINPUT_GAMEPAD Gamepad; XAMINPUT_VIBRATION Vibration; } XAMINPUT_CAPABILITIES, * PXAMINPUT_CAPABILITIES; typedef struct _XAMINPUT_STATE { uint32_t dwPacketNumber; XAMINPUT_GAMEPAD Gamepad; } XAMINPUT_STATE, * PXAMINPUT_STATE;