diff options
Diffstat (limited to 'src/core/hle/kernel/process.cpp')
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 2cd1cfc14..1f45e6cf8 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -96,7 +96,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 96 | 96 | ||
| 97 | int minor = kernel_version & 0xFF; | 97 | int minor = kernel_version & 0xFF; |
| 98 | int major = (kernel_version >> 8) & 0xFF; | 98 | int major = (kernel_version >> 8) & 0xFF; |
| 99 | LOG_DEBUG(Loader, "ExHeader kernel version: %d.%d", major, minor); | 99 | LOG_INFO(Loader, "ExHeader kernel version: %d.%d", major, minor); |
| 100 | } else { | 100 | } else { |
| 101 | LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); | 101 | LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); |
| 102 | } | 102 | } |
| @@ -104,6 +104,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | void Process::Run(s32 main_thread_priority, u32 stack_size) { | 106 | void Process::Run(s32 main_thread_priority, u32 stack_size) { |
| 107 | memory_region = GetMemoryRegion(flags.memory_region); | ||
| 108 | |||
| 107 | auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { | 109 | auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { |
| 108 | auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, | 110 | auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, |
| 109 | segment.offset, segment.size, memory_state).Unwrap(); | 111 | segment.offset, segment.size, memory_state).Unwrap(); |
| @@ -124,6 +126,15 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| 124 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | 126 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 129 | VAddr Process::GetLinearHeapBase() const { | ||
| 130 | return (kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_SIZE) | ||
| 131 | + memory_region->base; | ||
| 132 | } | ||
| 133 | |||
| 134 | VAddr Process::GetLinearHeapLimit() const { | ||
| 135 | return GetLinearHeapBase() + memory_region->size; | ||
| 136 | } | ||
| 137 | |||
| 127 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { | 138 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { |
| 128 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { | 139 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { |
| 129 | return ERR_INVALID_ADDRESS; | 140 | return ERR_INVALID_ADDRESS; |
| @@ -166,19 +177,16 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | |||
| 166 | } | 177 | } |
| 167 | 178 | ||
| 168 | ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) { | 179 | ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) { |
| 169 | if (linear_heap_memory == nullptr) { | 180 | auto& linheap_memory = memory_region->linear_heap_memory; |
| 170 | // Initialize heap | ||
| 171 | linear_heap_memory = std::make_shared<std::vector<u8>>(); | ||
| 172 | } | ||
| 173 | 181 | ||
| 174 | VAddr heap_end = Memory::LINEAR_HEAP_VADDR + (u32)linear_heap_memory->size(); | 182 | VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size(); |
| 175 | // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address), | 183 | // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address), |
| 176 | // but explicit addresses are also accepted and respected. | 184 | // but explicit addresses are also accepted and respected. |
| 177 | if (target == 0) { | 185 | if (target == 0) { |
| 178 | target = heap_end; | 186 | target = heap_end; |
| 179 | } | 187 | } |
| 180 | 188 | ||
| 181 | if (target < Memory::LINEAR_HEAP_VADDR || target + size > Memory::LINEAR_HEAP_VADDR_END || | 189 | if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || |
| 182 | target > heap_end || target + size < target) { | 190 | target > heap_end || target + size < target) { |
| 183 | 191 | ||
| 184 | return ERR_INVALID_ADDRESS; | 192 | return ERR_INVALID_ADDRESS; |
| @@ -188,25 +196,29 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p | |||
| 188 | // end. It's possible to free gaps in the middle of the heap and then reallocate them later, | 196 | // end. It's possible to free gaps in the middle of the heap and then reallocate them later, |
| 189 | // but expansions are only allowed at the end. | 197 | // but expansions are only allowed at the end. |
| 190 | if (target == heap_end) { | 198 | if (target == heap_end) { |
| 191 | linear_heap_memory->insert(linear_heap_memory->end(), size, 0); | 199 | linheap_memory->insert(linheap_memory->end(), size, 0); |
| 192 | vm_manager.RefreshMemoryBlockMappings(linear_heap_memory.get()); | 200 | vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 193 | } | 201 | } |
| 194 | 202 | ||
| 195 | size_t offset = target - Memory::LINEAR_HEAP_VADDR; | 203 | // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the |
| 196 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linear_heap_memory, offset, size, MemoryState::Continuous)); | 204 | // same region. It is unknown if or how the 3DS kernel checks against this. |
| 205 | size_t offset = target - GetLinearHeapBase(); | ||
| 206 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous)); | ||
| 197 | vm_manager.Reprotect(vma, perms); | 207 | vm_manager.Reprotect(vma, perms); |
| 198 | 208 | ||
| 199 | return MakeResult<VAddr>(target); | 209 | return MakeResult<VAddr>(target); |
| 200 | } | 210 | } |
| 201 | 211 | ||
| 202 | ResultCode Process::LinearFree(VAddr target, u32 size) { | 212 | ResultCode Process::LinearFree(VAddr target, u32 size) { |
| 203 | if (linear_heap_memory == nullptr || target < Memory::LINEAR_HEAP_VADDR || | 213 | auto& linheap_memory = memory_region->linear_heap_memory; |
| 204 | target + size > Memory::LINEAR_HEAP_VADDR_END || target + size < target) { | 214 | |
| 215 | if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || | ||
| 216 | target + size < target) { | ||
| 205 | 217 | ||
| 206 | return ERR_INVALID_ADDRESS; | 218 | return ERR_INVALID_ADDRESS; |
| 207 | } | 219 | } |
| 208 | 220 | ||
| 209 | VAddr heap_end = Memory::LINEAR_HEAP_VADDR + (u32)linear_heap_memory->size(); | 221 | VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size(); |
| 210 | if (target + size > heap_end) { | 222 | if (target + size > heap_end) { |
| 211 | return ERR_INVALID_ADDRESS_STATE; | 223 | return ERR_INVALID_ADDRESS_STATE; |
| 212 | } | 224 | } |
| @@ -221,8 +233,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { | |||
| 221 | ASSERT(vma != vm_manager.vma_map.end()); | 233 | ASSERT(vma != vm_manager.vma_map.end()); |
| 222 | ASSERT(vma->second.type == VMAType::Free); | 234 | ASSERT(vma->second.type == VMAType::Free); |
| 223 | VAddr new_end = vma->second.base; | 235 | VAddr new_end = vma->second.base; |
| 224 | if (new_end >= Memory::LINEAR_HEAP_VADDR) { | 236 | if (new_end >= GetLinearHeapBase()) { |
| 225 | linear_heap_memory->resize(new_end - Memory::LINEAR_HEAP_VADDR); | 237 | linheap_memory->resize(new_end - GetLinearHeapBase()); |
| 226 | } | 238 | } |
| 227 | } | 239 | } |
| 228 | 240 | ||