Files
exectos/xtoskrnl/mm/probe.cc
Aiken Harris d8f4f6bfd0
All checks were successful
Builds / ExectOS (i686, release) (push) Successful in 34s
Builds / ExectOS (i686, debug) (push) Successful in 41s
Builds / ExectOS (amd64, release) (push) Successful in 36s
Builds / ExectOS (amd64, debug) (push) Successful in 43s
Add memory manager probe functions
2026-06-30 22:28:39 +02:00

279 lines
7.7 KiB
C++

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/mm/probe.cc
* DESCRIPTION: Memory Manager read/write probe support
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Probes a generic memory buffer for read accessibility.
*
* @param Address
* Supplies the base address of the buffer to probe.
*
* @param Size
* Supplies the size of the buffer in bytes.
*
* @param Alignment
* Supplies the required data alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForRead(IN CONST PVOID Address,
IN SIZE_T Size,
IN ULONG Alignment)
{
/* Check if the buffer size is non-zero */
if(Size)
{
/* Check if the base address violates the required alignment */
if(((ULONG_PTR)Address & (Alignment - 1)) != 0)
{
/* Raise datatype misalignment exception */
RTL::Exception::RaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
}
/* Verify that the end address do not overflow and remains within user space */
if((((ULONG_PTR)Address + Size) < (ULONG_PTR)Address) ||
(((ULONG_PTR)Address + Size) > MM::Paging::GetUserProbeAddress()))
{
/* Raise access violation exception */
RTL::Exception::RaiseStatus(STATUS_ACCESS_VIOLATION);
}
}
}
/**
* Probes an array of fixed-size items for read accessibility.
*
* @param Array
* Supplies the base address of the array.
*
* @param ItemSize
* Supplies the size of a single array element in bytes.
*
* @param ItemCount
* Supplies the total number of elements in the array.
*
* @param Alignment
* Supplies the required array alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForReadArray(IN CONST PVOID Array,
IN ULONG ItemSize,
IN ULONG ItemCount,
IN ULONG Alignment)
{
ULONG ArraySize;
/* Calculate total array size */
ArraySize = ItemSize * ItemCount;
/* Check for integer overflow */
if((ItemSize != 0) && (ArraySize / ItemSize != ItemCount))
{
RTL::Exception::RaiseStatus(STATUS_INVALID_PARAMETER);
}
/* Perform boundary and alignment verification */
ProbeForRead(Array, ArraySize, Alignment);
}
/**
* Probes a structure for read accessibility.
*
* @param Address
* Supplies the base address of the structure to probe.
*
* @param Size
* Supplies the total size of the structure in bytes.
*
* @param Alignment
* Supplies the required structure alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForReadStructure(IN CONST PVOID Address,
IN SIZE_T Size,
IN ULONG Alignment)
{
/* Check if the buffer size is zero or greater than 64k */
if((Size == 0) || (Size > 0x10000))
{
/* Perform boundary and alignment verification */
ProbeForRead(Address, Size, Alignment);
}
else
{
/* Check if the base address violates the required alignment */
if(((ULONG_PTR)Address & (Alignment - 1)) != 0)
{
/* Raise datatype misalignment exception */
RTL::Exception::RaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
}
/* Check address space boundary */
if((ULONG_PTR)Address >= (ULONG_PTR)MM::Paging::GetUserProbeAddress())
{
/* Force access violation on the invalid probe boundary */
*(VOLATILE PULONG CONST)MM::Paging::GetUserProbeAddress() = 0;
}
}
}
/**
* Probes a generic memory buffer for write accessibility.
*
* @param Address
* Supplies the base address of the buffer to probe.
*
* @param Size
* Supplies the size of the buffer in bytes.
*
* @param Alignment
* Supplies the required data alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForWrite(IN PVOID Address,
IN SIZE_T Size,
IN ULONG Alignment)
{
ULONG_PTR CurrentAddress, LastAddress;
/* Check if the buffer size is non-zero */
if(Size)
{
/* Perform boundary and alignment verification */
ProbeForRead(Address, Size, Alignment);
/* Store the current address */
CurrentAddress = (ULONG_PTR)Address;
/* Calculate the end boundary of the requested buffer */
LastAddress = CurrentAddress + Size - 1;
LastAddress = (LastAddress & ~(MM_PAGE_SIZE - 1)) + MM_PAGE_SIZE;
/* Loop through each page in the range */
while(CurrentAddress < LastAddress)
{
/* Touch the page with a read-write cycle */
*(VOLATILE PCHAR)CurrentAddress = *(volatile CHAR*)CurrentAddress;
/* Advance to the next page */
CurrentAddress = (CurrentAddress & ~(MM_PAGE_SIZE - 1)) + MM_PAGE_SIZE;
}
}
}
/**
* Probes an array of fixed-size items for write accessibility.
*
* @param Array
* Supplies the base address of the array.
*
* @param ItemSize
* Supplies the size of a single array element in bytes.
*
* @param ItemCount
* Supplies the total number of elements in the array.
*
* @param Alignment
* Supplies the required data alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForWriteArray(IN OUT PVOID Array,
IN ULONG ItemSize,
IN ULONG ItemCount,
IN ULONG Alignment)
{
ULONG ArraySize;
/* Calculate total array size */
ArraySize = ItemSize * ItemCount;
/* Check for integer overflow */
if((ItemSize != 0) && (ArraySize / ItemSize != ItemCount))
{
RTL::Exception::RaiseStatus(STATUS_INVALID_PARAMETER);
}
/* Perform write accessibility verification */
ProbeForWrite(Array, ArraySize, Alignment);
}
/**
* Probes a structure for write accessibility.
*
* @param Address
* Supplies the base address of the structure to probe.
*
* @param Size
* Supplies the total size of the structure in bytes.
*
* @param Alignment
* Supplies the required structure alignment (must be 1, 2, 4, 8, or 16).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
MM::Probe::ProbeForWriteStructure(IN PVOID Address,
IN SIZE_T Size,
IN ULONG Alignment)
{
/* Delegate fast-path boundary and alignment verification to the Read probe (DRY) */
ProbeForReadStructure(Address, Size, Alignment);
/* Check if the buffer size is zero or exceeds the page size */
if((Size == 0) || (Size >= MM_PAGE_SIZE))
{
/* Perform write accessibility verification */
ProbeForWrite(Address, Size, Alignment);
}
else
{
/* Touch the first byte to verify write access */
*(VOLATILE PUCHAR)Address = *(VOLATILE PUCHAR)Address;
/* Check if the buffer size exceeds the alignment */
if(Size > Alignment)
{
/* Touch the last byte to ensure full structure spans valid memory */
((VOLATILE PUCHAR)Address)[(Size - 1) & ~(SIZE_T)(Alignment - 1)] =
((VOLATILE PUCHAR)Address)[(Size - 1) & ~(SIZE_T)(Alignment - 1)];
}
}
}