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