/*! @file Platform.h @brief Platform specific API. @author Satoshi Tanda @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. */ #pragma once #include "Common.h" // // Spin lock type and state names. // #if defined(MV_PLATFORM_WINDOWS) typedef volatile LONG64 SPIN_LOCK; typedef enum _SPIN_LOCK_STATE { SpinLockReleased, SpinLockAcquired, } SPIN_LOCK_STATE; #else #include #endif /*! @brief Initializes platform specific bits. @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. */ _IRQL_requires_max_(PASSIVE_LEVEL) _Must_inspect_result_ MV_STATUS InitializePlatform ( ); /*! @brief Cleans up platform specific bits. */ _IRQL_requires_max_(PASSIVE_LEVEL) VOID CleanupPlatform ( ); /*! @brief Stalls execution of the current processor. @details Use of this API from the host is not allowed. @param[in] Milliseconds - The time to stall in milliseconds. */ _IRQL_requires_max_(APC_LEVEL) VOID Sleep ( _In_ UINT64 Milliseconds ); /*! @brief Returns the active logical processor count. @details Use of this API from the host is not allowed. @return The active logical processor count. */ UINT32 GetActiveProcessorCount ( ); /*! @brief Returns the current processor number. The BSP will return 0. @details Use of this API from the host is not allowed. @return The current processor number. 0 for BSP. */ UINT32 GetCurrentProcessorNumber ( ); /*! @brief Returns the physical address of the given virtual address. @param[in] VirualAddress - The virtual address to retrieve its physical address for the current CR3. This must be non paged pool, otherwise the result is undefined. @return The physical address of the given virtual address. */ UINT64 GetPhysicalAddress ( _In_ VOID* VirualAddress ); /*! @brief Returns the virtual address of the given physical address. @param[in] PhysicalAddress - The physical address to retrieve its virtual address for the current CR3. @return The virtual address of the given physical address. */ VOID* GetVirtualAddress ( _In_ UINT64 PhysicalAddress ); /*! @brief Allocates page-aligned, zero-initialized physical memory resident pages. @details Use of this API from the host is not allowed. @param[in] PageCount - The page count to allocate. @return The base of allocated pointer, or NULL on failure. The caller must free the return value with FreeSystemMemory(). */ __drv_allocatesMem(Mem) _IRQL_requires_max_(DISPATCH_LEVEL) _Post_maybenull_ _Post_writable_byte_size_(PageCount * PAGE_SIZE) _Must_inspect_result_ VOID* AllocateSystemMemory ( _In_ UINT64 PageCount ); /*! @brief Frees the memory allocated by AllocateSystemMemory(). @details Use of this API from the host is not allowed. @param[in] Pages - The pointer to free. @param[in] PageCount - Unused. */ _IRQL_requires_max_(DISPATCH_LEVEL) VOID FreeSystemMemory ( _Pre_notnull_ __drv_freesMem(Mem) VOID* Pages, _In_ UINT64 PageCount ); /*! @brief Reserves the virtual address. The returned address is not accessible. @details Use of this API from the host is not allowed. @param[in] PageCount - The page count to reserve. @return The address of reserved region on success or NULL. The caller must free this value with FreeReservedVirtualAddress(). */ _IRQL_requires_max_(APC_LEVEL) _Must_inspect_result_ VOID* ReserveVirtualAddress ( _In_ UINT64 PageCount ); /*! @brief Frees the address reserved with ReserveVirtualAddress(). @details Use of this API from the host is not allowed. @param[in] Pages - The pointer returned from ReserveVirtualAddress(). @param[in] PageCount - Unused. */ _IRQL_requires_max_(APC_LEVEL) VOID FreeReservedVirtualAddress ( _In_ VOID* Pages, _In_ UINT64 PageCount ); typedef VOID USER_PASSIVE_CALLBACK ( _Inout_ VOID* Context ); /*! @brief Executes the callback at the PASSIVE_LEVEL on each processor one by one. @details Use of this API from the host is not allowed. @param[in] Callback - The pointer to the function to execute. @param[in,out] Context - The pointer to arbitrary context data. */ _IRQL_requires_max_(APC_LEVEL) VOID RunOnAllProcessors ( _In_ USER_PASSIVE_CALLBACK* Callback, _Inout_ VOID* Context ); /*! @brief Initializes the spin lock. @param[out] SpinLock - The pointer to spin lock to initialize. */ VOID InitializeSystemSpinLock ( _Out_ SPIN_LOCK* SpinLock ); /*! @brief Acquires the spin lock. @details The custom spin lock is used because NT provided spin lock API is not compatible with Driver Verifier when they are used from hypervisor. @param[in,out] SpinLock - The pointer to the spin lock to acquire. @return The opaque previous context. */ _Requires_lock_not_held_(*SpinLock) _Acquires_lock_(*SpinLock) _IRQL_requires_max_(HIGH_LEVEL) _IRQL_saves_ _IRQL_raises_(DISPATCH_LEVEL) UINT8 AcquireSystemSpinLock ( _Inout_ SPIN_LOCK* SpinLock ); /*! @brief Release the spin lock and lowers IRQL if necessary. @details The custom spin lock is used because NT provided spin lock API is not compatible with Driver Verifier when they are used from hypervisor. @param[in,out] SpinLock - The spin lock to release. @param[in] PreviousContext - The opaque previous context returned by the AcquireSpinLock function. */ _Requires_lock_held_(*SpinLock) _Releases_lock_(*SpinLock) _IRQL_requires_max_(HIGH_LEVEL) VOID ReleaseSystemSpinLock ( _Inout_ SPIN_LOCK* SpinLock, _In_ _IRQL_restores_ UINT8 PreviousContext );