Explorar o código

Merge pull request #232 from bunnei/heap-fixes

Various heap fixes for libtransistor
bunnei %!s(int64=8) %!d(string=hai) anos
pai
achega
e7ba2a4447

+ 5 - 1
src/core/arm/arm_interface.h

@@ -39,8 +39,12 @@ public:
         Run(1);
     }
 
+    /// Maps a backing memory region for the CPU
     virtual void MapBackingMemory(VAddr address, size_t size, u8* memory,
-                                  Kernel::VMAPermission perms) {}
+                                  Kernel::VMAPermission perms) = 0;
+
+    /// Unmaps a region of memory that was previously mapped using MapBackingMemory
+    virtual void UnmapMemory(VAddr address, size_t size) = 0;
 
     /// Clear all instruction cache
     virtual void ClearInstructionCache() = 0;

+ 4 - 0
src/core/arm/dynarmic/arm_dynarmic.cpp

@@ -136,6 +136,10 @@ void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory,
     inner_unicorn.MapBackingMemory(address, size, memory, perms);
 }
 
+void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) {
+    inner_unicorn.UnmapMemory(address, size);
+}
+
 void ARM_Dynarmic::SetPC(u64 pc) {
     jit->SetPC(pc);
 }

+ 1 - 1
src/core/arm/dynarmic/arm_dynarmic.h

@@ -19,7 +19,7 @@ public:
 
     void MapBackingMemory(VAddr address, size_t size, u8* memory,
                           Kernel::VMAPermission perms) override;
-
+    void UnmapMemory(u64 address, size_t size) override;
     void SetPC(u64 pc) override;
     u64 GetPC() const override;
     u64 GetReg(int index) const override;

+ 4 - 0
src/core/arm/unicorn/arm_unicorn.cpp

@@ -77,6 +77,10 @@ void ARM_Unicorn::MapBackingMemory(VAddr address, size_t size, u8* memory,
     CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory));
 }
 
+void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) {
+    CHECKED(uc_mem_unmap(uc, address, size));
+}
+
 void ARM_Unicorn::SetPC(u64 pc) {
     CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
 }

+ 1 - 0
src/core/arm/unicorn/arm_unicorn.h

@@ -14,6 +14,7 @@ public:
     ~ARM_Unicorn();
     void MapBackingMemory(VAddr address, size_t size, u8* memory,
                           Kernel::VMAPermission perms) override;
+    void UnmapMemory(VAddr address, size_t size) override;
     void SetPC(u64 pc) override;
     u64 GetPC() const override;
     u64 GetReg(int index) const override;

+ 0 - 4
src/core/hle/kernel/kernel.h

@@ -33,10 +33,6 @@ enum class HandleType : u32 {
     ServerSession,
 };
 
-enum {
-    DEFAULT_STACK_SIZE = 0x10000,
-};
-
 enum class ResetType {
     OneShot,
     Sticky,

+ 12 - 9
src/core/hle/kernel/process.cpp

@@ -117,11 +117,12 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
 }
 
 void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
-    // Allocate and map stack
+    // Allocate and map the main thread stack
+    // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
+    // of the user address space.
     vm_manager
-        .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
-                        std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
-                        MemoryState::Heap)
+        .MapMemoryBlock(Memory::STACK_VADDR, std::make_shared<std::vector<u8>>(stack_size, 0), 0,
+                        stack_size, MemoryState::Mapped)
         .Unwrap();
     misc_memory_used += stack_size;
     memory_region->used += stack_size;
@@ -153,9 +154,9 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
     };
 
     // Map CodeSet segments
-    MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::Code);
-    MapSegment(module_->rodata, VMAPermission::Read, MemoryState::Static);
-    MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::Static);
+    MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic);
+    MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable);
+    MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable);
 }
 
 VAddr Process::GetLinearHeapAreaAddress() const {
@@ -182,6 +183,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
         // Initialize heap
         heap_memory = std::make_shared<std::vector<u8>>();
         heap_start = heap_end = target;
+    } else {
+        vm_manager.UnmapRange(heap_start, heap_end - heap_start);
     }
 
     // If necessary, expand backing vector to cover new heap extents.
@@ -201,7 +204,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
                                                        size, MemoryState::Heap));
     vm_manager.Reprotect(vma, perms);
 
-    heap_used += size;
+    heap_used = size;
     memory_region->used += size;
 
     return MakeResult<VAddr>(heap_end - size);
@@ -288,7 +291,7 @@ ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
 
     CASCADE_RESULT(auto new_vma,
                    vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
-                                             vma->second.meminfo_state));
+                                             MemoryState::Mapped));
     // Protect mirror with permissions from old region
     vm_manager.Reprotect(new_vma, vma->second.permissions);
     // Remove permissions from old region

+ 6 - 6
src/core/hle/kernel/svc.cpp

@@ -317,13 +317,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
         *result = Core::CurrentProcess()->allowed_thread_priority_mask;
         break;
     case GetInfoType::MapRegionBaseAddr:
-        *result = vm_manager.GetMapRegionBaseAddr();
+        *result = Memory::MAP_REGION_VADDR;
         break;
     case GetInfoType::MapRegionSize:
