summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/object.cpp2
-rw-r--r--src/core/hle/kernel/process.cpp43
-rw-r--r--src/core/hle/kernel/process.h30
-rw-r--r--src/core/hle/kernel/readable_event.cpp12
-rw-r--r--src/core/hle/kernel/readable_event.h11
-rw-r--r--src/core/hle/kernel/shared_memory.cpp14
-rw-r--r--src/core/hle/kernel/shared_memory.h6
-rw-r--r--src/core/hle/kernel/svc.cpp48
-rw-r--r--src/core/hle/kernel/svc_wrap.h2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp4
-rw-r--r--src/core/hle/kernel/vm_manager.h26
11 files changed, 151 insertions, 47 deletions
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index bb1b68778..0ea851a74 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -15,6 +15,7 @@ bool Object::IsWaitable() const {
switch (GetHandleType()) {
case HandleType::ReadableEvent:
case HandleType::Thread:
+ case HandleType::Process:
case HandleType::Timer:
case HandleType::ServerPort:
case HandleType::ServerSession:
@@ -23,7 +24,6 @@ bool Object::IsWaitable() const {
case HandleType::Unknown:
case HandleType::WritableEvent:
case HandleType::SharedMemory:
- case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::ClientPort:
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 4ecb8c926..c817fb449 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -9,6 +9,7 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/program_metadata.h"
+#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@@ -48,8 +49,24 @@ SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
return resource_limit;
}
+ResultCode Process::ClearSignalState() {
+ if (status == ProcessStatus::Exited) {
+ LOG_ERROR(Kernel, "called on a terminated process instance.");
+ return ERR_INVALID_STATE;
+ }
+
+ if (!is_signaled) {
+ LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
+ return ERR_INVALID_STATE;
+ }
+
+ is_signaled = false;
+ return RESULT_SUCCESS;
+}
+
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
+ ideal_processor = metadata.GetMainThreadCore();
is_64bit_process = metadata.Is64BitProgram();
vm_manager.Reset(metadata.GetAddressSpaceType());
}
@@ -137,13 +154,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
.Unwrap();
vm_manager.LogLayout();
- status = ProcessStatus::Running;
+ ChangeStatus(ProcessStatus::Running);
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
}
void Process::PrepareForTermination() {
- status = ProcessStatus::Exited;
+ ChangeStatus(ProcessStatus::Exiting);
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
for (auto& thread : thread_list) {
@@ -167,6 +184,8 @@ void Process::PrepareForTermination() {
stop_threads(system.Scheduler(1).GetThreadList());
stop_threads(system.Scheduler(2).GetThreadList());
stop_threads(system.Scheduler(3).GetThreadList());
+
+ ChangeStatus(ProcessStatus::Exited);
}
/**
@@ -265,7 +284,25 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
return vm_manager.UnmapRange(dst_addr, size);
}
-Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
+Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
Kernel::Process::~Process() {}
+void Process::Acquire(Thread* thread) {
+ ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
+}
+
+bool Process::ShouldWait(Thread* thread) const {
+ return !is_signaled;
+}
+
+void Process::ChangeStatus(ProcessStatus new_status) {
+ if (status == new_status) {
+ return;
+ }
+
+ status = new_status;
+ is_signaled = true;
+ WakeupAllWaitingThreads();
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 49345aa66..bcb9ac4b8 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -14,9 +14,10 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
+#include "core/hle/kernel/wait_object.h"
+#include "core/hle/result.h"
namespace FileSys {
class ProgramMetadata;
@@ -117,7 +118,7 @@ struct CodeSet final {
VAddr entrypoint = 0;
};
-class Process final : public Object {
+class Process final : public WaitObject {
public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
@@ -212,6 +213,16 @@ public:
return random_entropy.at(index);
}
+ /// Clears the signaled state of the process if and only if it's signaled.
+ ///
+ /// @pre The process must not be already terminated. If this is called on a
+ /// terminated process, then ERR_INVALID_STATE will be returned.
+ ///
+ /// @pre The process must be in a signaled state. If this is called on a
+ /// process instance that is not signaled, ERR_INVALID_STATE will be
+ /// returned.
+ ResultCode ClearSignalState();
+
/**
* Loads process-specifics configuration info with metadata provided
* by an executable.
@@ -260,6 +271,17 @@ private:
explicit Process(KernelCore& kernel);
~Process() override;
+ /// Checks if the specified thread should wait until this process is available.
+ bool ShouldWait(Thread* thread) const override;
+
+ /// Acquires/locks this process for the specified thread if it's available.
+ void Acquire(Thread* thread) override;
+
+ /// Changes the process status. If the status is different
+ /// from the current process status, then this will trigger
+ /// a process signal.
+ void ChangeStatus(ProcessStatus new_status);
+
/// Memory manager for this process.
Kernel::VMManager vm_manager;
@@ -305,6 +327,10 @@ private:
/// specified by metadata provided to the process during loading.
bool is_64bit_process = true;
+ /// Whether or not this process is signaled. This occurs
+ /// upon the process changing to a different state.
+ bool is_signaled = false;
+
/// Total running time for the process in ticks.
u64 total_process_running_time_ticks = 0;
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index 92e16b4e6..ba01f495c 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -4,10 +4,10 @@
#include <algorithm>
#include "common/assert.h"
+#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h"
-#include "core/hle/kernel/writable_event.h"
namespace Kernel {
@@ -34,6 +34,16 @@ void ReadableEvent::Clear() {
signaled = false;
}
+ResultCode ReadableEvent::Reset() {
+ if (!signaled) {
+ return ERR_INVALID_STATE;
+ }
+
+ Clear();
+
+ return RESULT_SUCCESS;
+}
+
void ReadableEvent::WakeupAllWaitingThreads() {
WaitObject::WakeupAllWaitingThreads();
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 867ff3051..80b3b0aba 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -7,6 +7,8 @@
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
+union ResultCode;
+
namespace Kernel {
class KernelCore;
@@ -39,8 +41,17 @@ public:
void WakeupAllWaitingThreads() override;
+ /// Unconditionally clears the readable event's state.
void Clear();
+ /// Clears the readable event's state if and only if it
+ /// has already been signaled.
+ ///
+ /// @pre The event must be in a signaled state. If this event
+ /// is in an unsignaled state and this function is called,
+ /// then ERR_INVALID_STATE will be returned.
+ ResultCode Reset();
+
private:
explicit ReadableEvent(KernelCore& kernel);
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 0494581f5..22d0c1dd5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -17,13 +17,13 @@ namespace Kernel {
SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
SharedMemory::~SharedMemory() = default;
-SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Process> owner_process,
- u64 size, MemoryPermission permissions,
+SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size,
+ MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address,
MemoryRegion region, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
- shared_memory->owner_process = std::move(owner_process);
+ shared_memory->owner_process = owner_process;
shared_memory->name = std::move(name);
shared_memory->size = size;
shared_memory->permissions = permissions;
@@ -39,15 +39,15 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
shared_memory->backing_block.get());
}
} else {
- auto& vm_manager = shared_memory->owner_process->VMManager();
+ const auto& vm_manager = shared_memory->owner_process->VMManager();
// The memory is already available and mapped in the owner process.
- auto vma = vm_manager.FindVMA(address);
- ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
+ const auto vma = vm_manager.FindVMA(address);
+ ASSERT_MSG(vm_manager.IsValidHandle(vma), "Invalid memory address");
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
// The returned VMA might be a bigger one encompassing the desired address.
- auto vma_offset = address - vma->first;
+ const auto vma_offset = address - vma->first;
ASSERT_MSG(vma_offset + size <= vma->second.size,
"Shared memory exceeds bounds of mapped block");
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0b48db699..dab2a6bea 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -45,8 +45,8 @@ public:
* linear heap.
* @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> Create(KernelCore& kernel, SharedPtr<Process> owner_process,
- u64 size, MemoryPermission permissions,
+ static SharedPtr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, u64 size,
+ MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address = 0,
MemoryRegion region = MemoryRegion::BASE,
std::string name = "Unknown");
@@ -139,7 +139,7 @@ private:
/// Permission restrictions applied to other processes mapping the block.
MemoryPermission other_permissions{};
/// Process that created this shared memory block.
- SharedPtr<Process> owner_process;
+ Process* owner_process;
/// Address of shared memory block in the owner process if specified.
VAddr base_address = 0;
/// Name of shared memory object.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index e6c77f9db..8b0b3671a 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -239,7 +239,7 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
}
const VMManager::VMAHandle iter = vm_manager.FindVMA(addr);
- if (iter == vm_manager.vma_map.end()) {
+ if (!vm_manager.IsValidHandle(iter)) {
LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr);
return ERR_INVALID_ADDRESS_STATE;
}
@@ -1077,19 +1077,23 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
process_handle);
return ERR_INVALID_HANDLE;
}
- auto vma = process->VMManager().FindVMA(addr);
+
+ const auto& vm_manager = process->VMManager();
+ const auto vma = vm_manager.FindVMA(addr);
+
memory_info->attributes = 0;
- if (vma == process->VMManager().vma_map.end()) {
- memory_info->base_address = 0;
- memory_info->permission = static_cast<u32>(VMAPermission::None);
- memory_info->size = 0;
- memory_info->type = static_cast<u32>(MemoryState::Unmapped);
- } else {
+ if (vm_manager.IsValidHandle(vma)) {
memory_info->base_address = vma->second.base;
memory_info->permission = static_cast<u32>(vma->second.permissions);
memory_info->size = vma->second.size;
memory_info->type = static_cast<u32>(vma->second.meminfo_state);
+ } else {
+ memory_info->base_address = 0;
+ memory_info->permission = static_cast<u32>(VMAPermission::None);
+ memory_info->size = 0;
+ memory_info->type = static_cast<u32>(MemoryState::Unmapped);
}
+
return RESULT_SUCCESS;
}
@@ -1433,17 +1437,24 @@ static ResultCode CloseHandle(Handle handle) {
return handle_table.Close(handle);
}
-/// Reset an event
+/// Clears the signaled state of an event or process.
static ResultCode ResetSignal(Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+
auto event = handle_table.Get<ReadableEvent>(handle);
+ if (event) {
+ return event->Reset();
+ }
- ASSERT(event != nullptr);
+ auto process = handle_table.Get<Process>(handle);
+ if (process) {
+ return process->ClearSignalState();
+ }
- event->Clear();
- return RESULT_SUCCESS;
+ LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle);
+ return ERR_INVALID_HANDLE;
}
/// Creates a TransferMemory object
@@ -1476,9 +1487,9 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
}
auto& kernel = Core::System::GetInstance().Kernel();
- auto& handle_table = Core::CurrentProcess()->GetHandleTable();
- const auto shared_mem_handle = SharedMemory::Create(
- kernel, handle_table.Get<Process>(CurrentProcess), size, perms, perms, addr);
+ auto process = kernel.CurrentProcess();
+ auto& handle_table = process->GetHandleTable();
+ const auto shared_mem_handle = SharedMemory::Create(kernel, process, size, perms, perms, addr);
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
return RESULT_SUCCESS;
@@ -1588,10 +1599,9 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
}
auto& kernel = Core::System::GetInstance().Kernel();
- auto& handle_table = Core::CurrentProcess()->GetHandleTable();
- auto shared_mem_handle =
- SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
- local_perms, remote_perms);
+ auto process = kernel.CurrentProcess();
+ auto& handle_table = process->GetHandleTable();
+ auto shared_mem_handle = SharedMemory::Create(kernel, process, size, local_perms, remote_perms);
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 24aef46c9..f38e0cb6f 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -129,7 +129,7 @@ void SvcWrap() {
template <ResultCode func(u64, u64, u32, u32)>
void SvcWrap() {
FuncReturn(
- func(Param(0), Param(1), static_cast<u32>(Param(3)), static_cast<u32>(Param(3))).raw);
+ func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
}
template <ResultCode func(u32, u64, u32)>
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 100f8f6bf..6187993ce 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -87,6 +87,10 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
}
}
+bool VMManager::IsValidHandle(VMAHandle handle) const {
+ return handle != vma_map.cend();
+}
+
ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
std::shared_ptr<std::vector<u8>> block,
std::size_t offset, u64 size,
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index d522404fe..a12419d1e 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -113,16 +113,10 @@ struct VirtualMemoryArea {
* - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
*/
class VMManager final {
+ using VMAMap = std::map<VAddr, VirtualMemoryArea>;
+
public:
- /**
- * A map covering the entirety of the managed address space, keyed by the `base` field of each
- * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
- * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
- * merged when possible so that no two similar and adjacent regions exist that have not been
- * merged.
- */
- std::map<VAddr, VirtualMemoryArea> vma_map;
- using VMAHandle = decltype(vma_map)::const_iterator;
+ using VMAHandle = VMAMap::const_iterator;
VMManager();
~VMManager();
@@ -133,6 +127,9 @@ public:
/// Finds the VMA in which the given address is included in, or `vma_map.end()`.
VMAHandle FindVMA(VAddr target) const;
+ /// Indicates whether or not the given handle is within the VMA map.
+ bool IsValidHandle(VMAHandle handle) const;
+
// TODO(yuriks): Should these functions actually return the handle?
/**
@@ -281,7 +278,7 @@ public:
Memory::PageTable page_table;
private:
- using VMAIter = decltype(vma_map)::iterator;
+ using VMAIter = VMAMap::iterator;
/// Converts a VMAHandle to a mutable VMAIter.
VMAIter StripIterConstness(const VMAHandle& iter);
@@ -328,6 +325,15 @@ private:
/// Clears out the page table
void ClearPageTable();
+ /**
+ * A map covering the entirety of the managed address space, keyed by the `base` field of each
+ * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
+ * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
+ * merged when possible so that no two similar and adjacent regions exist that have not been
+ * merged.
+ */
+ VMAMap vma_map;
+
u32 address_space_width = 0;
VAddr address_space_base = 0;
VAddr address_space_end = 0;