mirror of
https://github.com/reactos/reactos.git
synced 2026-09-30 06:38:12 +08:00
[SDK][APITESTS:NTDLL][NTDLL] Add RtlMemIoResource support (#9392)
* [SDK][APITESTS:NTDLL][NTDLL] Add RtlMemIoResource support - RtlCmEncodeMemIoResource - RtlCmDecodeMemIoResource - RtlIoEncodeMemIoResource - RtlIoDecodeMemIoResource - RtlFindClosestEncodableLength
This commit is contained in:
@@ -678,8 +678,8 @@
|
||||
@ stdcall RtlClearBits(ptr long long)
|
||||
@ stdcall RtlCloneMemoryStream(ptr ptr)
|
||||
@ stdcall -stub -version=0x600+ RtlCloneUserProcess(long long long long long)
|
||||
@ stdcall -stub -version=0x600+ RtlCmDecodeMemIoResource(ptr ptr)
|
||||
@ stdcall -stub -version=0x600+ RtlCmEncodeMemIoResource(ptr long long long)
|
||||
@ stdcall -ret64 -version=0x600+ RtlCmDecodeMemIoResource(ptr ptr)
|
||||
@ stdcall -version=0x600+ RtlCmEncodeMemIoResource(ptr long int64 int64)
|
||||
@ stdcall -stub -version=0x600+ RtlCommitDebugInfo(ptr long)
|
||||
@ stdcall RtlCommitMemoryStream(ptr long)
|
||||
@ stdcall RtlCompactHeap(long long)
|
||||
@@ -840,7 +840,7 @@
|
||||
@ stdcall RtlFindClearBits(ptr long long)
|
||||
@ stdcall RtlFindClearBitsAndSet(ptr long long)
|
||||
@ stdcall RtlFindClearRuns(ptr ptr long long)
|
||||
@ stdcall -stub -version=0x600+ RtlFindClosestEncodableLength(long ptr)
|
||||
@ stdcall -version=0x600+ RtlFindClosestEncodableLength(int64 ptr)
|
||||
@ stdcall RtlFindLastBackwardRunClear(ptr long ptr)
|
||||
@ stdcall RtlFindLeastSignificantBit(double)
|
||||
@ stdcall RtlFindLongestRunClear(ptr long)
|
||||
@@ -973,8 +973,8 @@
|
||||
@ stdcall -arch=x86_64 RtlInterlockedPushListSList(ptr ptr ptr long)
|
||||
@ stdcall -version=0x602+ -arch=i386 RtlInterlockedPushListSListEx(ptr ptr ptr long)
|
||||
@ stdcall -version=0x602+ -arch=!i386 RtlInterlockedPushListSListEx(ptr ptr ptr long) RtlInterlockedPushListSList
|
||||
@ stdcall -stub -version=0x600+ RtlIoDecodeMemIoResource(ptr ptr ptr ptr)
|
||||
@ stdcall -stub -version=0x600+ RtlIoEncodeMemIoResource(ptr long long long long long)
|
||||
@ stdcall -ret64 -version=0x600+ RtlIoDecodeMemIoResource(ptr ptr ptr ptr)
|
||||
@ stdcall -version=0x600+ RtlIoEncodeMemIoResource(ptr long int64 int64 int64 int64)
|
||||
@ stdcall RtlIpv4AddressToStringA(ptr ptr)
|
||||
@ stdcall RtlIpv4AddressToStringExA(ptr long ptr ptr)
|
||||
@ stdcall RtlIpv4AddressToStringExW(ptr long ptr ptr)
|
||||
|
||||
@@ -128,6 +128,7 @@ list(APPEND SOURCE
|
||||
RtlIsNameInExpression.c
|
||||
RtlIsNameLegalDOS8Dot3.c
|
||||
RtlLocale.c
|
||||
RtlMemIoResource.c
|
||||
RtlMemoryStream.c
|
||||
RtlMultipleAllocateHeap.c
|
||||
RtlNtPathNameToDosPathName.c
|
||||
|
||||
502
modules/rostests/apitests/ntdll/RtlMemIoResource.c
Normal file
502
modules/rostests/apitests/ntdll/RtlMemIoResource.c
Normal file
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* PROJECT: ReactOS API Tests
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Tests for the Rtl memory/port resource descriptor encoding API:
|
||||
* RtlCmEncodeMemIoResource, RtlCmDecodeMemIoResource,
|
||||
* RtlIoEncodeMemIoResource, RtlIoDecodeMemIoResource and
|
||||
* RtlFindClosestEncodableLength.
|
||||
* COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <limits.h>
|
||||
|
||||
static ULONGLONG (NTAPI *pRtlCmDecodeMemIoResource)(
|
||||
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_Out_opt_ PULONGLONG Start);
|
||||
|
||||
static NTSTATUS (NTAPI *pRtlCmEncodeMemIoResource)(
|
||||
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ UCHAR Type,
|
||||
_In_ ULONGLONG Length,
|
||||
_In_ ULONGLONG Start);
|
||||
|
||||
static NTSTATUS (NTAPI *pRtlFindClosestEncodableLength)(
|
||||
_In_ ULONGLONG SourceLength,
|
||||
_Out_ PULONGLONG TargetLength);
|
||||
|
||||
static ULONGLONG (NTAPI *pRtlIoDecodeMemIoResource)(
|
||||
_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_Out_opt_ PULONGLONG Alignment,
|
||||
_Out_opt_ PULONGLONG MinimumAddress,
|
||||
_Out_opt_ PULONGLONG MaximumAddress);
|
||||
|
||||
static NTSTATUS (NTAPI *pRtlIoEncodeMemIoResource)(
|
||||
_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ UCHAR Type,
|
||||
_In_ ULONGLONG Length,
|
||||
_In_ ULONGLONG Alignment,
|
||||
_In_ ULONGLONG MinimumAddress,
|
||||
_In_ ULONGLONG MaximumAddress);
|
||||
|
||||
static
|
||||
void
|
||||
Test_CmEncode(void)
|
||||
{
|
||||
CM_PARTIAL_RESOURCE_DESCRIPTOR Desc, Saved;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Unsupported types must fail without touching the descriptor */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Saved = Desc;
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeNull, 0x1000, 0);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
ok(!memcmp(&Desc, &Saved, sizeof(Desc)), "Descriptor modified on failure\n");
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeInterrupt, 0x1000, 0);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeDma, 0x1000, 0);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
ok(!memcmp(&Desc, &Saved, sizeof(Desc)), "Descriptor modified on failure\n");
|
||||
|
||||
/* Basic port descriptor */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypePort, 0x100, 0x3F8);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypePort);
|
||||
ok_eq_ulong(Desc.u.Port.Length, 0x100UL);
|
||||
ok_eq_hex64(Desc.u.Port.Start.QuadPart, 0x3F8);
|
||||
/* The port path does not clean stale large flags */
|
||||
ok_eq_hex(Desc.Flags, 0x5555);
|
||||
|
||||
/* A port length cannot exceed 32 bits, and the failure leaves no writes */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Saved = Desc;
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypePort, 0x100000000ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
ok(!memcmp(&Desc, &Saved, sizeof(Desc)), "Descriptor modified on failure\n");
|
||||
|
||||
/* Small memory length: plain descriptor, stale large flags are cleared */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_48 | CM_RESOURCE_MEMORY_READ_ONLY;
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x1000, 0xFFFFFFFFFF000000ULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemory);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x1000UL);
|
||||
ok_eq_hex64(Desc.u.Memory.Start.QuadPart, 0xFFFFFFFFFF000000ULL);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_READ_ONLY);
|
||||
|
||||
/* Asking for MemoryLarge with a small length demotes to plain Memory */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemoryLarge, MAXULONG, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemory);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, MAXULONG);
|
||||
|
||||
/* Asking for plain Memory with a big length promotes to MemoryLarge (40-bit) */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000000ULL, 0x8000000000ULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemoryLarge);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_40);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x01000000UL);
|
||||
ok_eq_hex64(Desc.u.Memory.Start.QuadPart, 0x8000000000ULL);
|
||||
|
||||
/* 40-bit tier upper bound */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemoryLarge, CM_RESOURCE_MEMORY_LARGE_40_MAXLEN, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_40);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, MAXULONG);
|
||||
|
||||
/* Low 8 bits set in the 40-bit tier: not encodable */
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000080ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
|
||||
/* 48-bit tier */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x10000000000ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemoryLarge);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_48);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x01000000UL);
|
||||
|
||||
/*
|
||||
* The tier is picked by magnitude alone: a 256-byte-aligned length in the
|
||||
* 48-bit tier still fails because it is not 64K-aligned
|
||||
*/
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x10000000100ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
|
||||
/* 64-bit tier and its upper bound */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x1000000000000ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_64);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x10000UL);
|
||||
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, CM_RESOURCE_MEMORY_LARGE_64_MAXLEN, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_64);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, MAXULONG);
|
||||
|
||||
/* Low 32 bits set in the 64-bit tier, and beyond-the-max lengths */
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000000000100ULL, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, CM_RESOURCE_MEMORY_LARGE_64_MAXLEN + 1, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, ULLONG_MAX, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Test_CmDecode(void)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
ULONGLONG Length;
|
||||
USHORT ExpectedFlags;
|
||||
} RoundTrips[] =
|
||||
{
|
||||
{ 0x1000, 0 },
|
||||
{ MAXULONG, 0 },
|
||||
{ 0x100000000ULL, CM_RESOURCE_MEMORY_LARGE_40 },
|
||||
{ 0xFFFFFFFF00ULL, CM_RESOURCE_MEMORY_LARGE_40 },
|
||||
{ 0x10000000000ULL, CM_RESOURCE_MEMORY_LARGE_48 },
|
||||
{ 0xFFFFFFFF0000ULL, CM_RESOURCE_MEMORY_LARGE_48 },
|
||||
{ 0x1000000000000ULL, CM_RESOURCE_MEMORY_LARGE_64 },
|
||||
{ 0xFFFFFFFF00000000ULL, CM_RESOURCE_MEMORY_LARGE_64 },
|
||||
};
|
||||
CM_PARTIAL_RESOURCE_DESCRIPTOR Desc;
|
||||
ULONGLONG Length, Start;
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
/* Plain port descriptor decodes verbatim */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Type = CmResourceTypePort;
|
||||
Desc.u.Port.Start.QuadPart = 0x1122334455667788ULL;
|
||||
Desc.u.Port.Length = 0x1234;
|
||||
Start = 0;
|
||||
Length = pRtlCmDecodeMemIoResource(&Desc, &Start);
|
||||
ok_eq_hex64(Length, 0x1234);
|
||||
ok_eq_hex64(Start, 0x1122334455667788ULL);
|
||||
|
||||
/* Start is optional */
|
||||
Length = pRtlCmDecodeMemIoResource(&Desc, NULL);
|
||||
ok_eq_hex64(Length, 0x1234);
|
||||
|
||||
/* Large flags are ignored for plain port/memory types */
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_64;
|
||||
Length = pRtlCmDecodeMemIoResource(&Desc, NULL);
|
||||
ok_eq_hex64(Length, 0x1234);
|
||||
|
||||
/* Hand-built large forms decode to the shifted length */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Type = CmResourceTypeMemoryLarge;
|
||||
Desc.u.Memory.Length = 0x01000000;
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_40;
|
||||
ok_eq_hex64(pRtlCmDecodeMemIoResource(&Desc, NULL), 0x100000000ULL);
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_48;
|
||||
ok_eq_hex64(pRtlCmDecodeMemIoResource(&Desc, NULL), 0x10000000000ULL);
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_64;
|
||||
ok_eq_hex64(pRtlCmDecodeMemIoResource(&Desc, NULL), 0x100000000000000ULL);
|
||||
|
||||
/* A large type without any large flag decodes to zero, Start still returned */
|
||||
Desc.Flags = 0;
|
||||
Desc.u.Memory.Start.QuadPart = 0xABCD;
|
||||
Start = 0;
|
||||
ok_eq_hex64(pRtlCmDecodeMemIoResource(&Desc, &Start), 0);
|
||||
ok_eq_hex64(Start, 0xABCD);
|
||||
|
||||
/* Encode/decode round-trips across all tiers */
|
||||
for (i = 0; i < ARRAYSIZE(RoundTrips); i++)
|
||||
{
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc,
|
||||
CmResourceTypeMemory,
|
||||
RoundTrips[i].Length,
|
||||
0x40000000ULL + i);
|
||||
ok(Status == STATUS_SUCCESS, "[%lu] encode failed: 0x%lx\n", i, Status);
|
||||
ok(Desc.Flags == RoundTrips[i].ExpectedFlags,
|
||||
"[%lu] Flags = 0x%x, expected 0x%x\n",
|
||||
i, Desc.Flags, RoundTrips[i].ExpectedFlags);
|
||||
Start = 0;
|
||||
Length = pRtlCmDecodeMemIoResource(&Desc, &Start);
|
||||
ok(Length == RoundTrips[i].Length,
|
||||
"[%lu] Length = 0x%I64x, expected 0x%I64x\n",
|
||||
i, Length, RoundTrips[i].Length);
|
||||
ok(Start == 0x40000000ULL + i,
|
||||
"[%lu] Start = 0x%I64x\n", i, Start);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Test_IoEncode(void)
|
||||
{
|
||||
IO_RESOURCE_DESCRIPTOR Desc, Saved;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Unsupported types fail without touching the descriptor */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Saved = Desc;
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeInterrupt, 0x1000, 4, 0, 0xFFFF);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
ok(!memcmp(&Desc, &Saved, sizeof(Desc)), "Descriptor modified on failure\n");
|
||||
|
||||
/* Basic port requirement */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypePort, 0x100, 4, 0x1000, 0xFFFF);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypePort);
|
||||
ok_eq_ulong(Desc.u.Port.Length, 0x100UL);
|
||||
ok_eq_ulong(Desc.u.Port.Alignment, 4UL);
|
||||
ok_eq_hex64(Desc.u.Port.MinimumAddress.QuadPart, 0x1000);
|
||||
ok_eq_hex64(Desc.u.Port.MaximumAddress.QuadPart, 0xFFFF);
|
||||
|
||||
/* Port length/alignment above 32 bits are rejected, no writes */
|
||||
RtlFillMemory(&Desc, sizeof(Desc), 0x55);
|
||||
Saved = Desc;
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypePort, 0x100000000ULL, 4, 0, 0xFFFF);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypePort, 0x100, 0x100000000ULL, 0, 0xFFFF);
|
||||
ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
ok(!memcmp(&Desc, &Saved, sizeof(Desc)), "Descriptor modified on failure\n");
|
||||
|
||||
/* Small memory requirement stays plain and clears stale large flags */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_40 | CM_RESOURCE_MEMORY_PREFETCHABLE;
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x1000, 0x1000, 0, 0xFFFFFFFFULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemory);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_PREFETCHABLE);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x1000UL);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 0x1000UL);
|
||||
ok_eq_hex64(Desc.u.Memory.MinimumAddress.QuadPart, 0);
|
||||
ok_eq_hex64(Desc.u.Memory.MaximumAddress.QuadPart, 0xFFFFFFFFULL);
|
||||
|
||||
/* Large length: a small alignment is scaled up to the tier granularity */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x100000000ULL, 1,
|
||||
0, 0xFFFFFFFFFFULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemoryLarge);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_40);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x01000000UL);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 1UL); /* i.e. 0x100 bytes */
|
||||
ok_eq_hex64(Desc.u.Memory.MaximumAddress.QuadPart, 0xFFFFFFFFFFULL);
|
||||
|
||||
/* Zero alignment encodes as zero */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000000ULL, 0, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 0UL);
|
||||
|
||||
/* A non-power-of-two alignment is doubled until it fits the granularity */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000000ULL, 0x81, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 0x81UL); /* 0x81 << 8 == 0x8100 bytes */
|
||||
|
||||
/*
|
||||
* A small length with a >4GB alignment still selects the large form
|
||||
* (the plain path needs both to fit in 32 bits)
|
||||
*/
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x1000, 0x100000000ULL, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_uint(Desc.Type, CmResourceTypeMemoryLarge);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_40);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x10UL);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 0x01000000UL);
|
||||
|
||||
/* Length not representable at the tier granularity */
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x100000080ULL, 1, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory, 0x10000000100ULL, 1, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
|
||||
/* Alignment above the tier picked by the length */
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x100000000ULL, 0x10000000000ULL, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
|
||||
/* Alignment whose scaling overflows 64 bits */
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x1000000000000ULL, 0x8000000000000001ULL, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
|
||||
/* 64-bit tier */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x1000000000000ULL, 0x100000000ULL,
|
||||
0x100000000ULL, 0xFFFFFFFFFFFFFFFFULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex(Desc.Flags, CM_RESOURCE_MEMORY_LARGE_64);
|
||||
ok_eq_ulong(Desc.u.Memory.Length, 0x10000UL);
|
||||
ok_eq_ulong(Desc.u.Memory.Alignment, 1UL);
|
||||
ok_eq_hex64(Desc.u.Memory.MinimumAddress.QuadPart, 0x100000000ULL);
|
||||
ok_eq_hex64(Desc.u.Memory.MaximumAddress.QuadPart, 0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
/* Length beyond every tier */
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
ULLONG_MAX, 1, 0, 0);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Test_IoDecode(void)
|
||||
{
|
||||
IO_RESOURCE_DESCRIPTOR Desc;
|
||||
ULONGLONG Length, Alignment, Minimum, Maximum;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Plain memory requirement */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Type = CmResourceTypeMemory;
|
||||
Desc.u.Memory.Length = 0x2000;
|
||||
Desc.u.Memory.Alignment = 0x1000;
|
||||
Desc.u.Memory.MinimumAddress.QuadPart = 0x100000;
|
||||
Desc.u.Memory.MaximumAddress.QuadPart = 0xFFFFFFFFULL;
|
||||
Alignment = Minimum = Maximum = 0;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, &Minimum, &Maximum);
|
||||
ok_eq_hex64(Length, 0x2000);
|
||||
ok_eq_hex64(Alignment, 0x1000);
|
||||
ok_eq_hex64(Minimum, 0x100000);
|
||||
ok_eq_hex64(Maximum, 0xFFFFFFFFULL);
|
||||
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, NULL, NULL, NULL);
|
||||
ok_eq_hex64(Length, 0x2000);
|
||||
|
||||
/* Length and alignment both scale */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Desc.Type = CmResourceTypeMemoryLarge;
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_40;
|
||||
Desc.u.Memory.Length = 0x01000000;
|
||||
Desc.u.Memory.Alignment = 0x01000000;
|
||||
Alignment = 0;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, NULL, NULL);
|
||||
ok_eq_hex64(Length, 0x100000000ULL);
|
||||
ok_eq_hex64(Alignment, 0x100000000ULL);
|
||||
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_48;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, NULL, NULL);
|
||||
ok_eq_hex64(Length, 0x10000000000ULL);
|
||||
ok_eq_hex64(Alignment, 0x10000000000ULL);
|
||||
|
||||
Desc.Flags = CM_RESOURCE_MEMORY_LARGE_64;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, NULL, NULL);
|
||||
ok_eq_hex64(Length, 0x100000000000000ULL);
|
||||
ok_eq_hex64(Alignment, 0x100000000000000ULL);
|
||||
|
||||
/* A large type without large flags decodes to zero, bounds still returned */
|
||||
Desc.Flags = 0;
|
||||
Desc.u.Memory.MinimumAddress.QuadPart = 0x1234;
|
||||
Desc.u.Memory.MaximumAddress.QuadPart = 0x5678;
|
||||
Alignment = Minimum = Maximum = ULLONG_MAX;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, &Minimum, &Maximum);
|
||||
ok_eq_hex64(Length, 0);
|
||||
ok_eq_hex64(Alignment, 0);
|
||||
ok_eq_hex64(Minimum, 0x1234);
|
||||
ok_eq_hex64(Maximum, 0x5678);
|
||||
|
||||
/* Encode/decode round-trip: the rounded-up alignment is what comes back */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlIoEncodeMemIoResource(&Desc, CmResourceTypeMemory,
|
||||
0x10000000000ULL, 0x1000,
|
||||
0x10000, 0xFFFFFFFFFFFFULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Alignment = Minimum = Maximum = 0;
|
||||
Length = pRtlIoDecodeMemIoResource(&Desc, &Alignment, &Minimum, &Maximum);
|
||||
ok_eq_hex64(Length, 0x10000000000ULL);
|
||||
ok_eq_hex64(Alignment, 0x10000); /* 0x1000 rounded up to the 64K granularity */
|
||||
ok_eq_hex64(Minimum, 0x10000);
|
||||
ok_eq_hex64(Maximum, 0xFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Test_FindClosest(void)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
ULONGLONG Source;
|
||||
ULONGLONG Expected;
|
||||
} Cases[] =
|
||||
{
|
||||
/* 32-bit values are always exact */
|
||||
{ 0, 0 },
|
||||
{ 0x1234, 0x1234 },
|
||||
{ MAXULONG, MAXULONG },
|
||||
/* 40-bit tier: rounded up to 256 bytes */
|
||||
{ 0x100000000ULL, 0x100000000ULL },
|
||||
{ 0x100000001ULL, 0x100000100ULL },
|
||||
{ 0xFFFFFFFF00ULL, 0xFFFFFFFF00ULL },
|
||||
/* just past the 40-bit tier: 64K granularity now */
|
||||
{ 0xFFFFFFFF01ULL, 0x10000000000ULL },
|
||||
{ 0x10000000001ULL, 0x10000010000ULL },
|
||||
{ 0xFFFFFFFF0000ULL, 0xFFFFFFFF0000ULL },
|
||||
/* just past the 48-bit tier: 4G granularity */
|
||||
{ 0xFFFFFFFF0001ULL, 0x1000000000000ULL },
|
||||
{ 0x1000000000000ULL, 0x1000000000000ULL },
|
||||
{ 0x1000000000001ULL, 0x1000100000000ULL },
|
||||
{ 0xFFFFFFFF00000000ULL, 0xFFFFFFFF00000000ULL },
|
||||
};
|
||||
CM_PARTIAL_RESOURCE_DESCRIPTOR Desc;
|
||||
ULONGLONG Target;
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < ARRAYSIZE(Cases); i++)
|
||||
{
|
||||
Target = ULLONG_MAX;
|
||||
Status = pRtlFindClosestEncodableLength(Cases[i].Source, &Target);
|
||||
ok(Status == STATUS_SUCCESS, "[%lu] failed: 0x%lx\n", i, Status);
|
||||
ok(Target == Cases[i].Expected,
|
||||
"[%lu] Target = 0x%I64x, expected 0x%I64x\n",
|
||||
i, Target, Cases[i].Expected);
|
||||
|
||||
/* The returned length must itself be encodable */
|
||||
RtlZeroMemory(&Desc, sizeof(Desc));
|
||||
Status = pRtlCmEncodeMemIoResource(&Desc, CmResourceTypeMemory, Target, 0);
|
||||
ok(Status == STATUS_SUCCESS, "[%lu] closest length not encodable: 0x%lx\n", i, Status);
|
||||
}
|
||||
|
||||
/* Beyond the 64-bit tier there is nothing to round to */
|
||||
Target = ULLONG_MAX;
|
||||
Status = pRtlFindClosestEncodableLength(CM_RESOURCE_MEMORY_LARGE_64_MAXLEN + 1, &Target);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
ok_eq_hex64(Target, 0);
|
||||
Status = pRtlFindClosestEncodableLength(ULLONG_MAX, &Target);
|
||||
ok_eq_hex(Status, STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
START_TEST(RtlMemIoResource)
|
||||
{
|
||||
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
|
||||
|
||||
pRtlCmDecodeMemIoResource = (PVOID)GetProcAddress(hNtdll, "RtlCmDecodeMemIoResource");
|
||||
pRtlCmEncodeMemIoResource = (PVOID)GetProcAddress(hNtdll, "RtlCmEncodeMemIoResource");
|
||||
pRtlFindClosestEncodableLength = (PVOID)GetProcAddress(hNtdll, "RtlFindClosestEncodableLength");
|
||||
pRtlIoDecodeMemIoResource = (PVOID)GetProcAddress(hNtdll, "RtlIoDecodeMemIoResource");
|
||||
pRtlIoEncodeMemIoResource = (PVOID)GetProcAddress(hNtdll, "RtlIoEncodeMemIoResource");
|
||||
|
||||
if (!pRtlCmDecodeMemIoResource || !pRtlCmEncodeMemIoResource ||
|
||||
!pRtlFindClosestEncodableLength ||
|
||||
!pRtlIoDecodeMemIoResource || !pRtlIoEncodeMemIoResource)
|
||||
{
|
||||
skip("Rtl*MemIoResource API not available (NT 6.0+ only)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Test_CmEncode();
|
||||
Test_CmDecode();
|
||||
Test_IoEncode();
|
||||
Test_IoDecode();
|
||||
Test_FindClosest();
|
||||
}
|
||||
@@ -114,6 +114,7 @@ extern void func_RtlIntSafe(void);
|
||||
extern void func_RtlIsNameInExpression(void);
|
||||
extern void func_RtlIsNameLegalDOS8Dot3(void);
|
||||
extern void func_RtlLocale(void);
|
||||
extern void func_RtlMemIoResource(void);
|
||||
extern void func_RtlMemoryStream(void);
|
||||
extern void func_RtlMultipleAllocateHeap(void);
|
||||
extern void func_RtlNtPathNameToDosPathName(void);
|
||||
@@ -252,6 +253,7 @@ const struct test winetest_testlist[] =
|
||||
{ "RtlIsNameInExpression", func_RtlIsNameInExpression},
|
||||
{ "RtlIsNameLegalDOS8Dot3", func_RtlIsNameLegalDOS8Dot3 },
|
||||
{ "RtlLocale", func_RtlLocale },
|
||||
{ "RtlMemIoResource", func_RtlMemIoResource },
|
||||
{ "RtlMemoryStream", func_RtlMemoryStream },
|
||||
{ "RtlMultipleAllocateHeap", func_RtlMultipleAllocateHeap },
|
||||
{ "RtlNtPathNameToDosPathName", func_RtlNtPathNameToDosPathName },
|
||||
|
||||
@@ -61,6 +61,7 @@ list(APPEND SOURCE
|
||||
largeint.c
|
||||
locale.c
|
||||
luid.c
|
||||
memres.c
|
||||
memstream.c
|
||||
message.c
|
||||
network.c
|
||||
|
||||
329
sdk/lib/rtl/memres.c
Normal file
329
sdk/lib/rtl/memres.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* PROJECT: ReactOS system libraries
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Encode/decode helpers for memory and port resource descriptors.
|
||||
* COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <rtl.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
/*
|
||||
* A plain Port/Memory descriptor stores its Length (and, for a requirement, its
|
||||
* Alignment) in a 32-bit field, so it can only describe regions up to 4 GB. A
|
||||
* CmResourceTypeMemoryLarge descriptor reuses that same 32-bit field to hold a
|
||||
* bigger value by dropping the low bits that are known to be zero; the Flags say
|
||||
* how many were dropped:
|
||||
*
|
||||
* CM_RESOURCE_MEMORY_LARGE_40 (0x200) field holds bits [39:8] (<< 8)
|
||||
* CM_RESOURCE_MEMORY_LARGE_48 (0x400) field holds bits [47:16] (<< 16)
|
||||
* CM_RESOURCE_MEMORY_LARGE_64 (0x800) field holds bits [63:32] (<< 32)
|
||||
*/
|
||||
static
|
||||
ULONGLONG
|
||||
RtlpDecodeMemIoValue(
|
||||
_In_ UCHAR Type,
|
||||
_In_ USHORT Flags,
|
||||
_In_ ULONG Encoded)
|
||||
{
|
||||
if (Type == CmResourceTypePort || Type == CmResourceTypeMemory)
|
||||
return Encoded;
|
||||
|
||||
if (Flags & CM_RESOURCE_MEMORY_LARGE_40)
|
||||
return (ULONGLONG)Encoded << 8;
|
||||
|
||||
if (Flags & CM_RESOURCE_MEMORY_LARGE_48)
|
||||
return (ULONGLONG)Encoded << 16;
|
||||
|
||||
if (Flags & CM_RESOURCE_MEMORY_LARGE_64)
|
||||
return (ULONGLONG)Encoded << 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Decode an assigned (CM_PARTIAL_RESOURCE_DESCRIPTOR) memory or port descriptor:
|
||||
* return its full 64-bit length and, optionally, its start address.
|
||||
*/
|
||||
ULONGLONG
|
||||
NTAPI
|
||||
RtlCmDecodeMemIoResource(
|
||||
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_Out_opt_ PULONGLONG Start)
|
||||
{
|
||||
if (Start != NULL)
|
||||
*Start = Descriptor->u.Generic.Start.QuadPart;
|
||||
|
||||
return RtlpDecodeMemIoValue(Descriptor->Type,
|
||||
Descriptor->Flags,
|
||||
Descriptor->u.Generic.Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Decode a requirement (IO_RESOURCE_DESCRIPTOR) memory or port descriptor:
|
||||
* return its full 64-bit length, maybe its (also large-encoded)
|
||||
* alignment and the 64-bit minimum/maximum address bounds.
|
||||
*/
|
||||
ULONGLONG
|
||||
NTAPI
|
||||
RtlIoDecodeMemIoResource(
|
||||
_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_Out_opt_ PULONGLONG Alignment,
|
||||
_Out_opt_ PULONGLONG MinimumAddress,
|
||||
_Out_opt_ PULONGLONG MaximumAddress)
|
||||
{
|
||||
if (Alignment != NULL)
|
||||
{
|
||||
*Alignment = RtlpDecodeMemIoValue(Descriptor->Type,
|
||||
Descriptor->Flags,
|
||||
Descriptor->u.Generic.Alignment);
|
||||
}
|
||||
|
||||
if (MinimumAddress != NULL)
|
||||
*MinimumAddress = Descriptor->u.Generic.MinimumAddress.QuadPart;
|
||||
|
||||
if (MaximumAddress != NULL)
|
||||
*MaximumAddress = Descriptor->u.Generic.MaximumAddress.QuadPart;
|
||||
|
||||
return RtlpDecodeMemIoValue(Descriptor->Type,
|
||||
Descriptor->Flags,
|
||||
Descriptor->u.Generic.Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Fill in a CM_PARTIAL_RESOURCE_DESCRIPTOR for a port or memory region. When a
|
||||
* memory Length does not fit in 32 bits the descriptor is promoted to a
|
||||
* CmResourceTypeMemoryLarge form.
|
||||
*
|
||||
* Returns STATUS_INVALID_PARAMETER for an unsupported Type (or a port length
|
||||
* above 4 GB) and STATUS_UNSUCCESSFUL if the length cannot be represented by any
|
||||
* large form without dropping bits.
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlCmEncodeMemIoResource(
|
||||
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ UCHAR Type,
|
||||
_In_ ULONGLONG Length,
|
||||
_In_ ULONGLONG Start)
|
||||
{
|
||||
if (Type != CmResourceTypePort &&
|
||||
Type != CmResourceTypeMemory &&
|
||||
Type != CmResourceTypeMemoryLarge)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* A port descriptor has only a 32-bit length and no large form. */
|
||||
if (Type == CmResourceTypePort)
|
||||
{
|
||||
if (Length > MAXULONG)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
Descriptor->Type = CmResourceTypePort;
|
||||
Descriptor->u.Generic.Start.QuadPart = Start;
|
||||
Descriptor->u.Generic.Length = (ULONG)Length;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Drop any stale large-form flags and record the start address. */
|
||||
Descriptor->Flags &= ~CM_RESOURCE_MEMORY_LARGE;
|
||||
Descriptor->u.Generic.Start.QuadPart = Start;
|
||||
|
||||
/* A length that fits 32 bits stays a plain memory descriptor. */
|
||||
if (Length <= MAXULONG)
|
||||
{
|
||||
Descriptor->Type = CmResourceTypeMemory;
|
||||
Descriptor->u.Generic.Length = (ULONG)Length;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Otherwise pick the tightest large form whose dropped low bits are zero. */
|
||||
if (Length <= ((ULONGLONG)MAXULONG << 8) && (Length & 0xFF) == 0)
|
||||
{
|
||||
Descriptor->u.Generic.Length = (ULONG)(Length >> 8);
|
||||
Descriptor->Flags |= CM_RESOURCE_MEMORY_LARGE_40;
|
||||
}
|
||||
else if (Length <= ((ULONGLONG)MAXULONG << 16) && (Length & 0xFFFF) == 0)
|
||||
{
|
||||
Descriptor->u.Generic.Length = (ULONG)(Length >> 16);
|
||||
Descriptor->Flags |= CM_RESOURCE_MEMORY_LARGE_48;
|
||||
}
|
||||
else if (Length <= ((ULONGLONG)MAXULONG << 32) && (Length & 0xFFFFFFFF) == 0)
|
||||
{
|
||||
Descriptor->u.Generic.Length = (ULONG)(Length >> 32);
|
||||
Descriptor->Flags |= CM_RESOURCE_MEMORY_LARGE_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
Descriptor->Type = CmResourceTypeMemoryLarge;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* A large descriptor expresses alignment at the same granularity as its length.
|
||||
* Scale the alignment up until it is a multiple of that granularity.
|
||||
*/
|
||||
static
|
||||
BOOLEAN
|
||||
RtlpEncodeLargeAlignment(
|
||||
_In_ ULONGLONG Alignment,
|
||||
_In_ ULONG Shift,
|
||||
_Out_ PULONG Encoded)
|
||||
{
|
||||
ULONGLONG LowMask = ((ULONGLONG)1 << Shift) - 1;
|
||||
|
||||
while ((Alignment & LowMask) != 0)
|
||||
{
|
||||
ULONGLONG Doubled = Alignment << 1;
|
||||
|
||||
if (Doubled < Alignment) /* overflowed past 64 bits */
|
||||
return FALSE;
|
||||
|
||||
Alignment = Doubled;
|
||||
}
|
||||
|
||||
*Encoded = (ULONG)(Alignment >> Shift);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Fill in an IO_RESOURCE_DESCRIPTOR (a resource *requirement*) for a port or
|
||||
* memory range. Also encodes the alignment and the 64-bit address bounds.
|
||||
* A memory length above 4 GB is promoted to a CmResourceTypeMemoryLarge form,
|
||||
* which matters as drivers depend on this behavior.
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlIoEncodeMemIoResource(
|
||||
_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ UCHAR Type,
|
||||
_In_ ULONGLONG Length,
|
||||
_In_ ULONGLONG Alignment,
|
||||
_In_ ULONGLONG MinimumAddress,
|
||||
_In_ ULONGLONG MaximumAddress)
|
||||
{
|
||||
ULONG Shift;
|
||||
USHORT LargeFlag;
|
||||
|
||||
if (Type != CmResourceTypePort &&
|
||||
Type != CmResourceTypeMemory &&
|
||||
Type != CmResourceTypeMemoryLarge)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* A port descriptor is limited to 32-bit length and alignment. */
|
||||
if (Type == CmResourceTypePort)
|
||||
{
|
||||
if (Length > MAXULONG || Alignment > MAXULONG)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
Descriptor->Type = CmResourceTypePort;
|
||||
Descriptor->u.Generic.MinimumAddress.QuadPart = MinimumAddress;
|
||||
Descriptor->u.Generic.MaximumAddress.QuadPart = MaximumAddress;
|
||||
Descriptor->u.Generic.Length = (ULONG)Length;
|
||||
Descriptor->u.Generic.Alignment = (ULONG)Alignment;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Memory: reset any stale large-form flags and record the address bounds. */
|
||||
Descriptor->Flags &= ~CM_RESOURCE_MEMORY_LARGE;
|
||||
Descriptor->u.Generic.MinimumAddress.QuadPart = MinimumAddress;
|
||||
Descriptor->u.Generic.MaximumAddress.QuadPart = MaximumAddress;
|
||||
|
||||
/* Both values fit 32 bits: a plain memory descriptor. */
|
||||
if (Length <= MAXULONG && Alignment <= MAXULONG)
|
||||
{
|
||||
Descriptor->Type = CmResourceTypeMemory;
|
||||
Descriptor->u.Generic.Length = (ULONG)Length;
|
||||
Descriptor->u.Generic.Alignment = (ULONG)Alignment;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Select the large form from the length; the alignment must fit that tier. */
|
||||
if (Length <= ((ULONGLONG)MAXULONG << 8))
|
||||
{
|
||||
if (Alignment > ((ULONGLONG)MAXULONG << 8))
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
Shift = 8;
|
||||
LargeFlag = CM_RESOURCE_MEMORY_LARGE_40;
|
||||
}
|
||||
else if (Length <= ((ULONGLONG)MAXULONG << 16))
|
||||
{
|
||||
if (Alignment > ((ULONGLONG)MAXULONG << 16))
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
Shift = 16;
|
||||
LargeFlag = CM_RESOURCE_MEMORY_LARGE_48;
|
||||
}
|
||||
else if (Length <= ((ULONGLONG)MAXULONG << 32))
|
||||
{
|
||||
Shift = 32;
|
||||
LargeFlag = CM_RESOURCE_MEMORY_LARGE_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* The length must be exactly representable at this granularity. */
|
||||
if ((Length & (((ULONGLONG)1 << Shift) - 1)) != 0)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
if (!RtlpEncodeLargeAlignment(Alignment, Shift, &Descriptor->u.Generic.Alignment))
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
Descriptor->Type = CmResourceTypeMemoryLarge;
|
||||
Descriptor->u.Generic.Length = (ULONG)(Length >> Shift);
|
||||
Descriptor->Flags |= LargeFlag;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Round a requested length up to the nearest value the descriptor
|
||||
* 1:1 when it fits 32 bits, otherwise the next multiple of the
|
||||
* granularity.
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlFindClosestEncodableLength(
|
||||
_In_ ULONGLONG SourceLength,
|
||||
_Out_ PULONGLONG TargetLength)
|
||||
{
|
||||
if (SourceLength <= MAXULONG)
|
||||
*TargetLength = SourceLength;
|
||||
else if (SourceLength <= ((ULONGLONG)MAXULONG << 8))
|
||||
*TargetLength = (SourceLength + 0xFF) & ~(ULONGLONG)0xFF;
|
||||
else if (SourceLength <= ((ULONGLONG)MAXULONG << 16))
|
||||
*TargetLength = (SourceLength + 0xFFFF) & ~(ULONGLONG)0xFFFF;
|
||||
else if (SourceLength <= ((ULONGLONG)MAXULONG << 32))
|
||||
*TargetLength = (SourceLength + 0xFFFFFFFF) & ~(ULONGLONG)0xFFFFFFFF;
|
||||
else
|
||||
{
|
||||
*TargetLength = 0;
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user