-        *result = vm_manager.GetAddressSpaceSize();
+        *result = Memory::MAP_REGION_SIZE;
         break;
     case GetInfoType::HeapRegionBaseAddr:
-        *result = vm_manager.GetNewMapRegionBaseAddr() + vm_manager.GetNewMapRegionSize();
+        *result = Memory::HEAP_VADDR;
         break;
     case GetInfoType::HeapRegionSize:
         *result = Memory::HEAP_SIZE;
@@ -347,10 +347,10 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
         *result = vm_manager.GetAddressSpaceSize();
         break;
     case GetInfoType::NewMapRegionBaseAddr:
-        *result = vm_manager.GetNewMapRegionBaseAddr();
+        *result = Memory::NEW_MAP_REGION_VADDR;
         break;
     case GetInfoType::NewMapRegionSize:
-        *result = vm_manager.GetNewMapRegionSize();
+        *result = Memory::NEW_MAP_REGION_SIZE;
         break;
     case GetInfoType::IsVirtualAddressMemoryEnabled:
         *result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
@@ -468,7 +468,7 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
         memory_info->base_address = 0;
         memory_info->permission = static_cast<u32>(VMAPermission::None);
         memory_info->size = 0;
-        memory_info->type = static_cast<u32>(MemoryState::Free);
+        memory_info->type = static_cast<u32>(MemoryState::Unmapped);
     } else {
         memory_info->base_address = vma->second.base;
         memory_info->permission = static_cast<u32>(vma->second.permissions);

+ 2 - 2
src/core/hle/kernel/thread.cpp

@@ -314,7 +314,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
         // TODO(Subv): Find the correct MemoryState for this region.
         vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
                                   linheap_memory, offset, Memory::PAGE_SIZE,
-                                  MemoryState::ThreadLocalStorage);
+                                  MemoryState::ThreadLocal);
     }
 
     // Mark the slot as used
@@ -357,7 +357,7 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
 
     // Initialize new "main" thread
     auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
-                                     Memory::HEAP_VADDR_END, owner_process);
+                                     Memory::STACK_VADDR_END, owner_process);
 
     SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
 

+ 24 - 18
src/core/hle/kernel/vm_manager.cpp

@@ -18,8 +18,26 @@ namespace Kernel {
 
 static const char* GetMemoryStateName(MemoryState state) {
     static const char* names[] = {
-        "Free",   "Reserved",   "IO",      "Static", "Code",      "Private",
-        "Shared", "Continuous", "Aliased", "Alias",  "AliasCode", "Locked",
+        "Unmapped",
+        "Io",
+        "Normal",
+        "CodeStatic",
+        "CodeMutable",
+        "Heap",
+        "Shared",
+        "Unknown1"
+        "ModuleCodeStatic",
+        "ModuleCodeMutable",
+        "IpcBuffer0",
+        "Mapped",
+        "ThreadLocal",
+        "TransferMemoryIsolated",
+        "TransferMemory",
+        "ProcessMemory",
+        "Unknown2"
+        "IpcBuffer1",
+        "IpcBuffer3",
+        "KernelStack",
     };
 
     return names[(int)state];
@@ -142,7 +160,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
     VirtualMemoryArea& vma = vma_handle->second;
     vma.type = VMAType::Free;
     vma.permissions = VMAPermission::None;
-    vma.meminfo_state = MemoryState::Free;
+    vma.meminfo_state = MemoryState::Unmapped;
 
     vma.backing_block = nullptr;
     vma.offset = 0;
@@ -166,6 +184,9 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
     }
 
     ASSERT(FindVMA(target)->second.size >= size);
+
+    Core::CPU().UnmapMemory(target, size);
+
     return RESULT_SUCCESS;
 }
 
@@ -377,19 +398,4 @@ u64 VMManager::GetAddressSpaceSize() {
     return MAX_ADDRESS;
 }
 
-VAddr VMManager::GetMapRegionBaseAddr() {
-    LOG_WARNING(Kernel, "(STUBBED) called");
-    return Memory::HEAP_VADDR;
-}
-
-VAddr VMManager::GetNewMapRegionBaseAddr() {
-    LOG_WARNING(Kernel, "(STUBBED) called");
-    return 0x8000000;
-}
-
-u64 VMManager::GetNewMapRegionSize() {
-    LOG_WARNING(Kernel, "(STUBBED) called");
-    return 0x8000000;
-}
-
 } // namespace Kernel

+ 19 - 19
src/core/hle/kernel/vm_manager.h

