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