Merge pull request #232 from bunnei/heap-fixes

Various heap fixes for libtransistor
This commit is contained in:
bunnei 2018-03-16 20:06:27 -04:00 committed by GitHub
commit e7ba2a4447
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 110 additions and 82 deletions

View file

@ -39,8 +39,12 @@ public:
Run(1); Run(1);
} }
/// Maps a backing memory region for the CPU
virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, 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 /// Clear all instruction cache
virtual void ClearInstructionCache() = 0; virtual void ClearInstructionCache() = 0;

View file

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

View file

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

View file

@ -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)); 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) { void ARM_Unicorn::SetPC(u64 pc) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc)); CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
} }

View file

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

View file

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

View file

@ -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) { 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 vm_manager
.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, .MapMemoryBlock(Memory::STACK_VADDR, std::make_shared<std::vector<u8>>(stack_size, 0), 0,
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, stack_size, MemoryState::Mapped)
MemoryState::Heap)
.Unwrap(); .Unwrap();
misc_memory_used += stack_size; misc_memory_used += stack_size;
memory_region->used += stack_size; memory_region->used += stack_size;
@ -153,9 +154,9 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
}; };
// Map CodeSet segments // Map CodeSet segments
MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::Code); MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic);
MapSegment(module_->rodata, VMAPermission::Read, MemoryState::Static); MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable);
MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::Static); MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable);
} }
VAddr Process::GetLinearHeapAreaAddress() const { VAddr Process::GetLinearHeapAreaAddress() const {
@ -182,6 +183,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
// Initialize heap // Initialize heap
heap_memory = std::make_shared<std::vector<u8>>(); heap_memory = std::make_shared<std::vector<u8>>();
heap_start = heap_end = target; 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. // 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)); size, MemoryState::Heap));
vm_manager.Reprotect(vma, perms); vm_manager.Reprotect(vma, perms);
heap_used += size; heap_used = size;
memory_region->used += size; memory_region->used += size;
return MakeResult<VAddr>(heap_end - 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, CASCADE_RESULT(auto new_vma,
vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
vma->second.meminfo_state)); MemoryState::Mapped));
// Protect mirror with permissions from old region // Protect mirror with permissions from old region
vm_manager.Reprotect(new_vma, vma->second.permissions); vm_manager.Reprotect(new_vma, vma->second.permissions);
// Remove permissions from old region // Remove permissions from old region

View file

@ -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; *result = Core::CurrentProcess()->allowed_thread_priority_mask;
break; break;
case GetInfoType::MapRegionBaseAddr: case GetInfoType::MapRegionBaseAddr:
*result = vm_manager.GetMapRegionBaseAddr(); *result = Memory::MAP_REGION_VADDR;
break; break;
case GetInfoType::MapRegionSize: case GetInfoType::MapRegionSize:
*result = vm_manager.GetAddressSpaceSize(); *result = Memory::MAP_REGION_SIZE;
break; break;
case GetInfoType::HeapRegionBaseAddr: case GetInfoType::HeapRegionBaseAddr:
*result = vm_manager.GetNewMapRegionBaseAddr() + vm_manager.GetNewMapRegionSize(); *result = Memory::HEAP_VADDR;
break; break;
case GetInfoType::HeapRegionSize: case GetInfoType::HeapRegionSize:
*result = Memory::HEAP_SIZE; *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(); *result = vm_manager.GetAddressSpaceSize();
break; break;
case GetInfoType::NewMapRegionBaseAddr: case GetInfoType::NewMapRegionBaseAddr:
*result = vm_manager.GetNewMapRegionBaseAddr(); *result = Memory::NEW_MAP_REGION_VADDR;
break; break;
case GetInfoType::NewMapRegionSize: case GetInfoType::NewMapRegionSize:
*result = vm_manager.GetNewMapRegionSize(); *result = Memory::NEW_MAP_REGION_SIZE;
break; break;
case GetInfoType::IsVirtualAddressMemoryEnabled: case GetInfoType::IsVirtualAddressMemoryEnabled:
*result = Core::CurrentProcess()->is_virtual_address_memory_enabled; *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->base_address = 0;
memory_info->permission = static_cast<u32>(VMAPermission::None); memory_info->permission = static_cast<u32>(VMAPermission::None);
memory_info->size = 0; memory_info->size = 0;
memory_info->type = static_cast<u32>(MemoryState::Free); memory_info->type = static_cast<u32>(MemoryState::Unmapped);
} else { } else {
memory_info->base_address = vma->second.base; memory_info->base_address = vma->second.base;
memory_info->permission = static_cast<u32>(vma->second.permissions); memory_info->permission = static_cast<u32>(vma->second.permissions);

View file

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

View file

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

View file

@ -41,15 +41,24 @@ enum class VMAPermission : u8 {
/// Set of values returned in MemoryInfo.state by svcQueryMemory. /// Set of values returned in MemoryInfo.state by svcQueryMemory.
enum class MemoryState : u32 { enum class MemoryState : u32 {
Free = 0, Unmapped = 0x0,
IO = 1, Io = 0x1,
Normal = 2, Normal = 0x2,
Code = 3, CodeStatic = 0x3,
Static = 4, CodeMutable = 0x4,
Heap = 5, Heap = 0x5,
Shared = 6, Shared = 0x6,
Mapped = 6, ModuleCodeStatic = 0x8,
ThreadLocalStorage = 12, 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; VMAType type = VMAType::Free;
VMAPermission permissions = VMAPermission::None; VMAPermission permissions = VMAPermission::None;
/// Tag returned by svcQueryMemory. Not otherwise used. /// Tag returned by svcQueryMemory. Not otherwise used.
MemoryState meminfo_state = MemoryState::Free; MemoryState meminfo_state = MemoryState::Unmapped;
// Settings for type = AllocatedMemoryBlock // Settings for type = AllocatedMemoryBlock
/// Memory block backing this VMA. /// Memory block backing this VMA.
@ -192,15 +201,6 @@ public:
/// Gets the total address space address size, used by svcGetInfo /// Gets the total address space address size, used by svcGetInfo
u64 GetAddressSpaceSize(); 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 /// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled. /// is scheduled.
Memory::PageTable page_table; Memory::PageTable page_table;

View file

@ -414,7 +414,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 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; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;

View file

@ -137,7 +137,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->address_mappings = default_address_mappings; process->address_mappings = default_address_mappings;
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 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; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;

View file

@ -165,7 +165,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->address_mappings = default_address_mappings; process->address_mappings = default_address_mappings;
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 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; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;

View file

@ -129,21 +129,6 @@ enum : VAddr {
PROCESS_IMAGE_MAX_SIZE = 0x08000000, PROCESS_IMAGE_MAX_SIZE = 0x08000000,
PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, 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 /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
/// memory. /// memory.
LINEAR_HEAP_VADDR = 0x14000000, LINEAR_HEAP_VADDR = 0x14000000,
@ -176,14 +161,39 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000, SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 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. /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
NEW_LINEAR_HEAP_VADDR = 0x30000000, NEW_LINEAR_HEAP_VADDR = 0x30000000,
NEW_LINEAR_HEAP_SIZE = 0x10000000, NEW_LINEAR_HEAP_SIZE = 0x10000000,
NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE, 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 /// Currently active page table