diff options
| author | 2015-01-30 15:00:17 +0100 | |
|---|---|---|
| committer | 2015-01-30 15:00:17 +0100 | |
| commit | 28702cbfeb1fe21109f8b1efa189785594319b78 (patch) | |
| tree | 64e4b1ec43b7699fe1a6ab1be1c688b6d63c0d75 /src/core/hle/svc.cpp | |
| parent | Merge pull request #412 from purpasmart96/svc_table_cleanup (diff) | |
| parent | Kernel: Mark all appropriate kernel objects as "final" (diff) | |
| download | yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.gz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.xz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.zip | |
Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 296 |
1 files changed, 187 insertions, 109 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 3d743f125..88813c2ce 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | // Namespace SVC | 26 | // Namespace SVC |
| 27 | 27 | ||
| 28 | using Kernel::SharedPtr; | 28 | using Kernel::SharedPtr; |
| 29 | using Kernel::ERR_INVALID_HANDLE; | ||
| 29 | 30 | ||
| 30 | namespace SVC { | 31 | namespace SVC { |
| 31 | 32 | ||
| @@ -38,7 +39,7 @@ enum ControlMemoryOperation { | |||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | /// Map application or GSP heap memory | 41 | /// Map application or GSP heap memory |
| 41 | static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | 42 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { |
| 42 | LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | 43 | LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", |
| 43 | operation, addr0, addr1, size, permissions); | 44 | operation, addr0, addr1, size, permissions); |
| 44 | 45 | ||
| @@ -58,35 +59,42 @@ static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, | |||
| 58 | default: | 59 | default: |
| 59 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); | 60 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); |
| 60 | } | 61 | } |
| 61 | return 0; | 62 | return RESULT_SUCCESS; |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | /// Maps a memory block to specified address | 65 | /// Maps a memory block to specified address |
| 65 | static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { | 66 | static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { |
| 67 | using Kernel::SharedMemory; | ||
| 68 | using Kernel::MemoryPermission; | ||
| 69 | |||
| 66 | LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | 70 | LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", |
| 67 | handle, addr, permissions, other_permissions); | 71 | handle, addr, permissions, other_permissions); |
| 68 | 72 | ||
| 69 | Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); | 73 | SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); |
| 74 | if (shared_memory == nullptr) | ||
| 75 | return ERR_INVALID_HANDLE; | ||
| 76 | |||
| 77 | MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); | ||
| 70 | switch (permissions_type) { | 78 | switch (permissions_type) { |
| 71 | case Kernel::MemoryPermission::Read: | 79 | case MemoryPermission::Read: |
| 72 | case Kernel::MemoryPermission::Write: | 80 | case MemoryPermission::Write: |
| 73 | case Kernel::MemoryPermission::ReadWrite: | 81 | case MemoryPermission::ReadWrite: |
| 74 | case Kernel::MemoryPermission::Execute: | 82 | case MemoryPermission::Execute: |
| 75 | case Kernel::MemoryPermission::ReadExecute: | 83 | case MemoryPermission::ReadExecute: |
| 76 | case Kernel::MemoryPermission::WriteExecute: | 84 | case MemoryPermission::WriteExecute: |
| 77 | case Kernel::MemoryPermission::ReadWriteExecute: | 85 | case MemoryPermission::ReadWriteExecute: |
| 78 | case Kernel::MemoryPermission::DontCare: | 86 | case MemoryPermission::DontCare: |
| 79 | Kernel::MapSharedMemory(handle, addr, permissions_type, | 87 | shared_memory->Map(addr, permissions_type, |
| 80 | static_cast<Kernel::MemoryPermission>(other_permissions)); | 88 | static_cast<MemoryPermission>(other_permissions)); |
| 81 | break; | 89 | break; |
| 82 | default: | 90 | default: |
| 83 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | 91 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |
| 84 | } | 92 | } |
| 85 | return 0; | 93 | return RESULT_SUCCESS; |
| 86 | } | 94 | } |
| 87 | 95 | ||
| 88 | /// Connect to an OS service given the port name, returns the handle to the port to out | 96 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 89 | static Result ConnectToPort(Handle* out, const char* port_name) { | 97 | static ResultCode ConnectToPort(Handle* out, const char* port_name) { |
| 90 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | 98 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |
| 91 | 99 | ||
| 92 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); | 100 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); |
| @@ -94,33 +102,33 @@ static Result ConnectToPort(Handle* out, const char* port_name) { | |||
| 94 | 102 | ||
| 95 | *out = service->GetHandle(); | 103 | *out = service->GetHandle(); |
| 96 | 104 | ||
| 97 | return 0; | 105 | return RESULT_SUCCESS; |
| 98 | } | 106 | } |
| 99 | 107 | ||
| 100 | /// Synchronize to an OS service | 108 | /// Synchronize to an OS service |
| 101 | static Result SendSyncRequest(Handle handle) { | 109 | static ResultCode SendSyncRequest(Handle handle) { |
| 102 | SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); | 110 | SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); |
| 103 | if (session == nullptr) { | 111 | if (session == nullptr) { |
| 104 | return InvalidHandle(ErrorModule::Kernel).raw; | 112 | return ERR_INVALID_HANDLE; |
| 105 | } | 113 | } |
| 106 | 114 | ||
| 107 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); | 115 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); |
| 108 | 116 | ||
| 109 | return session->SyncRequest().Code().raw; | 117 | return session->SyncRequest().Code(); |
| 110 | } | 118 | } |
| 111 | 119 | ||
| 112 | /// Close a handle | 120 | /// Close a handle |
| 113 | static Result CloseHandle(Handle handle) { | 121 | static ResultCode CloseHandle(Handle handle) { |
| 114 | // ImplementMe | 122 | // ImplementMe |
| 115 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); | 123 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); |
| 116 | return 0; | 124 | return RESULT_SUCCESS; |
| 117 | } | 125 | } |
| 118 | 126 | ||
| 119 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | 127 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds |
| 120 | static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | 128 | static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { |
| 121 | auto object = Kernel::g_handle_table.GetWaitObject(handle); | 129 | auto object = Kernel::g_handle_table.GetWaitObject(handle); |
| 122 | if (object == nullptr) | 130 | if (object == nullptr) |
| 123 | return InvalidHandle(ErrorModule::Kernel).raw; | 131 | return ERR_INVALID_HANDLE; |
| 124 | 132 | ||
| 125 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, | 133 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, |
| 126 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); | 134 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); |
| @@ -137,22 +145,22 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 137 | HLE::Reschedule(__func__); | 145 | HLE::Reschedule(__func__); |
| 138 | 146 | ||
| 139 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 147 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 140 | return RESULT_INVALID.raw; | 148 | return RESULT_INVALID; |
| 141 | } | 149 | } |
| 142 | 150 | ||
| 143 | object->Acquire(); | 151 | object->Acquire(); |
| 144 | 152 | ||
| 145 | return RESULT_SUCCESS.raw; | 153 | return RESULT_SUCCESS; |
| 146 | } | 154 | } |
| 147 | 155 | ||
| 148 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 156 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 149 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | 157 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { |
| 150 | bool wait_thread = !wait_all; | 158 | bool wait_thread = !wait_all; |
| 151 | int handle_index = 0; | 159 | int handle_index = 0; |
| 152 | 160 | ||
| 153 | // Check if 'handles' is invalid | 161 | // Check if 'handles' is invalid |
| 154 | if (handles == nullptr) | 162 | if (handles == nullptr) |
| 155 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; | 163 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 156 | 164 | ||
| 157 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If | 165 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If |
| 158 | // this happens, the running application will crash. | 166 | // this happens, the running application will crash. |
| @@ -160,7 +168,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 160 | 168 | ||
| 161 | // Check if 'handle_count' is invalid | 169 | // Check if 'handle_count' is invalid |
| 162 | if (handle_count < 0) | 170 | if (handle_count < 0) |
| 163 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; | 171 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 164 | 172 | ||
| 165 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if | 173 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if |
| 166 | // necessary | 174 | // necessary |
| @@ -169,7 +177,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 169 | for (int i = 0; i < handle_count; ++i) { | 177 | for (int i = 0; i < handle_count; ++i) { |
| 170 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); | 178 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); |
| 171 | if (object == nullptr) | 179 | if (object == nullptr) |
| 172 | return InvalidHandle(ErrorModule::Kernel).raw; | 180 | return ERR_INVALID_HANDLE; |
| 173 | 181 | ||
| 174 | // Check if the current thread should wait on this object... | 182 | // Check if the current thread should wait on this object... |
| 175 | if (object->ShouldWait()) { | 183 | if (object->ShouldWait()) { |
| @@ -213,7 +221,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 213 | HLE::Reschedule(__func__); | 221 | HLE::Reschedule(__func__); |
| 214 | 222 | ||
| 215 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 223 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 216 | return RESULT_INVALID.raw; | 224 | return RESULT_INVALID; |
| 217 | } | 225 | } |
| 218 | 226 | ||
| 219 | // Acquire objects if we did not wait... | 227 | // Acquire objects if we did not wait... |
| @@ -235,22 +243,32 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 235 | // not seem to set it to any meaningful value. | 243 | // not seem to set it to any meaningful value. |
| 236 | *out = wait_all ? 0 : handle_index; | 244 | *out = wait_all ? 0 : handle_index; |
| 237 | 245 | ||
| 238 | return RESULT_SUCCESS.raw; | 246 | return RESULT_SUCCESS; |
| 239 | } | 247 | } |
| 240 | 248 | ||
| 241 | /// Create an address arbiter (to allocate access to shared resources) | 249 | /// Create an address arbiter (to allocate access to shared resources) |
| 242 | static Result CreateAddressArbiter(u32* arbiter) { | 250 | static ResultCode CreateAddressArbiter(Handle* out_handle) { |
| 243 | Handle handle = Kernel::CreateAddressArbiter(); | 251 | using Kernel::AddressArbiter; |
| 244 | *arbiter = handle; | 252 | |
| 245 | return 0; | 253 | CASCADE_RESULT(SharedPtr<AddressArbiter> arbiter, AddressArbiter::Create()); |
| 254 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); | ||
| 255 | LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); | ||
| 256 | return RESULT_SUCCESS; | ||
| 246 | } | 257 | } |
| 247 | 258 | ||
| 248 | /// Arbitrate address | 259 | /// Arbitrate address |
| 249 | static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { | 260 | static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { |
| 250 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter, | 261 | using Kernel::AddressArbiter; |
| 262 | |||
| 263 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, | ||
| 251 | address, type, value); | 264 | address, type, value); |
| 252 | return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), | 265 | |
| 253 | address, value, nanoseconds).raw; | 266 | SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); |
| 267 | if (arbiter == nullptr) | ||
| 268 | return ERR_INVALID_HANDLE; | ||
| 269 | |||
| 270 | return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), | ||
| 271 | address, value, nanoseconds); | ||
| 254 | } | 272 | } |
| 255 | 273 | ||
| 256 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 274 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| @@ -259,26 +277,26 @@ static void OutputDebugString(const char* string) { | |||
| 259 | } | 277 | } |
| 260 | 278 | ||
| 261 | /// Get resource limit | 279 | /// Get resource limit |
| 262 | static Result GetResourceLimit(Handle* resource_limit, Handle process) { | 280 | static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { |
| 263 | // With regards to proceess values: | 281 | // With regards to proceess values: |
| 264 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for | 282 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for |
| 265 | // the current KThread. | 283 | // the current KThread. |
| 266 | *resource_limit = 0xDEADBEEF; | 284 | *resource_limit = 0xDEADBEEF; |
| 267 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); | 285 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); |
| 268 | return 0; | 286 | return RESULT_SUCCESS; |
| 269 | } | 287 | } |
| 270 | 288 | ||
| 271 | /// Get resource limit current values | 289 | /// Get resource limit current values |
| 272 | static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, | 290 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, |
| 273 | s32 name_count) { | 291 | s32 name_count) { |
| 274 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", | 292 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", |
| 275 | resource_limit, names, name_count); | 293 | resource_limit, names, name_count); |
| 276 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now | 294 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now |
| 277 | return 0; | 295 | return RESULT_SUCCESS; |
| 278 | } | 296 | } |
| 279 | 297 | ||
| 280 | /// Creates a new thread | 298 | /// Creates a new thread |
| 281 | static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { | 299 | static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { |
| 282 | using Kernel::Thread; | 300 | using Kernel::Thread; |
| 283 | 301 | ||
| 284 | std::string name; | 302 | std::string name; |
| @@ -289,25 +307,20 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | |||
| 289 | name = Common::StringFromFormat("unknown-%08x", entry_point); | 307 | name = Common::StringFromFormat("unknown-%08x", entry_point); |
| 290 | } | 308 | } |
| 291 | 309 | ||
| 292 | ResultVal<SharedPtr<Thread>> thread_res = Kernel::Thread::Create( | 310 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( |
| 293 | name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE); | 311 | name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE)); |
| 294 | if (thread_res.Failed()) | 312 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); |
| 295 | return thread_res.Code().raw; | ||
| 296 | SharedPtr<Thread> thread = std::move(*thread_res); | ||
| 297 | |||
| 298 | // TODO(yuriks): Create new handle instead of using built-in | ||
| 299 | Core::g_app_core->SetReg(1, thread->GetHandle()); | ||
| 300 | 313 | ||
| 301 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 314 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 302 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | 315 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |
| 303 | name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle()); | 316 | name.c_str(), arg, stack_top, priority, processor_id, *out_handle); |
| 304 | 317 | ||
| 305 | if (THREADPROCESSORID_1 == processor_id) { | 318 | if (THREADPROCESSORID_1 == processor_id) { |
| 306 | LOG_WARNING(Kernel_SVC, | 319 | LOG_WARNING(Kernel_SVC, |
| 307 | "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); | 320 | "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); |
| 308 | } | 321 | } |
| 309 | 322 | ||
| 310 | return 0; | 323 | return RESULT_SUCCESS; |
| 311 | } | 324 | } |
| 312 | 325 | ||
| 313 | /// Called when a thread exits | 326 | /// Called when a thread exits |
| @@ -319,128 +332,192 @@ static void ExitThread() { | |||
| 319 | } | 332 | } |
| 320 | 333 | ||
| 321 | /// Gets the priority for the specified thread | 334 | /// Gets the priority for the specified thread |
| 322 | static Result GetThreadPriority(s32* priority, Handle handle) { | 335 | static ResultCode GetThreadPriority(s32* priority, Handle handle) { |
| 323 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 336 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 324 | if (thread == nullptr) | 337 | if (thread == nullptr) |
| 325 | return InvalidHandle(ErrorModule::Kernel).raw; | 338 | return ERR_INVALID_HANDLE; |
| 326 | 339 | ||
| 327 | *priority = thread->GetPriority(); | 340 | *priority = thread->GetPriority(); |
| 328 | return RESULT_SUCCESS.raw; | 341 | return RESULT_SUCCESS; |
| 329 | } | 342 | } |
| 330 | 343 | ||
| 331 | /// Sets the priority for the specified thread | 344 | /// Sets the priority for the specified thread |
| 332 | static Result SetThreadPriority(Handle handle, s32 priority) { | 345 | static ResultCode SetThreadPriority(Handle handle, s32 priority) { |
| 333 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 346 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 334 | if (thread == nullptr) | 347 | if (thread == nullptr) |
| 335 | return InvalidHandle(ErrorModule::Kernel).raw; | 348 | return ERR_INVALID_HANDLE; |
| 336 | 349 | ||
| 337 | thread->SetPriority(priority); | 350 | thread->SetPriority(priority); |
| 338 | return RESULT_SUCCESS.raw; | 351 | return RESULT_SUCCESS; |
| 339 | } | 352 | } |
| 340 | 353 | ||
| 341 | /// Create a mutex | 354 | /// Create a mutex |
| 342 | static Result CreateMutex(Handle* mutex, u32 initial_locked) { | 355 | static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { |
| 343 | *mutex = Kernel::CreateMutex((initial_locked != 0)); | 356 | using Kernel::Mutex; |
| 357 | |||
| 358 | CASCADE_RESULT(SharedPtr<Mutex> mutex, Mutex::Create(initial_locked != 0)); | ||
| 359 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); | ||
| 360 | |||
| 344 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | 361 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |
| 345 | initial_locked ? "true" : "false", *mutex); | 362 | initial_locked ? "true" : "false", *out_handle); |
| 346 | return 0; | 363 | return RESULT_SUCCESS; |
| 347 | } | 364 | } |
| 348 | 365 | ||
| 349 | /// Release a mutex | 366 | /// Release a mutex |
| 350 | static Result ReleaseMutex(Handle handle) { | 367 | static ResultCode ReleaseMutex(Handle handle) { |
| 368 | using Kernel::Mutex; | ||
| 369 | |||
| 351 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); | 370 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); |
| 352 | ResultCode res = Kernel::ReleaseMutex(handle); | 371 | |
| 353 | return res.raw; | 372 | SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle); |
| 373 | if (mutex == nullptr) | ||
| 374 | return ERR_INVALID_HANDLE; | ||
| 375 | |||
| 376 | mutex->Release(); | ||
| 377 | return RESULT_SUCCESS; | ||
| 354 | } | 378 | } |
| 355 | 379 | ||
| 356 | /// Get the ID for the specified thread. | 380 | /// Get the ID for the specified thread. |
| 357 | static Result GetThreadId(u32* thread_id, Handle handle) { | 381 | static ResultCode GetThreadId(u32* thread_id, Handle handle) { |
| 358 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); | 382 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); |
| 359 | 383 | ||
| 360 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 384 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 361 | if (thread == nullptr) | 385 | if (thread == nullptr) |
| 362 | return InvalidHandle(ErrorModule::Kernel).raw; | 386 | return ERR_INVALID_HANDLE; |
| 363 | 387 | ||
| 364 | *thread_id = thread->GetThreadId(); | 388 | *thread_id = thread->GetThreadId(); |
| 365 | return RESULT_SUCCESS.raw; | 389 | return RESULT_SUCCESS; |
| 366 | } | 390 | } |
| 367 | 391 | ||
| 368 | /// Creates a semaphore | 392 | /// Creates a semaphore |
| 369 | static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) { | 393 | static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { |
| 370 | ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count); | 394 | using Kernel::Semaphore; |
| 395 | |||
| 396 | CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count)); | ||
| 397 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); | ||
| 398 | |||
| 371 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", | 399 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", |
| 372 | initial_count, max_count, *semaphore); | 400 | initial_count, max_count, *out_handle); |
| 373 | return res.raw; | 401 | return RESULT_SUCCESS; |
| 374 | } | 402 | } |
| 375 | 403 | ||
| 376 | /// Releases a certain number of slots in a semaphore | 404 | /// Releases a certain number of slots in a semaphore |
| 377 | static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) { | 405 | static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { |
| 378 | LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore); | 406 | using Kernel::Semaphore; |
| 379 | ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count); | 407 | |
| 380 | return res.raw; | 408 | LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); |
| 409 | |||
| 410 | SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle); | ||
| 411 | if (semaphore == nullptr) | ||
| 412 | return ERR_INVALID_HANDLE; | ||
| 413 | |||
| 414 | CASCADE_RESULT(*count, semaphore->Release(release_count)); | ||
| 415 | return RESULT_SUCCESS; | ||
| 381 | } | 416 | } |
| 382 | 417 | ||
| 383 | /// Query memory | 418 | /// Query memory |
| 384 | static Result QueryMemory(void* info, void* out, u32 addr) { | 419 | static ResultCode QueryMemory(void* info, void* out, u32 addr) { |
| 385 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); | 420 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); |
| 386 | return 0; | 421 | return RESULT_SUCCESS; |
| 387 | } | 422 | } |
| 388 | 423 | ||
| 389 | /// Create an event | 424 | /// Create an event |
| 390 | static Result CreateEvent(Handle* evt, u32 reset_type) { | 425 | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { |
| 391 | *evt = Kernel::CreateEvent((ResetType)reset_type); | 426 | CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast<ResetType>(reset_type))); |
| 427 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); | ||
| 428 | |||
| 392 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 429 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |
| 393 | reset_type, *evt); | 430 | reset_type, *out_handle); |
| 394 | return 0; | 431 | return RESULT_SUCCESS; |
| 395 | } | 432 | } |
| 396 | 433 | ||
| 397 | /// Duplicates a kernel handle | 434 | /// Duplicates a kernel handle |
| 398 | static Result DuplicateHandle(Handle* out, Handle handle) { | 435 | static ResultCode DuplicateHandle(Handle* out, Handle handle) { |
| 399 | ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); | 436 | ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); |
| 400 | if (out_h.Succeeded()) { | 437 | if (out_h.Succeeded()) { |
| 401 | *out = *out_h; | 438 | *out = *out_h; |
| 402 | LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); | 439 | LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); |
| 403 | } | 440 | } |
| 404 | return out_h.Code().raw; | 441 | return out_h.Code(); |
| 405 | } | 442 | } |
| 406 | 443 | ||
| 407 | /// Signals an event | 444 | /// Signals an event |
| 408 | static Result SignalEvent(Handle evt) { | 445 | static ResultCode SignalEvent(Handle handle) { |
| 409 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); | 446 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |
| 447 | |||
| 448 | auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||
| 449 | if (evt == nullptr) | ||
| 450 | return ERR_INVALID_HANDLE; | ||
| 451 | |||
| 452 | evt->Signal(); | ||
| 410 | HLE::Reschedule(__func__); | 453 | HLE::Reschedule(__func__); |
| 411 | return Kernel::SignalEvent(evt).raw; | 454 | return RESULT_SUCCESS; |
| 412 | } | 455 | } |
| 413 | 456 | ||
| 414 | /// Clears an event | 457 | /// Clears an event |
| 415 | static Result ClearEvent(Handle evt) { | 458 | static ResultCode ClearEvent(Handle handle) { |
| 416 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); | 459 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |
| 417 | return Kernel::ClearEvent(evt).raw; | 460 | |
| 461 | auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||
| 462 | if (evt == nullptr) | ||
| 463 | return ERR_INVALID_HANDLE; | ||
| 464 | |||
| 465 | evt->Clear(); | ||
| 466 | return RESULT_SUCCESS; | ||
| 418 | } | 467 | } |
| 419 | 468 | ||
| 420 | /// Creates a timer | 469 | /// Creates a timer |
| 421 | static Result CreateTimer(Handle* handle, u32 reset_type) { | 470 | static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { |
| 422 | ResultCode res = Kernel::CreateTimer(handle, static_cast<ResetType>(reset_type)); | 471 | using Kernel::Timer; |
| 472 | |||
| 473 | CASCADE_RESULT(auto timer, Timer::Create(static_cast<ResetType>(reset_type))); | ||
| 474 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); | ||
| 475 | |||
| 423 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 476 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |
| 424 | reset_type, *handle); | 477 | reset_type, *out_handle); |
| 425 | return res.raw; | 478 | return RESULT_SUCCESS; |
| 426 | } | 479 | } |
| 427 | 480 | ||
| 428 | /// Clears a timer | 481 | /// Clears a timer |
| 429 | static Result ClearTimer(Handle handle) { | 482 | static ResultCode ClearTimer(Handle handle) { |
| 483 | using Kernel::Timer; | ||
| 484 | |||
| 430 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 485 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 431 | return Kernel::ClearTimer(handle).raw; | 486 | |
| 487 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 488 | if (timer == nullptr) | ||
| 489 | return ERR_INVALID_HANDLE; | ||
| 490 | |||
| 491 | timer->Clear(); | ||
| 492 | return RESULT_SUCCESS; | ||
| 432 | } | 493 | } |
| 433 | 494 | ||
| 434 | /// Starts a timer | 495 | /// Starts a timer |
| 435 | static Result SetTimer(Handle handle, s64 initial, s64 interval) { | 496 | static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { |
| 497 | using Kernel::Timer; | ||
| 498 | |||
| 436 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 499 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 437 | return Kernel::SetTimer(handle, initial, interval).raw; | 500 | |
| 501 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 502 | if (timer == nullptr) | ||
| 503 | return ERR_INVALID_HANDLE; | ||
| 504 | |||
| 505 | timer->Set(initial, interval); | ||
| 506 | return RESULT_SUCCESS; | ||
| 438 | } | 507 | } |
| 439 | 508 | ||
| 440 | /// Cancels a timer | 509 | /// Cancels a timer |
| 441 | static Result CancelTimer(Handle handle) { | 510 | static ResultCode CancelTimer(Handle handle) { |
| 511 | using Kernel::Timer; | ||
| 512 | |||
| 442 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 513 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 443 | return Kernel::CancelTimer(handle).raw; | 514 | |
| 515 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 516 | if (timer == nullptr) | ||
| 517 | return ERR_INVALID_HANDLE; | ||
| 518 | |||
| 519 | timer->Cancel(); | ||
| 520 | return RESULT_SUCCESS; | ||
| 444 | } | 521 | } |
| 445 | 522 | ||
| 446 | /// Sleep the current thread | 523 | /// Sleep the current thread |
| @@ -462,15 +539,16 @@ static s64 GetSystemTick() { | |||
| 462 | } | 539 | } |
| 463 | 540 | ||
| 464 | /// Creates a memory block at the specified address with the specified permissions and size | 541 | /// Creates a memory block at the specified address with the specified permissions and size |
| 465 | static Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 my_permission, | 542 | static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, |
| 466 | u32 other_permission) { | 543 | u32 other_permission) { |
| 467 | 544 | using Kernel::SharedMemory; | |
| 468 | // TODO(Subv): Implement this function | 545 | // TODO(Subv): Implement this function |
| 469 | 546 | ||
| 470 | Handle shared_memory = Kernel::CreateSharedMemory(); | 547 | CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); |
| 471 | *memblock = shared_memory; | 548 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); |
| 549 | |||
| 472 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); | 550 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); |
| 473 | return 0; | 551 | return RESULT_SUCCESS; |
| 474 | } | 552 | } |
| 475 | 553 | ||
| 476 | const HLE::FunctionDef SVC_Table[] = { | 554 | const HLE::FunctionDef SVC_Table[] = { |