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
9 /* INCLUDES ******************************************************************/
15 /* Share with Mm headers? */
16 #define MM_HAL_HEAP_START (PVOID)(MM_HAL_VA_START + (1024 * 1024))
18 /* GLOBALS *******************************************************************/
20 ULONG HalpUsedAllocDescriptors
;
21 MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray
[64];
22 PVOID HalpHeapStart
= MM_HAL_HEAP_START
;
25 /* PRIVATE FUNCTIONS *********************************************************/
29 HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
30 IN ULONG64 MaxAddress
,
31 IN PFN_NUMBER PageCount
,
34 ULONG UsedDescriptors
;
35 ULONG64 PhysicalAddress
;
36 PFN_NUMBER MaxPage
, BasePage
, Alignment
;
37 PLIST_ENTRY NextEntry
;
38 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
, NewBlock
, FreeBlock
;
40 /* Highest page we'll go */
41 MaxPage
= MaxAddress
>> PAGE_SHIFT
;
43 /* We need at least two blocks */
44 if ((HalpUsedAllocDescriptors
+ 2) > 64) return 0;
46 /* Remember how many we have now */
47 UsedDescriptors
= HalpUsedAllocDescriptors
;
49 /* Loop the loader block memory descriptors */
50 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
51 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
54 MdBlock
= CONTAINING_RECORD(NextEntry
,
55 MEMORY_ALLOCATION_DESCRIPTOR
,
58 /* No alignment by default */
61 /* Unless requested, in which case we use a 64KB block alignment */
62 if (Aligned
) Alignment
= ((MdBlock
->BasePage
+ 0x0F) & ~0x0F) - MdBlock
->BasePage
;
64 /* Search for free memory */
65 if ((MdBlock
->MemoryType
== LoaderFree
) ||
66 (MdBlock
->MemoryType
== LoaderFirmwareTemporary
))
68 /* Make sure the page is within bounds, including alignment */
69 BasePage
= MdBlock
->BasePage
;
71 (MdBlock
->PageCount
>= PageCount
+ Alignment
) &&
72 (BasePage
+ PageCount
+ Alignment
< MaxPage
))
74 /* We found an address */
75 PhysicalAddress
= ((ULONG64
)BasePage
+ Alignment
) << PAGE_SHIFT
;
81 NextEntry
= NextEntry
->Flink
;
84 /* If we didn't find anything, get out of here */
85 if (NextEntry
== &LoaderBlock
->MemoryDescriptorListHead
) return 0;
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
;
95 HalpUsedAllocDescriptors
= UsedDescriptors
;
97 /* Check if we had any alignment */
100 /* Check if we had leftovers */
101 if (MdBlock
->PageCount
> (PageCount
+ Alignment
))
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
;
109 HalpUsedAllocDescriptors
++;
111 /* Insert it into the list */
112 InsertHeadList(&MdBlock
->ListEntry
, &FreeBlock
->ListEntry
);
115 /* Trim the original block to the alignment only */
116 MdBlock
->PageCount
= Alignment
;
118 /* Insert the descriptor after the original one */
119 InsertHeadList(&MdBlock
->ListEntry
, &NewBlock
->ListEntry
);
123 /* Consume memory from this block */
124 MdBlock
->BasePage
+= (ULONG
)PageCount
;
125 MdBlock
->PageCount
-= (ULONG
)PageCount
;
127 /* Insert the descriptor before the original one */
128 InsertTailList(&MdBlock
->ListEntry
, &NewBlock
->ListEntry
);
130 /* Remove the entry if the whole block was allocated */
131 if (MdBlock
->PageCount
== 0) RemoveEntryList(&MdBlock
->ListEntry
);
134 /* Return the address */
135 return PhysicalAddress
;
140 HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress
,
141 IN PFN_COUNT PageCount
)
143 return HalpMapPhysicalMemory64Vista(PhysicalAddress
, PageCount
, TRUE
);
148 HalpUnmapVirtualAddress(IN PVOID VirtualAddress
,
149 IN PFN_COUNT PageCount
)
151 HalpUnmapVirtualAddressVista(VirtualAddress
, PageCount
, TRUE
);
156 HalpMapPhysicalMemory64Vista(IN PHYSICAL_ADDRESS PhysicalAddress
,
157 IN PFN_COUNT PageCount
,
158 IN BOOLEAN FlushCurrentTLB
)
160 PHARDWARE_PTE PointerPte
;
161 PFN_NUMBER UsedPages
= 0;
162 PVOID VirtualAddress
, BaseAddress
;
164 /* Start at the current HAL heap base */
165 BaseAddress
= HalpHeapStart
;
166 VirtualAddress
= BaseAddress
;
168 /* Loop until we have all the pages required */
169 while (UsedPages
< PageCount
)
171 /* If this overflows past the HAL heap, it means there's no space */
172 if (VirtualAddress
== NULL
) return NULL
;
174 /* Get the PTE for this address */
175 PointerPte
= HalAddressToPte(VirtualAddress
);
177 /* Go to the next page */
178 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
180 /* Check if the page is available */
181 if (PointerPte
->Valid
)
183 /* PTE has data, skip it and start with a new base address */
184 BaseAddress
= VirtualAddress
;
189 /* PTE is available, keep going on this run */
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
));
197 /* If we are starting at the heap, move the heap */
198 if (BaseAddress
== HalpHeapStart
)
200 /* Past this allocation */
201 HalpHeapStart
= (PVOID
)((ULONG_PTR
)BaseAddress
+ (PageCount
* PAGE_SIZE
));
204 /* Loop pages that can be mapped */
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;
213 /* Move to the next address */
214 PhysicalAddress
.QuadPart
+= PAGE_SIZE
;
215 BaseAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
+ PAGE_SIZE
);
218 /* Flush the TLB and return the address */
222 return VirtualAddress
;
227 HalpUnmapVirtualAddressVista(IN PVOID VirtualAddress
,
228 IN PFN_COUNT PageCount
,
229 IN BOOLEAN FlushCurrentTLB
)
231 PHARDWARE_PTE PointerPte
;
234 /* Only accept valid addresses */
235 if (VirtualAddress
< (PVOID
)MM_HAL_VA_START
) return;
237 /* Align it down to page size */
238 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
& ~(PAGE_SIZE
- 1));
241 PointerPte
= HalAddressToPte(VirtualAddress
);
242 for (i
= 0; i
< PageCount
; i
++)
244 *(PULONG
)PointerPte
= 0;
252 /* Put the heap back */
253 if (HalpHeapStart
> VirtualAddress
) HalpHeapStart
= VirtualAddress
;