Sync with trunk head (r48654)
[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_VA_START (PVOID)0xFFC00000
17 #define MM_HAL_HEAP_START (PVOID)((ULONG_PTR)MM_HAL_VA_START + (1024 * 1024))
18
19 /* GLOBALS *******************************************************************/
20
21 ULONG HalpUsedAllocDescriptors;
22 MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64];
23 PVOID HalpHeapStart = MM_HAL_HEAP_START;
24
25
26 /* PRIVATE FUNCTIONS *********************************************************/
27
28
29 ULONG
30 NTAPI
31 HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
32 IN ULONG MaxAddress,
33 IN ULONG PageCount,
34 IN BOOLEAN Aligned)
35 {
36 ULONG UsedDescriptors, Alignment, PhysicalAddress;
37 PFN_NUMBER MaxPage, BasePage;
38 PLIST_ENTRY NextEntry;
39 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock, NewBlock, FreeBlock;
40
41 /* Highest page we'll go */
42 MaxPage = MaxAddress >> PAGE_SHIFT;
43
44 /* We need at least two blocks */
45 if ((HalpUsedAllocDescriptors + 2) > 64) return 0;
46
47 /* Remember how many we have now */
48 UsedDescriptors = HalpUsedAllocDescriptors;
49
50 /* Loop the loader block memory descriptors */
51 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
52 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
53 {
54 /* Get the block */
55 MdBlock = CONTAINING_RECORD(NextEntry,
56 MEMORY_ALLOCATION_DESCRIPTOR,
57 ListEntry);
58
59 /* No alignment by default */
60 Alignment = 0;
61
62 /* Unless requested, in which case we use a 64KB block alignment */
63 if (Aligned) Alignment = ((MdBlock->BasePage + 0x0F) & ~0x0F) - MdBlock->BasePage;
64
65 /* Search for free memory */
66 if ((MdBlock->MemoryType == LoaderFree) ||
67 (MdBlock->MemoryType == LoaderFirmwareTemporary))
68 {
69 /* Make sure the page is within bounds, including alignment */
70 BasePage = MdBlock->BasePage;
71 if ((BasePage) &&
72 (MdBlock->PageCount >= PageCount + Alignment) &&
73 (BasePage + PageCount + Alignment < MaxPage))
74 {
75
76 /* We found an address */
77 PhysicalAddress = (BasePage + Alignment) << PAGE_SHIFT;
78 break;
79 }
80 }
81
82 /* Keep trying */
83 NextEntry = NextEntry->Flink;
84 }
85
86 /* If we didn't find anything, get out of here */
87 if (NextEntry == &LoaderBlock->MemoryDescriptorListHead) return 0;
88
89 /* Okay, now get a descriptor */
90 NewBlock = &HalpAllocationDescriptorArray[HalpUsedAllocDescriptors];
91 NewBlock->PageCount = PageCount;
92 NewBlock->BasePage = MdBlock->BasePage + Alignment;
93 NewBlock->MemoryType = LoaderHALCachedMemory;
94
95 /* Update count */
96 UsedDescriptors++;
97 HalpUsedAllocDescriptors = UsedDescriptors;
98
99 /* Check if we had any alignment */
100 if (Alignment)
101 {
102 /* Check if we had leftovers */
103 if ((MdBlock->PageCount - Alignment) != PageCount)
104 {
105 /* Get the next descriptor */
106 FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors];
107 FreeBlock->PageCount = MdBlock->PageCount - Alignment - PageCount;
108 FreeBlock->BasePage = MdBlock->BasePage + Alignment + PageCount;
109
110 /* One more */
111 HalpUsedAllocDescriptors++;
112
113 /* Insert it into the list */
114 InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry);
115 }
116
117 /* Use this descriptor */
118 NewBlock->PageCount = Alignment;
119 InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry);
120 }
121 else
122 {
123 /* Consume memory from this block */
124 MdBlock->BasePage += PageCount;
125 MdBlock->PageCount -= PageCount;
126
127 /* Insert the descriptor */
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 ULONG PageCount)
142 {
143 PHARDWARE_PTE PointerPte;
144 ULONG 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 = 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 ULONG PageCount)
210 {
211 PHARDWARE_PTE PointerPte;
212 ULONG i;
213
214 /* Only accept valid addresses */
215 if (VirtualAddress < 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