[CMAKE]
[reactos.git] / ntoskrnl / cache / section / sptab.c
1 /*
2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Section object page tables
22 *
23 * PROGRAMMERS: arty
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include <ntoskrnl.h>
29 #include "newmm.h"
30 #define NDEBUG
31 #include <debug.h>
32
33 #define DPRINTC DPRINT
34
35 /* TYPES *********************************************************************/
36
37 extern KSPIN_LOCK MiSectionPageTableLock;
38
39 static
40 PVOID
41 NTAPI
42 MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
43 {
44 PVOID Result;
45 Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, 'MmPt');
46 DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result);
47 return Result;
48 }
49
50 static
51 VOID
52 NTAPI
53 MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data)
54 {
55 DPRINT("MiSectionPageTableFree(%p)\n", Data);
56 ExFreePoolWithTag(Data, 'MmPt');
57 }
58
59 static
60 RTL_GENERIC_COMPARE_RESULTS
61 NTAPI
62 MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
63 {
64 PLARGE_INTEGER A = PtrA, B = PtrB;
65 BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan :
66 (A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan;
67
68 DPRINT
69 ("Compare: %08x%08x vs %08x%08x => %s\n",
70 A->u.HighPart, A->u.LowPart,
71 B->u.HighPart, B->u.LowPart,
72 Result == GenericLessThan ? "GenericLessThan" :
73 Result == GenericGreaterThan ? "GenericGreaterThan" :
74 "GenericEqual");
75
76 return Result;
77 }
78
79 static
80 PCACHE_SECTION_PAGE_TABLE
81 NTAPI
82 MiSectionPageTableGet
83 (PRTL_GENERIC_TABLE Table,
84 PLARGE_INTEGER FileOffset)
85 {
86 LARGE_INTEGER SearchFileOffset;
87 PCACHE_SECTION_PAGE_TABLE PageTable;
88 SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
89 PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset);
90 DPRINT
91 ("MiSectionPageTableGet(%08x,%08x%08x)\n",
92 Table,
93 FileOffset->HighPart,
94 FileOffset->LowPart);
95 return PageTable;
96 }
97
98 static
99 PCACHE_SECTION_PAGE_TABLE
100 NTAPI
101 MiSectionPageTableGetOrAllocate
102 (PRTL_GENERIC_TABLE Table,
103 PLARGE_INTEGER FileOffset)
104 {
105 LARGE_INTEGER SearchFileOffset;
106 PCACHE_SECTION_PAGE_TABLE PageTableSlice =
107 MiSectionPageTableGet(Table, FileOffset);
108 if (!PageTableSlice)
109 {
110 CACHE_SECTION_PAGE_TABLE SectionZeroPageTable = { };
111 SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
112 SectionZeroPageTable.FileOffset = SearchFileOffset;
113 SectionZeroPageTable.Refcount = 1;
114 PageTableSlice = RtlInsertElementGenericTable
115 (Table, &SectionZeroPageTable, sizeof(SectionZeroPageTable), NULL);
116 DPRINT
117 ("Allocate page table %x (%08x%08x)\n",
118 PageTableSlice,
119 PageTableSlice->FileOffset.u.HighPart,
120 PageTableSlice->FileOffset.u.LowPart);
121 if (!PageTableSlice) return NULL;
122 }
123 return PageTableSlice;
124 }
125
126 VOID
127 NTAPI
128 MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment)
129 {
130 RtlInitializeGenericTable
131 (&Segment->PageTable,
132 MiSectionPageTableCompare,
133 MiSectionPageTableAllocate,
134 MiSectionPageTableFree,
135 NULL);
136 DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable);
137 }
138
139 NTSTATUS
140 NTAPI
141 _MiSetPageEntryCacheSectionSegment
142 (PMM_CACHE_SECTION_SEGMENT Segment,
143 PLARGE_INTEGER Offset,
144 ULONG Entry,
145 const char *file,
146 int line)
147 {
148 ULONG PageIndex, OldEntry;
149 PCACHE_SECTION_PAGE_TABLE PageTable;
150 PageTable =
151 MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);
152 if (!PageTable) return STATUS_NO_MEMORY;
153 ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset));
154 PageTable->Segment = Segment;
155 PageIndex =
156 (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
157 OldEntry = PageTable->PageEntries[PageIndex];
158 if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
159 MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
160 }
161 if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
162 MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset);
163 }
164 PageTable->PageEntries[PageIndex] = Entry;
165 DPRINT
166 ("MiSetPageEntrySectionSegment(%p,%08x%08x,%x) %s:%d\n",
167 Segment, Offset->u.HighPart, Offset->u.LowPart, Entry, file, line);
168 return STATUS_SUCCESS;
169 }
170
171 ULONG
172 NTAPI
173 _MiGetPageEntryCacheSectionSegment
174 (PMM_CACHE_SECTION_SEGMENT Segment,
175 PLARGE_INTEGER Offset,
176 const char *file,
177 int line)
178 {
179 LARGE_INTEGER FileOffset;
180 ULONG PageIndex, Result;
181 PCACHE_SECTION_PAGE_TABLE PageTable;
182
183 FileOffset.QuadPart =
184 ROUND_DOWN(Offset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
185 PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset);
186 if (!PageTable) return 0;
187 PageIndex =
188 (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
189 Result = PageTable->PageEntries[PageIndex];
190 #if 0
191 DPRINTC
192 ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n",
193 Segment,
194 FileOffset.u.HighPart,
195 FileOffset.u.LowPart + PageIndex * PAGE_SIZE,
196 Result,
197 file, line);
198 #endif
199 return Result;
200 }
201
202 VOID
203 NTAPI
204 MiFreePageTablesSectionSegment
205 (PMM_CACHE_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage)
206 {
207 PCACHE_SECTION_PAGE_TABLE Element;
208 DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
209 while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
210 DPRINT
211 ("Delete table for %x -> %08x%08x\n",
212 Segment,
213 Element->FileOffset.u.HighPart,
214 Element->FileOffset.u.LowPart);
215 if (FreePage)
216 {
217 int i;
218 for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
219 {
220 ULONG Entry;
221 LARGE_INTEGER Offset;
222 Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
223 Entry = Element->PageEntries[i];
224 if (Entry && !IS_SWAP_FROM_SSE(Entry))
225 {
226 DPRINTC("Freeing page %x:%x @ %x\n", Segment, Entry, Offset.LowPart);
227 FreePage(Segment, &Offset);
228 }
229 }
230 }
231 DPRINT("Remove memory\n");
232 RtlDeleteElementGenericTable(&Segment->PageTable, Element);
233 }
234 DPRINT("Done\n");
235 }
236
237 PMM_CACHE_SECTION_SEGMENT
238 NTAPI
239 MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
240 {
241 ULONG RawOffset;
242 PMM_CACHE_SECTION_SEGMENT Segment = NULL;
243 PCACHE_SECTION_PAGE_TABLE PageTable;
244
245 PageTable = (PCACHE_SECTION_PAGE_TABLE)MmGetSegmentRmap(Page, &RawOffset);
246 if (PageTable)
247 {
248 Segment = PageTable->Segment;
249 Offset->QuadPart = PageTable->FileOffset.QuadPart + (RawOffset << PAGE_SHIFT);
250 }
251
252 return(Segment);
253 }
254
255 NTSTATUS
256 NTAPI
257 MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
258 {
259 PCACHE_SECTION_PAGE_TABLE PageTable;
260 ULONG ActualOffset;
261 PageTable = MiSectionPageTableGet(&Segment->PageTable, Offset);
262 ASSERT(PageTable);
263 ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart);
264 MmInsertRmap(Page, (PEPROCESS)PageTable, (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT)));
265 return STATUS_SUCCESS;
266 }