Merge pull request #2284 from lioncash/heap-alloc
kernel/vm_manager: Unify heap allocation/freeing functions
This commit is contained in:
commit
16dc3a1dd5
3 changed files with 82 additions and 60 deletions
|
@ -175,11 +175,8 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
||||||
return ERR_INVALID_SIZE;
|
return ERR_INVALID_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
auto& vm_manager = Core::System::GetInstance().Kernel().CurrentProcess()->VMManager();
|
||||||
const VAddr heap_base = vm_manager.GetHeapRegionBaseAddress();
|
const auto alloc_result = vm_manager.SetHeapSize(heap_size);
|
||||||
const auto alloc_result =
|
|
||||||
vm_manager.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite);
|
|
||||||
|
|
||||||
if (alloc_result.Failed()) {
|
if (alloc_result.Failed()) {
|
||||||
return alloc_result.Code();
|
return alloc_result.Code();
|
||||||
}
|
}
|
||||||
|
@ -809,7 +806,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
|
||||||
case GetInfoType::TotalHeapUsage:
|
case GetInfoType::TotalHeapUsage:
|
||||||
*result = process->VMManager().GetTotalHeapUsage();
|
*result = process->VMManager().GetCurrentHeapSize();
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
|
||||||
case GetInfoType::IsVirtualAddressMemoryEnabled:
|
case GetInfoType::IsVirtualAddressMemoryEnabled:
|
||||||
|
|
|
@ -256,57 +256,50 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
|
ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
|
||||||
if (!IsWithinHeapRegion(target, size)) {
|
if (size > GetHeapRegionSize()) {
|
||||||
return ERR_INVALID_ADDRESS;
|
return ERR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to do any additional work if the heap is already the given size.
|
||||||
|
if (size == GetCurrentHeapSize()) {
|
||||||
|
return MakeResult(heap_region_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heap_memory == nullptr) {
|
if (heap_memory == nullptr) {
|
||||||
// Initialize heap
|
// Initialize heap
|
||||||
heap_memory = std::make_shared<std::vector<u8>>();
|
heap_memory = std::make_shared<std::vector<u8>>(size);
|
||||||
heap_start = heap_end = target;
|
heap_end = heap_region_base + size;
|
||||||
} else {
|
} else {
|
||||||
UnmapRange(heap_start, heap_end - heap_start);
|
UnmapRange(heap_region_base, GetCurrentHeapSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If necessary, expand backing vector to cover new heap extents.
|
// If necessary, expand backing vector to cover new heap extents in
|
||||||
if (target < heap_start) {
|
// the case of allocating. Otherwise, shrink the backing memory,
|
||||||
heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
|
// if a smaller heap has been requested.
|
||||||
heap_start = target;
|
const u64 old_heap_size = GetCurrentHeapSize();
|
||||||
|
if (size > old_heap_size) {
|
||||||
|
const u64 alloc_size = size - old_heap_size;
|
||||||
|
|
||||||
|
heap_memory->insert(heap_memory->end(), alloc_size, 0);
|
||||||
|
RefreshMemoryBlockMappings(heap_memory.get());
|
||||||
|
} else if (size < old_heap_size) {
|
||||||
|
heap_memory->resize(size);
|
||||||
|
heap_memory->shrink_to_fit();
|
||||||
|
|
||||||
RefreshMemoryBlockMappings(heap_memory.get());
|
RefreshMemoryBlockMappings(heap_memory.get());
|
||||||
}
|
}
|
||||||
if (target + size > heap_end) {
|
|
||||||
heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
|
|
||||||
heap_end = target + size;
|
|
||||||
RefreshMemoryBlockMappings(heap_memory.get());
|
|
||||||
}
|
|
||||||
ASSERT(heap_end - heap_start == heap_memory->size());
|
|
||||||
|
|
||||||
CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size,
|
heap_end = heap_region_base + size;
|
||||||
MemoryState::Heap));
|
ASSERT(GetCurrentHeapSize() == heap_memory->size());
|
||||||
Reprotect(vma, perms);
|
|
||||||
|
|
||||||
heap_used = size;
|
const auto mapping_result =
|
||||||
|
MapMemoryBlock(heap_region_base, heap_memory, 0, size, MemoryState::Heap);
|
||||||
return MakeResult<VAddr>(heap_end - size);
|
if (mapping_result.Failed()) {
|
||||||
|
return mapping_result.Code();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode VMManager::HeapFree(VAddr target, u64 size) {
|
return MakeResult<VAddr>(heap_region_base);
|
||||||
if (!IsWithinHeapRegion(target, size)) {
|
|
||||||
return ERR_INVALID_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ResultCode result = UnmapRange(target, size);
|
|
||||||
if (result.IsError()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_used -= size;
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryInfo VMManager::QueryMemory(VAddr address) const {
|
MemoryInfo VMManager::QueryMemory(VAddr address) const {
|
||||||
|
@ -598,6 +591,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
|
||||||
|
|
||||||
heap_region_base = map_region_end;
|
heap_region_base = map_region_end;
|
||||||
heap_region_end = heap_region_base + heap_region_size;
|
heap_region_end = heap_region_base + heap_region_size;
|
||||||
|
heap_end = heap_region_base;
|
||||||
|
|
||||||
new_map_region_base = heap_region_end;
|
new_map_region_base = heap_region_end;
|
||||||
new_map_region_end = new_map_region_base + new_map_region_size;
|
new_map_region_end = new_map_region_base + new_map_region_size;
|
||||||
|
@ -692,10 +686,6 @@ u64 VMManager::GetTotalMemoryUsage() const {
|
||||||
return 0xF8000000;
|
return 0xF8000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 VMManager::GetTotalHeapUsage() const {
|
|
||||||
return heap_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
VAddr VMManager::GetAddressSpaceBaseAddress() const {
|
VAddr VMManager::GetAddressSpaceBaseAddress() const {
|
||||||
return address_space_base;
|
return address_space_base;
|
||||||
}
|
}
|
||||||
|
@ -778,6 +768,10 @@ u64 VMManager::GetHeapRegionSize() const {
|
||||||
return heap_region_end - heap_region_base;
|
return heap_region_end - heap_region_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 VMManager::GetCurrentHeapSize() const {
|
||||||
|
return heap_end - heap_region_base;
|
||||||
|
}
|
||||||
|
|
||||||
bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const {
|
bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const {
|
||||||
return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(),
|
return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(),
|
||||||
GetHeapRegionEndAddress());
|
GetHeapRegionEndAddress());
|
||||||
|
|
|
@ -380,11 +380,41 @@ public:
|
||||||
/// Changes the permissions of a range of addresses, splitting VMAs as necessary.
|
/// Changes the permissions of a range of addresses, splitting VMAs as necessary.
|
||||||
ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
|
ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
|
||||||
|
|
||||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
|
||||||
ResultCode HeapFree(VAddr target, u64 size);
|
|
||||||
|
|
||||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
|
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
|
||||||
|
|
||||||
|
/// Attempts to allocate a heap with the given size.
|
||||||
|
///
|
||||||
|
/// @param size The size of the heap to allocate in bytes.
|
||||||
|
///
|
||||||
|
/// @note If a heap is currently allocated, and this is called
|
||||||
|
/// with a size that is equal to the size of the current heap,
|
||||||
|
/// then this function will do nothing and return the current
|
||||||
|
/// heap's starting address, as there's no need to perform
|
||||||
|
/// any additional heap allocation work.
|
||||||
|
///
|
||||||
|
/// @note If a heap is currently allocated, and this is called
|
||||||
|
/// with a size less than the current heap's size, then
|
||||||
|
/// this function will attempt to shrink the heap.
|
||||||
|
///
|
||||||
|
/// @note If a heap is currently allocated, and this is called
|
||||||
|
/// with a size larger than the current heap's size, then
|
||||||
|
/// this function will attempt to extend the size of the heap.
|
||||||
|
///
|
||||||
|
/// @returns A result indicating either success or failure.
|
||||||
|
/// <p>
|
||||||
|
/// If successful, this function will return a result
|
||||||
|
/// containing the starting address to the allocated heap.
|
||||||
|
/// <p>
|
||||||
|
/// If unsuccessful, this function will return a result
|
||||||
|
/// containing an error code.
|
||||||
|
///
|
||||||
|
/// @pre The given size must lie within the allowable heap
|
||||||
|
/// memory region managed by this VMManager instance.
|
||||||
|
/// Failure to abide by this will result in ERR_OUT_OF_MEMORY
|
||||||
|
/// being returned as the result.
|
||||||
|
///
|
||||||
|
ResultVal<VAddr> SetHeapSize(u64 size);
|
||||||
|
|
||||||
/// Queries the memory manager for information about the given address.
|
/// Queries the memory manager for information about the given address.
|
||||||
///
|
///
|
||||||
/// @param address The address to query the memory manager about for information.
|
/// @param address The address to query the memory manager about for information.
|
||||||
|
@ -418,9 +448,6 @@ public:
|
||||||
/// Gets the total memory usage, used by svcGetInfo
|
/// Gets the total memory usage, used by svcGetInfo
|
||||||
u64 GetTotalMemoryUsage() const;
|
u64 GetTotalMemoryUsage() const;
|
||||||
|
|
||||||
/// Gets the total heap usage, used by svcGetInfo
|
|
||||||
u64 GetTotalHeapUsage() const;
|
|
||||||
|
|
||||||
/// Gets the address space base address
|
/// Gets the address space base address
|
||||||
VAddr GetAddressSpaceBaseAddress() const;
|
VAddr GetAddressSpaceBaseAddress() const;
|
||||||
|
|
||||||
|
@ -469,6 +496,13 @@ public:
|
||||||
/// Gets the total size of the heap region in bytes.
|
/// Gets the total size of the heap region in bytes.
|
||||||
u64 GetHeapRegionSize() const;
|
u64 GetHeapRegionSize() const;
|
||||||
|
|
||||||
|
/// Gets the total size of the current heap in bytes.
|
||||||
|
///
|
||||||
|
/// @note This is the current allocated heap size, not the size
|
||||||
|
/// of the region it's allowed to exist within.
|
||||||
|
///
|
||||||
|
u64 GetCurrentHeapSize() const;
|
||||||
|
|
||||||
/// Determines whether or not the specified range is within the heap region.
|
/// Determines whether or not the specified range is within the heap region.
|
||||||
bool IsWithinHeapRegion(VAddr address, u64 size) const;
|
bool IsWithinHeapRegion(VAddr address, u64 size) const;
|
||||||
|
|
||||||
|
@ -617,9 +651,6 @@ private:
|
||||||
VAddr new_map_region_base = 0;
|
VAddr new_map_region_base = 0;
|
||||||
VAddr new_map_region_end = 0;
|
VAddr new_map_region_end = 0;
|
||||||
|
|
||||||
VAddr main_code_region_base = 0;
|
|
||||||
VAddr main_code_region_end = 0;
|
|
||||||
|
|
||||||
VAddr tls_io_region_base = 0;
|
VAddr tls_io_region_base = 0;
|
||||||
VAddr tls_io_region_end = 0;
|
VAddr tls_io_region_end = 0;
|
||||||
|
|
||||||
|
@ -628,9 +659,9 @@ private:
|
||||||
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
||||||
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
|
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
|
||||||
std::shared_ptr<std::vector<u8>> heap_memory;
|
std::shared_ptr<std::vector<u8>> heap_memory;
|
||||||
// The left/right bounds of the address space covered by heap_memory.
|
|
||||||
VAddr heap_start = 0;
|
// The end of the currently allocated heap. This is not an inclusive
|
||||||
|
// end of the range. This is essentially 'base_address + current_size'.
|
||||||
VAddr heap_end = 0;
|
VAddr heap_end = 0;
|
||||||
u64 heap_used = 0;
|
|
||||||
};
|
};
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
Loading…
Reference in a new issue