aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r--src/core/hle/svc.cpp158
1 files changed, 40 insertions, 118 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index e8ca419d5..e4b803046 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -31,7 +31,6 @@
#include "core/hle/kernel/timer.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/kernel/wait_object.h"
-#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -201,21 +200,17 @@ static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) {
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-static ResultCode ConnectToPort(Kernel::Handle* out_handle, VAddr port_name_address) {
- if (!Memory::IsValidVirtualAddress(port_name_address))
+static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) {
+ if (port_name == nullptr)
return Kernel::ERR_NOT_FOUND;
-
- static constexpr std::size_t PortNameMaxLength = 11;
- // Read 1 char beyond the max allowed port name to detect names that are too long.
- std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
- if (port_name.size() > PortNameMaxLength)
+ if (std::strlen(port_name) > 11)
return Kernel::ERR_PORT_NAME_TOO_LONG;
- LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name.c_str());
+ LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
auto it = Service::g_kernel_named_ports.find(port_name);
if (it == Service::g_kernel_named_ports.end()) {
- LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str());
+ LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name);
return Kernel::ERR_NOT_FOUND;
}
@@ -275,24 +270,6 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds)
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- thread->wakeup_callback = [](ThreadWakeupReason reason,
- Kernel::SharedPtr<Kernel::Thread> thread,
- Kernel::SharedPtr<Kernel::WaitObject> object) {
-
- ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
-
- if (reason == ThreadWakeupReason::Timeout) {
- thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
- return;
- }
-
- ASSERT(reason == ThreadWakeupReason::Signal);
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
-
- // WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
- // don't have to do anything else here.
- };
-
Core::System::GetInstance().PrepareReschedule();
// Note: The output of this SVC will be set to RESULT_SUCCESS if the thread
@@ -307,11 +284,12 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds)
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count,
+static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count,
bool wait_all, s64 nano_seconds) {
Kernel::Thread* thread = Kernel::GetCurrentThread();
- if (!Memory::IsValidVirtualAddress(handles_address))
+ // Check if 'handles' is invalid
+ if (handles == nullptr)
return Kernel::ERR_INVALID_POINTER;
// NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
@@ -326,8 +304,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
std::vector<ObjectPtr> objects(handle_count);
for (int i = 0; i < handle_count; ++i) {
- Kernel::Handle handle = Memory::Read32(handles_address + i * sizeof(Kernel::Handle));
- auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
+ auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
if (object == nullptr)
return ERR_INVALID_HANDLE;
objects[i] = object;
@@ -366,23 +343,6 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- thread->wakeup_callback = [](ThreadWakeupReason reason,
- Kernel::SharedPtr<Kernel::Thread> thread,
- Kernel::SharedPtr<Kernel::WaitObject> object) {
-
- ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ALL);
-
- if (reason == ThreadWakeupReason::Timeout) {
- thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
- return;
- }
-
- ASSERT(reason == ThreadWakeupReason::Signal);
-
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
- // The wait_all case does not update the output index.
- };
-
Core::System::GetInstance().PrepareReschedule();
// This value gets set to -1 by default in this case, it is not modified after this.
@@ -400,7 +360,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
// We found a ready object, acquire it and set the result value
Kernel::WaitObject* object = itr->get();
object->Acquire(thread);
- *out = static_cast<s32>(std::distance(objects.begin(), itr));
+ *out = std::distance(objects.begin(), itr);
return RESULT_SUCCESS;
}
@@ -428,37 +388,22 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- thread->wakeup_callback = [](ThreadWakeupReason reason,
- Kernel::SharedPtr<Kernel::Thread> thread,
- Kernel::SharedPtr<Kernel::WaitObject> object) {
-
- ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
-
- if (reason == ThreadWakeupReason::Timeout) {
- thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
- return;
- }
-
- ASSERT(reason == ThreadWakeupReason::Signal);
-
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
- thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
- };
-
Core::System::GetInstance().PrepareReschedule();
// Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
// signal in one of its wait objects.
// Otherwise we retain the default value of timeout, and -1 in the out parameter
+ thread->wait_set_output = true;
*out = -1;
return Kernel::RESULT_TIMEOUT;
}
}
/// In a single operation, sends a IPC reply and waits for a new request.
-static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count,
+static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count,
Kernel::Handle reply_target) {
- if (!Memory::IsValidVirtualAddress(handles_address))
+ // 'handles' has to be a valid pointer even if 'handle_count' is 0.
+ if (handles == nullptr)
return Kernel::ERR_INVALID_POINTER;
// Check if 'handle_count' is invalid
@@ -469,8 +414,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
std::vector<ObjectPtr> objects(handle_count);
for (int i = 0; i < handle_count; ++i) {
- Kernel::Handle handle = Memory::Read32(handles_address + i * sizeof(Kernel::Handle));
- auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
+ auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
if (object == nullptr)
return ERR_INVALID_HANDLE;
objects[i] = object;
@@ -524,7 +468,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
// We found a ready object, acquire it and set the result value
Kernel::WaitObject* object = itr->get();
object->Acquire(thread);
- *index = static_cast<s32>(std::distance(objects.begin(), itr));
+ *index = std::distance(objects.begin(), itr);
if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
auto server_session = static_cast<Kernel::ServerSession*>(object);
@@ -538,6 +482,8 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
// No objects were ready to be acquired, prepare to suspend the thread.
+ // TODO(Subv): Perform IPC translation upon wakeup.
+
// Put the thread to sleep
thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
@@ -549,24 +495,12 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
thread->wait_objects = std::move(objects);
- thread->wakeup_callback = [](ThreadWakeupReason reason,
- Kernel::SharedPtr<Kernel::Thread> thread,
- Kernel::SharedPtr<Kernel::WaitObject> object) {
-
- ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
- ASSERT(reason == ThreadWakeupReason::Signal);
-
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
- thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
-
- // TODO(Subv): Perform IPC translation upon wakeup.
- };
-
Core::System::GetInstance().PrepareReschedule();
// Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
// signal in one of its wait objects, or to 0xC8A01836 if there was a translation error.
// By default the index is set to -1.
+ thread->wait_set_output = true;
*index = -1;
return RESULT_SUCCESS;
}
@@ -623,10 +557,8 @@ static void Break(u8 break_reason) {
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
-static void OutputDebugString(VAddr address, int len) {
- std::vector<char> string(len);
- Memory::ReadBlock(address, string.data(), len);
- LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data());
+static void OutputDebugString(const char* string, int len) {
+ LOG_DEBUG(Debug_Emulated, "%.*s", len, string);
}
/// Get resource limit
@@ -644,9 +576,9 @@ static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handl
}
/// Get resource limit current values
-static ResultCode GetResourceLimitCurrentValues(VAddr values, Kernel::Handle resource_limit_handle,
- VAddr names, u32 name_count) {
- LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%08X, name_count=%d",
+static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle,
+ u32* names, u32 name_count) {
+ LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
SharedPtr<Kernel::ResourceLimit> resource_limit =
@@ -654,19 +586,16 @@ static ResultCode GetResourceLimitCurrentValues(VAddr values, Kernel::Handle res
if (resource_limit == nullptr)
return ERR_INVALID_HANDLE;
- for (unsigned int i = 0; i < name_count; ++i) {
- u32 name = Memory::Read32(names + i * sizeof(u32));
- s64 value = resource_limit->GetCurrentResourceValue(name);
- Memory::Write64(values + i * sizeof(u64), value);
- }
+ for (unsigned int i = 0; i < name_count; ++i)
+ values[i] = resource_limit->GetCurrentResourceValue(names[i]);
return RESULT_SUCCESS;
}
/// Get resource limit max values
-static ResultCode GetResourceLimitLimitValues(VAddr values, Kernel::Handle resource_limit_handle,
- VAddr names, u32 name_count) {
- LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%08X, name_count=%d",
+static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle,
+ u32* names, u32 name_count) {
+ LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
SharedPtr<Kernel::ResourceLimit> resource_limit =
@@ -674,11 +603,8 @@ static ResultCode GetResourceLimitLimitValues(VAddr values, Kernel::Handle resou
if (resource_limit == nullptr)
return ERR_INVALID_HANDLE;
- for (unsigned int i = 0; i < name_count; ++i) {
- u32 name = Memory::Read32(names + i * sizeof(u32));
- s64 value = resource_limit->GetMaxResourceValue(names);
- Memory::Write64(values + i * sizeof(u64), value);
- }
+ for (unsigned int i = 0; i < name_count; ++i)
+ values[i] = resource_limit->GetMaxResourceValue(names[i]);
return RESULT_SUCCESS;
}
@@ -729,9 +655,8 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 ent
"Newly created thread must run in the SysCore (Core1), unimplemented.");
}
- CASCADE_RESULT(SharedPtr<Thread> thread,
- Kernel::Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
- Kernel::g_current_process));
+ CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority,
+ arg, processor_id, stack_top));
thread->context.fpscr =
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
@@ -756,7 +681,7 @@ static void ExitThread() {
}
/// Gets the priority for the specified thread
-static ResultCode GetThreadPriority(u32* priority, Kernel::Handle handle) {
+static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) {
const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr)
return ERR_INVALID_HANDLE;
@@ -766,7 +691,7 @@ static ResultCode GetThreadPriority(u32* priority, Kernel::Handle handle) {
}
/// Sets the priority for the specified thread
-static ResultCode SetThreadPriority(Kernel::Handle handle, u32 priority) {
+static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) {
if (priority > THREADPRIO_LOWEST) {
return Kernel::ERR_OUT_OF_RANGE;
}
@@ -1051,7 +976,7 @@ static void SleepThread(s64 nanoseconds) {
static s64 GetSystemTick() {
s64 result = CoreTiming::GetTicks();
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
- CoreTiming::AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
+ Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
return result;
}
@@ -1110,9 +1035,9 @@ static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 si
}
static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port,
- VAddr name_address, u32 max_sessions) {
+ const char* name, u32 max_sessions) {
// TODO(Subv): Implement named ports.
- ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented");
+ ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
using Kernel::ServerPort;
using Kernel::ClientPort;
@@ -1263,7 +1188,7 @@ struct FunctionDef {
Func* func;
const char* name;
};
-} // namespace
+}
static const FunctionDef SVC_Table[] = {
{0x00, nullptr, "Unknown"},
@@ -1407,9 +1332,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
void CallSVC(u32 immediate) {
MICROPROFILE_SCOPE(Kernel_SVC);
- // Lock the global kernel mutex when we enter the kernel HLE.
- std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
-
const FunctionDef* info = GetSVCInfo(immediate);
if (info) {
if (info->func) {
@@ -1420,4 +1342,4 @@ void CallSVC(u32 immediate) {
}
}
-} // namespace SVC
+} // namespace