xref: /reactos/hal/halx86/generic/memory.c (revision 845faec4)
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     PHARDWARE_PTE PointerPte;
144     PFN_NUMBER UsedPages = 0;
145     PVOID VirtualAddress, BaseAddress;
146 
147     /* Start at the current HAL heap base */
148     BaseAddress = HalpHeapStart;
149     VirtualAddress = BaseAddress;
150 
151     /* Loop until we have all the pages required */
152     while (UsedPages < PageCount)
153     {
154         /* If this overflows past the HAL heap, it means there's no space */
155         if (VirtualAddress == NULL) return NULL;
156 
157         /* Get the PTE for this address */
158         PointerPte = HalAddressToPte(VirtualAddress);
159 
160         /* Go to the next page */
161         VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
162 
163         /* Check if the page is available */
164         if (PointerPte->Valid)
165         {
166             /* PTE has data, skip it and start with a new base address */
167             BaseAddress = VirtualAddress;
168             UsedPages = 0;
169             continue;
170         }
171 
172         /* PTE is available, keep going on this run */
173         UsedPages++;
174     }
175 
176     /* Take the base address of the page plus the actual offset in the address */
177     VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress +
178                              BYTE_OFFSET(PhysicalAddress.LowPart));
179 
180     /* If we are starting at the heap, move the heap */
181     if (BaseAddress == HalpHeapStart)
182     {
183         /* Past this allocation */
184         HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
185     }
186 
187     /* Loop pages that can be mapped */
188     while (UsedPages--)
189     {
190         /* Fill out the PTE */
191         PointerPte = HalAddressToPte(BaseAddress);
192         PointerPte->PageFrameNumber = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
193         PointerPte->Valid = 1;
194         PointerPte->Write = 1;
195 
196         /* Move to the next address */
197         PhysicalAddress.QuadPart += PAGE_SIZE;
198         BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
199     }
200 
201     /* Flush the TLB and return the address */
202     HalpFlushTLB();
203     return VirtualAddress;
204 }
205 
206 VOID
207 NTAPI
208 HalpUnmapVirtualAddress(IN PVOID VirtualAddress,
209                         IN PFN_COUNT PageCount)
210 {
211     PHARDWARE_PTE PointerPte;
212     ULONG i;
213 
214     /* Only accept valid addresses */
215     if (VirtualAddress < (PVOID)MM_HAL_VA_START) return;
216 
217     /* Align it down to page size */
218     VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
219 
220     /* Loop PTEs */
221     PointerPte = HalAddressToPte(VirtualAddress);
222     for (i = 0; i < PageCount; i++)
223     {
224         *(PULONG)PointerPte = 0;
225         PointerPte++;
226     }
227 
228     /* Flush the TLB */
229     HalpFlushTLB();
230 
231     /* Put the heap back */
232     if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress;
233 }
234 
235