core: Ignore constraints on allocations if allocator is exhausted

Try to allocate within constraint area first. In case the area is exhausted,
try allocation at other memory locations.

The motivation for this is to limit DMA allocations to 4GB (since some
devices require addresses below 4GB). On some platforms there is little
physical RAM in this area (<1GB) and the constrainted area exhausts. In
case an IOMMU is present, RAM at higher locations can still be mapped
below 4GB, which is done in the platform drivers.

issue #4665
This commit is contained in:
Sebastian Sumpf 2022-11-04 08:10:20 +01:00 committed by Christian Helmuth
parent 77fc2f1e86
commit 0a8d6ddba9

View File

@ -40,16 +40,24 @@ Ram_dataspace_factory::try_alloc(size_t ds_size, Cache cache)
*/
Range_allocator::Alloc_result allocated_range = Allocator::Alloc_error::DENIED;
/*
* If no physical constraint exists, try to allocate physical memory at
* high locations (3G for 32-bit / 4G for 64-bit platforms) in order to
* preserve lower physical regions for device drivers, which may have DMA
* constraints.
*/
if (_phys_range.start == 0 && _phys_range.end == ~0UL) {
/* apply constraints */
if (_phys_range.start != 0 || _phys_range.end != ~0UL) {
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, _phys_range);
if (allocated_range.ok())
break;
}
}
/*
* If no physical constraint exists or constraints failed, try to allocate
* physical memory at high locations (3G for 32-bit / 4G for 64-bit platforms)
* in order to preserve lower physical regions for device drivers, which may
* have DMA constraints.
*/
if (!allocated_range.ok()) {
addr_t const high_start = (sizeof(void *) == 4 ? 3UL : 4UL) << 30;
Phys_range const range { .start = high_start, .end = _phys_range.end };
Phys_range const range { .start = high_start, .end = ~0UL };
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, range);
@ -58,7 +66,7 @@ Ram_dataspace_factory::try_alloc(size_t ds_size, Cache cache)
}
}
/* apply constraints, or retry if larger memory allocation failed */
/* retry if larger non-constrained memory allocation failed */
if (!allocated_range.ok()) {
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, _phys_range);