xref: /reactos/ntoskrnl/ex/zone.c (revision 40462c92)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/ex/zone.c
5  * PURPOSE:         Implements zone buffers
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  David Welch (welch@mcmail.com)
8  */
9 
10 /* INCLUDES ****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS ***************************************************************/
17 
18 /*
19  * @implemented
20  */
21 NTSTATUS
22 NTAPI
23 ExExtendZone(PZONE_HEADER Zone,
24              PVOID Segment,
25              ULONG SegmentSize)
26 {
27     ULONG_PTR Entry;
28     ULONG i;
29 
30     /*
31      * BlockSize and Segment must be 8-byte aligned.
32      * Blocksize cannot exceed Segment Size.
33      */
34     if (((ULONG_PTR)Segment & 7) ||
35         (SegmentSize & 7) ||
36         (Zone->BlockSize > SegmentSize))
37     {
38         DPRINT1("Invalid ExExtendZone Alignment and/or Size\n");
39         return STATUS_INVALID_PARAMETER;
40     }
41 
42     /* Link the Zone and Segment */
43     PushEntryList(&Zone->SegmentList,
44                   &((PZONE_SEGMENT_HEADER)Segment)->SegmentList);
45 
46     /* Get to the first entry */
47     Entry = (ULONG_PTR)Segment + sizeof(ZONE_SEGMENT_HEADER);
48 
49     /* Loop through the segments */
50     for (i = sizeof(ZONE_SEGMENT_HEADER);
51          i <= SegmentSize - Zone->BlockSize;
52          i+= Zone->BlockSize)
53     {
54         /* Link the Free and Segment Lists */
55         PushEntryList(&Zone->FreeList, (PSINGLE_LIST_ENTRY)Entry);
56 
57         /* Go to the next entry */
58         Entry += Zone->BlockSize;
59     }
60 
61     /* Update Segment Size */
62     Zone->TotalSegmentSize += i;
63 
64     /* Return Success */
65     return STATUS_SUCCESS;
66 }
67 
68 /*
69  * @implemented
70  */
71 NTSTATUS
72 NTAPI
73 ExInterlockedExtendZone(PZONE_HEADER Zone,
74                         PVOID Segment,
75                         ULONG SegmentSize,
76                         PKSPIN_LOCK Lock)
77 {
78     NTSTATUS Status;
79     KIRQL OldIrql;
80 
81     /* Get the lock */
82     KeAcquireSpinLock(Lock, &OldIrql);
83 
84     /* Extend the Zone */
85     Status = ExExtendZone(Zone, Segment, SegmentSize);
86 
87     /* Release lock and return status */
88     KeReleaseSpinLock(Lock, OldIrql);
89     return Status;
90 }
91 
92 /*
93  * FUNCTION: Initializes a zone header
94  * ARGUMENTS:
95  *          Zone = zone header to be initialized
96  *          BlockSize = Size (in bytes) of the allocation size of the zone
97  *          InitialSegment = Initial segment of storage allocated by the
98  *                           caller
99  *          InitialSegmentSize = Initial size of the segment
100  *
101  * @implemented
102  */
103 NTSTATUS
104 NTAPI
105 ExInitializeZone(PZONE_HEADER Zone,
106                  ULONG BlockSize,
107                  PVOID InitialSegment,
108                  ULONG InitialSegmentSize)
109 {
110     ULONG i;
111     ULONG_PTR Entry;
112 
113     /*
114      * BlockSize and Segment must be 8-byte aligned.
115      * Blocksize cannot exceed Segment Size.
116      */
117     if (((ULONG_PTR)InitialSegment & 7) ||
118         (InitialSegmentSize & 7) ||
119         (BlockSize > InitialSegmentSize))
120     {
121         DPRINT1("Invalid ExInitializeZone Alignment and/or Size\n");
122         return STATUS_INVALID_PARAMETER;
123     }
124 
125     /* Set the Zone Header */
126     Zone->BlockSize = BlockSize;
127 
128     /* Link empty list */
129     Zone->FreeList.Next = NULL;
130     Zone->SegmentList.Next = NULL;
131     PushEntryList(&Zone->SegmentList,
132                   &((PZONE_SEGMENT_HEADER)InitialSegment)->SegmentList);
133     ((PZONE_SEGMENT_HEADER)InitialSegment)->Reserved = NULL;
134 
135     /* Get first entry */
136     Entry = (ULONG_PTR)InitialSegment + sizeof(ZONE_SEGMENT_HEADER);
137 
138     /* Loop through the segments */
139     for (i = sizeof(ZONE_SEGMENT_HEADER);
140          i <= InitialSegmentSize - BlockSize;
141          i+= BlockSize)
142     {
143         /* Link the Free and Segment Lists */
144         PushEntryList(&Zone->FreeList, (PSINGLE_LIST_ENTRY)Entry);
145 
146         /* Go to the next entry */
147         Entry += Zone->BlockSize;
148     }
149 
150     /* Set Segment Size */
151     Zone->TotalSegmentSize = i;
152 
153     /* Return success */
154     return STATUS_SUCCESS;
155 }
156 
157 /* EOF */
158