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