diff options
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 158 |
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 |