@@ -41,15 +41,24 @@ enum class VMAPermission : u8 {
 
 /// Set of values returned in MemoryInfo.state by svcQueryMemory.
 enum class MemoryState : u32 {
-    Free = 0,
-    IO = 1,
-    Normal = 2,
-    Code = 3,
-    Static = 4,
-    Heap = 5,
-    Shared = 6,
-    Mapped = 6,
-    ThreadLocalStorage = 12,
+    Unmapped = 0x0,
+    Io = 0x1,
+    Normal = 0x2,
+    CodeStatic = 0x3,
+    CodeMutable = 0x4,
+    Heap = 0x5,
+    Shared = 0x6,
+    ModuleCodeStatic = 0x8,
+    ModuleCodeMutable = 0x9,
+    IpcBuffer0 = 0xA,
+    Mapped = 0xB,
+    ThreadLocal = 0xC,
+    TransferMemoryIsolated = 0xD,
+    TransferMemory = 0xE,
+    ProcessMemory = 0xF,
+    IpcBuffer1 = 0x11,
+    IpcBuffer3 = 0x12,
+    KernelStack = 0x13,
 };
 
 /**
@@ -66,7 +75,7 @@ struct VirtualMemoryArea {
     VMAType type = VMAType::Free;
     VMAPermission permissions = VMAPermission::None;
     /// Tag returned by svcQueryMemory. Not otherwise used.
-    MemoryState meminfo_state = MemoryState::Free;
+    MemoryState meminfo_state = MemoryState::Unmapped;
 
     // Settings for type = AllocatedMemoryBlock
     /// Memory block backing this VMA.
@@ -192,15 +201,6 @@ public:
     /// Gets the total address space address size, used by svcGetInfo
     u64 GetAddressSpaceSize();
 
-    /// Gets the map region base address, used by svcGetInfo
-    VAddr GetMapRegionBaseAddr();
-
-    /// Gets the base address for a new memory region, used by svcGetInfo
-    VAddr GetNewMapRegionBaseAddr();
-
-    /// Gets the size for a new memory region, used by svcGetInfo
-    u64 GetNewMapRegionSize();
-
     /// Each VMManager has its own page table, which is set as the main one when the owning process
     /// is scheduled.
     Memory::PageTable page_table;

+ 1 - 1
src/core/loader/elf.cpp

@@ -414,7 +414,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     process->resource_limit =
         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
 
-    process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE);
+    process->Run(codeset->entrypoint, 48, Memory::STACK_SIZE);
 
     is_loaded = true;
     return ResultStatus::Success;

+ 1 - 1
src/core/loader/nro.cpp

@@ -137,7 +137,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     process->address_mappings = default_address_mappings;
     process->resource_limit =
         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
-    process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
+    process->Run(base_addr, 48, Memory::STACK_SIZE);
 
     is_loaded = true;
     return ResultStatus::Success;

+ 1 - 1
src/core/loader/nso.cpp

@@ -165,7 +165,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     process->address_mappings = default_address_mappings;
     process->resource_limit =
         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
-    process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
+    process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Memory::STACK_SIZE);
 
     is_loaded = true;
     return ResultStatus::Success;

+ 29 - 19
src/core/memory.h

@@ -129,21 +129,6 @@ enum : VAddr {
     PROCESS_IMAGE_MAX_SIZE = 0x08000000,
     PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
 
-    /// Area where IPC buffers are mapped onto.
-    IPC_MAPPING_VADDR = 0x04000000,
-    IPC_MAPPING_SIZE = 0x04000000,
-    IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE,
-
-    /// Application heap (includes stack).
-    HEAP_VADDR = 0x108000000,
-    HEAP_SIZE = 0xF0000000,
-    HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
-
-    /// Area where shared memory buffers are mapped onto.
-    SHARED_MEMORY_VADDR = 0x10000000,
-    SHARED_MEMORY_SIZE = 0x04000000,
-    SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE,
-
     /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
     /// memory.
     LINEAR_HEAP_VADDR = 0x14000000,
@@ -176,14 +161,39 @@ enum : VAddr {
     SHARED_PAGE_SIZE = 0x00001000,
     SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
 
-    /// Area where TLS (Thread-Local Storage) buffers are allocated.
-    TLS_AREA_VADDR = 0x228000000,
-    TLS_ENTRY_SIZE = 0x200,
-
     /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
     NEW_LINEAR_HEAP_VADDR = 0x30000000,
     NEW_LINEAR_HEAP_SIZE = 0x10000000,
     NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
+
+    /// Area where TLS (Thread-Local Storage) buffers are allocated.
+    TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END,
+    TLS_ENTRY_SIZE = 0x200,
+    TLS_AREA_SIZE = 0x10000000,
+    TLS_ADREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
+
+    /// Application stack
+    STACK_VADDR = TLS_ADREA_VADDR_END,
+    STACK_SIZE = 0x10000,
+    STACK_VADDR_END = STACK_VADDR + STACK_SIZE,
+
+    /// Application heap
+    /// Size is confirmed to be a static value on fw 3.0.0
+    HEAP_VADDR = 0x108000000,
+    HEAP_SIZE = 0x180000000,
+    HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
+
+    /// New map region
+    /// Size is confirmed to be a static value on fw 3.0.0
+    NEW_MAP_REGION_VADDR = HEAP_VADDR_END,
+    NEW_MAP_REGION_SIZE = 0x80000000,
+    NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE,
+
+    /// Map region
+    /// Size is confirmed to be a static value on fw 3.0.0
+    MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END,
+    MAP_REGION_SIZE = 0x1000000000,
+    MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE,
 };
 
 /// Currently active page table