Publish the files
This commit is contained in:
437
Sources/Platform/Windows/WinPlatform.c
Normal file
437
Sources/Platform/Windows/WinPlatform.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/*!
|
||||
@file WinPlatform.c
|
||||
|
||||
@brief Windows specific platform API.
|
||||
|
||||
@details Some of API in this module can be called from the host. See the
|
||||
description of each API.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#include "WinPlatform.h"
|
||||
#include "WinLogger.h"
|
||||
#include "../../MiniVisor.h"
|
||||
|
||||
MV_SECTION_INIT DRIVER_INITIALIZE DriverEntry;
|
||||
|
||||
MV_SECTION_PAGED static DRIVER_UNLOAD DriverUnload;
|
||||
|
||||
//
|
||||
// The pool tag value used across the project.
|
||||
//
|
||||
#define MV_POOL_TAG ((UINT32)'vniM')
|
||||
|
||||
//
|
||||
// Maps conversion between MV_STATUS and NTSTATUS.
|
||||
//
|
||||
typedef struct _STATUS_MAPPING
|
||||
{
|
||||
MV_STATUS MvStatus;
|
||||
NTSTATUS NtStatus;
|
||||
} STATUS_MAPPING;
|
||||
|
||||
static CONST STATUS_MAPPING k_StatusMapping[] =
|
||||
{
|
||||
{ MV_STATUS_SUCCESS, STATUS_SUCCESS, },
|
||||
{ MV_STATUS_UNSUCCESSFUL, STATUS_UNSUCCESSFUL, },
|
||||
{ MV_STATUS_ACCESS_DENIED, STATUS_ACCESS_DENIED, },
|
||||
{ MV_STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES, },
|
||||
{ MV_STATUS_HV_OPERATION_FAILED, STATUS_HV_OPERATION_FAILED, },
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief Converts MV_STATUS to NTSTATUS.
|
||||
|
||||
@param[in] Status - The MV_STATUS to convert from.
|
||||
|
||||
@return The converted NTSTATUS.
|
||||
*/
|
||||
static
|
||||
NTSTATUS
|
||||
ConvertMvToNtStatus (
|
||||
_In_ MV_STATUS Status
|
||||
)
|
||||
{
|
||||
for (UINT32 i = 0; i < RTL_NUMBER_OF(k_StatusMapping); ++i)
|
||||
{
|
||||
if (Status == k_StatusMapping[i].MvStatus)
|
||||
{
|
||||
return k_StatusMapping[i].NtStatus;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update the mapping when this assert hits.
|
||||
//
|
||||
MV_ASSERT(FALSE);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Converts NTSTATUS to MV_STATUS.
|
||||
|
||||
@param[in] Status - The NTSTATUS to convert from.
|
||||
|
||||
@return The converted MV_STATUS.
|
||||
*/
|
||||
static
|
||||
MV_STATUS
|
||||
ConvertNtToMvStatus (
|
||||
_In_ NTSTATUS Status
|
||||
)
|
||||
{
|
||||
for (UINT32 i = 0; i < RTL_NUMBER_OF(k_StatusMapping); ++i)
|
||||
{
|
||||
if (Status == k_StatusMapping[i].NtStatus)
|
||||
{
|
||||
return k_StatusMapping[i].MvStatus;
|
||||
}
|
||||
}
|
||||
return MV_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief The platform specific module entry point.
|
||||
|
||||
@param[in] DriverObject - The driver's driver object.
|
||||
|
||||
@param[in] RegistryPath - A path to the driver's registry key.
|
||||
|
||||
@return STATUS_SUCCESS on success; otherwise, an appropriate error code.
|
||||
*/
|
||||
MV_SECTION_INIT
|
||||
_Use_decl_annotations_
|
||||
NTSTATUS
|
||||
DriverEntry (
|
||||
PDRIVER_OBJECT DriverObject,
|
||||
PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(RegistryPath);
|
||||
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
|
||||
//
|
||||
// Opts-in no-execute (NX) non-paged pool for security when available.
|
||||
//
|
||||
// By defining POOL_NX_OPTIN as 1 and calling this function, non-paged pool
|
||||
// allocation by the ExAllocatePool family with the NonPagedPool flag
|
||||
// automatically allocates NX non-paged pool on Windows 8 and later versions
|
||||
// of Windows, while on Windows 7 where NX non-paged pool is unsupported,
|
||||
// executable non-paged pool is returned as usual. The merit of this is that
|
||||
// the NonPagedPoolNx flag does not have to be used. Since the flag is
|
||||
// unsupported on Windows 7, being able to stick with the NonPagedPool flag
|
||||
// help keep code concise.
|
||||
//
|
||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||
|
||||
//
|
||||
// Start cross-platform initialization.
|
||||
//
|
||||
return ConvertMvToNtStatus(InitializeMiniVisor());
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief The platform specific module unload callback.
|
||||
|
||||
@param[in] DriverObject - The driver's driver object.
|
||||
*/
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
static
|
||||
VOID
|
||||
DriverUnload (
|
||||
PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DriverObject);
|
||||
|
||||
PAGED_CODE()
|
||||
|
||||
//
|
||||
// Start cross-platform clean up.
|
||||
//
|
||||
CleanupMiniVisor();
|
||||
}
|
||||
|
||||
MV_SECTION_INIT
|
||||
_Use_decl_annotations_
|
||||
MV_STATUS
|
||||
InitializePlatform (
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
LOGGER_CONFIGURATION loggerConfig;
|
||||
|
||||
PAGED_CODE()
|
||||
|
||||
//
|
||||
// Initialize in-house logger. Enable all flags.
|
||||
//
|
||||
loggerConfig.Level = LogLevelDebug;
|
||||
loggerConfig.Flags.AsUInt32 = MAXUINT32;
|
||||
loggerConfig.FlushIntervalInMs = 500;
|
||||
loggerConfig.BufferSize = (SIZE_T)(32 * PAGE_SIZE) * GetActiveProcessorCount();
|
||||
loggerConfig.FilePath = L"\\SystemRoot\\Minivisor.log";
|
||||
status = InitializeLogger(&loggerConfig);
|
||||
if (NT_ERROR(status))
|
||||
{
|
||||
LOG_EARLY_ERROR("InitializeLogger failed : %08x", status);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
return ConvertNtToMvStatus(status);
|
||||
}
|
||||
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
CleanupPlatform (
|
||||
)
|
||||
{
|
||||
PAGED_CODE()
|
||||
|
||||
CleanupLogger();
|
||||
}
|
||||
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
Sleep (
|
||||
UINT64 Milliseconds
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER interval;
|
||||
|
||||
PAGED_CODE()
|
||||
|
||||
interval.QuadPart = -(LONGLONG)(10000 * Milliseconds);
|
||||
(VOID)KeDelayExecutionThread(KernelMode, FALSE, &interval);
|
||||
}
|
||||
|
||||
UINT32
|
||||
GetActiveProcessorCount (
|
||||
)
|
||||
{
|
||||
return KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
|
||||
}
|
||||
|
||||
UINT32
|
||||
GetCurrentProcessorNumber (
|
||||
)
|
||||
{
|
||||
return KeGetCurrentProcessorNumberEx(NULL);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
UINT64
|
||||
GetPhysicalAddress (
|
||||
VOID* VirualAddress
|
||||
)
|
||||
{
|
||||
return (UINT64)MmGetPhysicalAddress(VirualAddress).QuadPart;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID*
|
||||
GetVirtualAddress (
|
||||
UINT64 PhysicalAddress
|
||||
)
|
||||
{
|
||||
PHYSICAL_ADDRESS pa;
|
||||
|
||||
pa.QuadPart = (LONGLONG)PhysicalAddress;
|
||||
return MmGetVirtualForPhysical(pa);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID*
|
||||
AllocateSystemMemory (
|
||||
UINT64 PageCount
|
||||
)
|
||||
{
|
||||
VOID* pages;
|
||||
SIZE_T allocationBytes;
|
||||
|
||||
MV_ASSERT(PageCount > 0);
|
||||
|
||||
allocationBytes = (SIZE_T)PageCount * PAGE_SIZE;
|
||||
|
||||
//
|
||||
// This is bogus.
|
||||
// "The current function is permitted to run at an IRQ level above the
|
||||
// maximum permitted for 'ExAllocatePoolWithTag' (1)."
|
||||
//
|
||||
#pragma warning(suppress: 28118)
|
||||
pages = ExAllocatePoolWithTag(NonPagedPool, allocationBytes, MV_POOL_TAG);
|
||||
if (pages == NULL)
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
RtlZeroMemory(pages, allocationBytes);
|
||||
|
||||
Exit:
|
||||
return pages;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
FreeSystemMemory (
|
||||
VOID* Pages,
|
||||
UINT64 PageCount
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PageCount);
|
||||
|
||||
ExFreePoolWithTag(Pages, MV_POOL_TAG);
|
||||
}
|
||||
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
VOID*
|
||||
ReserveVirtualAddress (
|
||||
UINT64 PageCount
|
||||
)
|
||||
{
|
||||
PAGED_CODE()
|
||||
|
||||
return MmAllocateMappingAddress(PageCount * PAGE_SIZE, MV_POOL_TAG);
|
||||
}
|
||||
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
FreeReservedVirtualAddress (
|
||||
VOID* Pages,
|
||||
UINT64 PageCount
|
||||
)
|
||||
{
|
||||
PAGED_CODE()
|
||||
|
||||
UNREFERENCED_PARAMETER(PageCount);
|
||||
|
||||
MmFreeMappingAddress(Pages, MV_POOL_TAG);
|
||||
}
|
||||
|
||||
MV_SECTION_PAGED
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
RunOnAllProcessors (
|
||||
USER_PASSIVE_CALLBACK* Callback,
|
||||
VOID* Context
|
||||
)
|
||||
{
|
||||
UINT32 numberOfProcessors;
|
||||
|
||||
PAGED_CODE()
|
||||
|
||||
numberOfProcessors = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
|
||||
for (UINT32 index = 0; index < numberOfProcessors; ++index)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PROCESSOR_NUMBER processorNumber;
|
||||
GROUP_AFFINITY newAffinity, prevAffinity;
|
||||
|
||||
status = KeGetProcessorNumberFromIndex(index, &processorNumber);
|
||||
if (NT_ERROR(status))
|
||||
{
|
||||
MV_ASSERT(FALSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&newAffinity, sizeof(newAffinity));
|
||||
newAffinity.Group = processorNumber.Group;
|
||||
newAffinity.Mask = 1ull << processorNumber.Number;
|
||||
KeSetSystemGroupAffinityThread(&newAffinity, &prevAffinity);
|
||||
Callback(Context);
|
||||
KeRevertToUserGroupAffinityThread(&prevAffinity);
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
InitializeSystemSpinLock (
|
||||
SPIN_LOCK* SpinLock
|
||||
)
|
||||
{
|
||||
*SpinLock = SpinLockReleased;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
UINT8
|
||||
AcquireSystemSpinLock (
|
||||
SPIN_LOCK* SpinLock
|
||||
)
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
|
||||
//
|
||||
// Raise IRQL if the current is lower than DISPATCH_LEVEL.
|
||||
//
|
||||
oldIrql = KeGetCurrentIrql();
|
||||
if (oldIrql < DISPATCH_LEVEL)
|
||||
{
|
||||
oldIrql = KeRaiseIrqlToDpcLevel();
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
//
|
||||
// Attempt to acquire the lock.
|
||||
//
|
||||
if (InterlockedBitTestAndSet64(SpinLock, 0) == SpinLockReleased)
|
||||
{
|
||||
//
|
||||
// Acquired the lock.
|
||||
//
|
||||
MV_ASSERT(*SpinLock == SpinLockAcquired);
|
||||
_Analysis_assume_lock_acquired_(*SpinLock);
|
||||
break;
|
||||
}
|
||||
|
||||
while (*SpinLock == SpinLockAcquired)
|
||||
{
|
||||
//
|
||||
// Someone already acquired it. Spin unless the some of release it.
|
||||
//
|
||||
YieldProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
return oldIrql;
|
||||
}
|
||||
|
||||
//
|
||||
// "The IRQL in 'PreviousContext' was never restored."
|
||||
//
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: __WARNING_IRQL_NOT_USED)
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
ReleaseSystemSpinLock (
|
||||
SPIN_LOCK* SpinLock,
|
||||
UINT8 PreviousContext
|
||||
)
|
||||
{
|
||||
//
|
||||
// Prevent CPU and compiler re-ordering, and make sure any operations are
|
||||
// done before releasing the spin lock.
|
||||
//
|
||||
MemoryBarrier();
|
||||
*SpinLock = SpinLockReleased;
|
||||
_Analysis_assume_lock_released_(*SpinLock);
|
||||
|
||||
//
|
||||
// Lowers IRQL if necessary.
|
||||
//
|
||||
if (PreviousContext < DISPATCH_LEVEL)
|
||||
{
|
||||
KeLowerIrql(PreviousContext);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
Reference in New Issue
Block a user