diff options
| author | 2017-10-09 23:56:20 -0400 | |
|---|---|---|
| committer | 2017-10-09 23:56:20 -0400 | |
| commit | b1d5db1cf60344b6b081c9d03cb6ccc3264326cd (patch) | |
| tree | fde377c4ba3c0f92c032e6f5ec8627aae37270ef /src/core/hle/kernel | |
| parent | loader: Various improvements for NSO/NRO loaders. (diff) | |
| parent | Merge pull request #2996 from MerryMage/split-travis (diff) | |
| download | yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.tar.gz yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.tar.xz yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.zip | |
Merge remote-tracking branch 'upstream/master' into nx
# Conflicts:
# src/core/CMakeLists.txt
# src/core/arm/dynarmic/arm_dynarmic.cpp
# src/core/arm/dyncom/arm_dyncom.cpp
# src/core/hle/kernel/process.cpp
# src/core/hle/kernel/thread.cpp
# src/core/hle/kernel/thread.h
# src/core/hle/kernel/vm_manager.cpp
# src/core/loader/3dsx.cpp
# src/core/loader/elf.cpp
# src/core/loader/ncch.cpp
# src/core/memory.cpp
# src/core/memory.h
# src/core/memory_setup.h
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory.cpp | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/resource_limit.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/resource_limit.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 68 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 48 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/wait_object.cpp | 13 |
18 files changed, 143 insertions, 103 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5ebe2eca4..6020e9764 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -37,7 +37,7 @@ SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const | |||
| 37 | 37 | ||
| 38 | u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) { | 38 | u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) { |
| 39 | request_handles.push_back(std::move(object)); | 39 | request_handles.push_back(std::move(object)); |
| 40 | return request_handles.size() - 1; | 40 | return static_cast<u32>(request_handles.size() - 1); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | void HLERequestContext::ClearIncomingObjects() { | 43 | void HLERequestContext::ClearIncomingObjects() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9cf288b08..73fab3981 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | #include <boost/smart_ptr/intrusive_ptr.hpp> | 10 | #include <boost/smart_ptr/intrusive_ptr.hpp> |
| 11 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| @@ -84,6 +85,8 @@ public: | |||
| 84 | case HandleType::ClientSession: | 85 | case HandleType::ClientSession: |
| 85 | return false; | 86 | return false; |
| 86 | } | 87 | } |
| 88 | |||
| 89 | UNREACHABLE(); | ||
| 87 | } | 90 | } |
| 88 | 91 | ||
| 89 | public: | 92 | public: |
| @@ -129,4 +132,4 @@ void Init(u32 system_mode); | |||
| 129 | /// Shutdown the kernel | 132 | /// Shutdown the kernel |
| 130 | void Shutdown(); | 133 | void Shutdown(); |
| 131 | 134 | ||
| 132 | } // namespace | 135 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 496d07cb5..7f27e9655 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | #include "audio_core/audio_core.h" | ||
| 12 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 14 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| @@ -24,7 +23,7 @@ | |||
| 24 | 23 | ||
| 25 | namespace Kernel { | 24 | namespace Kernel { |
| 26 | 25 | ||
| 27 | static MemoryRegionInfo memory_regions[3]; | 26 | MemoryRegionInfo memory_regions[3]; |
| 28 | 27 | ||
| 29 | /// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system | 28 | /// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system |
| 30 | /// memory configuration type. | 29 | /// memory configuration type. |
| @@ -96,9 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { | |||
| 96 | } | 95 | } |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | std::array<u8, Memory::VRAM_SIZE> vram; | ||
| 100 | std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram; | ||
| 101 | |||
| 102 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) { | 98 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) { |
| 103 | using namespace Memory; | 99 | using namespace Memory; |
| 104 | 100 | ||
| @@ -143,30 +139,14 @@ void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mappin | |||
| 143 | return; | 139 | return; |
| 144 | } | 140 | } |
| 145 | 141 | ||
| 146 | // TODO(yuriks): Use GetPhysicalPointer when that becomes independent of the virtual | 142 | u8* target_pointer = Memory::GetPhysicalPointer(area->paddr_base + offset_into_region); |
| 147 | // mappings. | ||
| 148 | u8* target_pointer = nullptr; | ||
| 149 | switch (area->paddr_base) { | ||
| 150 | case VRAM_PADDR: | ||
| 151 | target_pointer = vram.data(); | ||
| 152 | break; | ||
| 153 | case DSP_RAM_PADDR: | ||
| 154 | target_pointer = AudioCore::GetDspMemory().data(); | ||
| 155 | break; | ||
| 156 | case N3DS_EXTRA_RAM_PADDR: | ||
| 157 | target_pointer = n3ds_extra_ram.data(); | ||
| 158 | break; | ||
| 159 | default: | ||
| 160 | UNREACHABLE(); | ||
| 161 | } | ||
| 162 | 143 | ||
| 163 | // TODO(yuriks): This flag seems to have some other effect, but it's unknown what | 144 | // TODO(yuriks): This flag seems to have some other effect, but it's unknown what |
| 164 | MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO; | 145 | MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO; |
| 165 | 146 | ||
| 166 | auto vma = address_space | 147 | auto vma = |
| 167 | .MapBackingMemory(mapping.address, target_pointer + offset_into_region, | 148 | address_space.MapBackingMemory(mapping.address, target_pointer, mapping.size, memory_state) |
| 168 | mapping.size, memory_state) | 149 | .Unwrap(); |
| 169 | .Unwrap(); | ||
| 170 | address_space.Reprotect(vma, | 150 | address_space.Reprotect(vma, |
| 171 | mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite); | 151 | mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite); |
| 172 | } | 152 | } |
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index 08c1a9989..da6bb3563 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h | |||
| @@ -26,4 +26,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); | |||
| 26 | 26 | ||
| 27 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); | 27 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); |
| 28 | void MapSharedPages(VMManager& address_space); | 28 | void MapSharedPages(VMManager& address_space); |
| 29 | |||
| 30 | extern MemoryRegionInfo memory_regions[3]; | ||
| 29 | } // namespace Kernel | 31 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index cef961289..30dade552 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -25,10 +25,11 @@ void ReleaseThreadMutexes(Thread* thread) { | |||
| 25 | Mutex::Mutex() {} | 25 | Mutex::Mutex() {} |
| 26 | Mutex::~Mutex() {} | 26 | Mutex::~Mutex() {} |
| 27 | 27 | ||
| 28 | SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { | 28 | SharedPtr<Mutex> Mutex::Create(bool initial_locked, VAddr addr, std::string name) { |
| 29 | SharedPtr<Mutex> mutex(new Mutex); | 29 | SharedPtr<Mutex> mutex(new Mutex); |
| 30 | 30 | ||
| 31 | mutex->lock_count = 0; | 31 | mutex->lock_count = 0; |
| 32 | mutex->addr = addr; | ||
| 32 | mutex->name = std::move(name); | 33 | mutex->name = std::move(name); |
| 33 | mutex->holding_thread = nullptr; | 34 | mutex->holding_thread = nullptr; |
| 34 | 35 | ||
| @@ -90,7 +91,7 @@ void Mutex::UpdatePriority() { | |||
| 90 | if (!holding_thread) | 91 | if (!holding_thread) |
| 91 | return; | 92 | return; |
| 92 | 93 | ||
| 93 | s32 best_priority = THREADPRIO_LOWEST; | 94 | u32 best_priority = THREADPRIO_LOWEST; |
| 94 | for (auto& waiter : GetWaitingThreads()) { | 95 | for (auto& waiter : GetWaitingThreads()) { |
| 95 | if (waiter->current_priority < best_priority) | 96 | if (waiter->current_priority < best_priority) |
| 96 | best_priority = waiter->current_priority; | 97 | best_priority = waiter->current_priority; |
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bacacd690..503d3ee75 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h | |||
| @@ -21,7 +21,7 @@ public: | |||
| 21 | * @param name Optional name of mutex | 21 | * @param name Optional name of mutex |
| 22 | * @return Pointer to new Mutex object | 22 | * @return Pointer to new Mutex object |
| 23 | */ | 23 | */ |
| 24 | static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); | 24 | static SharedPtr<Mutex> Create(bool initial_locked, VAddr addr, std::string name = "Unknown"); |
| 25 | 25 | ||
| 26 | std::string GetTypeName() const override { | 26 | std::string GetTypeName() const override { |
| 27 | return "Mutex"; | 27 | return "Mutex"; |
| @@ -39,6 +39,7 @@ public: | |||
| 39 | u32 priority; ///< The priority of the mutex, used for priority inheritance. | 39 | u32 priority; ///< The priority of the mutex, used for priority inheritance. |
| 40 | std::string name; ///< Name of mutex (optional) | 40 | std::string name; ///< Name of mutex (optional) |
| 41 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | 41 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex |
| 42 | VAddr addr; | ||
| 42 | 43 | ||
| 43 | /** | 44 | /** |
| 44 | * Elevate the mutex priority to the best priority | 45 | * Elevate the mutex priority to the best priority |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 84ebdbc58..9e145866f 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -129,7 +129,8 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | vm_manager.LogLayout(Log::Level::Debug); | 131 | vm_manager.LogLayout(Log::Level::Debug); |
| 132 | Kernel::SetupMainThread(entry_point, main_thread_priority); | 132 | |
| 133 | Kernel::SetupMainThread(entry_point, main_thread_priority, this); | ||
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { | 136 | void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { |
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index a8f10a3ee..517dc47a8 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp | |||
| @@ -61,7 +61,7 @@ s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const { | |||
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | s32 ResourceLimit::GetMaxResourceValue(u32 resource) const { | 64 | u32 ResourceLimit::GetMaxResourceValue(u32 resource) const { |
| 65 | switch (resource) { | 65 | switch (resource) { |
| 66 | case PRIORITY: | 66 | case PRIORITY: |
| 67 | return max_priority; | 67 | return max_priority; |
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 6cdfbcf8d..42874eb8d 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h | |||
| @@ -67,7 +67,7 @@ public: | |||
| 67 | * @param resource Requested resource type | 67 | * @param resource Requested resource type |
| 68 | * @returns The max value of the resource type | 68 | * @returns The max value of the resource type |
| 69 | */ | 69 | */ |
| 70 | s32 GetMaxResourceValue(u32 resource) const; | 70 | u32 GetMaxResourceValue(u32 resource) const; |
| 71 | 71 | ||
| 72 | /// Name of resource limit object. | 72 | /// Name of resource limit object. |
| 73 | std::string name; | 73 | std::string name; |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index fcf586728..2605b2595 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -13,7 +13,7 @@ namespace Kernel { | |||
| 13 | Semaphore::Semaphore() {} | 13 | Semaphore::Semaphore() {} |
| 14 | Semaphore::~Semaphore() {} | 14 | Semaphore::~Semaphore() {} |
| 15 | 15 | ||
| 16 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, | 16 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, VAddr address, |
| 17 | std::string name) { | 17 | std::string name) { |
| 18 | 18 | ||
| 19 | if (initial_count > max_count) | 19 | if (initial_count > max_count) |
| @@ -25,6 +25,7 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou | |||
| 25 | // and the rest is reserved for the caller thread | 25 | // and the rest is reserved for the caller thread |
| 26 | semaphore->max_count = max_count; | 26 | semaphore->max_count = max_count; |
| 27 | semaphore->available_count = initial_count; | 27 | semaphore->available_count = initial_count; |
| 28 | semaphore->address = address; | ||
| 28 | semaphore->name = std::move(name); | 29 | semaphore->name = std::move(name); |
| 29 | 30 | ||
| 30 | return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); | 31 | return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); |
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 7b0cacf2e..77c491a24 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h | |||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | * @param name Optional name of semaphore | 22 | * @param name Optional name of semaphore |
| 23 | * @return The created semaphore | 23 | * @return The created semaphore |
| 24 | */ | 24 | */ |
| 25 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, | 25 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, VAddr address, |
| 26 | std::string name = "Unknown"); | 26 | std::string name = "Unknown"); |
| 27 | 27 | ||
| 28 | std::string GetTypeName() const override { | 28 | std::string GetTypeName() const override { |
| @@ -39,6 +39,7 @@ public: | |||
| 39 | 39 | ||
| 40 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | 40 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have |
| 41 | s32 available_count; ///< Number of free slots left in the semaphore | 41 | s32 available_count; ///< Number of free slots left in the semaphore |
| 42 | VAddr address; | ||
| 42 | std::string name; ///< Name of semaphore (optional) | 43 | std::string name; ///< Name of semaphore (optional) |
| 43 | 44 | ||
| 44 | bool ShouldWait(Thread* thread) const override; | 45 | bool ShouldWait(Thread* thread) const override; |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index a7b66142f..d45daca35 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -42,7 +42,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 42 | memory_region->used += size; | 42 | memory_region->used += size; |
| 43 | 43 | ||
| 44 | shared_memory->linear_heap_phys_address = | 44 | shared_memory->linear_heap_phys_address = |
| 45 | Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset; | 45 | Memory::FCRAM_PADDR + memory_region->base + |
| 46 | static_cast<PAddr>(shared_memory->backing_block_offset); | ||
| 46 | 47 | ||
| 47 | // Increase the amount of used linear heap memory for the owner process. | 48 | // Increase the amount of used linear heap memory for the owner process. |
| 48 | if (shared_memory->owner_process != nullptr) { | 49 | if (shared_memory->owner_process != nullptr) { |
| @@ -54,22 +55,19 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 54 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); | 55 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 55 | } | 56 | } |
| 56 | } else { | 57 | } else { |
| 57 | // TODO(Subv): What happens if an application tries to create multiple memory blocks | ||
| 58 | // pointing to the same address? | ||
| 59 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 58 | auto& vm_manager = shared_memory->owner_process->vm_manager; |
| 60 | // The memory is already available and mapped in the owner process. | 59 | // The memory is already available and mapped in the owner process. |
| 61 | auto vma = vm_manager.FindVMA(address)->second; | 60 | auto vma = vm_manager.FindVMA(address); |
| 62 | // Copy it over to our own storage | 61 | ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); |
| 63 | shared_memory->backing_block = std::make_shared<std::vector<u8>>( | 62 | ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); |
| 64 | vma.backing_block->data() + vma.offset, vma.backing_block->data() + vma.offset + size); | 63 | |
| 65 | shared_memory->backing_block_offset = 0; | 64 | // The returned VMA might be a bigger one encompassing the desired address. |
| 66 | // Unmap the existing pages | 65 | auto vma_offset = address - vma->first; |
| 67 | vm_manager.UnmapRange(address, size); | 66 | ASSERT_MSG(vma_offset + size <= vma->second.size, |
| 68 | // Map our own block into the address space | 67 | "Shared memory exceeds bounds of mapped block"); |
| 69 | vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, | 68 | |
| 70 | MemoryState::Shared); | 69 | shared_memory->backing_block = vma->second.backing_block; |
| 71 | // Reprotect the block with the new permissions | 70 | shared_memory->backing_block_offset = vma->second.offset + vma_offset; |
| 72 | vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions)); | ||
| 73 | } | 71 | } |
| 74 | 72 | ||
| 75 | shared_memory->base_address = address; | 73 | shared_memory->base_address = address; |
| @@ -183,4 +181,4 @@ u8* SharedMemory::GetPointer(u32 offset) { | |||
| 183 | return backing_block->data() + backing_block_offset + offset; | 181 | return backing_block->data() + backing_block_offset + offset; |
| 184 | } | 182 | } |
| 185 | 183 | ||
| 186 | } // namespace | 184 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 94b335ed1..93a6f2182 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -114,7 +114,7 @@ public: | |||
| 114 | /// Backing memory for this shared memory block. | 114 | /// Backing memory for this shared memory block. |
| 115 | std::shared_ptr<std::vector<u8>> backing_block; | 115 | std::shared_ptr<std::vector<u8>> backing_block; |
| 116 | /// Offset into the backing block for this shared memory. | 116 | /// Offset into the backing block for this shared memory. |
| 117 | u32 backing_block_offset; | 117 | size_t backing_block_offset; |
| 118 | /// Size of the memory block. Page-aligned. | 118 | /// Size of the memory block. Page-aligned. |
| 119 | u32 size; | 119 | u32 size; |
| 120 | /// Permission restrictions applied to the process which created the block. | 120 | /// Permission restrictions applied to the process which created the block. |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index c01d08ebb..75df49ac2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -111,7 +111,7 @@ void Thread::Stop() { | |||
| 111 | 111 | ||
| 112 | Thread* ArbitrateHighestPriorityThread(u32 address) { | 112 | Thread* ArbitrateHighestPriorityThread(u32 address) { |
| 113 | Thread* highest_priority_thread = nullptr; | 113 | Thread* highest_priority_thread = nullptr; |
| 114 | s32 priority = THREADPRIO_LOWEST; | 114 | u32 priority = THREADPRIO_LOWEST; |
| 115 | 115 | ||
| 116 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 116 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 117 | for (auto& thread : thread_list) { | 117 | for (auto& thread : thread_list) { |
| @@ -171,15 +171,24 @@ static void SwitchContext(Thread* new_thread) { | |||
| 171 | // Cancel any outstanding wakeup events for this thread | 171 | // Cancel any outstanding wakeup events for this thread |
| 172 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); | 172 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); |
| 173 | 173 | ||
| 174 | auto previous_process = Kernel::g_current_process; | ||
| 175 | |||
| 174 | current_thread = new_thread; | 176 | current_thread = new_thread; |
| 175 | 177 | ||
| 176 | ready_queue.remove(new_thread->current_priority, new_thread); | 178 | ready_queue.remove(new_thread->current_priority, new_thread); |
| 177 | new_thread->status = THREADSTATUS_RUNNING; | 179 | new_thread->status = THREADSTATUS_RUNNING; |
| 178 | 180 | ||
| 181 | if (previous_process != current_thread->owner_process) { | ||
| 182 | Kernel::g_current_process = current_thread->owner_process; | ||
| 183 | SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); | ||
| 184 | } | ||
| 185 | |||
| 179 | Core::CPU().LoadContext(new_thread->context); | 186 | Core::CPU().LoadContext(new_thread->context); |
| 180 | Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress()); | 187 | Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress()); |
| 181 | } else { | 188 | } else { |
| 182 | current_thread = nullptr; | 189 | current_thread = nullptr; |
| 190 | // Note: We do not reset the current process and current page table when idling because | ||
| 191 | // technically we haven't changed processes, our threads are just paused. | ||
| 183 | } | 192 | } |
| 184 | } | 193 | } |
| 185 | 194 | ||
| @@ -238,12 +247,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 238 | 247 | ||
| 239 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | 248 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 240 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { | 249 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { |
| 241 | thread->wait_set_output = false; | 250 | |
| 251 | // Invoke the wakeup callback before clearing the wait objects | ||
| 252 | if (thread->wakeup_callback) | ||
| 253 | thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr); | ||
| 254 | |||
| 242 | // Remove the thread from each of its waiting objects' waitlists | 255 | // Remove the thread from each of its waiting objects' waitlists |
| 243 | for (auto& object : thread->wait_objects) | 256 | for (auto& object : thread->wait_objects) |
| 244 | object->RemoveWaitingThread(thread.get()); | 257 | object->RemoveWaitingThread(thread.get()); |
| 245 | thread->wait_objects.clear(); | 258 | thread->wait_objects.clear(); |
| 246 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | ||
| 247 | } | 259 | } |
| 248 | 260 | ||
| 249 | thread->ResumeFromWait(); | 261 | thread->ResumeFromWait(); |
| @@ -269,6 +281,9 @@ void Thread::ResumeFromWait() { | |||
| 269 | break; | 281 | break; |
| 270 | 282 | ||
| 271 | case THREADSTATUS_READY: | 283 | case THREADSTATUS_READY: |
| 284 | // The thread's wakeup callback must have already been cleared when the thread was first | ||
| 285 | // awoken. | ||
| 286 | ASSERT(wakeup_callback == nullptr); | ||
| 272 | // If the thread is waiting on multiple wait objects, it might be awoken more than once | 287 | // If the thread is waiting on multiple wait objects, it might be awoken more than once |
| 273 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | 288 | // before actually resuming. We can ignore subsequent wakeups if the thread status has |
| 274 | // already been set to THREADSTATUS_READY. | 289 | // already been set to THREADSTATUS_READY. |
| @@ -284,6 +299,8 @@ void Thread::ResumeFromWait() { | |||
| 284 | return; | 299 | return; |
| 285 | } | 300 | } |
| 286 | 301 | ||
| 302 | wakeup_callback = nullptr; | ||
| 303 | |||
| 287 | ready_queue.push_back(current_priority, this); | 304 | ready_queue.push_back(current_priority, this); |
| 288 | status = THREADSTATUS_READY; | 305 | status = THREADSTATUS_READY; |
| 289 | Core::System::GetInstance().PrepareReschedule(); | 306 | Core::System::GetInstance().PrepareReschedule(); |
| @@ -302,7 +319,7 @@ static void DebugThreadQueue() { | |||
| 302 | } | 319 | } |
| 303 | 320 | ||
| 304 | for (auto& t : thread_list) { | 321 | for (auto& t : thread_list) { |
| 305 | s32 priority = ready_queue.contains(t.get()); | 322 | u32 priority = ready_queue.contains(t.get()); |
| 306 | if (priority != -1) { | 323 | if (priority != -1) { |
| 307 | LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); | 324 | LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); |
| 308 | } | 325 | } |
| @@ -352,7 +369,8 @@ static void ResetThreadContext(ARM_Interface::ThreadContext& context, VAddr stac | |||
| 352 | } | 369 | } |
| 353 | 370 | ||
| 354 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, | 371 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, |
| 355 | u32 arg, s32 processor_id, VAddr stack_top) { | 372 | u32 arg, s32 processor_id, VAddr stack_top, |
| 373 | SharedPtr<Process> owner_process) { | ||
| 356 | // Check if priority is in ranged. Lowest priority -> highest priority id. | 374 | // Check if priority is in ranged. Lowest priority -> highest priority id. |
| 357 | if (priority > THREADPRIO_LOWEST) { | 375 | if (priority > THREADPRIO_LOWEST) { |
| 358 | LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority); | 376 | LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority); |
| @@ -366,7 +384,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 366 | 384 | ||
| 367 | // TODO(yuriks): Other checks, returning 0xD9001BEA | 385 | // TODO(yuriks): Other checks, returning 0xD9001BEA |
| 368 | 386 | ||
| 369 | if (!Memory::IsValidVirtualAddress(entry_point)) { | 387 | if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { |
| 370 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); | 388 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); |
| 371 | // TODO: Verify error | 389 | // TODO: Verify error |
| 372 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 390 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| @@ -385,15 +403,14 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 385 | thread->nominal_priority = thread->current_priority = priority; | 403 | thread->nominal_priority = thread->current_priority = priority; |
| 386 | thread->last_running_ticks = CoreTiming::GetTicks(); | 404 | thread->last_running_ticks = CoreTiming::GetTicks(); |
| 387 | thread->processor_id = processor_id; | 405 | thread->processor_id = processor_id; |
| 388 | thread->wait_set_output = false; | ||
| 389 | thread->wait_objects.clear(); | 406 | thread->wait_objects.clear(); |
| 390 | thread->wait_address = 0; | 407 | thread->wait_address = 0; |
| 391 | thread->name = std::move(name); | 408 | thread->name = std::move(name); |
| 392 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); | 409 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); |
| 393 | thread->owner_process = g_current_process; | 410 | thread->owner_process = owner_process; |
| 394 | 411 | ||
| 395 | // Find the next available TLS index, and mark it as used | 412 | // Find the next available TLS index, and mark it as used |
| 396 | auto& tls_slots = Kernel::g_current_process->tls_slots; | 413 | auto& tls_slots = owner_process->tls_slots; |
| 397 | bool needs_allocation = true; | 414 | bool needs_allocation = true; |
| 398 | u32 available_page; // Which allocated page has free space | 415 | u32 available_page; // Which allocated page has free space |
| 399 | u32 available_slot; // Which slot within the page is free | 416 | u32 available_slot; // Which slot within the page is free |
| @@ -412,18 +429,18 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 412 | return ERR_OUT_OF_MEMORY; | 429 | return ERR_OUT_OF_MEMORY; |
| 413 | } | 430 | } |
| 414 | 431 | ||
| 415 | u32 offset = linheap_memory->size(); | 432 | size_t offset = linheap_memory->size(); |
| 416 | 433 | ||
| 417 | // Allocate some memory from the end of the linear heap for this region. | 434 | // Allocate some memory from the end of the linear heap for this region. |
| 418 | linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0); | 435 | linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0); |
| 419 | memory_region->used += Memory::PAGE_SIZE; | 436 | memory_region->used += Memory::PAGE_SIZE; |
| 420 | Kernel::g_current_process->linear_heap_used += Memory::PAGE_SIZE; | 437 | owner_process->linear_heap_used += Memory::PAGE_SIZE; |
| 421 | 438 | ||
| 422 | tls_slots.emplace_back(0); // The page is completely available at the start | 439 | tls_slots.emplace_back(0); // The page is completely available at the start |
| 423 | available_page = tls_slots.size() - 1; | 440 | available_page = static_cast<u32>(tls_slots.size() - 1); |
| 424 | available_slot = 0; // Use the first slot in the new page | 441 | available_slot = 0; // Use the first slot in the new page |
| 425 | 442 | ||
| 426 | auto& vm_manager = Kernel::g_current_process->vm_manager; | 443 | auto& vm_manager = owner_process->vm_manager; |
| 427 | vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); | 444 | vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 428 | 445 | ||
| 429 | // Map the page to the current process' address space. | 446 | // Map the page to the current process' address space. |
| @@ -447,7 +464,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 447 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); | 464 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); |
| 448 | } | 465 | } |
| 449 | 466 | ||
| 450 | void Thread::SetPriority(s32 priority) { | 467 | void Thread::SetPriority(u32 priority) { |
| 451 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, | 468 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, |
| 452 | "Invalid priority value."); | 469 | "Invalid priority value."); |
| 453 | // If thread was ready, adjust queues | 470 | // If thread was ready, adjust queues |
| @@ -460,7 +477,7 @@ void Thread::SetPriority(s32 priority) { | |||
| 460 | } | 477 | } |
| 461 | 478 | ||
| 462 | void Thread::UpdatePriority() { | 479 | void Thread::UpdatePriority() { |
| 463 | s32 best_priority = nominal_priority; | 480 | u32 best_priority = nominal_priority; |
| 464 | for (auto& mutex : held_mutexes) { | 481 | for (auto& mutex : held_mutexes) { |
| 465 | if (mutex->priority < best_priority) | 482 | if (mutex->priority < best_priority) |
| 466 | best_priority = mutex->priority; | 483 | best_priority = mutex->priority; |
| @@ -468,7 +485,7 @@ void Thread::UpdatePriority() { | |||
| 468 | BoostPriority(best_priority); | 485 | BoostPriority(best_priority); |
| 469 | } | 486 | } |
| 470 | 487 | ||
| 471 | void Thread::BoostPriority(s32 priority) { | 488 | void Thread::BoostPriority(u32 priority) { |
| 472 | // If thread was ready, adjust queues | 489 | // If thread was ready, adjust queues |
| 473 | if (status == THREADSTATUS_READY) | 490 | if (status == THREADSTATUS_READY) |
| 474 | ready_queue.move(this, current_priority, priority); | 491 | ready_queue.move(this, current_priority, priority); |
| @@ -477,21 +494,20 @@ void Thread::BoostPriority(s32 priority) { | |||
| 477 | current_priority = priority; | 494 | current_priority = priority; |
| 478 | } | 495 | } |
| 479 | 496 | ||
| 480 | SharedPtr<Thread> SetupMainThread(VAddr entry_point, s32 priority) { | 497 | SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process) { |
| 481 | DEBUG_ASSERT(!GetCurrentThread()); | 498 | // Setup page table so we can write to memory |
| 499 | SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); | ||
| 482 | 500 | ||
| 483 | // Initialize new "main" thread | 501 | // Initialize new "main" thread |
| 484 | auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, | 502 | auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, |
| 485 | Memory::HEAP_VADDR_END); | 503 | Memory::HEAP_VADDR_END, owner_process); |
| 486 | 504 | ||
| 487 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); | 505 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); |
| 488 | 506 | ||
| 489 | thread->context.fpscr = | 507 | thread->context.fpscr = |
| 490 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 | 508 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 |
| 491 | 509 | ||
| 492 | // Run new "main" thread | 510 | // Note: The newly created thread will be run when the scheduler fires. |
| 493 | SwitchContext(thread.get()); | ||
| 494 | |||
| 495 | return thread; | 511 | return thread; |
| 496 | } | 512 | } |
| 497 | 513 | ||
| @@ -525,7 +541,13 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { | |||
| 525 | s32 Thread::GetWaitObjectIndex(WaitObject* object) const { | 541 | s32 Thread::GetWaitObjectIndex(WaitObject* object) const { |
| 526 | ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); | 542 | ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); |
| 527 | auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); | 543 | auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); |
| 528 | return std::distance(match, wait_objects.rend()) - 1; | 544 | return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); |
| 545 | } | ||
| 546 | |||
| 547 | VAddr Thread::GetCommandBufferAddress() const { | ||
| 548 | // Offset from the start of TLS at which the IPC command buffer begins. | ||
| 549 | static constexpr int CommandHeaderOffset = 0x80; | ||
| 550 | return GetTLSAddress() + CommandHeaderOffset; | ||
| 529 | } | 551 | } |
| 530 | 552 | ||
| 531 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 553 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 2cadb91db..fafcab156 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include "core/hle/kernel/wait_object.h" | 15 | #include "core/hle/kernel/wait_object.h" |
| 16 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 17 | 17 | ||
| 18 | enum ThreadPriority : s32 { | 18 | enum ThreadPriority : u32 { |
| 19 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority | 19 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority |
| 20 | THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps | 20 | THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps |
| 21 | THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps | 21 | THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps |
| @@ -41,6 +41,11 @@ enum ThreadStatus { | |||
| 41 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated | 41 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | enum class ThreadWakeupReason { | ||
| 45 | Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. | ||
| 46 | Timeout // The thread was woken up due to a wait timeout. | ||
| 47 | }; | ||
| 48 | |||
| 44 | namespace Kernel { | 49 | namespace Kernel { |
| 45 | 50 | ||
| 46 | class Mutex; | 51 | class Mutex; |
| @@ -56,10 +61,12 @@ public: | |||
| 56 | * @param arg User data to pass to the thread | 61 | * @param arg User data to pass to the thread |
| 57 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | 62 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run |
| 58 | * @param stack_top The address of the thread's stack top | 63 | * @param stack_top The address of the thread's stack top |
| 64 | * @param owner_process The parent process for the thread | ||
| 59 | * @return A shared pointer to the newly created thread | 65 | * @return A shared pointer to the newly created thread |
| 60 | */ | 66 | */ |
| 61 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, | 67 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, |
| 62 | u32 arg, s32 processor_id, VAddr stack_top); | 68 | u32 arg, s32 processor_id, VAddr stack_top, |
| 69 | SharedPtr<Process> owner_process); | ||
| 63 | 70 | ||
| 64 | std::string GetName() const override { | 71 | std::string GetName() const override { |
| 65 | return name; | 72 | return name; |
| @@ -80,7 +87,7 @@ public: | |||
| 80 | * Gets the thread's current priority | 87 | * Gets the thread's current priority |
| 81 | * @return The current thread's priority | 88 | * @return The current thread's priority |
| 82 | */ | 89 | */ |
| 83 | s32 GetPriority() const { | 90 | u32 GetPriority() const { |
| 84 | return current_priority; | 91 | return current_priority; |
| 85 | } | 92 | } |
| 86 | 93 | ||
| @@ -88,7 +95,7 @@ public: | |||
| 88 | * Sets the thread's current priority | 95 | * Sets the thread's current priority |
| 89 | * @param priority The new priority | 96 | * @param priority The new priority |
| 90 | */ | 97 | */ |
| 91 | void SetPriority(s32 priority); | 98 | void SetPriority(u32 priority); |
| 92 | 99 | ||
| 93 | /** | 100 | /** |
| 94 | * Boost's a thread's priority to the best priority among the thread's held mutexes. | 101 | * Boost's a thread's priority to the best priority among the thread's held mutexes. |
| @@ -100,7 +107,7 @@ public: | |||
| 100 | * Temporarily boosts the thread's priority until the next time it is scheduled | 107 | * Temporarily boosts the thread's priority until the next time it is scheduled |
| 101 | * @param priority The new priority | 108 | * @param priority The new priority |
| 102 | */ | 109 | */ |
| 103 | void BoostPriority(s32 priority); | 110 | void BoostPriority(u32 priority); |
| 104 | 111 | ||
| 105 | /** | 112 | /** |
| 106 | * Gets the thread's thread ID | 113 | * Gets the thread's thread ID |
| @@ -116,9 +123,9 @@ public: | |||
| 116 | void ResumeFromWait(); | 123 | void ResumeFromWait(); |
| 117 | 124 | ||
| 118 | /** | 125 | /** |
| 119 | * Schedules an event to wake up the specified thread after the specified delay | 126 | * Schedules an event to wake up the specified thread after the specified delay |
| 120 | * @param nanoseconds The time this thread will be allowed to sleep for | 127 | * @param nanoseconds The time this thread will be allowed to sleep for |
| 121 | */ | 128 | */ |
| 122 | void WakeAfterDelay(s64 nanoseconds); | 129 | void WakeAfterDelay(s64 nanoseconds); |
| 123 | 130 | ||
| 124 | /** | 131 | /** |
| @@ -157,6 +164,12 @@ public: | |||
| 157 | return tls_address; | 164 | return tls_address; |
| 158 | } | 165 | } |
| 159 | 166 | ||
| 167 | /* | ||
| 168 | * Returns the address of the current thread's command buffer, located in the TLS. | ||
| 169 | * @returns VAddr of the thread's command buffer. | ||
| 170 | */ | ||
| 171 | VAddr GetCommandBufferAddress() const; | ||
| 172 | |||
| 160 | /** | 173 | /** |
| 161 | * Returns whether this thread is waiting for all the objects in | 174 | * Returns whether this thread is waiting for all the objects in |
| 162 | * its wait list to become ready, as a result of a WaitSynchronizationN call | 175 | * its wait list to become ready, as a result of a WaitSynchronizationN call |
| @@ -174,8 +187,8 @@ public: | |||
| 174 | VAddr entry_point; | 187 | VAddr entry_point; |
| 175 | VAddr stack_top; | 188 | VAddr stack_top; |
| 176 | 189 | ||
| 177 | s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application | 190 | u32 nominal_priority; ///< Nominal thread priority, as set by the emulated application |
| 178 | s32 current_priority; ///< Current thread priority, can be temporarily changed | 191 | u32 current_priority; ///< Current thread priority, can be temporarily changed |
| 179 | 192 | ||
| 180 | u64 last_running_ticks; ///< CPU tick when thread was last running | 193 | u64 last_running_ticks; ///< CPU tick when thread was last running |
| 181 | 194 | ||
| @@ -197,14 +210,18 @@ public: | |||
| 197 | 210 | ||
| 198 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address | 211 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address |
| 199 | 212 | ||
| 200 | /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. | ||
| 201 | bool wait_set_output; | ||
| 202 | |||
| 203 | std::string name; | 213 | std::string name; |
| 204 | 214 | ||
| 205 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | 215 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. |
| 206 | Handle callback_handle; | 216 | Handle callback_handle; |
| 207 | 217 | ||
| 218 | using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread, | ||
| 219 | SharedPtr<WaitObject> object); | ||
| 220 | // Callback that will be invoked when the thread is resumed from a waiting state. If the thread | ||
| 221 | // was waiting via WaitSynchronizationN then the object will be the last object that became | ||
| 222 | // available. In case of a timeout, the object will be nullptr. | ||
| 223 | std::function<WakeupCallback> wakeup_callback; | ||
| 224 | |||
| 208 | private: | 225 | private: |
| 209 | Thread(); | 226 | Thread(); |
| 210 | ~Thread() override; | 227 | ~Thread() override; |
| @@ -214,9 +231,10 @@ private: | |||
| 214 | * Sets up the primary application thread | 231 | * Sets up the primary application thread |
| 215 | * @param entry_point The address at which the thread should start execution | 232 | * @param entry_point The address at which the thread should start execution |
| 216 | * @param priority The priority to give the main thread | 233 | * @param priority The priority to give the main thread |
| 234 | * @param owner_process The parent process for the main thread | ||
| 217 | * @return A shared pointer to the main thread | 235 | * @return A shared pointer to the main thread |
| 218 | */ | 236 | */ |
| 219 | SharedPtr<Thread> SetupMainThread(VAddr entry_point, s32 priority); | 237 | SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process); |
| 220 | 238 | ||
| 221 | /** | 239 | /** |
| 222 | * Returns whether there are any threads that are ready to run. | 240 | * Returns whether there are any threads that are ready to run. |
| @@ -276,4 +294,4 @@ void ThreadingShutdown(); | |||
| 276 | */ | 294 | */ |
| 277 | const std::vector<SharedPtr<Thread>>& GetThreadList(); | 295 | const std::vector<SharedPtr<Thread>>& GetThreadList(); |
| 278 | 296 | ||
| 279 | } // namespace | 297 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index f70c32501..9762ef535 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -4,8 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <iterator> | 5 | #include <iterator> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/arm/arm_interface.h" | ||
| 7 | #include "core/hle/kernel/errors.h" | 8 | #include "core/hle/kernel/errors.h" |
| 8 | #include "core/hle/kernel/vm_manager.h" | 9 | #include "core/hle/kernel/vm_manager.h" |
| 10 | #include "core/core.h" | ||
| 9 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 10 | #include "core/memory_setup.h" | 12 | #include "core/memory_setup.h" |
| 11 | #include "core/mmio.h" | 13 | #include "core/mmio.h" |
| @@ -56,6 +58,10 @@ void VMManager::Reset() { | |||
| 56 | initial_vma.size = MAX_ADDRESS; | 58 | initial_vma.size = MAX_ADDRESS; |
| 57 | vma_map.emplace(initial_vma.base, initial_vma); | 59 | vma_map.emplace(initial_vma.base, initial_vma); |
| 58 | 60 | ||
| 61 | page_table.pointers.fill(nullptr); | ||
| 62 | page_table.attributes.fill(Memory::PageType::Unmapped); | ||
| 63 | page_table.cached_res_count.fill(0); | ||
| 64 | |||
| 59 | //UpdatePageTableForVMA(initial_vma); | 65 | //UpdatePageTableForVMA(initial_vma); |
| 60 | } | 66 | } |
| 61 | 67 | ||
| @@ -79,6 +85,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | |||
| 79 | VirtualMemoryArea& final_vma = vma_handle->second; | 85 | VirtualMemoryArea& final_vma = vma_handle->second; |
| 80 | ASSERT(final_vma.size == size); | 86 | ASSERT(final_vma.size == size); |
| 81 | 87 | ||
| 88 | Core::CPU().MapBackingMemory(target, size, block->data() + offset, VMAPermission::ReadWriteExecute); | ||
| 89 | |||
| 82 | final_vma.type = VMAType::AllocatedMemoryBlock; | 90 | final_vma.type = VMAType::AllocatedMemoryBlock; |
| 83 | final_vma.permissions = VMAPermission::ReadWrite; | 91 | final_vma.permissions = VMAPermission::ReadWrite; |
| 84 | final_vma.meminfo_state = state; | 92 | final_vma.meminfo_state = state; |
| @@ -98,6 +106,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me | |||
| 98 | VirtualMemoryArea& final_vma = vma_handle->second; | 106 | VirtualMemoryArea& final_vma = vma_handle->second; |
| 99 | ASSERT(final_vma.size == size); | 107 | ASSERT(final_vma.size == size); |
| 100 | 108 | ||
| 109 | Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); | ||
| 110 | |||
| 101 | final_vma.type = VMAType::BackingMemory; | 111 | final_vma.type = VMAType::BackingMemory; |
| 102 | final_vma.permissions = VMAPermission::ReadWrite; | 112 | final_vma.permissions = VMAPermission::ReadWrite; |
| 103 | final_vma.meminfo_state = state; | 113 | final_vma.meminfo_state = state; |
| @@ -328,16 +338,17 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { | |||
| 328 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | 338 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { |
| 329 | switch (vma.type) { | 339 | switch (vma.type) { |
| 330 | case VMAType::Free: | 340 | case VMAType::Free: |
| 331 | Memory::UnmapRegion(vma.base, vma.size); | 341 | Memory::UnmapRegion(page_table, vma.base, vma.size); |
| 332 | break; | 342 | break; |
| 333 | case VMAType::AllocatedMemoryBlock: | 343 | case VMAType::AllocatedMemoryBlock: |
| 334 | Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset); | 344 | Memory::MapMemoryRegion(page_table, vma.base, vma.size, |
| 345 | vma.backing_block->data() + vma.offset); | ||
| 335 | break; | 346 | break; |
| 336 | case VMAType::BackingMemory: | 347 | case VMAType::BackingMemory: |
| 337 | Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory); | 348 | Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); |
| 338 | break; | 349 | break; |
| 339 | case VMAType::MMIO: | 350 | case VMAType::MMIO: |
| 340 | Memory::MapIoRegion(vma.base, vma.size, vma.mmio_handler); | 351 | Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); |
| 341 | break; | 352 | break; |
| 342 | } | 353 | } |
| 343 | } | 354 | } |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index aa2265ce6..cb5bb8243 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 12 | #include "core/memory.h" | ||
| 12 | #include "core/mmio.h" | 13 | #include "core/mmio.h" |
| 13 | 14 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| @@ -102,7 +103,6 @@ struct VirtualMemoryArea { | |||
| 102 | * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ | 103 | * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ |
| 103 | */ | 104 | */ |
| 104 | class VMManager final { | 105 | class VMManager final { |
| 105 | // TODO(yuriks): Make page tables switchable to support multiple VMManagers | ||
| 106 | public: | 106 | public: |
| 107 | /** | 107 | /** |
| 108 | * The maximum amount of address space managed by the kernel. Addresses above this are never | 108 | * The maximum amount of address space managed by the kernel. Addresses above this are never |
| @@ -184,6 +184,10 @@ public: | |||
| 184 | /// Dumps the address space layout to the log, for debugging | 184 | /// Dumps the address space layout to the log, for debugging |
| 185 | void LogLayout(Log::Level log_level) const; | 185 | void LogLayout(Log::Level log_level) const; |
| 186 | 186 | ||
| 187 | /// Each VMManager has its own page table, which is set as the main one when the owning process | ||
| 188 | /// is scheduled. | ||
| 189 | Memory::PageTable page_table; | ||
| 190 | |||
| 187 | private: | 191 | private: |
| 188 | using VMAIter = decltype(vma_map)::iterator; | 192 | using VMAIter = decltype(vma_map)::iterator; |
| 189 | 193 | ||
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index f245eda6c..469554908 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp | |||
| @@ -34,7 +34,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||
| 34 | 34 | ||
| 35 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | 35 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { |
| 36 | Thread* candidate = nullptr; | 36 | Thread* candidate = nullptr; |
| 37 | s32 candidate_priority = THREADPRIO_LOWEST + 1; | 37 | u32 candidate_priority = THREADPRIO_LOWEST + 1; |
| 38 | 38 | ||
| 39 | for (const auto& thread : waiting_threads) { | 39 | for (const auto& thread : waiting_threads) { |
| 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. | 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. |
| @@ -71,23 +71,20 @@ void WaitObject::WakeupAllWaitingThreads() { | |||
| 71 | while (auto thread = GetHighestPriorityReadyThread()) { | 71 | while (auto thread = GetHighestPriorityReadyThread()) { |
| 72 | if (!thread->IsSleepingOnWaitAll()) { | 72 | if (!thread->IsSleepingOnWaitAll()) { |
| 73 | Acquire(thread.get()); | 73 | Acquire(thread.get()); |
| 74 | // Set the output index of the WaitSynchronizationN call to the index of this object. | ||
| 75 | if (thread->wait_set_output) { | ||
| 76 | thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); | ||
| 77 | thread->wait_set_output = false; | ||
| 78 | } | ||
| 79 | } else { | 74 | } else { |
| 80 | for (auto& object : thread->wait_objects) { | 75 | for (auto& object : thread->wait_objects) { |
| 81 | object->Acquire(thread.get()); | 76 | object->Acquire(thread.get()); |
| 82 | } | 77 | } |
| 83 | // Note: This case doesn't update the output index of WaitSynchronizationN. | ||
| 84 | } | 78 | } |
| 85 | 79 | ||
| 80 | // Invoke the wakeup callback before clearing the wait objects | ||
| 81 | if (thread->wakeup_callback) | ||
| 82 | thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this); | ||
| 83 | |||
| 86 | for (auto& object : thread->wait_objects) | 84 | for (auto& object : thread->wait_objects) |
| 87 | object->RemoveWaitingThread(thread.get()); | 85 | object->RemoveWaitingThread(thread.get()); |
| 88 | thread->wait_objects.clear(); | 86 | thread->wait_objects.clear(); |
| 89 | 87 | ||
| 90 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 91 | thread->ResumeFromWait(); | 88 | thread->ResumeFromWait(); |
| 92 | } | 89 | } |
| 93 | } | 90 | } |