xref: /reactos/hal/halx86/generic/memory.c (revision ebaf247c)
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 
256