[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / section.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: Implements section objects
22 *
23 * PROGRAMMERS: Rex Jolliff
24 * David Welch
25 * Eric Kohl
26 * Emanuele Aliberti
27 * Eugene Ingerman
28 * Casper Hornstrup
29 * KJK::Hyperion
30 * Guido de Jong
31 * Ge van Geldorp
32 * Royce Mitchell III
33 * Filip Navara
34 * Aleksey Bragin
35 * Jason Filby
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
38 * Mike Nordell
39 * Alex Ionescu
40 * Gregor Anich
41 * Steven Edwards
42 * Herve Poussineau
43 */
44
45 /* INCLUDES *****************************************************************/
46
47 #include <ntoskrnl.h>
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
50 #define NDEBUG
51 #include <debug.h>
52 #include <reactos/exeformat.h>
53
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
57 #endif
58
59 #include "ARM3/miarm.h"
60
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%x,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
65 } while (0)
66
67 extern MMSESSION MmSession;
68
69 NTSTATUS
70 NTAPI
71 MiMapViewInSystemSpace(IN PVOID Section,
72 IN PVOID Session,
73 OUT PVOID *MappedBase,
74 IN OUT PSIZE_T ViewSize);
75
76 NTSTATUS
77 NTAPI
78 MmCreateArm3Section(OUT PVOID *SectionObject,
79 IN ACCESS_MASK DesiredAccess,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
81 IN PLARGE_INTEGER InputMaximumSize,
82 IN ULONG SectionPageProtection,
83 IN ULONG AllocationAttributes,
84 IN HANDLE FileHandle OPTIONAL,
85 IN PFILE_OBJECT FileObject OPTIONAL);
86
87 NTSTATUS
88 NTAPI
89 MmMapViewOfArm3Section(IN PVOID SectionObject,
90 IN PEPROCESS Process,
91 IN OUT PVOID *BaseAddress,
92 IN ULONG_PTR ZeroBits,
93 IN SIZE_T CommitSize,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
95 IN OUT PSIZE_T ViewSize,
96 IN SECTION_INHERIT InheritDisposition,
97 IN ULONG AllocationType,
98 IN ULONG Protect);
99
100 //
101 // PeFmtCreateSection depends on the following:
102 //
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
105
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
109
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
119
120 /* TYPES *********************************************************************/
121
122 typedef struct
123 {
124 PROS_SECTION_OBJECT Section;
125 PMM_SECTION_SEGMENT Segment;
126 LARGE_INTEGER Offset;
127 BOOLEAN WasDirty;
128 BOOLEAN Private;
129 PEPROCESS CallingProcess;
130 ULONG_PTR SectionEntry;
131 }
132 MM_SECTION_PAGEOUT_CONTEXT;
133
134 /* GLOBALS *******************************************************************/
135
136 POBJECT_TYPE MmSectionObjectType = NULL;
137
138 ULONG_PTR MmSubsectionBase;
139
140 static ULONG SectionCharacteristicsToProtect[16] =
141 {
142 PAGE_NOACCESS, /* 0 = NONE */
143 PAGE_NOACCESS, /* 1 = SHARED */
144 PAGE_EXECUTE, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY, /* 4 = READABLE */
147 PAGE_READONLY, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
150 /*
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
153 */
154 PAGE_READWRITE, /* 8 = WRITABLE */
155 PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
162 };
163
164 ACCESS_MASK NTAPI MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection);
165 static GENERIC_MAPPING MmpSectionMapping = {
166 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
167 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
168 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
169 SECTION_ALL_ACCESS};
170
171 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
172 {
173 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
174 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
175 };
176
177 /* FUNCTIONS *****************************************************************/
178
179
180 /*
181 References:
182 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
183 File Format Specification", revision 6.0 (February 1999)
184 */
185 NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
186 IN SIZE_T FileHeaderSize,
187 IN PVOID File,
188 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
189 OUT PULONG Flags,
190 IN PEXEFMT_CB_READ_FILE ReadFileCb,
191 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
192 {
193 NTSTATUS nStatus;
194 ULONG cbFileHeaderOffsetSize = 0;
195 ULONG cbSectionHeadersOffset = 0;
196 ULONG cbSectionHeadersSize;
197 ULONG cbSectionHeadersOffsetSize = 0;
198 ULONG cbOptHeaderSize;
199 ULONG cbHeadersSize = 0;
200 ULONG nSectionAlignment;
201 ULONG nFileAlignment;
202 const IMAGE_DOS_HEADER * pidhDosHeader;
203 const IMAGE_NT_HEADERS32 * pinhNtHeader;
204 const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
205 const IMAGE_SECTION_HEADER * pishSectionHeaders;
206 PMM_SECTION_SEGMENT pssSegments;
207 LARGE_INTEGER lnOffset;
208 PVOID pBuffer;
209 SIZE_T nPrevVirtualEndOfSegment = 0;
210 ULONG nFileSizeOfHeaders = 0;
211 ULONG i;
212
213 ASSERT(FileHeader);
214 ASSERT(FileHeaderSize > 0);
215 ASSERT(File);
216 ASSERT(ImageSectionObject);
217 ASSERT(ReadFileCb);
218 ASSERT(AllocateSegmentsCb);
219
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
221
222 ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
223
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
225
226 pBuffer = NULL;
227 pidhDosHeader = FileHeader;
228
229 /* DOS HEADER */
230 nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
231
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
235
236 /* no MZ signature */
237 if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
239
240 /* not a Windows executable */
241 if(pidhDosHeader->e_lfanew <= 0)
242 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
243
244 /* NT HEADER */
245 nStatus = STATUS_INVALID_IMAGE_FORMAT;
246
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
249
250 if(FileHeaderSize < cbFileHeaderOffsetSize)
251 pinhNtHeader = NULL;
252 else
253 {
254 /*
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
257 */
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
259 pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
260 }
261
262 /*
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
265 */
266 if(FileHeaderSize < cbFileHeaderOffsetSize ||
267 (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
268 {
269 ULONG cbNtHeaderSize;
270 ULONG cbReadSize;
271 PVOID pData;
272
273 l_ReadHeaderFromFile:
274 cbNtHeaderSize = 0;
275 lnOffset.QuadPart = pidhDosHeader->e_lfanew;
276
277 /* read the header from the file */
278 nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
279
280 if(!NT_SUCCESS(nStatus))
281 DIE(("ReadFile failed, status %08X\n", nStatus));
282
283 ASSERT(pData);
284 ASSERT(pBuffer);
285 ASSERT(cbReadSize > 0);
286
287 nStatus = STATUS_INVALID_IMAGE_FORMAT;
288
289 /* the buffer doesn't contain the file header */
290 if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
291 DIE(("The file doesn't contain the PE file header\n"));
292
293 pinhNtHeader = pData;
294
295 /* object still not aligned: copy it to the beginning of the buffer */
296 if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
297 {
298 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
299 RtlMoveMemory(pBuffer, pData, cbReadSize);
300 pinhNtHeader = pBuffer;
301 }
302
303 /* invalid NT header */
304 nStatus = STATUS_INVALID_IMAGE_PROTECT;
305
306 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
307 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
308
309 nStatus = STATUS_INVALID_IMAGE_FORMAT;
310
311 if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
312 DIE(("The full NT header is too large\n"));
313
314 /* the buffer doesn't contain the whole NT header */
315 if(cbReadSize < cbNtHeaderSize)
316 DIE(("The file doesn't contain the full NT header\n"));
317 }
318 else
319 {
320 ULONG cbOptHeaderOffsetSize = 0;
321
322 nStatus = STATUS_INVALID_IMAGE_FORMAT;
323
324 /* don't trust an invalid NT header */
325 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
326 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
327
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
329 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
330
331 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
332 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
333
334 /* the buffer doesn't contain the whole NT header: read it from the file */
335 if(cbOptHeaderOffsetSize > FileHeaderSize)
336 goto l_ReadHeaderFromFile;
337 }
338
339 /* read information from the NT header */
340 piohOptHeader = &pinhNtHeader->OptionalHeader;
341 cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
342
343 nStatus = STATUS_INVALID_IMAGE_FORMAT;
344
345 if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
346 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
347
348 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
349
350 switch(piohOptHeader->Magic)
351 {
352 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
353 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
354 break;
355
356 default:
357 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
358 }
359
360 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
361 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
362 {
363 /* See [1], section 3.4.2 */
364 if(piohOptHeader->SectionAlignment < PAGE_SIZE)
365 {
366 if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
367 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
368 }
369 else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
370 DIE(("The section alignment is smaller than the file alignment\n"));
371
372 nSectionAlignment = piohOptHeader->SectionAlignment;
373 nFileAlignment = piohOptHeader->FileAlignment;
374
375 if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
376 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
377 }
378 else
379 {
380 nSectionAlignment = PAGE_SIZE;
381 nFileAlignment = PAGE_SIZE;
382 }
383
384 ASSERT(IsPowerOf2(nSectionAlignment));
385 ASSERT(IsPowerOf2(nFileAlignment));
386
387 switch(piohOptHeader->Magic)
388 {
389 /* PE32 */
390 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
391 {
392 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
393 ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
394
395 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
396 ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
397
398 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
399 ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
400
401 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
402 ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
403
404 break;
405 }
406
407 /* PE64 */
408 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
409 {
410 const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
411
412 pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
413
414 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
415 {
416 if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
417 DIE(("ImageBase exceeds the address space\n"));
418
419 ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
420 }
421
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
423 {
424 if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
425 DIE(("SizeOfImage exceeds the address space\n"));
426
427 ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
428 }
429
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
431 {
432 if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
433 DIE(("SizeOfStackReserve exceeds the address space\n"));
434
435 ImageSectionObject->StackReserve = (ULONG_PTR)pioh64OptHeader->SizeOfStackReserve;
436 }
437
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
439 {
440 if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
441 DIE(("SizeOfStackCommit exceeds the address space\n"));
442
443 ImageSectionObject->StackCommit = (ULONG_PTR)pioh64OptHeader->SizeOfStackCommit;
444 }
445
446 break;
447 }
448 }
449
450 /* [1], section 3.4.2 */
451 if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
452 DIE(("ImageBase is not aligned on a 64KB boundary"));
453
454 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
455 {
456 ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
457
458 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
459 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
460 {
461 ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
462 ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
463 }
464 }
465
466 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
467 {
468 ImageSectionObject->EntryPoint = ImageSectionObject->ImageBase +
469 piohOptHeader->AddressOfEntryPoint;
470 }
471
472 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
473 ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
474 else
475 ImageSectionObject->Executable = TRUE;
476
477 ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
478 ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
479
480 /* SECTION HEADERS */
481 nStatus = STATUS_INVALID_IMAGE_FORMAT;
482
483 /* see [1], section 3.3 */
484 if(pinhNtHeader->FileHeader.NumberOfSections > 96)
485 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
486
487 /*
488 * the additional segment is for the file's headers. They need to be present for
489 * the benefit of the dynamic loader (to locate exports, defaults for thread
490 * parameters, resources, etc.)
491 */
492 ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
493
494 /* file offset for the section headers */
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
496 DIE(("Offset overflow\n"));
497
498 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
499 DIE(("Offset overflow\n"));
500
501 /* size of the section headers */
502 ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
503 cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
504
505 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
506 DIE(("Section headers too large\n"));
507
508 /* size of the executable's headers */
509 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
510 {
511 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
512 // DIE(("SizeOfHeaders is not aligned\n"));
513
514 if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
515 DIE(("The section headers overflow SizeOfHeaders\n"));
516
517 cbHeadersSize = piohOptHeader->SizeOfHeaders;
518 }
519 else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
520 DIE(("Overflow aligning the size of headers\n"));
521
522 if(pBuffer)
523 {
524 ExFreePool(pBuffer);
525 pBuffer = NULL;
526 }
527 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
528 /* WARNING: piohOptHeader IS NO LONGER USABLE */
529 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
530
531 if(FileHeaderSize < cbSectionHeadersOffsetSize)
532 pishSectionHeaders = NULL;
533 else
534 {
535 /*
536 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
537 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
538 */
539 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
540 pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
541 }
542
543 /*
544 * the buffer doesn't contain the section headers, or the alignment is wrong:
545 * read the headers from the file
546 */
547 if(FileHeaderSize < cbSectionHeadersOffsetSize ||
548 (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
549 {
550 PVOID pData;
551 ULONG cbReadSize;
552
553 lnOffset.QuadPart = cbSectionHeadersOffset;
554
555 /* read the header from the file */
556 nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
557
558 if(!NT_SUCCESS(nStatus))
559 DIE(("ReadFile failed with status %08X\n", nStatus));
560
561 ASSERT(pData);
562 ASSERT(pBuffer);
563 ASSERT(cbReadSize > 0);
564
565 nStatus = STATUS_INVALID_IMAGE_FORMAT;
566
567 /* the buffer doesn't contain all the section headers */
568 if(cbReadSize < cbSectionHeadersSize)
569 DIE(("The file doesn't contain all of the section headers\n"));
570
571 pishSectionHeaders = pData;
572
573 /* object still not aligned: copy it to the beginning of the buffer */
574 if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
575 {
576 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
577 RtlMoveMemory(pBuffer, pData, cbReadSize);
578 pishSectionHeaders = pBuffer;
579 }
580 }
581
582 /* SEGMENTS */
583 /* allocate the segments */
584 nStatus = STATUS_INSUFFICIENT_RESOURCES;
585 ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
586
587 if(ImageSectionObject->Segments == NULL)
588 DIE(("AllocateSegments failed\n"));
589
590 /* initialize the headers segment */
591 pssSegments = ImageSectionObject->Segments;
592
593 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
594
595 if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
596 DIE(("Cannot align the size of the section headers\n"));
597
598 nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment);
599 if (nPrevVirtualEndOfSegment < cbHeadersSize)
600 DIE(("Cannot align the size of the section headers\n"));
601
602 pssSegments[0].Image.FileOffset = 0;
603 pssSegments[0].Protection = PAGE_READONLY;
604 pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment;
605 pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders;
606 pssSegments[0].Image.VirtualAddress = 0;
607 pssSegments[0].Image.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
608 pssSegments[0].WriteCopy = TRUE;
609
610 /* skip the headers segment */
611 ++ pssSegments;
612
613 nStatus = STATUS_INVALID_IMAGE_FORMAT;
614
615 /* convert the executable sections into segments. See also [1], section 4 */
616 for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
617 {
618 ULONG nCharacteristics;
619
620 /* validate the alignment */
621 if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
622 DIE(("Image.VirtualAddress[%u] is not aligned\n", i));
623
624 /* sections must be contiguous, ordered by base address and non-overlapping */
625 if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
626 DIE(("Memory gap between section %u and the previous\n", i));
627
628 /* ignore explicit BSS sections */
629 if(pishSectionHeaders[i].SizeOfRawData != 0)
630 {
631 /* validate the alignment */
632 #if 0
633 /* Yes, this should be a multiple of FileAlignment, but there's
634 * stuff out there that isn't. We can cope with that
635 */
636 if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
637 DIE(("SizeOfRawData[%u] is not aligned\n", i));
638 #endif
639
640 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
641 // DIE(("PointerToRawData[%u] is not aligned\n", i));
642
643 /* conversion */
644 pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData;
645 pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData;
646 }
647 else
648 {
649 ASSERT(pssSegments[i].Image.FileOffset == 0);
650 ASSERT(pssSegments[i].RawLength.QuadPart == 0);
651 }
652
653 ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart));
654
655 nCharacteristics = pishSectionHeaders[i].Characteristics;
656
657 /* no explicit protection */
658 if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
659 {
660 if(nCharacteristics & IMAGE_SCN_CNT_CODE)
661 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
662
663 if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
664 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
665
666 if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
667 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
668 }
669
670 /* see table above */
671 pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
672 pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
673
674 if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
675 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData;
676 else
677 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize;
678
679 pssSegments[i].Length.LowPart = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment);
680 if (pssSegments[i].Length.QuadPart < pssSegments[i].Length.QuadPart)
681 DIE(("Cannot align the virtual size of section %u\n", i));
682
683 if(pssSegments[i].Length.QuadPart == 0)
684 DIE(("Virtual size of section %u is null\n", i));
685
686 pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress;
687 pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics;
688
689 /* ensure the memory image is no larger than 4GB */
690 nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart);
691 if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress)
692 DIE(("The image is too large\n"));
693 }
694
695 if(nSectionAlignment >= PAGE_SIZE)
696 *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
697
698 /* Success */
699 nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
700
701 l_Return:
702 if(pBuffer)
703 ExFreePool(pBuffer);
704
705 return nStatus;
706 }
707
708 /*
709 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
710 * ARGUMENTS: PFILE_OBJECT to wait for.
711 * RETURNS: Status of the wait.
712 */
713 NTSTATUS
714 MmspWaitForFileLock(PFILE_OBJECT File)
715 {
716 return STATUS_SUCCESS;
717 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
718 }
719
720 VOID
721 NTAPI
722 MmFreeSectionSegments(PFILE_OBJECT FileObject)
723 {
724 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
725 {
726 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
727 PMM_SECTION_SEGMENT SectionSegments;
728 ULONG NrSegments;
729 ULONG i;
730
731 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
732 NrSegments = ImageSectionObject->NrSegments;
733 SectionSegments = ImageSectionObject->Segments;
734 for (i = 0; i < NrSegments; i++)
735 {
736 if (SectionSegments[i].ReferenceCount != 0)
737 {
738 DPRINT1("Image segment %d still referenced (was %d)\n", i,
739 SectionSegments[i].ReferenceCount);
740 KeBugCheck(MEMORY_MANAGEMENT);
741 }
742 MmFreePageTablesSectionSegment(&SectionSegments[i], NULL);
743 }
744 ExFreePool(ImageSectionObject->Segments);
745 ExFreePool(ImageSectionObject);
746 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
747 }
748 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
749 {
750 PMM_SECTION_SEGMENT Segment;
751
752 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
753 DataSectionObject;
754
755 if (Segment->ReferenceCount != 0)
756 {
757 DPRINT1("Data segment still referenced\n");
758 KeBugCheck(MEMORY_MANAGEMENT);
759 }
760 MmFreePageTablesSectionSegment(Segment, NULL);
761 ExFreePool(Segment);
762 FileObject->SectionObjectPointer->DataSectionObject = NULL;
763 }
764 }
765
766 VOID
767 NTAPI
768 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
769 PLARGE_INTEGER Offset)
770 {
771 ULONG_PTR Entry;
772
773 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
774 if (Entry == 0)
775 {
776 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
777 KeBugCheck(MEMORY_MANAGEMENT);
778 }
779 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
780 {
781 DPRINT1("Maximum share count reached\n");
782 KeBugCheck(MEMORY_MANAGEMENT);
783 }
784 if (IS_SWAP_FROM_SSE(Entry))
785 {
786 KeBugCheck(MEMORY_MANAGEMENT);
787 }
788 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
789 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
790 }
791
792 BOOLEAN
793 NTAPI
794 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
795 PMM_SECTION_SEGMENT Segment,
796 PLARGE_INTEGER Offset,
797 BOOLEAN Dirty,
798 BOOLEAN PageOut,
799 ULONG_PTR *InEntry)
800 {
801 ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset);
802 BOOLEAN IsDirectMapped = FALSE;
803
804 if (Entry == 0)
805 {
806 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
807 KeBugCheck(MEMORY_MANAGEMENT);
808 }
809 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
810 {
811 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry));
812 KeBugCheck(MEMORY_MANAGEMENT);
813 }
814 if (IS_SWAP_FROM_SSE(Entry))
815 {
816 KeBugCheck(MEMORY_MANAGEMENT);
817 }
818 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
819 /*
820 * If we reducing the share count of this entry to zero then set the entry
821 * to zero and tell the cache the page is no longer mapped.
822 */
823 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
824 {
825 PFILE_OBJECT FileObject;
826 #ifndef NEWCC
827 PBCB Bcb;
828 #endif
829 SWAPENTRY SavedSwapEntry;
830 PFN_NUMBER Page;
831 BOOLEAN IsImageSection;
832 LARGE_INTEGER FileOffset;
833
834 FileOffset.QuadPart = Offset->QuadPart + Segment->Image.FileOffset;
835
836 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
837
838 Page = PFN_FROM_SSE(Entry);
839 FileObject = Section->FileObject;
840 if (FileObject != NULL &&
841 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
842 {
843
844 #ifndef NEWCC
845 if ((FileOffset.QuadPart % PAGE_SIZE) == 0 &&
846 (Offset->QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
847 {
848 NTSTATUS Status;
849 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
850 IsDirectMapped = TRUE;
851 #ifndef NEWCC
852 Status = CcRosUnmapCacheSegment(Bcb, FileOffset.LowPart, Dirty);
853 #else
854 Status = STATUS_SUCCESS;
855 #endif
856 if (!NT_SUCCESS(Status))
857 {
858 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
859 KeBugCheck(MEMORY_MANAGEMENT);
860 }
861 }
862 #endif
863 }
864
865 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
866 if (SavedSwapEntry == 0)
867 {
868 if (!PageOut &&
869 ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
870 (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)))
871 {
872 /*
873 * FIXME:
874 * Try to page out this page and set the swap entry
875 * within the section segment. There exist no rmap entry
876 * for this page. The pager thread can't page out a
877 * page without a rmap entry.
878 */
879 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
880 if (InEntry) *InEntry = Entry;
881 MiSetPageEvent(NULL, NULL);
882 }
883 else
884 {
885 MmSetPageEntrySectionSegment(Segment, Offset, 0);
886 if (InEntry) *InEntry = 0;
887 MiSetPageEvent(NULL, NULL);
888 if (!IsDirectMapped)
889 {
890 MmReleasePageMemoryConsumer(MC_USER, Page);
891 }
892 }
893 }
894 else
895 {
896 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
897 (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
898 {
899 if (!PageOut)
900 {
901 if (Dirty)
902 {
903 /*
904 * FIXME:
905 * We hold all locks. Nobody can do something with the current
906 * process and the current segment (also not within an other process).
907 */
908 NTSTATUS Status;
909 Status = MmWriteToSwapPage(SavedSwapEntry, Page);
910 if (!NT_SUCCESS(Status))
911 {
912 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
913 KeBugCheck(MEMORY_MANAGEMENT);
914 }
915 }
916 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
917 if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry);
918 MmSetSavedSwapEntryPage(Page, 0);
919 MiSetPageEvent(NULL, NULL);
920 }
921 MmReleasePageMemoryConsumer(MC_USER, Page);
922 }
923 else
924 {
925 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
926 KeBugCheck(MEMORY_MANAGEMENT);
927 }
928 }
929 }
930 else
931 {
932 if (InEntry)
933 *InEntry = Entry;
934 else
935 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
936 }
937 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
938 }
939
940 BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
941 ULONG SegOffset)
942 {
943 #ifndef NEWCC
944 if (!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
945 {
946 PBCB Bcb;
947 PCACHE_SEGMENT CacheSeg;
948 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
949 CacheSeg = CcRosLookupCacheSegment(Bcb, (ULONG)(SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset));
950 if (CacheSeg)
951 {
952 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
953 return TRUE;
954 }
955 }
956 #endif
957 return FALSE;
958 }
959
960 NTSTATUS
961 NTAPI
962 MiCopyFromUserPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage)
963 {
964 PEPROCESS Process;
965 KIRQL Irql, Irql2;
966 PVOID DestAddress, SrcAddress;
967
968 Process = PsGetCurrentProcess();
969 DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
970 SrcAddress = MiMapPageInHyperSpace(Process, SrcPage, &Irql2);
971 if (DestAddress == NULL || SrcAddress == NULL)
972 {
973 return(STATUS_NO_MEMORY);
974 }
975 ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0);
976 ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0);
977 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
978 MiUnmapPageInHyperSpace(Process, SrcAddress, Irql2);
979 MiUnmapPageInHyperSpace(Process, DestAddress, Irql);
980 return(STATUS_SUCCESS);
981 }
982
983 #ifndef NEWCC
984 NTSTATUS
985 NTAPI
986 MiReadPage(PMEMORY_AREA MemoryArea,
987 ULONG_PTR SegOffset,
988 PPFN_NUMBER Page)
989 /*
990 * FUNCTION: Read a page for a section backed memory area.
991 * PARAMETERS:
992 * MemoryArea - Memory area to read the page for.
993 * Offset - Offset of the page to read.
994 * Page - Variable that receives a page contains the read data.
995 */
996 {
997 ULONG BaseOffset;
998 ULONGLONG FileOffset;
999 PVOID BaseAddress;
1000 BOOLEAN UptoDate;
1001 PCACHE_SEGMENT CacheSeg;
1002 PFILE_OBJECT FileObject;
1003 NTSTATUS Status;
1004 ULONG_PTR RawLength;
1005 PBCB Bcb;
1006 BOOLEAN IsImageSection;
1007 ULONG_PTR Length;
1008
1009 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1010 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1011 RawLength = (ULONG_PTR)(MemoryArea->Data.SectionData.Segment->RawLength.QuadPart);
1012 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset;
1013 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1014
1015 ASSERT(Bcb);
1016
1017 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
1018
1019 /*
1020 * If the file system is letting us go directly to the cache and the
1021 * memory area was mapped at an offset in the file which is page aligned
1022 * then get the related cache segment.
1023 */
1024 if (((FileOffset % PAGE_SIZE) == 0) &&
1025 ((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) &&
1026 !(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1027 {
1028
1029 /*
1030 * Get the related cache segment; we use a lower level interface than
1031 * filesystems do because it is safe for us to use an offset with a
1032 * alignment less than the file system block size.
1033 */
1034 Status = CcRosGetCacheSegment(Bcb,
1035 (ULONG)FileOffset,
1036 &BaseOffset,
1037 &BaseAddress,
1038 &UptoDate,
1039 &CacheSeg);
1040 if (!NT_SUCCESS(Status))
1041 {
1042 return(Status);
1043 }
1044 if (!UptoDate)
1045 {
1046 /*
1047 * If the cache segment isn't up to date then call the file
1048 * system to read in the data.
1049 */
1050 Status = ReadCacheSegment(CacheSeg);
1051 if (!NT_SUCCESS(Status))
1052 {
1053 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1054 return Status;
1055 }
1056 }
1057 /*
1058 * Retrieve the page from the cache segment that we actually want.
1059 */
1060 (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
1061 FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
1062
1063 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
1064 }
1065 else
1066 {
1067 PEPROCESS Process;
1068 KIRQL Irql;
1069 PVOID PageAddr;
1070 ULONG_PTR CacheSegOffset;
1071
1072 /*
1073 * Allocate a page, this is rather complicated by the possibility
1074 * we might have to move other things out of memory
1075 */
1076 MI_SET_USAGE(MI_USAGE_SECTION);
1077 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
1078 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
1079 if (!NT_SUCCESS(Status))
1080 {
1081 return(Status);
1082 }
1083 Status = CcRosGetCacheSegment(Bcb,
1084 (ULONG)FileOffset,
1085 &BaseOffset,
1086 &BaseAddress,
1087 &UptoDate,
1088 &CacheSeg);
1089 if (!NT_SUCCESS(Status))
1090 {
1091 return(Status);
1092 }
1093 if (!UptoDate)
1094 {
1095 /*
1096 * If the cache segment isn't up to date then call the file
1097 * system to read in the data.
1098 */
1099 Status = ReadCacheSegment(CacheSeg);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1103 return Status;
1104 }
1105 }
1106
1107 Process = PsGetCurrentProcess();
1108 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1109 CacheSegOffset = (ULONG_PTR)(BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset);
1110 Length = RawLength - SegOffset;
1111 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
1112 {
1113 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
1114 }
1115 else if (CacheSegOffset >= PAGE_SIZE)
1116 {
1117 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
1118 }
1119 else
1120 {
1121 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
1122 MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1123 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
1124 Status = CcRosGetCacheSegment(Bcb,
1125 (ULONG)(FileOffset + CacheSegOffset),
1126 &BaseOffset,
1127 &BaseAddress,
1128 &UptoDate,
1129 &CacheSeg);
1130 if (!NT_SUCCESS(Status))
1131 {
1132 return(Status);
1133 }
1134 if (!UptoDate)
1135 {
1136 /*
1137 * If the cache segment isn't up to date then call the file
1138 * system to read in the data.
1139 */
1140 Status = ReadCacheSegment(CacheSeg);
1141 if (!NT_SUCCESS(Status))
1142 {
1143 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1144 return Status;
1145 }
1146 }
1147 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1148 if (Length < PAGE_SIZE)
1149 {
1150 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
1151 }
1152 else
1153 {
1154 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
1155 }
1156 }
1157 MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1158 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
1159 }
1160 return(STATUS_SUCCESS);
1161 }
1162 #else
1163 NTSTATUS
1164 NTAPI
1165 MiReadPage(PMEMORY_AREA MemoryArea,
1166 ULONG_PTR SegOffset,
1167 PPFN_NUMBER Page)
1168 /*
1169 * FUNCTION: Read a page for a section backed memory area.
1170 * PARAMETERS:
1171 * MemoryArea - Memory area to read the page for.
1172 * Offset - Offset of the page to read.
1173 * Page - Variable that receives a page contains the read data.
1174 */
1175 {
1176 MM_REQUIRED_RESOURCES Resources;
1177 NTSTATUS Status;
1178
1179 RtlZeroMemory(&Resources, sizeof(MM_REQUIRED_RESOURCES));
1180
1181 Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
1182 Resources.FileOffset.QuadPart = SegOffset +
1183 MemoryArea->Data.SectionData.Segment->Image.FileOffset;
1184 Resources.Consumer = MC_USER;
1185 Resources.Amount = PAGE_SIZE;
1186
1187 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT)Resources.Context)->FileName.Buffer, Resources.FileOffset.LowPart, Resources.Amount, Resources.Page[0]);
1188
1189 Status = MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea, &Resources);
1190 *Page = Resources.Page[0];
1191 return Status;
1192 }
1193 #endif
1194
1195 NTSTATUS
1196 NTAPI
1197 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
1198 MEMORY_AREA* MemoryArea,
1199 PVOID Address,
1200 BOOLEAN Locked)
1201 {
1202 LARGE_INTEGER Offset;
1203 PFN_NUMBER Page;
1204 NTSTATUS Status;
1205 PROS_SECTION_OBJECT Section;
1206 PMM_SECTION_SEGMENT Segment;
1207 ULONG_PTR Entry;
1208 ULONG_PTR Entry1;
1209 ULONG Attributes;
1210 PMM_REGION Region;
1211 BOOLEAN HasSwapEntry;
1212 PVOID PAddress;
1213 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1214 SWAPENTRY SwapEntry;
1215
1216 /*
1217 * There is a window between taking the page fault and locking the
1218 * address space when another thread could load the page so we check
1219 * that.
1220 */
1221 if (MmIsPagePresent(Process, Address))
1222 {
1223 return(STATUS_SUCCESS);
1224 }
1225
1226 if (MmIsDisabledPage(Process, Address))
1227 {
1228 return(STATUS_ACCESS_VIOLATION);
1229 }
1230
1231 /*
1232 * Check for the virtual memory area being deleted.
1233 */
1234 if (MemoryArea->DeleteInProgress)
1235 {
1236 return(STATUS_UNSUCCESSFUL);
1237 }
1238
1239 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1240 Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1241 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1242
1243 Segment = MemoryArea->Data.SectionData.Segment;
1244 Section = MemoryArea->Data.SectionData.Section;
1245 Region = MmFindRegion(MemoryArea->StartingAddress,
1246 &MemoryArea->Data.SectionData.RegionListHead,
1247 Address, NULL);
1248 ASSERT(Region != NULL);
1249 /*
1250 * Lock the segment
1251 */
1252 MmLockSectionSegment(Segment);
1253 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1254 /*
1255 * Check if this page needs to be mapped COW
1256 */
1257 if ((Segment->WriteCopy) &&
1258 (Region->Protect == PAGE_READWRITE ||
1259 Region->Protect == PAGE_EXECUTE_READWRITE))
1260 {
1261 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
1262 }
1263 else
1264 {
1265 Attributes = Region->Protect;
1266 }
1267
1268 /*
1269 * Check if someone else is already handling this fault, if so wait
1270 * for them
1271 */
1272 if (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY)
1273 {
1274 MmUnlockSectionSegment(Segment);
1275 MmUnlockAddressSpace(AddressSpace);
1276 MiWaitForPageEvent(NULL, NULL);
1277 MmLockAddressSpace(AddressSpace);
1278 DPRINT("Address 0x%.8X\n", Address);
1279 return(STATUS_MM_RESTART_OPERATION);
1280 }
1281
1282 HasSwapEntry = MmIsPageSwapEntry(Process, Address);
1283
1284 if (HasSwapEntry)
1285 {
1286 /*
1287 * Is it a wait entry?
1288 */
1289 MmGetPageFileMapping(Process, Address, &SwapEntry);
1290
1291 if (SwapEntry == MM_WAIT_ENTRY)
1292 {
1293 MmUnlockSectionSegment(Segment);
1294 MmUnlockAddressSpace(AddressSpace);
1295 MiWaitForPageEvent(NULL, NULL);
1296 MmLockAddressSpace(AddressSpace);
1297 return STATUS_MM_RESTART_OPERATION;
1298 }
1299
1300 /*
1301 * Must be private page we have swapped out.
1302 */
1303
1304 /*
1305 * Sanity check
1306 */
1307 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
1308 {
1309 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1310 KeBugCheck(MEMORY_MANAGEMENT);
1311 }
1312
1313 MmUnlockSectionSegment(Segment);
1314 MmDeletePageFileMapping(Process, Address, &SwapEntry);
1315 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
1316
1317 MmUnlockAddressSpace(AddressSpace);
1318 MI_SET_USAGE(MI_USAGE_SECTION);
1319 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1320 if (!Process) MI_SET_PROCESS2("Kernel Section");
1321 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1322 if (!NT_SUCCESS(Status))
1323 {
1324 KeBugCheck(MEMORY_MANAGEMENT);
1325 }
1326
1327 Status = MmReadFromSwapPage(SwapEntry, Page);
1328 if (!NT_SUCCESS(Status))
1329 {
1330 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1331 KeBugCheck(MEMORY_MANAGEMENT);
1332 }
1333 MmLockAddressSpace(AddressSpace);
1334 Status = MmCreateVirtualMapping(Process,
1335 PAddress,
1336 Region->Protect,
1337 &Page,
1338 1);
1339 if (!NT_SUCCESS(Status))
1340 {
1341 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1342 KeBugCheck(MEMORY_MANAGEMENT);
1343 return(Status);
1344 }
1345
1346 /*
1347 * Store the swap entry for later use.
1348 */
1349 MmSetSavedSwapEntryPage(Page, SwapEntry);
1350
1351 /*
1352 * Add the page to the process's working set
1353 */
1354 MmInsertRmap(Page, Process, Address);
1355 /*
1356 * Finish the operation
1357 */
1358 MiSetPageEvent(Process, Address);
1359 DPRINT("Address 0x%.8X\n", Address);
1360 return(STATUS_SUCCESS);
1361 }
1362
1363 /*
1364 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1365 */
1366 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1367 {
1368 MmUnlockSectionSegment(Segment);
1369 /*
1370 * Just map the desired physical page
1371 */
1372 Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
1373 Status = MmCreateVirtualMappingUnsafe(Process,
1374 PAddress,
1375 Region->Protect,
1376 &Page,
1377 1);
1378 if (!NT_SUCCESS(Status))
1379 {
1380 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1381 KeBugCheck(MEMORY_MANAGEMENT);
1382 return(Status);
1383 }
1384
1385 /*
1386 * Cleanup and release locks
1387 */
1388 MiSetPageEvent(Process, Address);
1389 DPRINT("Address 0x%.8X\n", Address);
1390 return(STATUS_SUCCESS);
1391 }
1392
1393 /*
1394 * Map anonymous memory for BSS sections
1395 */
1396 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1397 {
1398 /* We'll be unlocking the address space below. Prevent us from being preempted
1399 * in faulting in the page. */
1400 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
1401 MmUnlockSectionSegment(Segment);
1402 MI_SET_USAGE(MI_USAGE_SECTION);
1403 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1404 if (!Process) MI_SET_PROCESS2("Kernel Section");
1405 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
1406 if (!NT_SUCCESS(Status))
1407 {
1408 MmUnlockAddressSpace(AddressSpace);
1409 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1410 MmLockAddressSpace(AddressSpace);
1411 }
1412 if (!NT_SUCCESS(Status))
1413 {
1414 KeBugCheck(MEMORY_MANAGEMENT);
1415 }
1416 /* Remove the wait entry we placed, so that we can map the page */
1417 MmDeletePageFileMapping(Process, PAddress, &SwapEntry);
1418 Status = MmCreateVirtualMapping(Process,
1419 PAddress,
1420 Region->Protect,
1421 &Page,
1422 1);
1423 if (!NT_SUCCESS(Status))
1424 {
1425 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1426 KeBugCheck(MEMORY_MANAGEMENT);
1427 return(Status);
1428 }
1429 MmInsertRmap(Page, Process, Address);
1430
1431 /*
1432 * Cleanup and release locks
1433 */
1434 MiSetPageEvent(Process, Address);
1435 DPRINT("Address 0x%.8X\n", Address);
1436 return(STATUS_SUCCESS);
1437 }
1438
1439 /*
1440 * Get the entry corresponding to the offset within the section
1441 */
1442 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1443
1444 if (Entry == 0)
1445 {
1446 SWAPENTRY FakeSwapEntry;
1447
1448 /*
1449 * If the entry is zero (and it can't change because we have
1450 * locked the segment) then we need to load the page.
1451 */
1452
1453 /*
1454 * Release all our locks and read in the page from disk
1455 */
1456 MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
1457 MmUnlockSectionSegment(Segment);
1458 MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
1459 MmUnlockAddressSpace(AddressSpace);
1460
1461 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1462 ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) &&
1463 (Section->AllocationAttributes & SEC_IMAGE))))
1464 {
1465 MI_SET_USAGE(MI_USAGE_SECTION);
1466 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1467 if (!Process) MI_SET_PROCESS2("Kernel Section");
1468 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1469 if (!NT_SUCCESS(Status))
1470 {
1471 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
1472 }
1473
1474 }
1475 else
1476 {
1477 Status = MiReadPage(MemoryArea, (ULONG_PTR)Offset.QuadPart, &Page);
1478 if (!NT_SUCCESS(Status))
1479 {
1480 DPRINT1("MiReadPage failed (Status %x)\n", Status);
1481 }
1482 }
1483 if (!NT_SUCCESS(Status))
1484 {
1485 /*
1486 * FIXME: What do we know in this case?
1487 */
1488 /*
1489 * Cleanup and release locks
1490 */
1491 MmLockAddressSpace(AddressSpace);
1492 MiSetPageEvent(Process, Address);
1493 DPRINT("Address 0x%.8X\n", Address);
1494 return(Status);
1495 }
1496
1497 /*
1498 * Mark the offset within the section as having valid, in-memory
1499 * data
1500 */
1501 MmLockAddressSpace(AddressSpace);
1502 MmLockSectionSegment(Segment);
1503 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1504 MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1505 MmUnlockSectionSegment(Segment);
1506
1507 MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
1508 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1509 Page, Process, PAddress, Attributes);
1510 Status = MmCreateVirtualMapping(Process,
1511 PAddress,
1512 Attributes,
1513 &Page,
1514 1);
1515 if (!NT_SUCCESS(Status))
1516 {
1517 DPRINT1("Unable to create virtual mapping\n");
1518 KeBugCheck(MEMORY_MANAGEMENT);
1519 }
1520 ASSERT(MmIsPagePresent(Process, PAddress));
1521 MmInsertRmap(Page, Process, Address);
1522
1523 MiSetPageEvent(Process, Address);
1524 DPRINT("Address 0x%.8X\n", Address);
1525 return(STATUS_SUCCESS);
1526 }
1527 else if (IS_SWAP_FROM_SSE(Entry))
1528 {
1529 SWAPENTRY SwapEntry;
1530
1531 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1532
1533 /*
1534 * Release all our locks and read in the page from disk
1535 */
1536 MmUnlockSectionSegment(Segment);
1537
1538 MmUnlockAddressSpace(AddressSpace);
1539 MI_SET_USAGE(MI_USAGE_SECTION);
1540 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1541 if (!Process) MI_SET_PROCESS2("Kernel Section");
1542 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1543 if (!NT_SUCCESS(Status))
1544 {
1545 KeBugCheck(MEMORY_MANAGEMENT);
1546 }
1547
1548 Status = MmReadFromSwapPage(SwapEntry, Page);
1549 if (!NT_SUCCESS(Status))
1550 {
1551 KeBugCheck(MEMORY_MANAGEMENT);
1552 }
1553
1554 /*
1555 * Relock the address space and segment
1556 */
1557 MmLockAddressSpace(AddressSpace);
1558 MmLockSectionSegment(Segment);
1559
1560 /*
1561 * Check the entry. No one should change the status of a page
1562 * that has a pending page-in.
1563 */
1564 Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
1565 if (Entry != Entry1)
1566 {
1567 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
1568 KeBugCheck(MEMORY_MANAGEMENT);
1569 }
1570
1571 /*
1572 * Mark the offset within the section as having valid, in-memory
1573 * data
1574 */
1575 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1576 MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1577 MmUnlockSectionSegment(Segment);
1578
1579 /*
1580 * Save the swap entry.
1581 */
1582 MmSetSavedSwapEntryPage(Page, SwapEntry);
1583 Status = MmCreateVirtualMapping(Process,
1584 PAddress,
1585 Region->Protect,
1586 &Page,
1587 1);
1588 if (!NT_SUCCESS(Status))
1589 {
1590 DPRINT1("Unable to create virtual mapping\n");
1591 KeBugCheck(MEMORY_MANAGEMENT);
1592 }
1593 MmInsertRmap(Page, Process, Address);
1594 MiSetPageEvent(Process, Address);
1595 DPRINT("Address 0x%.8X\n", Address);
1596 return(STATUS_SUCCESS);
1597 }
1598 else
1599 {
1600 /*
1601 * If the section offset is already in-memory and valid then just
1602 * take another reference to the page
1603 */
1604
1605 Page = PFN_FROM_SSE(Entry);
1606
1607 MmSharePageEntrySectionSegment(Segment, &Offset);
1608 MmUnlockSectionSegment(Segment);
1609
1610 Status = MmCreateVirtualMapping(Process,
1611 PAddress,
1612 Attributes,
1613 &Page,
1614 1);
1615 if (!NT_SUCCESS(Status))
1616 {
1617 DPRINT1("Unable to create virtual mapping\n");
1618 KeBugCheck(MEMORY_MANAGEMENT);
1619 }
1620 MmInsertRmap(Page, Process, Address);
1621 MiSetPageEvent(Process, Address);
1622 DPRINT("Address 0x%.8X\n", Address);
1623 return(STATUS_SUCCESS);
1624 }
1625 }
1626
1627 NTSTATUS
1628 NTAPI
1629 MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
1630 MEMORY_AREA* MemoryArea,
1631 PVOID Address)
1632 {
1633 PMM_SECTION_SEGMENT Segment;
1634 PROS_SECTION_OBJECT Section;
1635 PFN_NUMBER OldPage;
1636 PFN_NUMBER NewPage;
1637 NTSTATUS Status;
1638 PVOID PAddress;
1639 LARGE_INTEGER Offset;
1640 PMM_REGION Region;
1641 ULONG_PTR Entry;
1642 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1643 SWAPENTRY SwapEntry;
1644
1645 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address);
1646
1647 /*
1648 * Check if the page has already been set readwrite
1649 */
1650 if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1651 {
1652 DPRINT("Address 0x%.8X\n", Address);
1653 return(STATUS_SUCCESS);
1654 }
1655
1656 /*
1657 * Find the offset of the page
1658 */
1659 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1660 Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1661 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1662
1663 Segment = MemoryArea->Data.SectionData.Segment;
1664 Section = MemoryArea->Data.SectionData.Section;
1665 Region = MmFindRegion(MemoryArea->StartingAddress,
1666 &MemoryArea->Data.SectionData.RegionListHead,
1667 Address, NULL);
1668 ASSERT(Region != NULL);
1669 /*
1670 * Lock the segment
1671 */
1672 MmLockSectionSegment(Segment);
1673
1674 OldPage = MmGetPfnForProcess(Process, Address);
1675 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1676
1677 MmUnlockSectionSegment(Segment);
1678
1679 /*
1680 * Check if we are doing COW
1681 */
1682 if (!((Segment->WriteCopy) &&
1683 (Region->Protect == PAGE_READWRITE ||
1684 Region->Protect == PAGE_EXECUTE_READWRITE)))
1685 {
1686 DPRINT("Address 0x%.8X\n", Address);
1687 return(STATUS_ACCESS_VIOLATION);
1688 }
1689
1690 if (IS_SWAP_FROM_SSE(Entry) ||
1691 PFN_FROM_SSE(Entry) != OldPage)
1692 {
1693 /* This is a private page. We must only change the page protection. */
1694 MmSetPageProtect(Process, Address, Region->Protect);
1695 return(STATUS_SUCCESS);
1696 }
1697
1698 if(OldPage == 0)
1699 DPRINT("OldPage == 0!\n");
1700
1701 /*
1702 * Get or create a pageop
1703 */
1704 MmLockSectionSegment(Segment);
1705 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1706
1707 /*
1708 * Wait for any other operations to complete
1709 */
1710 if (Entry == SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY))
1711 {
1712 MmUnlockSectionSegment(Segment);
1713 MmUnlockAddressSpace(AddressSpace);
1714 MiWaitForPageEvent(NULL, NULL);
1715 /*
1716 * Restart the operation
1717 */
1718 MmLockAddressSpace(AddressSpace);
1719 DPRINT("Address 0x%.8X\n", Address);
1720 return(STATUS_MM_RESTART_OPERATION);
1721 }
1722
1723 MmDeleteRmap(OldPage, Process, PAddress);
1724 MmDeleteVirtualMapping(Process, PAddress, FALSE, NULL, NULL);
1725 MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
1726
1727 /*
1728 * Release locks now we have the pageop
1729 */
1730 MmUnlockSectionSegment(Segment);
1731 MmUnlockAddressSpace(AddressSpace);
1732
1733 /*
1734 * Allocate a page
1735 */
1736 MI_SET_USAGE(MI_USAGE_SECTION);
1737 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1738 if (!Process) MI_SET_PROCESS2("Kernel Section");
1739 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1740 if (!NT_SUCCESS(Status))
1741 {
1742 KeBugCheck(MEMORY_MANAGEMENT);
1743 }
1744
1745 /*
1746 * Copy the old page
1747 */
1748 MiCopyFromUserPage(NewPage, OldPage);
1749
1750 MmLockAddressSpace(AddressSpace);
1751
1752 /*
1753 * Set the PTE to point to the new page
1754 */
1755 MmDeletePageFileMapping(Process, PAddress, &SwapEntry);
1756 Status = MmCreateVirtualMapping(Process,
1757 PAddress,
1758 Region->Protect,
1759 &NewPage,
1760 1);
1761 if (!NT_SUCCESS(Status))
1762 {
1763 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1764 KeBugCheck(MEMORY_MANAGEMENT);
1765 return(Status);
1766 }
1767 if (!NT_SUCCESS(Status))
1768 {
1769 DPRINT1("Unable to create virtual mapping\n");
1770 KeBugCheck(MEMORY_MANAGEMENT);
1771 }
1772
1773 /*
1774 * Unshare the old page.
1775 */
1776 DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
1777 MmInsertRmap(NewPage, Process, PAddress);
1778 MmLockSectionSegment(Segment);
1779 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
1780 MmUnlockSectionSegment(Segment);
1781
1782 MiSetPageEvent(Process, Address);
1783 DPRINT("Address 0x%.8X\n", Address);
1784 return(STATUS_SUCCESS);
1785 }
1786
1787 VOID
1788 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1789 {
1790 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1791 BOOLEAN WasDirty;
1792 PFN_NUMBER Page = 0;
1793
1794 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1795 if (Process)
1796 {
1797 MmLockAddressSpace(&Process->Vm);
1798 }
1799
1800 MmDeleteVirtualMapping(Process,
1801 Address,
1802 FALSE,
1803 &WasDirty,
1804 &Page);
1805 if (WasDirty)
1806 {
1807 PageOutContext->WasDirty = TRUE;
1808 }
1809 if (!PageOutContext->Private)
1810 {
1811 MmLockSectionSegment(PageOutContext->Segment);
1812 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
1813 PageOutContext->Segment,
1814 &PageOutContext->Offset,
1815 PageOutContext->WasDirty,
1816 TRUE,
1817 &PageOutContext->SectionEntry);
1818 MmUnlockSectionSegment(PageOutContext->Segment);
1819 }
1820 if (Process)
1821 {
1822 MmUnlockAddressSpace(&Process->Vm);
1823 }
1824
1825 if (PageOutContext->Private)
1826 {
1827 MmReleasePageMemoryConsumer(MC_USER, Page);
1828 }
1829 }
1830
1831 NTSTATUS
1832 NTAPI
1833 MmPageOutSectionView(PMMSUPPORT AddressSpace,
1834 MEMORY_AREA* MemoryArea,
1835 PVOID Address, ULONG_PTR Entry)
1836 {
1837 PFN_NUMBER Page;
1838 MM_SECTION_PAGEOUT_CONTEXT Context;
1839 SWAPENTRY SwapEntry;
1840 ULONGLONG FileOffset;
1841 NTSTATUS Status;
1842 PFILE_OBJECT FileObject;
1843 #ifndef NEWCC
1844 PBCB Bcb = NULL;
1845 #endif
1846 BOOLEAN DirectMapped;
1847 BOOLEAN IsImageSection;
1848 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1849 KIRQL OldIrql;
1850
1851 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1852
1853 /*
1854 * Get the segment and section.
1855 */
1856 Context.Segment = MemoryArea->Data.SectionData.Segment;
1857 Context.Section = MemoryArea->Data.SectionData.Section;
1858 Context.SectionEntry = Entry;
1859 Context.CallingProcess = Process;
1860
1861 Context.Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
1862 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1863 FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset;
1864
1865 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1866
1867 FileObject = Context.Section->FileObject;
1868 DirectMapped = FALSE;
1869
1870 MmLockSectionSegment(Context.Segment);
1871
1872 #ifndef NEWCC
1873 if (FileObject != NULL &&
1874 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1875 {
1876 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1877
1878 /*
1879 * If the file system is letting us go directly to the cache and the
1880 * memory area was mapped at an offset in the file which is page aligned
1881 * then note this is a direct mapped page.
1882 */
1883 if ((FileOffset % PAGE_SIZE) == 0 &&
1884 (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection))
1885 {
1886 DirectMapped = TRUE;
1887 }
1888 }
1889 #endif
1890
1891
1892 /*
1893 * This should never happen since mappings of physical memory are never
1894 * placed in the rmap lists.
1895 */
1896 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1897 {
1898 DPRINT1("Trying to page out from physical memory section address 0x%X "
1899 "process %d\n", Address,
1900 Process ? Process->UniqueProcessId : 0);
1901 KeBugCheck(MEMORY_MANAGEMENT);
1902 }
1903
1904 /*
1905 * Get the section segment entry and the physical address.
1906 */
1907 if (!MmIsPagePresent(Process, Address))
1908 {
1909 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1910 Process ? Process->UniqueProcessId : 0, Address);
1911 KeBugCheck(MEMORY_MANAGEMENT);
1912 }
1913 Page = MmGetPfnForProcess(Process, Address);
1914 SwapEntry = MmGetSavedSwapEntryPage(Page);
1915
1916 /*
1917 * Check the reference count to ensure this page can be paged out
1918 */
1919 if (MmGetReferenceCountPage(Page) != 1)
1920 {
1921 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1922 Page, MmGetReferenceCountPage(Page));
1923 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
1924 MmUnlockSectionSegment(Context.Segment);
1925 return STATUS_UNSUCCESSFUL;
1926 }
1927
1928 /*
1929 * Prepare the context structure for the rmap delete call.
1930 */
1931 MmUnlockSectionSegment(Context.Segment);
1932 Context.WasDirty = FALSE;
1933 if (Context.Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
1934 IS_SWAP_FROM_SSE(Entry) ||
1935 PFN_FROM_SSE(Entry) != Page)
1936 {
1937 Context.Private = TRUE;
1938 }
1939 else
1940 {
1941 Context.Private = FALSE;
1942 }
1943
1944 /*
1945 * Take an additional reference to the page or the cache segment.
1946 */
1947 if (DirectMapped && !Context.Private)
1948 {
1949 if(!MiIsPageFromCache(MemoryArea, Context.Offset.LowPart))
1950 {
1951 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1952 KeBugCheck(MEMORY_MANAGEMENT);
1953 }
1954 }
1955 else
1956 {
1957 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1958 MmReferencePage(Page);
1959 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1960 }
1961
1962 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
1963
1964 /* Since we passed in a surrogate, we'll get back the page entry
1965 * state in our context. This is intended to make intermediate
1966 * decrements of share count not release the wait entry.
1967 */
1968 Entry = Context.SectionEntry;
1969
1970 /*
1971 * If this wasn't a private page then we should have reduced the entry to
1972 * zero by deleting all the rmaps.
1973 */
1974 if (!Context.Private && Entry != 0)
1975 {
1976 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
1977 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1978 {
1979 KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
1980 }
1981 }
1982
1983 /*
1984 * If the page wasn't dirty then we can just free it as for a readonly page.
1985 * Since we unmapped all the mappings above we know it will not suddenly
1986 * become dirty.
1987 * If the page is from a pagefile section and has no swap entry,
1988 * we can't free the page at this point.
1989 */
1990 SwapEntry = MmGetSavedSwapEntryPage(Page);
1991 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
1992 {
1993 if (Context.Private)
1994 {
1995 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1996 Context.WasDirty ? "dirty" : "clean", Address);
1997 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
1998 }
1999 if (!Context.WasDirty && SwapEntry != 0)
2000 {
2001 MmSetSavedSwapEntryPage(Page, 0);
2002 MmLockSectionSegment(Context.Segment);
2003 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2004 MmUnlockSectionSegment(Context.Segment);
2005 MmReleasePageMemoryConsumer(MC_USER, Page);
2006 MiSetPageEvent(NULL, NULL);
2007 return(STATUS_SUCCESS);
2008 }
2009 }
2010 else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2011 {
2012 if (Context.Private)
2013 {
2014 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2015 Context.WasDirty ? "dirty" : "clean", Address);
2016 KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2017 }
2018 if (!Context.WasDirty || SwapEntry != 0)
2019 {
2020 MmSetSavedSwapEntryPage(Page, 0);
2021 if (SwapEntry != 0)
2022 {
2023 MmLockSectionSegment(Context.Segment);
2024 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2025 MmUnlockSectionSegment(Context.Segment);
2026 }
2027 MmReleasePageMemoryConsumer(MC_USER, Page);
2028 MiSetPageEvent(NULL, NULL);
2029 return(STATUS_SUCCESS);
2030 }
2031 }
2032 else if (!Context.Private && DirectMapped)
2033 {
2034 if (SwapEntry != 0)
2035 {
2036 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2037 Address);
2038 KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
2039 }
2040 #ifndef NEWCC
2041 Status = CcRosUnmapCacheSegment(Bcb, (ULONG)FileOffset, FALSE);
2042 #else
2043 Status = STATUS_SUCCESS;
2044 #endif
2045 #ifndef NEWCC
2046 if (!NT_SUCCESS(Status))
2047 {
2048 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
2049 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Bcb, (ULONG_PTR)FileOffset, (ULONG_PTR)Address);
2050 }
2051 #endif
2052 MiSetPageEvent(NULL, NULL);
2053 return(STATUS_SUCCESS);
2054 }
2055 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2056 {
2057 if (SwapEntry != 0)
2058 {
2059 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2060 Address);
2061 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
2062 }
2063 MmReleasePageMemoryConsumer(MC_USER, Page);
2064 MiSetPageEvent(NULL, NULL);
2065 return(STATUS_SUCCESS);
2066 }
2067 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2068 {
2069 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
2070 MmSetSavedSwapEntryPage(Page, 0);
2071 MmLockAddressSpace(AddressSpace);
2072 Status = MmCreatePageFileMapping(Process,
2073 Address,
2074 SwapEntry);
2075 MmUnlockAddressSpace(AddressSpace);
2076 if (!NT_SUCCESS(Status))
2077 {
2078 DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address);
2079 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2080 }
2081 MmReleasePageMemoryConsumer(MC_USER, Page);
2082 MiSetPageEvent(NULL, NULL);
2083 return(STATUS_SUCCESS);
2084 }
2085
2086 /*
2087 * If necessary, allocate an entry in the paging file for this page
2088 */
2089 if (SwapEntry == 0)
2090 {
2091 SwapEntry = MmAllocSwapPage();
2092 if (SwapEntry == 0)
2093 {
2094 MmShowOutOfSpaceMessagePagingFile();
2095 MmLockAddressSpace(AddressSpace);
2096 /*
2097 * For private pages restore the old mappings.
2098 */
2099 if (Context.Private)
2100 {
2101 Status = MmCreateVirtualMapping(Process,
2102 Address,
2103 MemoryArea->Protect,
2104 &Page,
2105 1);
2106 MmSetDirtyPage(Process, Address);
2107 MmInsertRmap(Page,
2108 Process,
2109 Address);
2110 }
2111 else
2112 {
2113 ULONG_PTR OldEntry;
2114 /*
2115 * For non-private pages if the page wasn't direct mapped then
2116 * set it back into the section segment entry so we don't loose
2117 * our copy. Otherwise it will be handled by the cache manager.
2118 */
2119 Status = MmCreateVirtualMapping(Process,
2120 Address,
2121 MemoryArea->Protect,
2122 &Page,
2123 1);
2124 MmSetDirtyPage(Process, Address);
2125 MmInsertRmap(Page,
2126 Process,
2127 Address);
2128 // If we got here, the previous entry should have been a wait
2129 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2130 MmLockSectionSegment(Context.Segment);
2131 OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2132 ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
2133 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2134 MmUnlockSectionSegment(Context.Segment);
2135 }
2136 MmUnlockAddressSpace(AddressSpace);
2137 MiSetPageEvent(NULL, NULL);
2138 return(STATUS_PAGEFILE_QUOTA);
2139 }
2140 }
2141
2142 /*
2143 * Write the page to the pagefile
2144 */
2145 Status = MmWriteToSwapPage(SwapEntry, Page);
2146 if (!NT_SUCCESS(Status))
2147 {
2148 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2149 Status);
2150 /*
2151 * As above: undo our actions.
2152 * FIXME: Also free the swap page.
2153 */
2154 MmLockAddressSpace(AddressSpace);
2155 if (Context.Private)
2156 {
2157 Status = MmCreateVirtualMapping(Process,
2158 Address,
2159 MemoryArea->Protect,
2160 &Page,
2161 1);
2162 MmSetDirtyPage(Process, Address);
2163 MmInsertRmap(Page,
2164 Process,
2165 Address);
2166 }
2167 else
2168 {
2169 Status = MmCreateVirtualMapping(Process,
2170 Address,
2171 MemoryArea->Protect,
2172 &Page,
2173 1);
2174 MmSetDirtyPage(Process, Address);
2175 MmInsertRmap(Page,
2176 Process,
2177 Address);
2178 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2179 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2180 }
2181 MmUnlockAddressSpace(AddressSpace);
2182 MiSetPageEvent(NULL, NULL);
2183 return(STATUS_UNSUCCESSFUL);
2184 }
2185
2186 /*
2187 * Otherwise we have succeeded.
2188 */
2189 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2190 MmSetSavedSwapEntryPage(Page, 0);
2191 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2192 Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2193 {
2194 MmLockSectionSegment(Context.Segment);
2195 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2196 MmUnlockSectionSegment(Context.Segment);
2197 }
2198 else
2199 {
2200 MmReleasePageMemoryConsumer(MC_USER, Page);
2201 }
2202
2203 if (Context.Private)
2204 {
2205 MmLockAddressSpace(AddressSpace);
2206 MmLockSectionSegment(Context.Segment);
2207 Status = MmCreatePageFileMapping(Process,
2208 Address,
2209 SwapEntry);
2210 /* We had placed a wait entry upon entry ... replace it before leaving */
2211 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2212 MmUnlockSectionSegment(Context.Segment);
2213 MmUnlockAddressSpace(AddressSpace);
2214 if (!NT_SUCCESS(Status))
2215 {
2216 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address);
2217 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2218 }
2219 }
2220 else
2221 {
2222 MmLockAddressSpace(AddressSpace);
2223 MmLockSectionSegment(Context.Segment);
2224 Entry = MAKE_SWAP_SSE(SwapEntry);
2225 /* We had placed a wait entry upon entry ... replace it before leaving */
2226 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2227 MmUnlockSectionSegment(Context.Segment);
2228 MmUnlockAddressSpace(AddressSpace);
2229 }
2230
2231 MiSetPageEvent(NULL, NULL);
2232 return(STATUS_SUCCESS);
2233 }
2234
2235 NTSTATUS
2236 NTAPI
2237 MmWritePageSectionView(PMMSUPPORT AddressSpace,
2238 PMEMORY_AREA MemoryArea,
2239 PVOID Address,
2240 ULONG PageEntry)
2241 {
2242 LARGE_INTEGER Offset;
2243 PROS_SECTION_OBJECT Section;
2244 PMM_SECTION_SEGMENT Segment;
2245 PFN_NUMBER Page;
2246 SWAPENTRY SwapEntry;
2247 ULONG_PTR Entry;
2248 BOOLEAN Private;
2249 NTSTATUS Status;
2250 PFILE_OBJECT FileObject;
2251 PBCB Bcb = NULL;
2252 BOOLEAN DirectMapped;
2253 BOOLEAN IsImageSection;
2254 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2255
2256 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2257
2258 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2259 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2260
2261 /*
2262 * Get the segment and section.
2263 */
2264 Segment = MemoryArea->Data.SectionData.Segment;
2265 Section = MemoryArea->Data.SectionData.Section;
2266 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2267
2268 FileObject = Section->FileObject;
2269 DirectMapped = FALSE;
2270 if (FileObject != NULL &&
2271 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2272 {
2273 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2274
2275 /*
2276 * If the file system is letting us go directly to the cache and the
2277 * memory area was mapped at an offset in the file which is page aligned
2278 * then note this is a direct mapped page.
2279 */
2280 if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 &&
2281 (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
2282 {
2283 DirectMapped = TRUE;
2284 }
2285 }
2286
2287 /*
2288 * This should never happen since mappings of physical memory are never
2289 * placed in the rmap lists.
2290 */
2291 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2292 {
2293 DPRINT1("Trying to write back page from physical memory mapped at %X "
2294 "process %d\n", Address,
2295 Process ? Process->UniqueProcessId : 0);
2296 KeBugCheck(MEMORY_MANAGEMENT);
2297 }
2298
2299 /*
2300 * Get the section segment entry and the physical address.
2301 */
2302 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2303 if (!MmIsPagePresent(Process, Address))
2304 {
2305 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2306 Process ? Process->UniqueProcessId : 0, Address);
2307 KeBugCheck(MEMORY_MANAGEMENT);
2308 }
2309 Page = MmGetPfnForProcess(Process, Address);
2310 SwapEntry = MmGetSavedSwapEntryPage(Page);
2311
2312 /*
2313 * Check for a private (COWed) page.
2314 */
2315 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2316 IS_SWAP_FROM_SSE(Entry) ||
2317 PFN_FROM_SSE(Entry) != Page)
2318 {
2319 Private = TRUE;
2320 }
2321 else
2322 {
2323 Private = FALSE;
2324 }
2325
2326 /*
2327 * Speculatively set all mappings of the page to clean.
2328 */
2329 MmSetCleanAllRmaps(Page);
2330
2331 /*
2332 * If this page was direct mapped from the cache then the cache manager
2333 * will take care of writing it back to disk.
2334 */
2335 if (DirectMapped && !Private)
2336 {
2337 LARGE_INTEGER SOffset;
2338 ASSERT(SwapEntry == 0);
2339 SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2340 #ifndef NEWCC
2341 CcRosMarkDirtyCacheSegment(Bcb, Offset.LowPart);
2342 #endif
2343 MmLockSectionSegment(Segment);
2344 MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry);
2345 MmUnlockSectionSegment(Segment);
2346 MiSetPageEvent(NULL, NULL);
2347 return(STATUS_SUCCESS);
2348 }
2349
2350 /*
2351 * If necessary, allocate an entry in the paging file for this page
2352 */
2353 if (SwapEntry == 0)
2354 {
2355 SwapEntry = MmAllocSwapPage();
2356 if (SwapEntry == 0)
2357 {
2358 MmSetDirtyAllRmaps(Page);
2359 MiSetPageEvent(NULL, NULL);
2360 return(STATUS_PAGEFILE_QUOTA);
2361 }
2362 MmSetSavedSwapEntryPage(Page, SwapEntry);
2363 }
2364
2365 /*
2366 * Write the page to the pagefile
2367 */
2368 Status = MmWriteToSwapPage(SwapEntry, Page);
2369 if (!NT_SUCCESS(Status))
2370 {
2371 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2372 Status);
2373 MmSetDirtyAllRmaps(Page);
2374 MiSetPageEvent(NULL, NULL);
2375 return(STATUS_UNSUCCESSFUL);
2376 }
2377
2378 /*
2379 * Otherwise we have succeeded.
2380 */
2381 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2382 MiSetPageEvent(NULL, NULL);
2383 return(STATUS_SUCCESS);
2384 }
2385
2386 static VOID
2387 MmAlterViewAttributes(PMMSUPPORT AddressSpace,
2388 PVOID BaseAddress,
2389 SIZE_T RegionSize,
2390 ULONG OldType,
2391 ULONG OldProtect,
2392 ULONG NewType,
2393 ULONG NewProtect)
2394 {
2395 PMEMORY_AREA MemoryArea;
2396 PMM_SECTION_SEGMENT Segment;
2397 BOOLEAN DoCOW = FALSE;
2398 ULONG i;
2399 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2400
2401 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
2402 ASSERT(MemoryArea != NULL);
2403 Segment = MemoryArea->Data.SectionData.Segment;
2404 MmLockSectionSegment(Segment);
2405
2406 if ((Segment->WriteCopy) &&
2407 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
2408 {
2409 DoCOW = TRUE;
2410 }
2411
2412 if (OldProtect != NewProtect)
2413 {
2414 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
2415 {
2416 SWAPENTRY SwapEntry;
2417 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
2418 ULONG Protect = NewProtect;
2419
2420 /* Wait for a wait entry to disappear */
2421 do {
2422 MmGetPageFileMapping(Process, Address, &SwapEntry);
2423 if (SwapEntry != MM_WAIT_ENTRY)
2424 break;
2425 MiWaitForPageEvent(Process, Address);
2426 } while (TRUE);
2427
2428 /*
2429 * If we doing COW for this segment then check if the page is
2430 * already private.
2431 */
2432 if (DoCOW && MmIsPagePresent(Process, Address))
2433 {
2434 LARGE_INTEGER Offset;
2435 ULONG_PTR Entry;
2436 PFN_NUMBER Page;
2437
2438 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2439 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2440 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2441 /*
2442 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2443 * IS_SWAP_FROM_SSE and we'll do the right thing.
2444 */
2445 Page = MmGetPfnForProcess(Process, Address);
2446
2447 Protect = PAGE_READONLY;
2448 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2449 IS_SWAP_FROM_SSE(Entry) ||
2450 PFN_FROM_SSE(Entry) != Page)
2451 {
2452 Protect = NewProtect;
2453 }
2454 }
2455
2456 if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
2457 {
2458 MmSetPageProtect(Process, Address,
2459 Protect);
2460 }
2461 }
2462 }
2463
2464 MmUnlockSectionSegment(Segment);
2465 }
2466
2467 NTSTATUS
2468 NTAPI
2469 MmProtectSectionView(PMMSUPPORT AddressSpace,
2470 PMEMORY_AREA MemoryArea,
2471 PVOID BaseAddress,
2472 SIZE_T Length,
2473 ULONG Protect,
2474 PULONG OldProtect)
2475 {
2476 PMM_REGION Region;
2477 NTSTATUS Status;
2478 ULONG_PTR MaxLength;
2479
2480 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
2481 if (Length > MaxLength)
2482 Length = (ULONG)MaxLength;
2483
2484 Region = MmFindRegion(MemoryArea->StartingAddress,
2485 &MemoryArea->Data.SectionData.RegionListHead,
2486 BaseAddress, NULL);
2487 ASSERT(Region != NULL);
2488
2489 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2490 Region->Protect != Protect)
2491 {
2492 return STATUS_INVALID_PAGE_PROTECTION;
2493 }
2494
2495 *OldProtect = Region->Protect;
2496 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
2497 &MemoryArea->Data.SectionData.RegionListHead,
2498 BaseAddress, Length, Region->Type, Protect,
2499 MmAlterViewAttributes);
2500
2501 return(Status);
2502 }
2503
2504 NTSTATUS NTAPI
2505 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2506 PVOID Address,
2507 PMEMORY_BASIC_INFORMATION Info,
2508 PSIZE_T ResultLength)
2509 {
2510 PMM_REGION Region;
2511 PVOID RegionBaseAddress;
2512 PROS_SECTION_OBJECT Section;
2513 PMM_SECTION_SEGMENT Segment;
2514
2515 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
2516 &MemoryArea->Data.SectionData.RegionListHead,
2517 Address, &RegionBaseAddress);
2518 if (Region == NULL)
2519 {
2520 return STATUS_UNSUCCESSFUL;
2521 }
2522
2523 Section = MemoryArea->Data.SectionData.Section;
2524 if (Section->AllocationAttributes & SEC_IMAGE)
2525 {
2526 Segment = MemoryArea->Data.SectionData.Segment;
2527 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->Image.VirtualAddress;
2528 Info->Type = MEM_IMAGE;
2529 }
2530 else
2531 {
2532 Info->AllocationBase = MemoryArea->StartingAddress;
2533 Info->Type = MEM_MAPPED;
2534 }
2535 Info->BaseAddress = RegionBaseAddress;
2536 Info->AllocationProtect = MemoryArea->Protect;
2537 Info->RegionSize = Region->Length;
2538 Info->State = MEM_COMMIT;
2539 Info->Protect = Region->Protect;
2540
2541 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2542 return(STATUS_SUCCESS);
2543 }
2544
2545 VOID
2546 NTAPI
2547 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2548 {
2549 ULONG Length;
2550 LARGE_INTEGER Offset;
2551 ULONG_PTR Entry;
2552 SWAPENTRY SavedSwapEntry;
2553 PFN_NUMBER Page;
2554
2555 Page = 0;
2556
2557 MmLockSectionSegment(Segment);
2558
2559 Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
2560 for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
2561 {
2562 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2563 if (Entry)
2564 {
2565 MmSetPageEntrySectionSegment(Segment, &Offset, 0);
2566 if (IS_SWAP_FROM_SSE(Entry))
2567 {
2568 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2569 }
2570 else
2571 {
2572 Page = PFN_FROM_SSE(Entry);
2573 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2574 if (SavedSwapEntry != 0)
2575 {
2576 MmSetSavedSwapEntryPage(Page, 0);
2577 MmFreeSwapPage(SavedSwapEntry);
2578 }
2579 MmReleasePageMemoryConsumer(MC_USER, Page);
2580 }
2581 }
2582 }
2583
2584 MmUnlockSectionSegment(Segment);
2585 }
2586
2587 VOID NTAPI
2588 MmpDeleteSection(PVOID ObjectBody)
2589 {
2590 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2591
2592 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
2593 if (Section->AllocationAttributes & SEC_IMAGE)
2594 {
2595 ULONG i;
2596 ULONG NrSegments;
2597 ULONG RefCount;
2598 PMM_SECTION_SEGMENT SectionSegments;
2599
2600 /*
2601 * NOTE: Section->ImageSection can be NULL for short time
2602 * during the section creating. If we fail for some reason
2603 * until the image section is properly initialized we shouldn't
2604 * process further here.
2605 */
2606 if (Section->ImageSection == NULL)
2607 return;
2608
2609 SectionSegments = Section->ImageSection->Segments;
2610 NrSegments = Section->ImageSection->NrSegments;
2611
2612 for (i = 0; i < NrSegments; i++)
2613 {
2614 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2615 {
2616 MmLockSectionSegment(&SectionSegments[i]);
2617 }
2618 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2619 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2620 {
2621 MmUnlockSectionSegment(&SectionSegments[i]);
2622 if (RefCount == 0)
2623 {
2624 MmpFreePageFileSegment(&SectionSegments[i]);
2625 }
2626 }
2627 }
2628 }
2629 #ifdef NEWCC
2630 else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT)
2631 {
2632 ULONG RefCount = 0;
2633 PMM_SECTION_SEGMENT Segment = Section->Segment;
2634
2635 if (Segment &&
2636 (RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
2637 {
2638 DPRINT("Freeing section segment\n");
2639 Section->Segment = NULL;
2640 MmFinalizeSegment(Segment);
2641 }
2642 else
2643 {
2644 DPRINT("RefCount %d\n", RefCount);
2645 }
2646 }
2647 #endif
2648 else
2649 {
2650 /*
2651 * NOTE: Section->Segment can be NULL for short time
2652 * during the section creating.
2653 */
2654 if (Section->Segment == NULL)
2655 return;
2656
2657 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2658 {
2659 MmpFreePageFileSegment(Section->Segment);
2660 MmFreePageTablesSectionSegment(Section->Segment, NULL);
2661 ExFreePool(Section->Segment);
2662 Section->Segment = NULL;
2663 }
2664 else
2665 {
2666 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2667 }
2668 }
2669 if (Section->FileObject != NULL)
2670 {
2671 #ifndef NEWCC
2672 CcRosDereferenceCache(Section->FileObject);
2673 #endif
2674 ObDereferenceObject(Section->FileObject);
2675 Section->FileObject = NULL;
2676 }
2677 }
2678
2679 VOID NTAPI
2680 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2681 IN PVOID Object,
2682 IN ACCESS_MASK GrantedAccess,
2683 IN ULONG ProcessHandleCount,
2684 IN ULONG SystemHandleCount)
2685 {
2686 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2687 Object, ProcessHandleCount);
2688 }
2689
2690 NTSTATUS
2691 INIT_FUNCTION
2692 NTAPI
2693 MmCreatePhysicalMemorySection(VOID)
2694 {
2695 PROS_SECTION_OBJECT PhysSection;
2696 NTSTATUS Status;
2697 OBJECT_ATTRIBUTES Obj;
2698 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2699 LARGE_INTEGER SectionSize;
2700 HANDLE Handle;
2701
2702 /*
2703 * Create the section mapping physical memory
2704 */
2705 SectionSize.QuadPart = 0xFFFFFFFF;
2706 InitializeObjectAttributes(&Obj,
2707 &Name,
2708 OBJ_PERMANENT,
2709 NULL,
2710 NULL);
2711 Status = MmCreateSection((PVOID)&PhysSection,
2712 SECTION_ALL_ACCESS,
2713 &Obj,
2714 &SectionSize,
2715 PAGE_EXECUTE_READWRITE,
2716 0,
2717 NULL,
2718 NULL);
2719 if (!NT_SUCCESS(Status))
2720 {
2721 DPRINT1("Failed to create PhysicalMemory section\n");
2722 KeBugCheck(MEMORY_MANAGEMENT);
2723 }
2724 Status = ObInsertObject(PhysSection,
2725 NULL,
2726 SECTION_ALL_ACCESS,
2727 0,
2728 NULL,
2729 &Handle);
2730 if (!NT_SUCCESS(Status))
2731 {
2732 ObDereferenceObject(PhysSection);
2733 }
2734 ObCloseHandle(Handle, KernelMode);
2735 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2736 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2737
2738 return(STATUS_SUCCESS);
2739 }
2740
2741 NTSTATUS
2742 INIT_FUNCTION
2743 NTAPI
2744 MmInitSectionImplementation(VOID)
2745 {
2746 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2747 UNICODE_STRING Name;
2748
2749 DPRINT("Creating Section Object Type\n");
2750
2751 /* Initialize the section based root */
2752 ASSERT(MmSectionBasedRoot.NumberGenericTableElements == 0);
2753 MmSectionBasedRoot.BalancedRoot.u1.Parent = &MmSectionBasedRoot.BalancedRoot;
2754
2755 /* Initialize the Section object type */
2756 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2757 RtlInitUnicodeString(&Name, L"Section");
2758 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2759 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2760 ObjectTypeInitializer.PoolType = PagedPool;
2761 ObjectTypeInitializer.UseDefaultObject = TRUE;
2762 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2763 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2764 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2765 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2766 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2767
2768 MmCreatePhysicalMemorySection();
2769
2770 return(STATUS_SUCCESS);
2771 }
2772
2773 NTSTATUS
2774 NTAPI
2775 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2776 ACCESS_MASK DesiredAccess,
2777 POBJECT_ATTRIBUTES ObjectAttributes,
2778 PLARGE_INTEGER UMaximumSize,
2779 ULONG SectionPageProtection,
2780 ULONG AllocationAttributes)
2781 /*
2782 * Create a section which is backed by the pagefile
2783 */
2784 {
2785 LARGE_INTEGER MaximumSize;
2786 PROS_SECTION_OBJECT Section;
2787 PMM_SECTION_SEGMENT Segment;
2788 NTSTATUS Status;
2789
2790 if (UMaximumSize == NULL)
2791 {
2792 return(STATUS_UNSUCCESSFUL);
2793 }
2794 MaximumSize = *UMaximumSize;
2795
2796 /*
2797 * Create the section
2798 */
2799 Status = ObCreateObject(ExGetPreviousMode(),
2800 MmSectionObjectType,
2801 ObjectAttributes,
2802 ExGetPreviousMode(),
2803 NULL,
2804 sizeof(ROS_SECTION_OBJECT),
2805 0,
2806 0,
2807 (PVOID*)(PVOID)&Section);
2808 if (!NT_SUCCESS(Status))
2809 {
2810 return(Status);
2811 }
2812
2813 /*
2814 * Initialize it
2815 */
2816 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2817 Section->Type = 'SC';
2818 Section->Size = 'TN';
2819 Section->SectionPageProtection = SectionPageProtection;
2820 Section->AllocationAttributes = AllocationAttributes;
2821 Section->MaximumSize = MaximumSize;
2822 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2823 TAG_MM_SECTION_SEGMENT);
2824 if (Segment == NULL)
2825 {
2826 ObDereferenceObject(Section);
2827 return(STATUS_NO_MEMORY);
2828 }
2829 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
2830 Section->Segment = Segment;
2831 Segment->ReferenceCount = 1;
2832 ExInitializeFastMutex(&Segment->Lock);
2833 Segment->Image.FileOffset = 0;
2834 Segment->Protection = SectionPageProtection;
2835 Segment->RawLength.QuadPart = MaximumSize.u.LowPart;
2836 Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2837 Segment->Flags = MM_PAGEFILE_SEGMENT;
2838 Segment->WriteCopy = FALSE;
2839 Segment->Image.VirtualAddress = 0;
2840 Segment->Image.Characteristics = 0;
2841 *SectionObject = Section;
2842 MiInitializeSectionPageTable(Segment);
2843 return(STATUS_SUCCESS);
2844 }
2845
2846 NTSTATUS
2847 NTAPI
2848 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2849 ACCESS_MASK DesiredAccess,
2850 POBJECT_ATTRIBUTES ObjectAttributes,
2851 PLARGE_INTEGER UMaximumSize,
2852 ULONG SectionPageProtection,
2853 ULONG AllocationAttributes,
2854 HANDLE FileHandle)
2855 /*
2856 * Create a section backed by a data file
2857 */
2858 {
2859 PROS_SECTION_OBJECT Section;
2860 NTSTATUS Status;
2861 LARGE_INTEGER MaximumSize;
2862 PFILE_OBJECT FileObject;
2863 PMM_SECTION_SEGMENT Segment;
2864 ULONG FileAccess;
2865 IO_STATUS_BLOCK Iosb;
2866 LARGE_INTEGER Offset;
2867 CHAR Buffer;
2868 FILE_STANDARD_INFORMATION FileInfo;
2869 ULONG Length;
2870
2871 /*
2872 * Create the section
2873 */
2874 Status = ObCreateObject(ExGetPreviousMode(),
2875 MmSectionObjectType,
2876 ObjectAttributes,
2877 ExGetPreviousMode(),
2878 NULL,
2879 sizeof(ROS_SECTION_OBJECT),
2880 0,
2881 0,
2882 (PVOID*)&Section);
2883 if (!NT_SUCCESS(Status))
2884 {
2885 return(Status);
2886 }
2887 /*
2888 * Initialize it
2889 */
2890 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2891 Section->Type = 'SC';
2892 Section->Size = 'TN';
2893 Section->SectionPageProtection = SectionPageProtection;
2894 Section->AllocationAttributes = AllocationAttributes;
2895
2896 /*
2897 * Reference the file handle
2898 */
2899 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection);
2900 Status = ObReferenceObjectByHandle(FileHandle,
2901 FileAccess,
2902 IoFileObjectType,
2903 ExGetPreviousMode(),
2904 (PVOID*)(PVOID)&FileObject,
2905 NULL);
2906 if (!NT_SUCCESS(Status))
2907 {
2908 ObDereferenceObject(Section);
2909 return(Status);
2910 }
2911
2912 /*
2913 * FIXME: This is propably not entirely correct. We can't look into
2914 * the standard FCB header because it might not be initialized yet
2915 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2916 * standard file information is filled on first request).
2917 */
2918 Status = IoQueryFileInformation(FileObject,
2919 FileStandardInformation,
2920 sizeof(FILE_STANDARD_INFORMATION),
2921 &FileInfo,
2922 &Length);
2923 Iosb.Information = Length;
2924 if (!NT_SUCCESS(Status))
2925 {
2926 ObDereferenceObject(Section);
2927 ObDereferenceObject(FileObject);
2928 return Status;
2929 }
2930
2931 /*
2932 * FIXME: Revise this once a locking order for file size changes is
2933 * decided
2934 */
2935 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
2936 {
2937 MaximumSize = *UMaximumSize;
2938 }
2939 else
2940 {
2941 MaximumSize = FileInfo.EndOfFile;
2942 /* Mapping zero-sized files isn't allowed. */
2943 if (MaximumSize.QuadPart == 0)
2944 {
2945 ObDereferenceObject(Section);
2946 ObDereferenceObject(FileObject);
2947 return STATUS_FILE_INVALID;
2948 }
2949 }
2950
2951 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2952 {
2953 Status = IoSetInformation(FileObject,
2954 FileAllocationInformation,
2955 sizeof(LARGE_INTEGER),
2956 &MaximumSize);
2957 if (!NT_SUCCESS(Status))
2958 {
2959 ObDereferenceObject(Section);
2960 ObDereferenceObject(FileObject);
2961 return(STATUS_SECTION_NOT_EXTENDED);
2962 }
2963 }
2964
2965 if (FileObject->SectionObjectPointer == NULL ||
2966 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2967 {
2968 /*
2969 * Read a bit so caching is initiated for the file object.
2970 * This is only needed because MiReadPage currently cannot
2971 * handle non-cached streams.
2972 */
2973 Offset.QuadPart = 0;
2974 Status = ZwReadFile(FileHandle,
2975 NULL,
2976 NULL,
2977 NULL,
2978 &Iosb,
2979 &Buffer,
2980 sizeof (Buffer),
2981 &Offset,
2982 0);
2983 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2984 {
2985 ObDereferenceObject(Section);
2986 ObDereferenceObject(FileObject);
2987 return(Status);
2988 }
2989 if (FileObject->SectionObjectPointer == NULL ||
2990 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2991 {
2992 /* FIXME: handle this situation */
2993 ObDereferenceObject(Section);
2994 ObDereferenceObject(FileObject);
2995 return STATUS_INVALID_PARAMETER;
2996 }
2997 }
2998
2999 /*
3000 * Lock the file
3001 */
3002 Status = MmspWaitForFileLock(FileObject);
3003 if (Status != STATUS_SUCCESS)
3004 {
3005 ObDereferenceObject(Section);
3006 ObDereferenceObject(FileObject);
3007 return(Status);
3008 }
3009
3010 /*
3011 * If this file hasn't been mapped as a data file before then allocate a
3012 * section segment to describe the data file mapping
3013 */
3014 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3015 {
3016 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
3017 TAG_MM_SECTION_SEGMENT);
3018 if (Segment == NULL)
3019 {
3020 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3021 ObDereferenceObject(Section);
3022 ObDereferenceObject(FileObject);
3023 return(STATUS_NO_MEMORY);
3024 }
3025 Section->Segment = Segment;
3026 Segment->ReferenceCount = 1;
3027 ExInitializeFastMutex(&Segment->Lock);
3028 /*
3029 * Set the lock before assigning the segment to the file object
3030 */
3031 ExAcquireFastMutex(&Segment->Lock);
3032 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3033
3034 Segment->Image.FileOffset = 0;
3035 Segment->Protection = SectionPageProtection;
3036 Segment->Flags = MM_DATAFILE_SEGMENT;
3037 Segment->Image.Characteristics = 0;
3038 Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY));
3039 if (AllocationAttributes & SEC_RESERVE)
3040 {
3041 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
3042 }
3043 else
3044 {
3045 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3046 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3047 }
3048 Segment->Image.VirtualAddress = 0;
3049 Segment->Locked = TRUE;
3050 MiInitializeSectionPageTable(Segment);
3051 }
3052 else
3053 {
3054 /*
3055 * If the file is already mapped as a data file then we may need
3056 * to extend it
3057 */
3058 Segment =
3059 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3060 DataSectionObject;
3061 Section->Segment = Segment;
3062 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3063 MmLockSectionSegment(Segment);
3064
3065 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
3066 !(AllocationAttributes & SEC_RESERVE))
3067 {
3068 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3069 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3070 }
3071 }
3072 MmUnlockSectionSegment(Segment);
3073 Section->FileObject = FileObject;
3074 Section->MaximumSize = MaximumSize;
3075 #ifndef NEWCC
3076 CcRosReferenceCache(FileObject);
3077 #endif
3078 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3079 *SectionObject = Section;
3080 return(STATUS_SUCCESS);
3081 }
3082
3083 /*
3084 TODO: not that great (declaring loaders statically, having to declare all of
3085 them, having to keep them extern, etc.), will fix in the future
3086 */
3087 extern NTSTATUS NTAPI PeFmtCreateSection
3088 (
3089 IN CONST VOID * FileHeader,
3090 IN SIZE_T FileHeaderSize,
3091 IN PVOID File,
3092 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3093 OUT PULONG Flags,
3094 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3095 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3096 );
3097
3098 extern NTSTATUS NTAPI ElfFmtCreateSection
3099 (
3100 IN CONST VOID * FileHeader,
3101 IN SIZE_T FileHeaderSize,
3102 IN PVOID File,
3103 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3104 OUT PULONG Flags,
3105 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3106 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3107 );
3108
3109 /* TODO: this is a standard DDK/PSDK macro */
3110 #ifndef RTL_NUMBER_OF
3111 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3112 #endif
3113
3114 static PEXEFMT_LOADER ExeFmtpLoaders[] =
3115 {
3116 PeFmtCreateSection,
3117 #ifdef __ELF
3118 ElfFmtCreateSection
3119 #endif
3120 };
3121
3122 static
3123 PMM_SECTION_SEGMENT
3124 NTAPI
3125 ExeFmtpAllocateSegments(IN ULONG NrSegments)
3126 {
3127 SIZE_T SizeOfSegments;
3128 PMM_SECTION_SEGMENT Segments;
3129
3130 /* TODO: check for integer overflow */
3131 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3132
3133 Segments = ExAllocatePoolWithTag(NonPagedPool,
3134 SizeOfSegments,
3135 TAG_MM_SECTION_SEGMENT);
3136
3137 if(Segments)
3138 RtlZeroMemory(Segments, SizeOfSegments);
3139
3140 return Segments;
3141 }
3142
3143 static
3144 NTSTATUS
3145 NTAPI
3146 ExeFmtpReadFile(IN PVOID File,
3147 IN PLARGE_INTEGER Offset,
3148 IN ULONG Length,
3149 OUT PVOID * Data,
3150 OUT PVOID * AllocBase,
3151 OUT PULONG ReadSize)
3152 {
3153 NTSTATUS Status;
3154 LARGE_INTEGER FileOffset;
3155 ULONG AdjustOffset;
3156 ULONG OffsetAdjustment;
3157 ULONG BufferSize;
3158 ULONG UsedSize;
3159 PVOID Buffer;
3160 PFILE_OBJECT FileObject = File;
3161 IO_STATUS_BLOCK Iosb;
3162
3163 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
3164
3165 if(Length == 0)
3166 {
3167 KeBugCheck(MEMORY_MANAGEMENT);
3168 }
3169
3170 FileOffset = *Offset;
3171
3172 /* Negative/special offset: it cannot be used in this context */
3173 if(FileOffset.u.HighPart < 0)
3174 {
3175 KeBugCheck(MEMORY_MANAGEMENT);
3176 }
3177
3178 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3179 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3180 FileOffset.u.LowPart = AdjustOffset;
3181
3182 BufferSize = Length + OffsetAdjustment;
3183 BufferSize = PAGE_ROUND_UP(BufferSize);
3184
3185 /*
3186 * It's ok to use paged pool, because this is a temporary buffer only used in
3187 * the loading of executables. The assumption is that MmCreateSection is
3188 * always called at low IRQLs and that these buffers don't survive a brief
3189 * initialization phase
3190 */
3191 Buffer = ExAllocatePoolWithTag(PagedPool,
3192 BufferSize,
3193 'rXmM');
3194 if (!Buffer)
3195 {
3196 KeBugCheck(MEMORY_MANAGEMENT);
3197 }
3198
3199 UsedSize = 0;
3200
3201 Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
3202
3203 UsedSize = (ULONG)Iosb.Information;
3204
3205 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3206 {
3207 Status = STATUS_IN_PAGE_ERROR;
3208 ASSERT(!NT_SUCCESS(Status));
3209 }
3210
3211 if(NT_SUCCESS(Status))
3212 {
3213 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3214 *AllocBase = Buffer;
3215 *ReadSize = UsedSize - OffsetAdjustment;
3216 }
3217 else
3218 {
3219 ExFreePoolWithTag(Buffer, 'rXmM');
3220 }
3221
3222 return Status;
3223 }
3224
3225 #ifdef NASSERT
3226 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3227 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3228 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3229 #else
3230 static
3231 VOID
3232 NTAPI
3233 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3234 {
3235 ULONG i;
3236
3237 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3238 {
3239 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3240 ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
3241 }
3242 }
3243
3244 static
3245 VOID
3246 NTAPI
3247 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3248 {
3249 ULONG i;
3250
3251 MmspAssertSegmentsSorted(ImageSectionObject);
3252
3253 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3254 {
3255 ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
3256
3257 if(i > 0)
3258 {
3259 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3260 (ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3261 ImageSectionObject->Segments[i - 1].Length.QuadPart));
3262 }
3263 }
3264 }
3265
3266 static
3267 VOID
3268 NTAPI
3269 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3270 {
3271 ULONG i;
3272
3273 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3274 {
3275 ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
3276 ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
3277 }
3278 }
3279 #endif
3280
3281 static
3282 int
3283 __cdecl
3284 MmspCompareSegments(const void * x,
3285 const void * y)
3286 {
3287 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3288 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3289
3290 return
3291 (Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >>
3292 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3293 }
3294
3295 /*
3296 * Ensures an image section's segments are sorted in memory
3297 */
3298 static
3299 VOID
3300 NTAPI
3301 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3302 IN ULONG Flags)
3303 {
3304 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
3305 {
3306 MmspAssertSegmentsSorted(ImageSectionObject);
3307 }
3308 else
3309 {
3310 qsort(ImageSectionObject->Segments,
3311 ImageSectionObject->NrSegments,
3312 sizeof(ImageSectionObject->Segments[0]),
3313 MmspCompareSegments);
3314 }
3315 }
3316
3317
3318 /*
3319 * Ensures an image section's segments don't overlap in memory and don't have
3320 * gaps and don't have a null size. We let them map to overlapping file regions,
3321 * though - that's not necessarily an error
3322 */
3323 static
3324 BOOLEAN
3325 NTAPI
3326 MmspCheckSegmentBounds
3327 (
3328 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3329 IN ULONG Flags
3330 )
3331 {
3332 ULONG i;
3333
3334 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
3335 {
3336 MmspAssertSegmentsNoOverlap(ImageSectionObject);
3337 return TRUE;
3338 }
3339
3340 ASSERT(ImageSectionObject->NrSegments >= 1);
3341
3342 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3343 {
3344 if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
3345 {
3346 return FALSE;
3347 }
3348
3349 if(i > 0)
3350 {
3351 /*
3352 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3353 * page could be OK (Windows seems to be OK with them), and larger gaps
3354 * could lead to image sections spanning several discontiguous regions
3355 * (NtMapViewOfSection could then refuse to map them, and they could
3356 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3357 */
3358 if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3359 ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
3360 ImageSectionObject->Segments[i].Image.VirtualAddress)
3361 {
3362 return FALSE;
3363 }
3364 }
3365 }
3366
3367 return TRUE;
3368 }
3369
3370 /*
3371 * Merges and pads an image section's segments until they all are page-aligned
3372 * and have a size that is a multiple of the page size
3373 */
3374 static
3375 BOOLEAN
3376 NTAPI
3377 MmspPageAlignSegments
3378 (
3379 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3380 IN ULONG Flags
3381 )
3382 {
3383 ULONG i;
3384 ULONG LastSegment;
3385 PMM_SECTION_SEGMENT EffectiveSegment;
3386
3387 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
3388 {
3389 MmspAssertSegmentsPageAligned(ImageSectionObject);
3390 return TRUE;
3391 }
3392
3393 LastSegment = 0;
3394 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3395
3396 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3397 {
3398 /*
3399 * The first segment requires special handling
3400 */
3401 if (i == 0)
3402 {
3403 ULONG_PTR VirtualAddress;
3404 ULONG_PTR VirtualOffset;
3405
3406 VirtualAddress = EffectiveSegment->Image.VirtualAddress;
3407
3408 /* Round down the virtual address to the nearest page */
3409 EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3410
3411 /* Round up the virtual size to the nearest page */
3412 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
3413 EffectiveSegment->Image.VirtualAddress;
3414
3415 /* Adjust the raw address and size */
3416 VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
3417
3418 if (EffectiveSegment->Image.FileOffset < VirtualOffset)
3419 {
3420 return FALSE;
3421 }
3422
3423 /*
3424 * Garbage in, garbage out: unaligned base addresses make the file
3425 * offset point in curious and odd places, but that's what we were
3426 * asked for
3427 */
3428 EffectiveSegment->Image.FileOffset -= VirtualOffset;
3429 EffectiveSegment->RawLength.QuadPart += VirtualOffset;
3430 }
3431 else
3432 {
3433 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3434 ULONG_PTR EndOfEffectiveSegment;
3435
3436 EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
3437 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3438
3439 /*
3440 * The current segment begins exactly where the current effective
3441 * segment ended, therefore beginning a new effective segment
3442 */
3443 if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
3444 {
3445 LastSegment ++;
3446 ASSERT(LastSegment <= i);
3447 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3448
3449 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3450
3451 if (LastSegment != i)
3452 {
3453 /*
3454 * Copy the current segment. If necessary, the effective segment
3455 * will be expanded later
3456 */
3457 *EffectiveSegment = *Segment;
3458 }
3459
3460 /*
3461 * Page-align the virtual size. We know for sure the virtual address
3462 * already is
3463 */
3464 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
3465 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
3466 }
3467 /*
3468 * The current segment is still part of the current effective segment:
3469 * extend the effective segment to reflect this
3470 */
3471 else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
3472 {
3473 static const ULONG FlagsToProtection[16] =
3474 {
3475 PAGE_NOACCESS,
3476 PAGE_READONLY,
3477 PAGE_READWRITE,
3478 PAGE_READWRITE,
3479 PAGE_EXECUTE_READ,
3480 PAGE_EXECUTE_READ,
3481 PAGE_EXECUTE_READWRITE,
3482 PAGE_EXECUTE_READWRITE,
3483 PAGE_WRITECOPY,
3484 PAGE_WRITECOPY,
3485 PAGE_WRITECOPY,
3486 PAGE_WRITECOPY,
3487 PAGE_EXECUTE_WRITECOPY,
3488 PAGE_EXECUTE_WRITECOPY,
3489 PAGE_EXECUTE_WRITECOPY,
3490 PAGE_EXECUTE_WRITECOPY
3491 };
3492
3493 unsigned ProtectionFlags;
3494
3495 /*
3496 * Extend the file size
3497 */
3498
3499 /* Unaligned segments must be contiguous within the file */
3500 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
3501 EffectiveSegment->RawLength.QuadPart))
3502 {
3503 return FALSE;
3504 }
3505
3506 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
3507
3508 /*
3509 * Extend the virtual size
3510 */
3511 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
3512
3513 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
3514 EffectiveSegment->Image.VirtualAddress;
3515
3516 /*
3517 * Merge the protection
3518 */
3519 EffectiveSegment->Protection |= Segment->Protection;
3520
3521 /* Clean up redundance */
3522 ProtectionFlags = 0;
3523
3524 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3525 ProtectionFlags |= 1 << 0;
3526
3527 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3528 ProtectionFlags |= 1 << 1;
3529
3530 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3531 ProtectionFlags |= 1 << 2;
3532
3533 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3534 ProtectionFlags |= 1 << 3;
3535
3536 ASSERT(ProtectionFlags < 16);
3537 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3538
3539 /* If a segment was required to be shared and cannot, fail */
3540 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3541 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3542 {
3543 return FALSE;
3544 }
3545 }
3546 /*
3547 * We assume no holes between segments at this point
3548 */
3549 else
3550 {
3551 KeBugCheck(MEMORY_MANAGEMENT);
3552 }
3553 }
3554 }
3555 ImageSectionObject->NrSegments = LastSegment + 1;
3556
3557 return TRUE;
3558 }
3559
3560 NTSTATUS
3561 ExeFmtpCreateImageSection(HANDLE FileHandle,
3562 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3563 {
3564 LARGE_INTEGER Offset;
3565 PVOID FileHeader;
3566 PVOID FileHeaderBuffer;
3567 ULONG FileHeaderSize;
3568 ULONG Flags;
3569 ULONG OldNrSegments;
3570 NTSTATUS Status;
3571 ULONG i;
3572
3573 /*
3574 * Read the beginning of the file (2 pages). Should be enough to contain
3575 * all (or most) of the headers
3576 */
3577 Offset.QuadPart = 0;
3578
3579 /* FIXME: use FileObject instead of FileHandle */
3580 Status = ExeFmtpReadFile (FileHandle,
3581 &Offset,
3582 PAGE_SIZE * 2,
3583 &FileHeader,
3584 &FileHeaderBuffer,
3585 &FileHeaderSize);
3586
3587 if (!NT_SUCCESS(Status))
3588 return Status;
3589
3590 if (FileHeaderSize == 0)
3591 {
3592 ExFreePool(FileHeaderBuffer);
3593 return STATUS_UNSUCCESSFUL;
3594 }
3595
3596 /*
3597 * Look for a loader that can handle this executable
3598 */
3599 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3600 {
3601 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3602 Flags = 0;
3603
3604 /* FIXME: use FileObject instead of FileHandle */
3605 Status = ExeFmtpLoaders[i](FileHeader,
3606 FileHeaderSize,
3607 FileHandle,
3608 ImageSectionObject,
3609 &Flags,
3610 ExeFmtpReadFile,
3611 ExeFmtpAllocateSegments);
3612
3613 if (!NT_SUCCESS(Status))
3614 {
3615 if (ImageSectionObject->Segments)
3616 {
3617 ExFreePool(ImageSectionObject->Segments);
3618 ImageSectionObject->Segments = NULL;
3619 }
3620 }
3621
3622 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3623 break;
3624 }
3625
3626 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3627
3628 /*
3629 * No loader handled the format
3630 */
3631 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3632 {
3633 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3634 ASSERT(!NT_SUCCESS(Status));
3635 }
3636
3637 if (!NT_SUCCESS(Status))
3638 return Status;
3639
3640 ASSERT(ImageSectionObject->Segments != NULL);
3641
3642 /*
3643 * Some defaults
3644 */
3645 /* FIXME? are these values platform-dependent? */
3646 if(ImageSectionObject->StackReserve == 0)
3647 ImageSectionObject->StackReserve = 0x40000;
3648
3649 if(ImageSectionObject->StackCommit == 0)
3650 ImageSectionObject->StackCommit = 0x1000;
3651
3652 if(ImageSectionObject->ImageBase == 0)
3653 {
3654 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3655 ImageSectionObject->ImageBase = 0x10000000;
3656 else
3657 ImageSectionObject->ImageBase = 0x00400000;
3658 }
3659
3660 /*
3661 * And now the fun part: fixing the segments
3662 */
3663
3664 /* Sort them by virtual address */
3665 MmspSortSegments(ImageSectionObject, Flags);
3666
3667 /* Ensure they don't overlap in memory */
3668 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3669 return STATUS_INVALID_IMAGE_FORMAT;
3670
3671 /* Ensure they are aligned */
3672 OldNrSegments = ImageSectionObject->NrSegments;
3673
3674 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3675 return STATUS_INVALID_IMAGE_FORMAT;
3676
3677 /* Trim them if the alignment phase merged some of them */
3678 if (ImageSectionObject->NrSegments < OldNrSegments)
3679 {
3680 PMM_SECTION_SEGMENT Segments;
3681 SIZE_T SizeOfSegments;
3682
3683 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3684
3685 Segments = ExAllocatePoolWithTag(PagedPool,
3686 SizeOfSegments,
3687 TAG_MM_SECTION_SEGMENT);
3688
3689 if (Segments == NULL)
3690 return STATUS_INSUFFICIENT_RESOURCES;
3691
3692 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3693 ExFreePool(ImageSectionObject->Segments);
3694 ImageSectionObject->Segments = Segments;
3695 }
3696
3697 /* And finish their initialization */
3698 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3699 {
3700 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3701 ImageSectionObject->Segments[i].ReferenceCount = 1;
3702 MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
3703 }
3704
3705 ASSERT(NT_SUCCESS(Status));
3706 return Status;
3707 }
3708
3709 NTSTATUS
3710 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3711 ACCESS_MASK DesiredAccess,
3712 POBJECT_ATTRIBUTES ObjectAttributes,
3713 PLARGE_INTEGER UMaximumSize,
3714 ULONG SectionPageProtection,
3715 ULONG AllocationAttributes,
3716 PFILE_OBJECT FileObject)
3717 {
3718 PROS_SECTION_OBJECT Section;
3719 NTSTATUS Status;
3720 PMM_SECTION_SEGMENT SectionSegments;
3721 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3722 ULONG i;
3723
3724 if (FileObject == NULL)
3725 return STATUS_INVALID_FILE_FOR_SECTION;
3726
3727 /*
3728 * Create the section
3729 */
3730 Status = ObCreateObject (ExGetPreviousMode(),
3731 MmSectionObjectType,
3732 ObjectAttributes,
3733 ExGetPreviousMode(),
3734 NULL,
3735 sizeof(ROS_SECTION_OBJECT),
3736 0,
3737 0,
3738 (PVOID*)(PVOID)&Section);
3739 if (!NT_SUCCESS(Status))
3740 {
3741 ObDereferenceObject(FileObject);
3742 return(Status);
3743 }
3744
3745 /*
3746 * Initialize it
3747 */
3748 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3749 Section->Type = 'SC';
3750 Section->Size = 'TN';
3751 Section->SectionPageProtection = SectionPageProtection;
3752 Section->AllocationAttributes = AllocationAttributes;
3753
3754 #ifndef NEWCC
3755 /*
3756 * Initialized caching for this file object if previously caching
3757 * was initialized for the same on disk file
3758 */
3759 Status = CcTryToInitializeFileCache(FileObject);
3760 #else
3761 Status = STATUS_SUCCESS;
3762 #endif
3763
3764 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3765 {
3766 NTSTATUS StatusExeFmt;
3767
3768 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3769 if (ImageSectionObject == NULL)
3770 {
3771 ObDereferenceObject(FileObject);
3772 ObDereferenceObject(Section);
3773 return(STATUS_NO_MEMORY);
3774 }
3775
3776 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3777
3778 StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
3779
3780 if (!NT_SUCCESS(StatusExeFmt))
3781 {
3782 if(ImageSectionObject->Segments != NULL)
3783 ExFreePool(ImageSectionObject->Segments);
3784
3785 ExFreePool(ImageSectionObject);
3786 ObDereferenceObject(Section);
3787 ObDereferenceObject(FileObject);
3788 return(StatusExeFmt);
3789 }
3790
3791 Section->ImageSection = ImageSectionObject;
3792 ASSERT(ImageSectionObject->Segments);
3793
3794 /*
3795 * Lock the file
3796 */
3797 Status = MmspWaitForFileLock(FileObject);
3798 if (!NT_SUCCESS(Status))
3799 {
3800 ExFreePool(ImageSectionObject->Segments);
3801 ExFreePool(ImageSectionObject);
3802 ObDereferenceObject(Section);
3803 ObDereferenceObject(FileObject);
3804 return(Status);
3805 }
3806
3807 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3808 ImageSectionObject, NULL))
3809 {
3810 /*
3811 * An other thread has initialized the same image in the background
3812 */
3813 ExFreePool(ImageSectionObject->Segments);
3814 ExFreePool(ImageSectionObject);
3815 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3816 Section->ImageSection = ImageSectionObject;
3817 SectionSegments = ImageSectionObject->Segments;
3818
3819 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3820 {
3821 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3822 }
3823 }
3824
3825 Status = StatusExeFmt;
3826 }
3827 else
3828 {
3829 /*
3830 * Lock the file
3831 */
3832 Status = MmspWaitForFileLock(FileObject);
3833 if (Status != STATUS_SUCCESS)
3834 {
3835 ObDereferenceObject(Section);
3836 ObDereferenceObject(FileObject);
3837 return(Status);
3838 }
3839
3840 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3841 Section->ImageSection = ImageSectionObject;
3842 SectionSegments = ImageSectionObject->Segments;
3843
3844 /*
3845 * Otherwise just reference all the section segments
3846 */
3847 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3848 {
3849 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3850 }
3851
3852 Status = STATUS_SUCCESS;
3853 }
3854 Section->FileObject = FileObject;
3855 #ifndef NEWCC
3856 CcRosReferenceCache(FileObject);
3857 #endif
3858 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3859 *SectionObject = Section;
3860 return(Status);
3861 }
3862
3863
3864
3865 static NTSTATUS
3866 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
3867 PROS_SECTION_OBJECT Section,
3868 PMM_SECTION_SEGMENT Segment,
3869 PVOID* BaseAddress,
3870 SIZE_T ViewSize,
3871 ULONG Protect,
3872 ULONG ViewOffset,
3873 ULONG AllocationType)
3874 {
3875 PMEMORY_AREA MArea;
3876 NTSTATUS Status;
3877 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3878
3879 if (Segment->WriteCopy)
3880 {
3881 /* We have to do this because the not present fault
3882 * and access fault handlers depend on the protection
3883 * that should be granted AFTER the COW fault takes
3884 * place to be in Region->Protect. The not present fault
3885 * handler changes this to the correct protection for COW when
3886 * mapping the pages into the process's address space. If a COW
3887 * fault takes place, the access fault handler sets the page protection
3888 * to these values for the newly copied pages
3889 */
3890 if (Protect == PAGE_WRITECOPY)
3891 Protect = PAGE_READWRITE;
3892 else if (Protect == PAGE_EXECUTE_WRITECOPY)
3893 Protect = PAGE_EXECUTE_READWRITE;
3894 }
3895
3896 BoundaryAddressMultiple.QuadPart = 0;
3897
3898 #ifdef NEWCC
3899 if (Segment->Flags & MM_DATAFILE_SEGMENT) {
3900 LARGE_INTEGER FileOffset;
3901 FileOffset.QuadPart = ViewOffset;
3902 ObReferenceObject(Section);
3903 return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__);
3904 }
3905 #endif
3906 Status = MmCreateMemoryArea(AddressSpace,
3907 MEMORY_AREA_SECTION_VIEW,
3908 BaseAddress,
3909 ViewSize,
3910 Protect,
3911 &MArea,
3912 FALSE,
3913 AllocationType,
3914 BoundaryAddressMultiple);
3915 if (!NT_SUCCESS(Status))
3916 {
3917 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3918 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3919 return(Status);
3920 }
3921
3922 ObReferenceObject((PVOID)Section);
3923
3924 MArea->Data.SectionData.Segment = Segment;
3925 MArea->Data.SectionData.Section = Section;
3926 MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset;
3927 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
3928 ViewSize, 0, Protect);
3929
3930 return(STATUS_SUCCESS);
3931 }
3932
3933
3934 static VOID
3935 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3936 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3937 {
3938 ULONG_PTR Entry;
3939 PFILE_OBJECT FileObject;
3940 PBCB Bcb;
3941 LARGE_INTEGER Offset;
3942 SWAPENTRY SavedSwapEntry;
3943 PROS_SECTION_OBJECT Section;
3944 PMM_SECTION_SEGMENT Segment;
3945 PMMSUPPORT AddressSpace;
3946 PEPROCESS Process;
3947
3948 AddressSpace = (PMMSUPPORT)Context;
3949 Process = MmGetAddressSpaceOwner(AddressSpace);
3950
3951 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3952
3953 Offset.QuadPart = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
3954 MemoryArea->Data.SectionData.ViewOffset.QuadPart;
3955
3956 Section = MemoryArea->Data.SectionData.Section;
3957 Segment = MemoryArea->Data.SectionData.Segment;
3958
3959 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
3960 while (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY)
3961 {
3962 MmUnlockSectionSegment(Segment);
3963 MmUnlockAddressSpace(AddressSpace);
3964
3965 MiWaitForPageEvent(NULL, NULL);
3966
3967 MmLockAddressSpace(AddressSpace);
3968 MmLockSectionSegment(Segment);
3969 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
3970 }
3971
3972 /*
3973 * For a dirty, datafile, non-private page mark it as dirty in the
3974 * cache manager.
3975 */
3976 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3977 {
3978 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3979 {
3980 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3981 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3982 #ifndef NEWCC
3983 CcRosMarkDirtyCacheSegment(Bcb, (ULONG)(Offset.QuadPart + Segment->Image.FileOffset));
3984 #endif
3985 ASSERT(SwapEntry == 0);
3986 }
3987 }
3988
3989 if (SwapEntry != 0)
3990 {
3991 /*
3992 * Sanity check
3993 */
3994 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3995 {
3996 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3997 KeBugCheck(MEMORY_MANAGEMENT);
3998 }
3999 MmFreeSwapPage(SwapEntry);
4000 }
4001 else if (Page != 0)
4002 {
4003 if (IS_SWAP_FROM_SSE(Entry) ||
4004 Page != PFN_FROM_SSE(Entry))
4005 {
4006 /*
4007 * Sanity check
4008 */
4009 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4010 {
4011 DPRINT1("Found a private page in a pagefile section.\n");
4012 KeBugCheck(MEMORY_MANAGEMENT);
4013 }
4014 /*
4015 * Just dereference private pages
4016 */
4017 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4018 if (SavedSwapEntry != 0)
4019 {
4020 MmFreeSwapPage(SavedSwapEntry);
4021 MmSetSavedSwapEntryPage(Page, 0);
4022 }
4023 MmDeleteRmap(Page, Process, Address);
4024 MmReleasePageMemoryConsumer(MC_USER, Page);
4025 }
4026 else
4027 {
4028 MmDeleteRmap(Page, Process, Address);
4029 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL);
4030 }
4031 }
4032 }
4033
4034 static NTSTATUS
4035 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
4036 PVOID BaseAddress)
4037 {
4038 NTSTATUS Status;
4039 PMEMORY_AREA MemoryArea;
4040 PROS_SECTION_OBJECT Section;
4041 PMM_SECTION_SEGMENT Segment;
4042 PLIST_ENTRY CurrentEntry;
4043 PMM_REGION CurrentRegion;
4044 PLIST_ENTRY RegionListHead;
4045
4046 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4047 BaseAddress);
4048 if (MemoryArea == NULL)
4049 {
4050 return(STATUS_UNSUCCESSFUL);
4051 }
4052
4053 MemoryArea->DeleteInProgress = TRUE;
4054 Section = MemoryArea->Data.SectionData.Section;
4055 Segment = MemoryArea->Data.SectionData.Segment;
4056
4057 #ifdef NEWCC
4058 if (Segment->Flags & MM_DATAFILE_SEGMENT)
4059 return MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress);
4060 #endif
4061
4062 MmLockSectionSegment(Segment);
4063
4064 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4065 while (!IsListEmpty(RegionListHead))
4066 {
4067 CurrentEntry = RemoveHeadList(RegionListHead);
4068 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4069 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4070 }
4071
4072 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4073 {
4074 Status = MmFreeMemoryArea(AddressSpace,
4075 MemoryArea,
4076 NULL,
4077 NULL);
4078 }
4079 else
4080 {
4081 Status = MmFreeMemoryArea(AddressSpace,
4082 MemoryArea,
4083 MmFreeSectionPage,
4084 AddressSpace);
4085 }
4086 MmUnlockSectionSegment(Segment);
4087 ObDereferenceObject(Section);
4088 return(Status);
4089 }
4090
4091 NTSTATUS
4092 NTAPI
4093 MiRosUnmapViewOfSection(IN PEPROCESS Process,
4094 IN PVOID BaseAddress,
4095 IN ULONG Flags)
4096 {
4097 NTSTATUS Status;
4098 PMEMORY_AREA MemoryArea;
4099 PMMSUPPORT AddressSpace;
4100 PROS_SECTION_OBJECT Section;
4101 PVOID ImageBaseAddress = 0;
4102
4103 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4104 Process, BaseAddress);
4105
4106 ASSERT(Process);
4107
4108 AddressSpace = &Process->Vm;
4109
4110 MmLockAddressSpace(AddressSpace);
4111 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4112 BaseAddress);
4113 if (MemoryArea == NULL ||
4114 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4115 MemoryArea->DeleteInProgress)
4116 {
4117 ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3);
4118 MmUnlockAddressSpace(AddressSpace);
4119 return STATUS_NOT_MAPPED_VIEW;
4120 }
4121
4122 MemoryArea->DeleteInProgress = TRUE;
4123
4124 Section = MemoryArea->Data.SectionData.Section;
4125
4126 if (Section->AllocationAttributes & SEC_IMAGE)
4127 {
4128 ULONG i;
4129 ULONG NrSegments;
4130 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4131 PMM_SECTION_SEGMENT SectionSegments;
4132 PMM_SECTION_SEGMENT Segment;
4133
4134 Segment = MemoryArea->Data.SectionData.Segment;
4135 ImageSectionObject = Section->ImageSection;
4136 SectionSegments = ImageSectionObject->Segments;
4137 NrSegments = ImageSectionObject->NrSegments;
4138
4139 /* Search for the current segment within the section segments
4140 * and calculate the image base address */
4141 for (i = 0; i < NrSegments; i++)
4142 {
4143 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4144 {
4145 if (Segment == &SectionSegments[i])
4146 {
4147 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
4148 break;
4149 }
4150 }
4151 }
4152 if (i >= NrSegments)
4153 {
4154 KeBugCheck(MEMORY_MANAGEMENT);
4155 }
4156
4157 for (i = 0; i < NrSegments; i++)
4158 {
4159 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4160 {
4161 PVOID SBaseAddress = (PVOID)
4162 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4163
4164 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4165 }
4166 }
4167 }
4168 else
4169 {
4170 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4171 }
4172
4173 MmUnlockAddressSpace(AddressSpace);
4174
4175 /* Notify debugger */
4176 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4177
4178 return(STATUS_SUCCESS);
4179 }
4180
4181
4182
4183
4184 /**
4185 * Queries the information of a section object.
4186 *
4187 * @param SectionHandle
4188 * Handle to the section object. It must be opened with SECTION_QUERY
4189 * access.
4190 * @param SectionInformationClass
4191 * Index to a certain information structure. Can be either
4192 * SectionBasicInformation or SectionImageInformation. The latter
4193 * is valid only for sections that were created with the SEC_IMAGE
4194 * flag.
4195 * @param SectionInformation
4196 * Caller supplies storage for resulting information.
4197 * @param Length
4198 * Size of the supplied storage.
4199 * @param ResultLength
4200 * Data written.
4201 *
4202 * @return Status.
4203 *
4204 * @implemented
4205 */
4206 NTSTATUS NTAPI
4207 NtQuerySection(IN HANDLE SectionHandle,
4208 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4209 OUT PVOID SectionInformation,
4210 IN SIZE_T SectionInformationLength,
4211 OUT PSIZE_T ResultLength OPTIONAL)
4212 {
4213 PROS_SECTION_OBJECT Section;
4214 KPROCESSOR_MODE PreviousMode;
4215 NTSTATUS Status;
4216 PAGED_CODE();
4217
4218 PreviousMode = ExGetPreviousMode();
4219
4220 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4221 ExSectionInfoClass,
4222 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4223 SectionInformation,
4224 (ULONG)SectionInformationLength,
4225 NULL,
4226 ResultLength,
4227 PreviousMode);
4228
4229 if(!NT_SUCCESS(Status))
4230 {
4231 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4232 return Status;
4233 }
4234
4235 Status = ObReferenceObjectByHandle(SectionHandle,
4236 SECTION_QUERY,
4237 MmSectionObjectType,
4238 PreviousMode,
4239 (PVOID*)(PVOID)&Section,
4240 NULL);
4241 if (NT_SUCCESS(Status))
4242 {
4243 switch (SectionInformationClass)
4244 {
4245 case SectionBasicInformation:
4246 {
4247 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4248
4249 _SEH2_TRY
4250 {
4251 Sbi->Attributes = Section->AllocationAttributes;
4252 if (Section->AllocationAttributes & SEC_IMAGE)
4253 {
4254 Sbi->BaseAddress = 0;
4255 Sbi->Size.QuadPart = 0;
4256 }
4257 else
4258 {
4259 Sbi->BaseAddress = (PVOID)Section->Segment->Image.VirtualAddress;
4260 Sbi->Size.QuadPart = Section->Segment->Length.QuadPart;
4261 }
4262
4263 if (ResultLength != NULL)
4264 {
4265 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4266 }
4267 Status = STATUS_SUCCESS;
4268 }
4269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4270 {
4271 Status = _SEH2_GetExceptionCode();
4272 }
4273 _SEH2_END;
4274
4275 break;
4276 }
4277
4278 case SectionImageInformation:
4279 {
4280 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4281
4282 _SEH2_TRY
4283 {
4284 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4285 if (Section->AllocationAttributes & SEC_IMAGE)
4286 {
4287 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4288 ImageSectionObject = Section->ImageSection;
4289
4290 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4291 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4292 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4293 Sii->SubSystemType = ImageSectionObject->Subsystem;
4294 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4295 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4296 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4297 Sii->Machine = ImageSectionObject->Machine;
4298 Sii->ImageContainsCode = ImageSectionObject->Executable;
4299 }
4300
4301 if (ResultLength != NULL)
4302 {
4303 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4304 }
4305 Status = STATUS_SUCCESS;
4306 }
4307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4308 {
4309 Status = _SEH2_GetExceptionCode();
4310 }
4311 _SEH2_END;
4312
4313 break;
4314 }
4315 }
4316
4317 ObDereferenceObject(Section);
4318 }
4319
4320 return(Status);
4321 }
4322
4323 /**********************************************************************
4324 * NAME EXPORTED
4325 * MmMapViewOfSection
4326 *
4327 * DESCRIPTION
4328 * Maps a view of a section into the virtual address space of a
4329 * process.
4330 *
4331 * ARGUMENTS
4332 * Section
4333 * Pointer to the section object.
4334 *
4335 * ProcessHandle
4336 * Pointer to the process.
4337 *
4338 * BaseAddress
4339 * Desired base address (or NULL) on entry;
4340 * Actual base address of the view on exit.
4341 *
4342 * ZeroBits
4343 * Number of high order address bits that must be zero.
4344 *
4345 * CommitSize
4346 * Size in bytes of the initially committed section of
4347 * the view.
4348 *
4349 * SectionOffset
4350 * Offset in bytes from the beginning of the section
4351 * to the beginning of the view.
4352 *
4353 * ViewSize
4354 * Desired length of map (or zero to map all) on entry
4355 * Actual length mapped on exit.
4356 *
4357 * InheritDisposition
4358 * Specified how the view is to be shared with
4359 * child processes.
4360 *
4361 * AllocationType
4362 * Type of allocation for the pages.
4363 *
4364 * Protect
4365 * Protection for the committed region of the view.
4366 *
4367 * RETURN VALUE
4368 * Status.
4369 *
4370 * @implemented
4371 */
4372 NTSTATUS NTAPI
4373 MmMapViewOfSection(IN PVOID SectionObject,
4374 IN PEPROCESS Process,
4375 IN OUT PVOID *BaseAddress,
4376 IN ULONG_PTR ZeroBits,
4377 IN SIZE_T CommitSize,
4378 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4379 IN OUT PSIZE_T ViewSize,
4380 IN SECTION_INHERIT InheritDisposition,
4381 IN ULONG AllocationType,
4382 IN ULONG Protect)
4383 {
4384 PROS_SECTION_OBJECT Section;
4385 PMMSUPPORT AddressSpace;
4386 ULONG ViewOffset;
4387 NTSTATUS Status = STATUS_SUCCESS;
4388 BOOLEAN NotAtBase = FALSE;
4389
4390 if (MiIsRosSectionObject(SectionObject) == FALSE)
4391 {
4392 DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName);
4393 return MmMapViewOfArm3Section(SectionObject,
4394 Process,
4395 BaseAddress,
4396 ZeroBits,
4397 CommitSize,
4398 SectionOffset,
4399 ViewSize,
4400 InheritDisposition,
4401 AllocationType,
4402 Protect);
4403 }
4404
4405 ASSERT(Process);
4406
4407 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4408 {
4409 return STATUS_INVALID_PAGE_PROTECTION;
4410 }
4411
4412
4413 Section = (PROS_SECTION_OBJECT)SectionObject;
4414 AddressSpace = &Process->Vm;
4415
4416 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4417
4418 MmLockAddressSpace(AddressSpace);
4419
4420 if (Section->AllocationAttributes & SEC_IMAGE)
4421 {
4422 ULONG i;
4423 ULONG NrSegments;
4424 ULONG_PTR ImageBase;
4425 SIZE_T ImageSize;
4426 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4427 PMM_SECTION_SEGMENT SectionSegments;
4428
4429 ImageSectionObject = Section->ImageSection;
4430 SectionSegments = ImageSectionObject->Segments;
4431 NrSegments = ImageSectionObject->NrSegments;
4432
4433
4434 ImageBase = (ULONG_PTR)*BaseAddress;
4435 if (ImageBase == 0)
4436 {
4437 ImageBase = ImageSectionObject->ImageBase;
4438 }
4439
4440 ImageSize = 0;
4441 for (i = 0; i < NrSegments; i++)
4442 {
4443 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4444 {
4445 ULONG_PTR MaxExtent;
4446 MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
4447 SectionSegments[i].Length.QuadPart);
4448 ImageSize = max(ImageSize, MaxExtent);
4449 }
4450 }
4451
4452 ImageSectionObject->ImageSize = (ULONG)ImageSize;
4453
4454 /* Check for an illegal base address */
4455 if ((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress)
4456 {
4457 ImageBase = PAGE_ROUND_DOWN((ULONG_PTR)MmHighestUserAddress - ImageSize);
4458 }
4459
4460 /* Check there is enough space to map the section at that point. */
4461 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4462 PAGE_ROUND_UP(ImageSize)) != NULL)
4463 {
4464 /* Fail if the user requested a fixed base address. */
4465 if ((*BaseAddress) != NULL)
4466 {
4467 MmUnlockAddressSpace(AddressSpace);
4468 return(STATUS_UNSUCCESSFUL);
4469 }
4470 /* Otherwise find a gap to map the image. */
4471 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4472 if (ImageBase == 0)
4473 {
4474 MmUnlockAddressSpace(AddressSpace);
4475 return(STATUS_UNSUCCESSFUL);
4476 }
4477 /* Remember that we loaded image at a different base address */
4478 NotAtBase = TRUE;
4479 }
4480
4481 for (i = 0; i < NrSegments; i++)
4482 {
4483 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4484 {
4485 PVOID SBaseAddress = (PVOID)
4486 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4487 MmLockSectionSegment(&SectionSegments[i]);
4488 Status = MmMapViewOfSegment(AddressSpace,
4489 Section,
4490 &SectionSegments[i],
4491 &SBaseAddress,
4492 SectionSegments[i].Length.LowPart,
4493 SectionSegments[i].Protection,
4494 0,
4495 0);
4496 MmUnlockSectionSegment(&SectionSegments[i]);
4497 if (!NT_SUCCESS(Status))
4498 {
4499 MmUnlockAddressSpace(AddressSpace);
4500 return(Status);
4501 }
4502 }
4503 }
4504
4505 *BaseAddress = (PVOID)ImageBase;
4506 *ViewSize = ImageSize;
4507 }
4508 else
4509 {
4510 /* check for write access */
4511 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4512 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4513 {
4514 MmUnlockAddressSpace(AddressSpace);
4515 return STATUS_SECTION_PROTECTION;
4516 }
4517 /* check for read access */
4518 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4519 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4520 {
4521 MmUnlockAddressSpace(AddressSpace);
4522 return STATUS_SECTION_PROTECTION;
4523 }
4524 /* check for execute access */
4525 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4526 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4527 {
4528 MmUnlockAddressSpace(AddressSpace);
4529 return STATUS_SECTION_PROTECTION;
4530 }
4531
4532 if (ViewSize == NULL)
4533 {
4534 /* Following this pointer would lead to us to the dark side */
4535 /* What to do? Bugcheck? Return status? Do the mambo? */
4536 KeBugCheck(MEMORY_MANAGEMENT);
4537 }
4538
4539 if (SectionOffset == NULL)
4540 {
4541 ViewOffset = 0;
4542 }
4543 else
4544 {
4545 ViewOffset = SectionOffset->u.LowPart;
4546 }
4547
4548 if ((ViewOffset % PAGE_SIZE) != 0)
4549 {
4550 MmUnlockAddressSpace(AddressSpace);
4551 return(STATUS_MAPPED_ALIGNMENT);
4552 }
4553
4554 if ((*ViewSize) == 0)
4555 {
4556 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4557 }
4558 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4559 {
4560 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4561 }
4562
4563 *ViewSize = PAGE_ROUND_UP(*ViewSize);
4564
4565 MmLockSectionSegment(Section->Segment);
4566 Status = MmMapViewOfSegment(AddressSpace,
4567 Section,
4568 Section->Segment,
4569 BaseAddress,
4570 *ViewSize,
4571 Protect,
4572 ViewOffset,
4573 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4574 MmUnlockSectionSegment(Section->Segment);
4575 if (!NT_SUCCESS(Status))
4576 {
4577 MmUnlockAddressSpace(AddressSpace);
4578 return(Status);
4579 }
4580 }
4581
4582 MmUnlockAddressSpace(AddressSpace);
4583
4584 if (NotAtBase)
4585 Status = STATUS_IMAGE_NOT_AT_BASE;
4586 else
4587 Status = STATUS_SUCCESS;
4588
4589 return Status;
4590 }
4591
4592 /*
4593 * @unimplemented
4594 */
4595 BOOLEAN NTAPI
4596 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4597 IN PLARGE_INTEGER NewFileSize)
4598 {
4599 /* Check whether an ImageSectionObject exists */
4600 if (SectionObjectPointer->ImageSectionObject != NULL)
4601 {
4602 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4603 return FALSE;
4604 }
4605
4606 if (SectionObjectPointer->DataSectionObject != NULL)
4607 {
4608 PMM_SECTION_SEGMENT Segment;
4609
4610 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4611 DataSectionObject;
4612
4613 if (Segment->ReferenceCount != 0)
4614 {
4615 #ifdef NEWCC
4616 CC_FILE_SIZES FileSizes;
4617 CcpLock();
4618 if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)))
4619 {
4620 CcpUnlock();
4621 /* Check size of file */
4622 if (SectionObjectPointer->SharedCacheMap)
4623 {
4624 if (!CcGetFileSizes(Segment->FileObject, &FileSizes))
4625 {
4626 return FALSE;
4627 }
4628
4629 if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart)
4630 {
4631 return FALSE;
4632 }
4633 }
4634 }
4635 else
4636 CcpUnlock();
4637 #else
4638 /* Check size of file */
4639 if (SectionObjectPointer->SharedCacheMap)
4640 {
4641 PBCB Bcb = SectionObjectPointer->SharedCacheMap;
4642 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
4643 {
4644 return FALSE;
4645 }
4646 }
4647 #endif
4648 }
4649 else
4650 {
4651 /* Something must gone wrong
4652 * how can we have a Section but no
4653 * reference? */
4654 DPRINT("ERROR: DataSectionObject without reference!\n");
4655 }
4656 }
4657
4658 DPRINT("FIXME: didn't check for outstanding write probes\n");
4659
4660 return TRUE;
4661 }
4662
4663
4664
4665
4666 /*
4667 * @implemented
4668 */
4669 BOOLEAN NTAPI
4670 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4671 IN MMFLUSH_TYPE FlushType)
4672 {
4673 BOOLEAN Result = TRUE;
4674 #ifdef NEWCC
4675 PMM_SECTION_SEGMENT Segment;
4676 #endif
4677
4678 switch(FlushType)
4679 {
4680 case MmFlushForDelete:
4681 if (SectionObjectPointer->ImageSectionObject ||
4682 SectionObjectPointer->DataSectionObject)
4683 {
4684 return FALSE;
4685 }
4686 #ifndef NEWCC
4687 CcRosSetRemoveOnClose(SectionObjectPointer);
4688 #endif
4689 return TRUE;
4690 case MmFlushForWrite:
4691 {
4692 DPRINT("MmFlushImageSection(%d)\n", FlushType);
4693 #ifdef NEWCC
4694 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject;
4695 #endif
4696
4697 if (SectionObjectPointer->ImageSectionObject) {
4698 DPRINT1("SectionObject has ImageSection\n");
4699 return FALSE;
4700 }
4701
4702 #ifdef NEWCC
4703 CcpLock();
4704 Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap));
4705 CcpUnlock();
4706 DPRINT("Result %d\n", Result);
4707 #endif
4708 return Result;
4709 }
4710 }
4711 return FALSE;
4712 }
4713
4714 /*
4715 * @implemented
4716 */
4717 NTSTATUS NTAPI
4718 MmMapViewInSystemSpace (IN PVOID SectionObject,
4719 OUT PVOID * MappedBase,
4720 IN OUT PSIZE_T ViewSize)
4721 {
4722 PROS_SECTION_OBJECT Section;
4723 PMMSUPPORT AddressSpace;
4724 NTSTATUS Status;
4725 PAGED_CODE();
4726
4727 if (MiIsRosSectionObject(SectionObject) == FALSE)
4728 {
4729 return MiMapViewInSystemSpace(SectionObject,
4730 &MmSession,
4731 MappedBase,
4732 ViewSize);
4733 }
4734
4735 DPRINT("MmMapViewInSystemSpace() called\n");
4736
4737 Section = (PROS_SECTION_OBJECT)SectionObject;
4738 AddressSpace = MmGetKernelAddressSpace();
4739
4740 MmLockAddressSpace(AddressSpace);
4741
4742
4743 if ((*ViewSize) == 0)
4744 {
4745 (*ViewSize) = Section->MaximumSize.u.LowPart;
4746 }
4747 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4748 {
4749 (*ViewSize) = Section->MaximumSize.u.LowPart;
4750 }
4751
4752 MmLockSectionSegment(Section->Segment);
4753
4754
4755 Status = MmMapViewOfSegment(AddressSpace,
4756 Section,
4757 Section->Segment,
4758 MappedBase,
4759 *ViewSize,
4760 PAGE_READWRITE,
4761 0,
4762 0);
4763
4764 MmUnlockSectionSegment(Section->Segment);
4765 MmUnlockAddressSpace(AddressSpace);
4766
4767 return Status;
4768 }
4769
4770 NTSTATUS
4771 NTAPI
4772 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase)
4773 {
4774 PMMSUPPORT AddressSpace;
4775 NTSTATUS Status;
4776
4777 DPRINT("MmUnmapViewInSystemSpace() called\n");
4778
4779 AddressSpace = MmGetKernelAddressSpace();
4780
4781 MmLockAddressSpace(AddressSpace);
4782
4783 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4784
4785 MmUnlockAddressSpace(AddressSpace);
4786
4787 return Status;
4788 }
4789
4790 /**********************************************************************
4791 * NAME EXPORTED
4792 * MmCreateSection@
4793 *
4794 * DESCRIPTION
4795 * Creates a section object.
4796 *
4797 * ARGUMENTS
4798 * SectionObject (OUT)
4799 * Caller supplied storage for the resulting pointer
4800 * to a SECTION_OBJECT instance;
4801 *
4802 * DesiredAccess
4803 * Specifies the desired access to the section can be a
4804 * combination of:
4805 * STANDARD_RIGHTS_REQUIRED |
4806 * SECTION_QUERY |
4807 * SECTION_MAP_WRITE |
4808 * SECTION_MAP_READ |
4809 * SECTION_MAP_EXECUTE
4810 *
4811 * ObjectAttributes [OPTIONAL]
4812 * Initialized attributes for the object can be used
4813 * to create a named section;
4814 *
4815 * MaximumSize
4816 * Maximizes the size of the memory section. Must be
4817 * non-NULL for a page-file backed section.
4818 * If value specified for a mapped file and the file is
4819 * not large enough, file will be extended.
4820 *
4821 * SectionPageProtection
4822 * Can be a combination of:
4823 * PAGE_READONLY |
4824 * PAGE_READWRITE |
4825 * PAGE_WRITEONLY |
4826 * PAGE_WRITECOPY
4827 *
4828 * AllocationAttributes
4829 * Can be a combination of:
4830 * SEC_IMAGE |
4831 * SEC_RESERVE
4832 *
4833 * FileHandle
4834 * Handle to a file to create a section mapped to a file
4835 * instead of a memory backed section;
4836 *
4837 * File
4838 * Unknown.
4839 *
4840 * RETURN VALUE
4841 * Status.
4842 *
4843 * @implemented
4844 */
4845 NTSTATUS NTAPI
4846 MmCreateSection (OUT PVOID * Section,
4847 IN ACCESS_MASK DesiredAccess,
4848 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4849 IN PLARGE_INTEGER MaximumSize,
4850 IN ULONG SectionPageProtection,
4851 IN ULONG AllocationAttributes,
4852 IN HANDLE FileHandle OPTIONAL,
4853 IN PFILE_OBJECT FileObject OPTIONAL)
4854 {
4855 NTSTATUS Status;
4856 ULONG Protection, FileAccess;
4857 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4858
4859 /* Check if an ARM3 section is being created instead */
4860 if (AllocationAttributes & 1)
4861 {
4862 DPRINT1("Creating ARM3 section\n");
4863 return MmCreateArm3Section(Section,
4864 DesiredAccess,
4865 ObjectAttributes,
4866 MaximumSize,
4867 SectionPageProtection,
4868 AllocationAttributes &~ 1,
4869 FileHandle,
4870 FileObject);
4871 }
4872
4873 /*
4874 * Check the protection
4875 */
4876 Protection = SectionPageProtection & ~(PAGE_GUARD | PAGE_NOCACHE);
4877 if (Protection != PAGE_READONLY &&
4878 Protection != PAGE_READWRITE &&
4879 Protection != PAGE_WRITECOPY &&
4880 Protection != PAGE_EXECUTE &&
4881 Protection != PAGE_EXECUTE_READ &&
4882 Protection != PAGE_EXECUTE_READWRITE &&
4883 Protection != PAGE_EXECUTE_WRITECOPY)
4884 {
4885 return STATUS_INVALID_PAGE_PROTECTION;
4886 }
4887
4888 if ((DesiredAccess & SECTION_MAP_WRITE) &&
4889 (Protection == PAGE_READWRITE ||
4890 Protection == PAGE_EXECUTE_READWRITE) &&
4891 !(AllocationAttributes & SEC_IMAGE))
4892 {
4893 DPRINT("Creating a section with WRITE access\n");
4894 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE;
4895 }
4896 else
4897 {
4898 DPRINT("Creating a section with READ access\n");
4899 FileAccess = FILE_READ_DATA | SYNCHRONIZE;
4900 }
4901
4902 /* FIXME: somehow combine this with the above checks */
4903 if (AllocationAttributes & SEC_IMAGE)
4904 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection);
4905
4906 if (!FileObject && FileHandle)
4907 {
4908 Status = ObReferenceObjectByHandle(FileHandle,
4909 FileAccess,
4910 IoFileObjectType,
4911 ExGetPreviousMode(),
4912 (PVOID *)&FileObject,
4913 NULL);
4914 if (!NT_SUCCESS(Status))
4915 {
4916 DPRINT("Failed: 0x%08lx\n", Status);
4917 return Status;
4918 }
4919 }
4920 else if (FileObject)
4921 ObReferenceObject(FileObject);
4922
4923 #ifndef NEWCC // A hack for initializing caching.
4924 // This is needed only in the old case.
4925 if (FileHandle)
4926 {
4927 IO_STATUS_BLOCK Iosb;
4928 NTSTATUS Status;
4929 CHAR Buffer;
4930 LARGE_INTEGER ByteOffset;
4931 ByteOffset.QuadPart = 0;
4932 Status = ZwReadFile(FileHandle,
4933 NULL,
4934 NULL,
4935 NULL,
4936 &Iosb,
4937 &Buffer,
4938 sizeof(Buffer),
4939 &ByteOffset,
4940 NULL);
4941 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
4942 return Status;
4943 // Caching is initialized...
4944 }
4945 #endif
4946
4947 if (AllocationAttributes & SEC_IMAGE)
4948 {
4949 Status = MmCreateImageSection(SectionObject,
4950 DesiredAccess,
4951 ObjectAttributes,
4952 MaximumSize,
4953 SectionPageProtection,
4954 AllocationAttributes,
4955 FileObject);
4956 }
4957 #ifndef NEWCC
4958 else if (FileHandle != NULL)
4959 {
4960 Status = MmCreateDataFileSection(SectionObject,
4961 DesiredAccess,
4962 ObjectAttributes,
4963 MaximumSize,
4964 SectionPageProtection,
4965 AllocationAttributes,
4966 FileHandle);
4967 if (FileObject)
4968 ObDereferenceObject(FileObject);
4969 }
4970 #else
4971 else if (FileHandle != NULL || FileObject != NULL)
4972 {
4973 Status = MmCreateCacheSection(SectionObject,
4974 DesiredAccess,
4975 ObjectAttributes,
4976 MaximumSize,
4977 SectionPageProtection,
4978 AllocationAttributes,
4979 FileObject);
4980 }
4981 #endif
4982 else
4983 {
4984 Status = MmCreatePageFileSection(SectionObject,
4985 DesiredAccess,
4986 ObjectAttributes,
4987 MaximumSize,
4988 SectionPageProtection,
4989 AllocationAttributes);
4990 }
4991
4992 return Status;
4993 }
4994
4995 VOID
4996 MmModifyAttributes(IN PMMSUPPORT AddressSpace,
4997 IN PVOID BaseAddress,
4998 IN SIZE_T RegionSize,
4999 IN ULONG OldType,
5000 IN ULONG OldProtect,
5001 IN ULONG NewType,
5002 IN ULONG NewProtect)
5003 {
5004 //
5005 // This function is deprecated but remains in order to support VirtualAlloc
5006 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5007 //
5008 // Win32k's shared user heap, for example, uses that mechanism. The two
5009 // conditions when this function needs to do something are ASSERTed for,
5010 // because they should not arise.
5011 //
5012 if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
5013 {
5014 ASSERT(FALSE);
5015 }
5016
5017 if ((NewType == MEM_COMMIT) && (OldType == MEM_COMMIT))
5018 {
5019 ASSERT(OldProtect == NewProtect);
5020 }
5021 }
5022
5023 NTSTATUS
5024 NTAPI
5025 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle,
5026 IN PEPROCESS Process,
5027 IN PMEMORY_AREA MemoryArea,
5028 IN PMMSUPPORT AddressSpace,
5029 IN OUT PVOID* UBaseAddress,
5030 IN BOOLEAN Attached,
5031 IN OUT PSIZE_T URegionSize,
5032 IN ULONG AllocationType,
5033 IN ULONG Protect)
5034 {
5035 ULONG_PTR PRegionSize;
5036 ULONG Type, RegionSize;
5037 NTSTATUS Status;
5038 PVOID PBaseAddress, BaseAddress;
5039 KAPC_STATE ApcState;
5040
5041 PBaseAddress = *UBaseAddress;
5042 PRegionSize = *URegionSize;
5043
5044 BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
5045 RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) -
5046 PAGE_ROUND_DOWN(PBaseAddress);
5047 Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
5048
5049 ASSERT(PBaseAddress != 0);
5050 ASSERT(Type == MEM_COMMIT);
5051 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
5052 ASSERT(((ULONG_PTR)BaseAddress + RegionSize) <= (ULONG_PTR)MemoryArea->EndingAddress);
5053 ASSERT(((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress) >= RegionSize);
5054 ASSERT(MemoryArea->Data.SectionData.RegionListHead.Flink);
5055
5056 Status = MmAlterRegion(AddressSpace,
5057 MemoryArea->StartingAddress,
5058 &MemoryArea->Data.SectionData.RegionListHead,
5059 BaseAddress,
5060 RegionSize,
5061 Type,
5062 Protect,
5063 MmModifyAttributes);
5064
5065 MmUnlockAddressSpace(AddressSpace);
5066 if (Attached) KeUnstackDetachProcess(&ApcState);
5067 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
5068 if (NT_SUCCESS(Status))
5069 {
5070 *UBaseAddress = BaseAddress;
5071 *URegionSize = RegionSize;
5072 }
5073
5074 return Status;
5075 }
5076
5077 NTSTATUS
5078 NTAPI
5079 MiRosProtectVirtualMemory(IN PEPROCESS Process,
5080 IN OUT PVOID *BaseAddress,
5081 IN OUT PSIZE_T NumberOfBytesToProtect,
5082 IN ULONG NewAccessProtection,
5083 OUT PULONG OldAccessProtection OPTIONAL)
5084 {
5085 PMEMORY_AREA MemoryArea;
5086 PMMSUPPORT AddressSpace;
5087 ULONG OldAccessProtection_;
5088 NTSTATUS Status;
5089
5090 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
5091 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
5092
5093 AddressSpace = &Process->Vm;
5094 MmLockAddressSpace(AddressSpace);
5095 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
5096 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
5097 {
5098 MmUnlockAddressSpace(AddressSpace);
5099 return STATUS_UNSUCCESSFUL;
5100 }
5101
5102 if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_;
5103
5104 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
5105 {
5106 Status = MmProtectSectionView(AddressSpace,
5107 MemoryArea,
5108 *BaseAddress,
5109 *NumberOfBytesToProtect,
5110 NewAccessProtection,
5111 OldAccessProtection);
5112 }
5113 else
5114 {
5115 /* FIXME: Should we return failure or success in this case? */
5116 Status = STATUS_CONFLICTING_ADDRESSES;
5117 }
5118
5119 MmUnlockAddressSpace(AddressSpace);
5120
5121 return Status;
5122 }
5123
5124 /* EOF */