ReactOS 0.4.17-dev-650-gd0e71de
memres.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS system libraries
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Encode/decode helpers for memory and port resource descriptors.
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *****************************************************************/
9
10#include <rtl.h>
11
12#define NDEBUG
13#include <debug.h>
14
15/* FUNCTIONS ****************************************************************/
16
17/*
18 * A plain Port/Memory descriptor stores its Length (and, for a requirement, its
19 * Alignment) in a 32-bit field, so it can only describe regions up to 4 GB. A
20 * CmResourceTypeMemoryLarge descriptor reuses that same 32-bit field to hold a
21 * bigger value by dropping the low bits that are known to be zero; the Flags say
22 * how many were dropped:
23 *
24 * CM_RESOURCE_MEMORY_LARGE_40 (0x200) field holds bits [39:8] (<< 8)
25 * CM_RESOURCE_MEMORY_LARGE_48 (0x400) field holds bits [47:16] (<< 16)
26 * CM_RESOURCE_MEMORY_LARGE_64 (0x800) field holds bits [63:32] (<< 32)
27 */
28static
33 _In_ ULONG Encoded)
34{
36 return Encoded;
37
39 return (ULONGLONG)Encoded << 8;
40
42 return (ULONGLONG)Encoded << 16;
43
45 return (ULONGLONG)Encoded << 32;
46
47 return 0;
48}
49
50/*
51 * @implemented
52 *
53 * Decode an assigned (CM_PARTIAL_RESOURCE_DESCRIPTOR) memory or port descriptor:
54 * return its full 64-bit length and, optionally, its start address.
55 */
61{
62 if (Start != NULL)
63 *Start = Descriptor->u.Generic.Start.QuadPart;
64
66 Descriptor->Flags,
67 Descriptor->u.Generic.Length);
68}
69
70/*
71 * @implemented
72 *
73 * Decode a requirement (IO_RESOURCE_DESCRIPTOR) memory or port descriptor:
74 * return its full 64-bit length, maybe its (also large-encoded)
75 * alignment and the 64-bit minimum/maximum address bounds.
76 */
84{
85 if (Alignment != NULL)
86 {
88 Descriptor->Flags,
89 Descriptor->u.Generic.Alignment);
90 }
91
92 if (MinimumAddress != NULL)
93 *MinimumAddress = Descriptor->u.Generic.MinimumAddress.QuadPart;
94
95 if (MaximumAddress != NULL)
96 *MaximumAddress = Descriptor->u.Generic.MaximumAddress.QuadPart;
97
99 Descriptor->Flags,
100 Descriptor->u.Generic.Length);
101}
102
103/*
104 * @implemented
105 *
106 * Fill in a CM_PARTIAL_RESOURCE_DESCRIPTOR for a port or memory region. When a
107 * memory Length does not fit in 32 bits the descriptor is promoted to a
108 * CmResourceTypeMemoryLarge form.
109 *
110 * Returns STATUS_INVALID_PARAMETER for an unsupported Type (or a port length
111 * above 4 GB) and STATUS_UNSUCCESSFUL if the length cannot be represented by any
112 * large form without dropping bits.
113 */
115NTAPI
121{
122 if (Type != CmResourceTypePort &&
125 {
127 }
128
129 /* A port descriptor has only a 32-bit length and no large form. */
131 {
132 if (Length > MAXULONG)
134
136 Descriptor->u.Generic.Start.QuadPart = Start;
137 Descriptor->u.Generic.Length = (ULONG)Length;
138 return STATUS_SUCCESS;
139 }
140
141 /* Drop any stale large-form flags and record the start address. */
142 Descriptor->Flags &= ~CM_RESOURCE_MEMORY_LARGE;
143 Descriptor->u.Generic.Start.QuadPart = Start;
144
145 /* A length that fits 32 bits stays a plain memory descriptor. */
146 if (Length <= MAXULONG)
147 {
149 Descriptor->u.Generic.Length = (ULONG)Length;
150 return STATUS_SUCCESS;
151 }
152
153 /* Otherwise pick the tightest large form whose dropped low bits are zero. */
154 if (Length <= ((ULONGLONG)MAXULONG << 8) && (Length & 0xFF) == 0)
155 {
156 Descriptor->u.Generic.Length = (ULONG)(Length >> 8);
158 }
159 else if (Length <= ((ULONGLONG)MAXULONG << 16) && (Length & 0xFFFF) == 0)
160 {
161 Descriptor->u.Generic.Length = (ULONG)(Length >> 16);
163 }
164 else if (Length <= ((ULONGLONG)MAXULONG << 32) && (Length & 0xFFFFFFFF) == 0)
165 {
166 Descriptor->u.Generic.Length = (ULONG)(Length >> 32);
168 }
169 else
170 {
171 return STATUS_UNSUCCESSFUL;
172 }
173
175 return STATUS_SUCCESS;
176}
177
178/*
179 * A large descriptor expresses alignment at the same granularity as its length.
180 * Scale the alignment up until it is a multiple of that granularity.
181 */
182static
187 _Out_ PULONG Encoded)
188{
189 ULONGLONG LowMask = ((ULONGLONG)1 << Shift) - 1;
190
191 while ((Alignment & LowMask) != 0)
192 {
193 ULONGLONG Doubled = Alignment << 1;
194
195 if (Doubled < Alignment) /* overflowed past 64 bits */
196 return FALSE;
197
198 Alignment = Doubled;
199 }
200
201 *Encoded = (ULONG)(Alignment >> Shift);
202 return TRUE;
203}
204
205/*
206 * @implemented
207 *
208 * Fill in an IO_RESOURCE_DESCRIPTOR (a resource *requirement*) for a port or
209 * memory range. Also encodes the alignment and the 64-bit address bounds.
210 * A memory length above 4 GB is promoted to a CmResourceTypeMemoryLarge form,
211 * which matters as drivers depend on this behavior.
212 */
214NTAPI
222{
223 ULONG Shift;
224 USHORT LargeFlag;
225
226 if (Type != CmResourceTypePort &&
229 {
231 }
232
233 /* A port descriptor is limited to 32-bit length and alignment. */
235 {
238
240 Descriptor->u.Generic.MinimumAddress.QuadPart = MinimumAddress;
241 Descriptor->u.Generic.MaximumAddress.QuadPart = MaximumAddress;
242 Descriptor->u.Generic.Length = (ULONG)Length;
243 Descriptor->u.Generic.Alignment = (ULONG)Alignment;
244 return STATUS_SUCCESS;
245 }
246
247 /* Memory: reset any stale large-form flags and record the address bounds. */
248 Descriptor->Flags &= ~CM_RESOURCE_MEMORY_LARGE;
249 Descriptor->u.Generic.MinimumAddress.QuadPart = MinimumAddress;
250 Descriptor->u.Generic.MaximumAddress.QuadPart = MaximumAddress;
251
252 /* Both values fit 32 bits: a plain memory descriptor. */
253 if (Length <= MAXULONG && Alignment <= MAXULONG)
254 {
256 Descriptor->u.Generic.Length = (ULONG)Length;
257 Descriptor->u.Generic.Alignment = (ULONG)Alignment;
258 return STATUS_SUCCESS;
259 }
260
261 /* Select the large form from the length; the alignment must fit that tier. */
262 if (Length <= ((ULONGLONG)MAXULONG << 8))
263 {
264 if (Alignment > ((ULONGLONG)MAXULONG << 8))
265 return STATUS_UNSUCCESSFUL;
266
267 Shift = 8;
268 LargeFlag = CM_RESOURCE_MEMORY_LARGE_40;
269 }
270 else if (Length <= ((ULONGLONG)MAXULONG << 16))
271 {
272 if (Alignment > ((ULONGLONG)MAXULONG << 16))
273 return STATUS_UNSUCCESSFUL;
274
275 Shift = 16;
276 LargeFlag = CM_RESOURCE_MEMORY_LARGE_48;
277 }
278 else if (Length <= ((ULONGLONG)MAXULONG << 32))
279 {
280 Shift = 32;
281 LargeFlag = CM_RESOURCE_MEMORY_LARGE_64;
282 }
283 else
284 {
285 return STATUS_UNSUCCESSFUL;
286 }
287
288 /* The length must be exactly representable at this granularity. */
289 if ((Length & (((ULONGLONG)1 << Shift) - 1)) != 0)
290 return STATUS_UNSUCCESSFUL;
291
292 if (!RtlpEncodeLargeAlignment(Alignment, Shift, &Descriptor->u.Generic.Alignment))
293 return STATUS_UNSUCCESSFUL;
294
296 Descriptor->u.Generic.Length = (ULONG)(Length >> Shift);
297 Descriptor->Flags |= LargeFlag;
298 return STATUS_SUCCESS;
299}
300
301/*
302 * @implemented
303 *
304 * Round a requested length up to the nearest value the descriptor
305 * 1:1 when it fits 32 bits, otherwise the next multiple of the
306 * granularity.
307 */
309NTAPI
311 _In_ ULONGLONG SourceLength,
313{
314 if (SourceLength <= MAXULONG)
315 *TargetLength = SourceLength;
316 else if (SourceLength <= ((ULONGLONG)MAXULONG << 8))
317 *TargetLength = (SourceLength + 0xFF) & ~(ULONGLONG)0xFF;
318 else if (SourceLength <= ((ULONGLONG)MAXULONG << 16))
319 *TargetLength = (SourceLength + 0xFFFF) & ~(ULONGLONG)0xFFFF;
320 else if (SourceLength <= ((ULONGLONG)MAXULONG << 32))
321 *TargetLength = (SourceLength + 0xFFFFFFFF) & ~(ULONGLONG)0xFFFFFFFF;
322 else
323 {
324 *TargetLength = 0;
325 return STATUS_UNSUCCESSFUL;
326 }
327
328 return STATUS_SUCCESS;
329}
static _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG MinimumAddress
static _Out_opt_ PULONGLONG Start
static _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG MaximumAddress
static _Out_ PULONGLONG TargetLength
Type
Definition: Type.h:7
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static ULONGLONG RtlpDecodeMemIoValue(_In_ UCHAR Type, _In_ USHORT Flags, _In_ ULONG Encoded)
Definition: memres.c:30
NTSTATUS NTAPI RtlFindClosestEncodableLength(_In_ ULONGLONG SourceLength, _Out_ PULONGLONG TargetLength)
Definition: memres.c:310
NTSTATUS NTAPI RtlCmEncodeMemIoResource(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, _In_ UCHAR Type, _In_ ULONGLONG Length, _In_ ULONGLONG Start)
Definition: memres.c:116
ULONGLONG NTAPI RtlIoDecodeMemIoResource(_In_ PIO_RESOURCE_DESCRIPTOR Descriptor, _Out_opt_ PULONGLONG Alignment, _Out_opt_ PULONGLONG MinimumAddress, _Out_opt_ PULONGLONG MaximumAddress)
Definition: memres.c:79
NTSTATUS NTAPI RtlIoEncodeMemIoResource(_In_ PIO_RESOURCE_DESCRIPTOR Descriptor, _In_ UCHAR Type, _In_ ULONGLONG Length, _In_ ULONGLONG Alignment, _In_ ULONGLONG MinimumAddress, _In_ ULONGLONG MaximumAddress)
Definition: memres.c:215
static BOOLEAN RtlpEncodeLargeAlignment(_In_ ULONGLONG Alignment, _In_ ULONG Shift, _Out_ PULONG Encoded)
Definition: memres.c:184
ULONGLONG NTAPI RtlCmDecodeMemIoResource(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, _Out_opt_ PULONGLONG Start)
Definition: memres.c:58
#define CM_RESOURCE_MEMORY_LARGE_40
Definition: cmtypes.h:134
#define CM_RESOURCE_MEMORY_LARGE_64
Definition: cmtypes.h:136
#define CM_RESOURCE_MEMORY_LARGE_48
Definition: cmtypes.h:135
#define _Out_opt_
Definition: no_sal2.h:214
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:395
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
unsigned short USHORT
Definition: pedump.c:61
#define CmResourceTypeMemory
Definition: restypes.h:106
#define CmResourceTypePort
Definition: restypes.h:104
#define STATUS_SUCCESS
Definition: shellext.h:65
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint64_t ULONGLONG
Definition: typedefs.h:67
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define CmResourceTypeMemoryLarge
Definition: cmtypes.h:231
_In_ ULONG Shift
Definition: rtlfuncs.h:2698