summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/svc.cpp9
-rw-r--r--src/core/hle/kernel/vm_manager.cpp76
-rw-r--r--src/core/hle/kernel/vm_manager.h55
3 files changed, 81 insertions, 59 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index e5e7f99e1..09d1eadb6 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -175,11 +175,8 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
175 return ERR_INVALID_SIZE; 175 return ERR_INVALID_SIZE;
176 } 176 }
177 177
178 auto& vm_manager = Core::CurrentProcess()->VMManager(); 178 auto& vm_manager = Core::System::GetInstance().Kernel().CurrentProcess()->VMManager();
179 const VAddr heap_base = vm_manager.GetHeapRegionBaseAddress(); 179 const auto alloc_result = vm_manager.SetHeapSize(heap_size);
180 const auto alloc_result =
181 vm_manager.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite);
182
183 if (alloc_result.Failed()) { 180 if (alloc_result.Failed()) {
184 return alloc_result.Code(); 181 return alloc_result.Code();
185 } 182 }
@@ -809,7 +806,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
809 return RESULT_SUCCESS; 806 return RESULT_SUCCESS;
810 807
811 case GetInfoType::TotalHeapUsage: 808 case GetInfoType::TotalHeapUsage:
812 *result = process->VMManager().GetTotalHeapUsage(); 809 *result = process->VMManager().GetCurrentHeapSize();
813 return RESULT_SUCCESS; 810 return RESULT_SUCCESS;
814 811
815 case GetInfoType::IsVirtualAddressMemoryEnabled: 812 case GetInfoType::IsVirtualAddressMemoryEnabled:
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 22bf55ce7..ec0a480ce 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -256,57 +256,50 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
256 return RESULT_SUCCESS; 256 return RESULT_SUCCESS;
257} 257}
258 258
259ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 259ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
260 if (!IsWithinHeapRegion(target, size)) { 260 if (size > GetHeapRegionSize()) {
261 return ERR_INVALID_ADDRESS; 261 return ERR_OUT_OF_MEMORY;
262 }
263
264 // No need to do any additional work if the heap is already the given size.
265 if (size == GetCurrentHeapSize()) {
266 return MakeResult(heap_region_base);
262 } 267 }
263 268
264 if (heap_memory == nullptr) { 269 if (heap_memory == nullptr) {
265 // Initialize heap 270 // Initialize heap
266 heap_memory = std::make_shared<std::vector<u8>>(); 271 heap_memory = std::make_shared<std::vector<u8>>(size);
267 heap_start = heap_end = target; 272 heap_end = heap_region_base + size;
268 } else { 273 } else {
269 UnmapRange(heap_start, heap_end - heap_start); 274 UnmapRange(heap_region_base, GetCurrentHeapSize());
270 }
271
272 // If necessary, expand backing vector to cover new heap extents.
273 if (target < heap_start) {
274 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
275 heap_start = target;
276 RefreshMemoryBlockMappings(heap_memory.get());
277 }
278 if (target + size > heap_end) {
279 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
280 heap_end = target + size;
281 RefreshMemoryBlockMappings(heap_memory.get());
282 } 275 }
283 ASSERT(heap_end - heap_start == heap_memory->size());
284 276
285 CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size, 277 // If necessary, expand backing vector to cover new heap extents in
286 MemoryState::Heap)); 278 // the case of allocating. Otherwise, shrink the backing memory,
287 Reprotect(vma, perms); 279 // if a smaller heap has been requested.
280 const u64 old_heap_size = GetCurrentHeapSize();
281 if (size > old_heap_size) {
282 const u64 alloc_size = size - old_heap_size;
288 283
289 heap_used = size; 284 heap_memory->insert(heap_memory->end(), alloc_size, 0);
290 285 RefreshMemoryBlockMappings(heap_memory.get());
291 return MakeResult<VAddr>(heap_end - size); 286 } else if (size < old_heap_size) {
292} 287 heap_memory->resize(size);
288 heap_memory->shrink_to_fit();
293 289
294ResultCode VMManager::HeapFree(VAddr target, u64 size) { 290 RefreshMemoryBlockMappings(heap_memory.get());
295 if (!IsWithinHeapRegion(target, size)) {
296 return ERR_INVALID_ADDRESS;
297 } 291 }
298 292
299 if (size == 0) { 293 heap_end = heap_region_base + size;
300 return RESULT_SUCCESS; 294 ASSERT(GetCurrentHeapSize() == heap_memory->size());
301 }
302 295
303 const ResultCode result = UnmapRange(target, size); 296 const auto mapping_result =
304 if (result.IsError()) { 297 MapMemoryBlock(heap_region_base, heap_memory, 0, size, MemoryState::Heap);
305 return result; 298 if (mapping_result.Failed()) {
299 return mapping_result.Code();
306 } 300 }
307 301
308 heap_used -= size; 302 return MakeResult<VAddr>(heap_region_base);
309 return RESULT_SUCCESS;
310} 303}
311 304
312MemoryInfo VMManager::QueryMemory(VAddr address) const { 305MemoryInfo VMManager::QueryMemory(VAddr address) const {
@@ -598,6 +591,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
598 591
599 heap_region_base = map_region_end; 592 heap_region_base = map_region_end;
600 heap_region_end = heap_region_base + heap_region_size; 593 heap_region_end = heap_region_base + heap_region_size;
594 heap_end = heap_region_base;
601 595
602 new_map_region_base = heap_region_end; 596 new_map_region_base = heap_region_end;
603 new_map_region_end = new_map_region_base + new_map_region_size; 597 new_map_region_end = new_map_region_base + new_map_region_size;
@@ -692,10 +686,6 @@ u64 VMManager::GetTotalMemoryUsage() const {
692 return 0xF8000000; 686 return 0xF8000000;
693} 687}
694 688
695u64 VMManager::GetTotalHeapUsage() const {
696 return heap_used;
697}
698
699VAddr VMManager::GetAddressSpaceBaseAddress() const { 689VAddr VMManager::GetAddressSpaceBaseAddress() const {
700 return address_space_base; 690 return address_space_base;
701} 691}
@@ -778,6 +768,10 @@ u64 VMManager::GetHeapRegionSize() const {
778 return heap_region_end - heap_region_base; 768 return heap_region_end - heap_region_base;
779} 769}
780 770
771u64 VMManager::GetCurrentHeapSize() const {
772 return heap_end - heap_region_base;
773}
774
781bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const { 775bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const {
782 return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(), 776 return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(),
783 GetHeapRegionEndAddress()); 777 GetHeapRegionEndAddress());
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 7cdff6094..6f484b7bf 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -380,11 +380,41 @@ public:
380 /// Changes the permissions of a range of addresses, splitting VMAs as necessary. 380 /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
381 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); 381 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
382 382
383 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
384 ResultCode HeapFree(VAddr target, u64 size);
385
386 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state); 383 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
387 384
385 /// Attempts to allocate a heap with the given size.
386 ///
387 /// @param size The size of the heap to allocate in bytes.
388 ///
389 /// @note If a heap is currently allocated, and this is called
390 /// with a size that is equal to the size of the current heap,
391 /// then this function will do nothing and return the current
392 /// heap's starting address, as there's no need to perform
393 /// any additional heap allocation work.
394 ///
395 /// @note If a heap is currently allocated, and this is called
396 /// with a size less than the current heap's size, then
397 /// this function will attempt to shrink the heap.
398 ///
399 /// @note If a heap is currently allocated, and this is called
400 /// with a size larger than the current heap's size, then
401 /// this function will attempt to extend the size of the heap.
402 ///
403 /// @returns A result indicating either success or failure.
404 /// <p>
405 /// If successful, this function will return a result
406 /// containing the starting address to the allocated heap.
407 /// <p>
408 /// If unsuccessful, this function will return a result
409 /// containing an error code.
410 ///
411 /// @pre The given size must lie within the allowable heap
412 /// memory region managed by this VMManager instance.
413 /// Failure to abide by this will result in ERR_OUT_OF_MEMORY
414 /// being returned as the result.
415 ///
416 ResultVal<VAddr> SetHeapSize(u64 size);
417
388 /// Queries the memory manager for information about the given address. 418 /// Queries the memory manager for information about the given address.
389 /// 419 ///
390 /// @param address The address to query the memory manager about for information. 420 /// @param address The address to query the memory manager about for information.
@@ -418,9 +448,6 @@ public:
418 /// Gets the total memory usage, used by svcGetInfo 448 /// Gets the total memory usage, used by svcGetInfo
419 u64 GetTotalMemoryUsage() const; 449 u64 GetTotalMemoryUsage() const;
420 450
421 /// Gets the total heap usage, used by svcGetInfo
422 u64 GetTotalHeapUsage() const;
423
424 /// Gets the address space base address 451 /// Gets the address space base address
425 VAddr GetAddressSpaceBaseAddress() const; 452 VAddr GetAddressSpaceBaseAddress() const;
426 453
@@ -469,6 +496,13 @@ public:
469 /// Gets the total size of the heap region in bytes. 496 /// Gets the total size of the heap region in bytes.
470 u64 GetHeapRegionSize() const; 497 u64 GetHeapRegionSize() const;
471 498
499 /// Gets the total size of the current heap in bytes.
500 ///
501 /// @note This is the current allocated heap size, not the size
502 /// of the region it's allowed to exist within.
503 ///
504 u64 GetCurrentHeapSize() const;
505
472 /// Determines whether or not the specified range is within the heap region. 506 /// Determines whether or not the specified range is within the heap region.
473 bool IsWithinHeapRegion(VAddr address, u64 size) const; 507 bool IsWithinHeapRegion(VAddr address, u64 size) const;
474 508
@@ -617,9 +651,6 @@ private:
617 VAddr new_map_region_base = 0; 651 VAddr new_map_region_base = 0;
618 VAddr new_map_region_end = 0; 652 VAddr new_map_region_end = 0;
619 653
620 VAddr main_code_region_base = 0;
621 VAddr main_code_region_end = 0;
622
623 VAddr tls_io_region_base = 0; 654 VAddr tls_io_region_base = 0;
624 VAddr tls_io_region_end = 0; 655 VAddr tls_io_region_end = 0;
625 656
@@ -628,9 +659,9 @@ private:
628 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous 659 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
629 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. 660 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
630 std::shared_ptr<std::vector<u8>> heap_memory; 661 std::shared_ptr<std::vector<u8>> heap_memory;
631 // The left/right bounds of the address space covered by heap_memory. 662
632 VAddr heap_start = 0; 663 // The end of the currently allocated heap. This is not an inclusive
664 // end of the range. This is essentially 'base_address + current_size'.
633 VAddr heap_end = 0; 665 VAddr heap_end = 0;
634 u64 heap_used = 0;
635}; 666};
636} // namespace Kernel 667} // namespace Kernel