2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/freelist.c
5 * PURPOSE: Handle the list of free physical pages
6 * PROGRAMMER: David Welch (welch@cwcom.net)
9 * 18/08/98: Added a fix from Robert Bergkvist
12 /* INCLUDES ****************************************************************/
14 #include <internal/stddef.h>
15 #include <ddk/ntddk.h>
16 #include <internal/mm.h>
17 #include <internal/mmhal.h>
18 #include <internal/ntoskrnl.h>
19 #include <internal/bitops.h>
20 #include <internal/i386/io.h>
23 #include <internal/debug.h>
25 /* TYPES *******************************************************************/
27 #define PHYSICAL_PAGE_FREE (0x1)
28 #define PHYSICAL_PAGE_INUSE (0x2)
29 #define PHYSICAL_PAGE_BIOS (0x4)
31 typedef struct _PHYSICAL_PAGE
35 } PHYSICAL_PAGE
, *PPHYSICAL_PAGE
;
37 /* GLOBALS ****************************************************************/
39 static PPHYSICAL_PAGE MmPageArray
;
41 static LIST_ENTRY UsedPageListHead
;
42 static KSPIN_LOCK UsedPageListLock
;
43 static LIST_ENTRY FreePageListHead
;
44 static KSPIN_LOCK FreePageListLock
;
45 static LIST_ENTRY BiosPageListHead
;
46 static KSPIN_LOCK BiosPageListLock
;
51 /* FUNCTIONS *************************************************************/
53 PVOID
MmInitializePageList(PVOID FirstPhysKernelAddress
,
54 PVOID LastPhysKernelAddress
,
55 ULONG MemorySizeInPages
,
56 ULONG LastKernelAddress
)
58 * FUNCTION: Initializes the page list with all pages free
59 * except those known to be reserved and those used by the kernel
61 * PageBuffer = Page sized buffer
62 * FirstKernelAddress = First physical address used by the kernel
63 * LastKernelAddress = Last physical address used by the kernel
69 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
70 "LastPhysKernelAddress %x, "
71 "MemorySizeInPages %x, LastKernelAddress %x)\n",
72 FirstPhysKernelAddress
,
73 LastPhysKernelAddress
,
77 InitializeListHead(&UsedPageListHead
);
78 KeInitializeSpinLock(&UsedPageListLock
);
79 InitializeListHead(&FreePageListHead
);
80 KeInitializeSpinLock(&FreePageListLock
);
81 InitializeListHead(&BiosPageListHead
);
82 KeInitializeSpinLock(&BiosPageListLock
);
84 Reserved
= (MemorySizeInPages
* sizeof(PHYSICAL_PAGE
)) / PAGESIZE
;
85 MmPageArray
= (PHYSICAL_PAGE
*)LastKernelAddress
;
87 DPRINT("Reserved %d\n", Reserved
);
93 if ((ULONG
)FirstPhysKernelAddress
< 0xa0000)
95 MiNrFreePages
= MiNrFreePages
+
96 ((ULONG
)FirstPhysKernelAddress
/PAGESIZE
);
97 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
99 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_FREE
;
100 InsertTailList(&FreePageListHead
,
101 &MmPageArray
[i
].ListEntry
);
103 MiNrUsedPages
= MiNrUsedPages
+
104 (((0xa0000) / PAGESIZE
) - i
);
105 for (; i
<(0xa0000 / PAGESIZE
); i
++)
107 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_INUSE
;
108 InsertTailList(&UsedPageListHead
,
109 &MmPageArray
[i
].ListEntry
);
111 for (; i
<(0x100000 / PAGESIZE
); i
++)
113 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_BIOS
;
114 InsertTailList(&BiosPageListHead
,
115 &MmPageArray
[i
].ListEntry
);
120 MiNrFreePages
= MiNrFreePages
+ (0xa0000 / PAGESIZE
);
121 for (; i
<(0xa0000 / PAGESIZE
); i
++)
123 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_FREE
;
124 InsertTailList(&FreePageListHead
,
125 &MmPageArray
[i
].ListEntry
);
127 for (; i
<(0x100000 / PAGESIZE
); i
++)
129 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_BIOS
;
130 InsertTailList(&BiosPageListHead
,
131 &MmPageArray
[i
].ListEntry
);
133 MiNrFreePages
= MiNrFreePages
+
134 (((ULONG
)FirstPhysKernelAddress
/PAGESIZE
) - i
);
135 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
137 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_FREE
;
138 InsertTailList(&FreePageListHead
,
139 &MmPageArray
[i
].ListEntry
);
141 MiNrUsedPages
= MiNrUsedPages
+
142 (((ULONG
)LastPhysKernelAddress
/PAGESIZE
) - i
);
143 for (; i
<((ULONG
)LastPhysKernelAddress
/PAGESIZE
); i
++)
145 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_INUSE
;
146 InsertTailList(&UsedPageListHead
,
147 &MmPageArray
[i
].ListEntry
);
151 MiNrFreePages
= MiNrFreePages
+ (MemorySizeInPages
- i
);
152 for (; i
<MemorySizeInPages
; i
++)
154 MmPageArray
[i
].Flags
= PHYSICAL_PAGE_FREE
;
155 InsertTailList(&FreePageListHead
,
156 &MmPageArray
[i
].ListEntry
);
158 DPRINT("\nMmInitializePageList() = %x\n",
159 LastKernelAddress
+ Reserved
* PAGESIZE
);
160 return((PVOID
)(LastKernelAddress
+ Reserved
* PAGESIZE
));
163 VOID
MmFreePage(PVOID PhysicalAddress
, ULONG Nr
)
166 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
169 DPRINT("MmFreePage(PhysicalAddress %x, Nr %x)\n", PhysicalAddress
, Nr
);
171 if (((ULONG
)PhysicalAddress
) > 0x400000)
173 DbgPrint("MmFreePage() failed with %x\n", PhysicalAddress
);
177 MiNrFreePages
= MiNrFreePages
+ Nr
;
178 MiNrUsedPages
= MiNrUsedPages
- Nr
;
182 KeAcquireSpinLock(&UsedPageListLock
, &oldIrql
);
183 RemoveEntryList(&MmPageArray
[Start
+ i
].ListEntry
);
184 MmPageArray
[Start
+ i
].Flags
= PHYSICAL_PAGE_FREE
;
185 KeReleaseSpinLock(&UsedPageListLock
, oldIrql
);
187 ExInterlockedInsertTailList(&FreePageListHead
,
188 &MmPageArray
[Start
+ i
].ListEntry
,
194 PVOID
MmAllocPage(VOID
)
197 PLIST_ENTRY ListEntry
;
198 PPHYSICAL_PAGE PageDescriptor
;
200 DPRINT("MmAllocPage()\n");
202 ListEntry
= ExInterlockedRemoveHeadList(&FreePageListHead
,
204 DPRINT("ListEntry %x\n",ListEntry
);
205 if (ListEntry
== NULL
)
207 DbgPrint("MmAllocPage(): Out of memory\n");
210 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
211 DPRINT("PageDescriptor %x\n",PageDescriptor
);
212 PageDescriptor
->Flags
= PHYSICAL_PAGE_INUSE
;
213 ExInterlockedInsertTailList(&UsedPageListHead
, ListEntry
,
216 DPRINT("PageDescriptor %x MmPageArray %x\n", PageDescriptor
, MmPageArray
);
217 offset
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
218 DPRINT("offset %x\n",offset
);
219 offset
= offset
/ sizeof(PHYSICAL_PAGE
) * PAGESIZE
;
220 DPRINT("offset %x\n",offset
);
222 MiNrUsedPages
= MiNrUsedPages
+ 1;
223 MiNrFreePages
= MiNrFreePages
- 1;
225 if (offset
> 0x400000)
227 DbgPrint("Failed in MmAllocPage() with offset %x\n", offset
);
231 DPRINT("MmAllocPage() = %x\n",offset
);
232 return((PVOID
)offset
);