[NDK][NTOS] Add global definition of INIT_FUNCTION/INIT_SECTION (#779)
[reactos.git] / hal / halx86 / generic / memory.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/memory.c
5 * PURPOSE: HAL memory management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* Share with Mm headers? */
16 #define MM_HAL_HEAP_START (PVOID)(MM_HAL_VA_START + (1024 * 1024))
17
18 /* GLOBALS *******************************************************************/
19
20 ULONG HalpUsedAllocDescriptors;
21 MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64];
22 PVOID HalpHeapStart = MM_HAL_HEAP_START;
23
24
25 /* PRIVATE FUNCTIONS *********************************************************/
26
27 ULONG64
28 NTAPI
29 HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
30 IN ULONG64 MaxAddress,
31 IN PFN_NUMBER PageCount,
32 IN BOOLEAN Aligned)
33 {
34 ULONG UsedDescriptors;
35 ULONG64 PhysicalAddress;
36 PFN_NUMBER MaxPage, BasePage, Alignment;
37 PLIST_ENTRY NextEntry;
38 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock, NewBlock, FreeBlock;
39
40 /* Highest page we'll go */
41 MaxPage = MaxAddress >> PAGE_SHIFT;
42
43 /* We need at least two blocks */
44 if ((HalpUsedAllocDescriptors + 2) > 64) return 0;
45
46 /* Remember how many we have now */
47 UsedDescriptors = HalpUsedAllocDescriptors;
48
49 /* Loop the loader block memory descriptors */
50 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
51 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
52 {
53 /* Get the block */
54 MdBlock = CONTAINING_RECORD(NextEntry,
55 MEMORY_ALLOCATION_DESCRIPTOR,
56 ListEntry);
57
58 /* No alignment by default */
59 Alignment = 0;
60
61 /* Unless requested, in which case we use a 64KB block alignment */
62 if (Aligned) Alignment = ((MdBlock->BasePage + 0x0F) & ~0x0F) - MdBlock->BasePage;
63
64 /* Search for free memory */
65 if ((MdBlock->MemoryType == LoaderFree) ||
66 (MdBlock->MemoryType == LoaderFirmwareTemporary))
67 {
68 /* Make sure the page is within bounds, including alignment */
69 BasePage = MdBlock->BasePage;
70 if ((BasePage) &&
71 (MdBlock->PageCount >= PageCount + Alignment) &&
72 (BasePage + PageCount + Alignment < MaxPage))
73 {
74 /* We found an address */
75 PhysicalAddress = ((ULONG64)BasePage + Alignment) << PAGE_SHIFT;
76 break;
77 }
78 }
79
80 /* Keep trying */
81 NextEntry = NextEntry->Flink;
82 }
83
84 /* If we didn't find anything, get out of here */
85 if (NextEntry == &LoaderBlock->MemoryDescriptorListHead) return 0;
86
87 /* Okay, now get a descriptor */
88 NewBlock = &HalpAllocationDescriptorArray[HalpUsedAllocDescriptors];
89 NewBlock->PageCount = (ULONG)PageCount;
90 NewBlock->BasePage = MdBlock->BasePage + Alignment;
91 NewBlock->MemoryType = LoaderHALCachedMemory;
92
93 /* Update count */
94 UsedDescriptors++;
95 HalpUsedAllocDescriptors = UsedDescriptors;
96
97 /* Check if we had any alignment */
98 if (Alignment)
99 {
100 /* Check if we had leftovers */
101 if (MdBlock->PageCount > (PageCount + Alignment))
102 {
103 /* Get the next descriptor */
104 FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors];
105 FreeBlock->PageCount = MdBlock->PageCount - Alignment - (ULONG)PageCount;
106 FreeBlock->BasePage = MdBlock->BasePage + Alignment + (ULONG)PageCount;
107
108 /* One more */
109 HalpUsedAllocDescriptors++;
110
111 /* Insert it into the list */
112 InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry);
113 }
114
115 /* Trim the original block to the alignment only */
116 MdBlock->PageCount = Alignment;
117
118 /* Insert the descriptor after the original one */
119 InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry);
120 }
121 else
122 {
123 /* Consume memory from this block */
124 MdBlock->BasePage += (ULONG)PageCount;
125 MdBlock->PageCount -= (ULONG)PageCount;
126
127 /* Insert the descriptor before the original one */
128 InsertTailList(&MdBlock->ListEntry, &NewBlock->ListEntry);
129
130 /* Remove the entry if the whole block was allocated */
131 if (MdBlock->PageCount == 0) RemoveEntryList(&MdBlock->ListEntry);
132 }
133
134 /* Return the address */
135 return PhysicalAddress;
136 }
137
138 PVOID
139 NTAPI
140 HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress,
141 IN PFN_COUNT PageCount)
142 {
143 return HalpMapPhysicalMemory64Vista(PhysicalAddress, PageCount, TRUE);
144 }
145
146 VOID
147 NTAPI
148 HalpUnmapVirtualAddress(IN PVOID VirtualAddress,
149 IN PFN_COUNT PageCount)
150 {
151 HalpUnmapVirtualAddressVista(VirtualAddress, PageCount, TRUE);
152 }
153
154 PVOID
155 NTAPI
156 HalpMapPhysicalMemory64Vista(IN PHYSICAL_ADDRESS PhysicalAddress,
157 IN PFN_COUNT PageCount,
158 IN BOOLEAN FlushCurrentTLB)
159 {
160 PHARDWARE_PTE PointerPte;
161 PFN_NUMBER UsedPages = 0;
162 PVOID VirtualAddress, BaseAddress;
163
164 /* Start at the current HAL heap base */
165 BaseAddress = HalpHeapStart;
166 VirtualAddress = BaseAddress;
167
168 /* Loop until we have all the pages required */
169 while (UsedPages < PageCount)
170 {
171 /* If this overflows past the HAL heap, it means there's no space */
172 if (VirtualAddress == NULL) return NULL;
173
174 /* Get the PTE for this address */
175 PointerPte = HalAddressToPte(VirtualAddress);
176
177 /* Go to the next page */
178 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
179
180 /* Check if the page is available */
181 if (PointerPte->Valid)
182 {
183 /* PTE has data, skip it and start with a new base address */
184 BaseAddress = VirtualAddress;
185 UsedPages = 0;
186 continue;
187 }
188
189 /* PTE is available, keep going on this run */
190 UsedPages++;
191 }
192
193 /* Take the base address of the page plus the actual offset in the address */
194 VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress +
195 BYTE_OFFSET(PhysicalAddress.LowPart));
196
197 /* If we are starting at the heap, move the heap */
198 if (BaseAddress == HalpHeapStart)
199 {
200 /* Past this allocation */
201 HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
202 }
203
204 /* Loop pages that can be mapped */
205 while (UsedPages--)
206 {
207 /* Fill out the PTE */
208 PointerPte = HalAddressToPte(BaseAddress);
209 PointerPte->PageFrameNumber = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
210 PointerPte->Valid = 1;
211 PointerPte->Write = 1;
212
213 /* Move to the next address */
214 PhysicalAddress.QuadPart += PAGE_SIZE;
215 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
216 }
217
218 /* Flush the TLB and return the address */
219 if (FlushCurrentTLB)
220 HalpFlushTLB();
221
222 return VirtualAddress;
223 }
224
225 VOID
226 NTAPI
227 HalpUnmapVirtualAddressVista(IN PVOID VirtualAddress,
228 IN PFN_COUNT PageCount,
229 IN BOOLEAN FlushCurrentTLB)
230 {
231 PHARDWARE_PTE PointerPte;
232 ULONG i;
233
234 /* Only accept valid addresses */
235 if (VirtualAddress < (PVOID)MM_HAL_VA_START) return;
236
237 /* Align it down to page size */
238 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
239
240 /* Loop PTEs */
241 PointerPte = HalAddressToPte(VirtualAddress);
242 for (i = 0; i < PageCount; i++)
243 {
244 *(PULONG)PointerPte = 0;
245 PointerPte++;
246 }
247
248 /* Flush the TLB */
249 if (FlushCurrentTLB)
250 HalpFlushTLB();
251
252 /* Put the heap back */
253 if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress;
254 }
255