diff options
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 512 |
1 files changed, 278 insertions, 234 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 5d71d5619..9d0a9c54c 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -10,8 +10,8 @@ | |||
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "common/symbols.h" | 11 | #include "common/symbols.h" |
| 12 | 12 | ||
| 13 | #include "core/core_timing.h" | ||
| 14 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 14 | #include "core/core_timing.h" | ||
| 15 | 15 | ||
| 16 | #include "core/hle/kernel/address_arbiter.h" | 16 | #include "core/hle/kernel/address_arbiter.h" |
| 17 | #include "core/hle/kernel/client_port.h" | 17 | #include "core/hle/kernel/client_port.h" |
| @@ -40,43 +40,46 @@ using Kernel::ERR_INVALID_HANDLE; | |||
| 40 | namespace SVC { | 40 | namespace SVC { |
| 41 | 41 | ||
| 42 | const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | 42 | const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, |
| 43 | ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA | 43 | ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA |
| 44 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, | 44 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, |
| 45 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E | 45 | ErrorSummary::InvalidArgument, |
| 46 | 46 | ErrorLevel::Usage); // 0xE0E0181E | |
| 47 | const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1 | 47 | |
| 48 | ErrorDescription::MisalignedAddress, ErrorModule::OS, | 48 | const ResultCode ERR_MISALIGNED_ADDRESS{// 0xE0E01BF1 |
| 49 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | 49 | ErrorDescription::MisalignedAddress, ErrorModule::OS, |
| 50 | const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2 | 50 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; |
| 51 | ErrorDescription::MisalignedSize, ErrorModule::OS, | 51 | const ResultCode ERR_MISALIGNED_SIZE{// 0xE0E01BF2 |
| 52 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | 52 | ErrorDescription::MisalignedSize, ErrorModule::OS, |
| 53 | const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE | 53 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; |
| 54 | ErrorDescription::InvalidCombination, ErrorModule::OS, | 54 | const ResultCode ERR_INVALID_COMBINATION{// 0xE0E01BEE |
| 55 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | 55 | ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 56 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 56 | 57 | ||
| 57 | enum ControlMemoryOperation { | 58 | enum ControlMemoryOperation { |
| 58 | MEMOP_FREE = 1, | 59 | MEMOP_FREE = 1, |
| 59 | MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel | 60 | MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel |
| 60 | MEMOP_COMMIT = 3, | 61 | MEMOP_COMMIT = 3, |
| 61 | MEMOP_MAP = 4, | 62 | MEMOP_MAP = 4, |
| 62 | MEMOP_UNMAP = 5, | 63 | MEMOP_UNMAP = 5, |
| 63 | MEMOP_PROTECT = 6, | 64 | MEMOP_PROTECT = 6, |
| 64 | MEMOP_OPERATION_MASK = 0xFF, | 65 | MEMOP_OPERATION_MASK = 0xFF, |
| 65 | 66 | ||
| 66 | MEMOP_REGION_APP = 0x100, | 67 | MEMOP_REGION_APP = 0x100, |
| 67 | MEMOP_REGION_SYSTEM = 0x200, | 68 | MEMOP_REGION_SYSTEM = 0x200, |
| 68 | MEMOP_REGION_BASE = 0x300, | 69 | MEMOP_REGION_BASE = 0x300, |
| 69 | MEMOP_REGION_MASK = 0xF00, | 70 | MEMOP_REGION_MASK = 0xF00, |
| 70 | 71 | ||
| 71 | MEMOP_LINEAR = 0x10000, | 72 | MEMOP_LINEAR = 0x10000, |
| 72 | }; | 73 | }; |
| 73 | 74 | ||
| 74 | /// Map application or GSP heap memory | 75 | /// Map application or GSP heap memory |
| 75 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | 76 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, |
| 77 | u32 permissions) { | ||
| 76 | using namespace Kernel; | 78 | using namespace Kernel; |
| 77 | 79 | ||
| 78 | LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X", | 80 | LOG_DEBUG(Kernel_SVC, |
| 79 | operation, addr0, addr1, size, permissions); | 81 | "called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X", |
| 82 | operation, addr0, addr1, size, permissions); | ||
| 80 | 83 | ||
| 81 | if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { | 84 | if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { |
| 82 | return ERR_MISALIGNED_ADDRESS; | 85 | return ERR_MISALIGNED_ADDRESS; |
| @@ -89,7 +92,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| 89 | operation &= ~MEMOP_REGION_MASK; | 92 | operation &= ~MEMOP_REGION_MASK; |
| 90 | 93 | ||
| 91 | if (region != 0) { | 94 | if (region != 0) { |
| 92 | LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region); | 95 | LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", |
| 96 | region); | ||
| 93 | } | 97 | } |
| 94 | 98 | ||
| 95 | if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) { | 99 | if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) { |
| @@ -100,15 +104,17 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| 100 | auto& process = *g_current_process; | 104 | auto& process = *g_current_process; |
| 101 | 105 | ||
| 102 | switch (operation & MEMOP_OPERATION_MASK) { | 106 | switch (operation & MEMOP_OPERATION_MASK) { |
| 103 | case MEMOP_FREE: | 107 | case MEMOP_FREE: { |
| 104 | { | 108 | // TODO(Subv): What happens if an application tries to FREE a block of memory that has a |
| 105 | // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it? | 109 | // SharedMemory pointing to it? |
| 106 | if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { | 110 | if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { |
| 107 | ResultCode result = process.HeapFree(addr0, size); | 111 | ResultCode result = process.HeapFree(addr0, size); |
| 108 | if (result.IsError()) return result; | 112 | if (result.IsError()) |
| 113 | return result; | ||
| 109 | } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) { | 114 | } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) { |
| 110 | ResultCode result = process.LinearFree(addr0, size); | 115 | ResultCode result = process.LinearFree(addr0, size); |
| 111 | if (result.IsError()) return result; | 116 | if (result.IsError()) |
| 117 | return result; | ||
| 112 | } else { | 118 | } else { |
| 113 | return ERR_INVALID_ADDRESS; | 119 | return ERR_INVALID_ADDRESS; |
| 114 | } | 120 | } |
| @@ -116,8 +122,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| 116 | break; | 122 | break; |
| 117 | } | 123 | } |
| 118 | 124 | ||
| 119 | case MEMOP_COMMIT: | 125 | case MEMOP_COMMIT: { |
| 120 | { | ||
| 121 | if (operation & MEMOP_LINEAR) { | 126 | if (operation & MEMOP_LINEAR) { |
| 122 | CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions)); | 127 | CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions)); |
| 123 | } else { | 128 | } else { |
| @@ -126,23 +131,26 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| 126 | break; | 131 | break; |
| 127 | } | 132 | } |
| 128 | 133 | ||
| 129 | case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented | 134 | case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is |
| 130 | { | 135 | // implemented |
| 131 | CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); | 136 | { |
| 132 | break; | 137 | CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); |
| 133 | } | 138 | break; |
| 139 | } | ||
| 134 | 140 | ||
| 135 | case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented | 141 | case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is |
| 136 | { | 142 | // implemented |
| 137 | ResultCode result = process.HeapFree(addr0, size); | 143 | { |
| 138 | if (result.IsError()) return result; | 144 | ResultCode result = process.HeapFree(addr0, size); |
| 139 | break; | 145 | if (result.IsError()) |
| 140 | } | 146 | return result; |
| 147 | break; | ||
| 148 | } | ||
| 141 | 149 | ||
| 142 | case MEMOP_PROTECT: | 150 | case MEMOP_PROTECT: { |
| 143 | { | ||
| 144 | ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); | 151 | ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); |
| 145 | if (result.IsError()) return result; | 152 | if (result.IsError()) |
| 153 | return result; | ||
| 146 | break; | 154 | break; |
| 147 | } | 155 | } |
| 148 | 156 | ||
| @@ -161,8 +169,9 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o | |||
| 161 | using Kernel::SharedMemory; | 169 | using Kernel::SharedMemory; |
| 162 | using Kernel::MemoryPermission; | 170 | using Kernel::MemoryPermission; |
| 163 | 171 | ||
| 164 | LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | 172 | LOG_TRACE(Kernel_SVC, |
| 165 | handle, addr, permissions, other_permissions); | 173 | "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", |
| 174 | handle, addr, permissions, other_permissions); | ||
| 166 | 175 | ||
| 167 | SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); | 176 | SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); |
| 168 | if (shared_memory == nullptr) | 177 | if (shared_memory == nullptr) |
| @@ -179,12 +188,13 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o | |||
| 179 | case MemoryPermission::ReadWriteExecute: | 188 | case MemoryPermission::ReadWriteExecute: |
| 180 | case MemoryPermission::DontCare: | 189 | case MemoryPermission::DontCare: |
| 181 | return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type, | 190 | return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type, |
| 182 | static_cast<MemoryPermission>(other_permissions)); | 191 | static_cast<MemoryPermission>(other_permissions)); |
| 183 | default: | 192 | default: |
| 184 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | 193 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |
| 185 | } | 194 | } |
| 186 | 195 | ||
| 187 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 196 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 197 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 188 | } | 198 | } |
| 189 | 199 | ||
| 190 | static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { | 200 | static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { |
| @@ -249,7 +259,7 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 249 | return ERR_INVALID_HANDLE; | 259 | return ERR_INVALID_HANDLE; |
| 250 | 260 | ||
| 251 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, | 261 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, |
| 252 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); | 262 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); |
| 253 | 263 | ||
| 254 | HLE::Reschedule(__func__); | 264 | HLE::Reschedule(__func__); |
| 255 | 265 | ||
| @@ -257,7 +267,7 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 257 | if (object->ShouldWait()) { | 267 | if (object->ShouldWait()) { |
| 258 | 268 | ||
| 259 | object->AddWaitingThread(thread); | 269 | object->AddWaitingThread(thread); |
| 260 | Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); | 270 | Kernel::WaitCurrentThread_WaitSynchronization({object}, false, false); |
| 261 | 271 | ||
| 262 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 272 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 263 | thread->WakeAfterDelay(nano_seconds); | 273 | thread->WakeAfterDelay(nano_seconds); |
| @@ -272,7 +282,8 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 272 | } | 282 | } |
| 273 | 283 | ||
| 274 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 284 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 275 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | 285 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, |
| 286 | s64 nano_seconds) { | ||
| 276 | bool wait_thread = !wait_all; | 287 | bool wait_thread = !wait_all; |
| 277 | int handle_index = 0; | 288 | int handle_index = 0; |
| 278 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | 289 | Kernel::Thread* thread = Kernel::GetCurrentThread(); |
| @@ -281,7 +292,8 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 281 | 292 | ||
| 282 | // Check if 'handles' is invalid | 293 | // Check if 'handles' is invalid |
| 283 | if (handles == nullptr) | 294 | if (handles == nullptr) |
| 284 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 295 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, |
| 296 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 285 | 297 | ||
| 286 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If | 298 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If |
| 287 | // this happens, the running application will crash. | 299 | // this happens, the running application will crash. |
| @@ -289,7 +301,8 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 289 | 301 | ||
| 290 | // Check if 'handle_count' is invalid | 302 | // Check if 'handle_count' is invalid |
| 291 | if (handle_count < 0) | 303 | if (handle_count < 0) |
| 292 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 304 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, |
| 305 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 293 | 306 | ||
| 294 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if | 307 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if |
| 295 | // necessary | 308 | // necessary |
| @@ -329,7 +342,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 329 | } | 342 | } |
| 330 | } | 343 | } |
| 331 | 344 | ||
| 332 | SCOPE_EXIT({HLE::Reschedule("WaitSynchronizationN");}); // Reschedule after putting the threads to sleep. | 345 | SCOPE_EXIT({ |
| 346 | HLE::Reschedule("WaitSynchronizationN"); | ||
| 347 | }); // Reschedule after putting the threads to sleep. | ||
| 333 | 348 | ||
| 334 | // If thread should wait, then set its state to waiting | 349 | // If thread should wait, then set its state to waiting |
| 335 | if (wait_thread) { | 350 | if (wait_thread) { |
| @@ -386,18 +401,19 @@ static ResultCode CreateAddressArbiter(Handle* out_handle) { | |||
| 386 | } | 401 | } |
| 387 | 402 | ||
| 388 | /// Arbitrate address | 403 | /// Arbitrate address |
| 389 | static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { | 404 | static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, |
| 405 | s64 nanoseconds) { | ||
| 390 | using Kernel::AddressArbiter; | 406 | using Kernel::AddressArbiter; |
| 391 | 407 | ||
| 392 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, | 408 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, |
| 393 | address, type, value); | 409 | address, type, value); |
| 394 | 410 | ||
| 395 | SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); | 411 | SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); |
| 396 | if (arbiter == nullptr) | 412 | if (arbiter == nullptr) |
| 397 | return ERR_INVALID_HANDLE; | 413 | return ERR_INVALID_HANDLE; |
| 398 | 414 | ||
| 399 | auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), | 415 | auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), address, value, |
| 400 | address, value, nanoseconds); | 416 | nanoseconds); |
| 401 | 417 | ||
| 402 | return res; | 418 | return res; |
| 403 | } | 419 | } |
| @@ -406,10 +422,18 @@ static void Break(u8 break_reason) { | |||
| 406 | LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); | 422 | LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); |
| 407 | std::string reason_str; | 423 | std::string reason_str; |
| 408 | switch (break_reason) { | 424 | switch (break_reason) { |
| 409 | case 0: reason_str = "PANIC"; break; | 425 | case 0: |
| 410 | case 1: reason_str = "ASSERT"; break; | 426 | reason_str = "PANIC"; |
| 411 | case 2: reason_str = "USER"; break; | 427 | break; |
| 412 | default: reason_str = "UNKNOWN"; break; | 428 | case 1: |
| 429 | reason_str = "ASSERT"; | ||
| 430 | break; | ||
| 431 | case 2: | ||
| 432 | reason_str = "USER"; | ||
| 433 | break; | ||
| 434 | default: | ||
| 435 | reason_str = "UNKNOWN"; | ||
| 436 | break; | ||
| 413 | } | 437 | } |
| 414 | LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str()); | 438 | LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str()); |
| 415 | } | 439 | } |
| @@ -423,7 +447,8 @@ static void OutputDebugString(const char* string) { | |||
| 423 | static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { | 447 | static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { |
| 424 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); | 448 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); |
| 425 | 449 | ||
| 426 | SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle); | 450 | SharedPtr<Kernel::Process> process = |
| 451 | Kernel::g_handle_table.Get<Kernel::Process>(process_handle); | ||
| 427 | if (process == nullptr) | 452 | if (process == nullptr) |
| 428 | return ERR_INVALID_HANDLE; | 453 | return ERR_INVALID_HANDLE; |
| 429 | 454 | ||
| @@ -433,12 +458,13 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle | |||
| 433 | } | 458 | } |
| 434 | 459 | ||
| 435 | /// Get resource limit current values | 460 | /// Get resource limit current values |
| 436 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names, | 461 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, |
| 437 | u32 name_count) { | 462 | u32* names, u32 name_count) { |
| 438 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", | 463 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", |
| 439 | resource_limit_handle, names, name_count); | 464 | resource_limit_handle, names, name_count); |
| 440 | 465 | ||
| 441 | SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); | 466 | SharedPtr<Kernel::ResourceLimit> resource_limit = |
| 467 | Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); | ||
| 442 | if (resource_limit == nullptr) | 468 | if (resource_limit == nullptr) |
| 443 | return ERR_INVALID_HANDLE; | 469 | return ERR_INVALID_HANDLE; |
| 444 | 470 | ||
| @@ -450,11 +476,12 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim | |||
| 450 | 476 | ||
| 451 | /// Get resource limit max values | 477 | /// Get resource limit max values |
| 452 | static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, | 478 | static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, |
| 453 | u32 name_count) { | 479 | u32 name_count) { |
| 454 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", | 480 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", |
| 455 | resource_limit_handle, names, name_count); | 481 | resource_limit_handle, names, name_count); |
| 456 | 482 | ||
| 457 | SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); | 483 | SharedPtr<Kernel::ResourceLimit> resource_limit = |
| 484 | Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); | ||
| 458 | if (resource_limit == nullptr) | 485 | if (resource_limit == nullptr) |
| 459 | return ERR_INVALID_HANDLE; | 486 | return ERR_INVALID_HANDLE; |
| 460 | 487 | ||
| @@ -465,7 +492,8 @@ static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit | |||
| 465 | } | 492 | } |
| 466 | 493 | ||
| 467 | /// Creates a new thread | 494 | /// Creates a new thread |
| 468 | static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { | 495 | static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, |
| 496 | u32 stack_top, s32 processor_id) { | ||
| 469 | using Kernel::Thread; | 497 | using Kernel::Thread; |
| 470 | 498 | ||
| 471 | std::string name; | 499 | std::string name; |
| @@ -499,20 +527,23 @@ static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point | |||
| 499 | } | 527 | } |
| 500 | 528 | ||
| 501 | if (processor_id == THREADPROCESSORID_1 || processor_id == THREADPROCESSORID_ALL || | 529 | if (processor_id == THREADPROCESSORID_1 || processor_id == THREADPROCESSORID_ALL || |
| 502 | (processor_id == THREADPROCESSORID_DEFAULT && Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1)) { | 530 | (processor_id == THREADPROCESSORID_DEFAULT && |
| 503 | LOG_WARNING(Kernel_SVC, "Newly created thread is allowed to be run in the SysCore, unimplemented."); | 531 | Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1)) { |
| 532 | LOG_WARNING(Kernel_SVC, | ||
| 533 | "Newly created thread is allowed to be run in the SysCore, unimplemented."); | ||
| 504 | } | 534 | } |
| 505 | 535 | ||
| 506 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( | 536 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority, |
| 507 | name, entry_point, priority, arg, processor_id, stack_top)); | 537 | arg, processor_id, stack_top)); |
| 508 | 538 | ||
| 509 | thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 | 539 | thread->context.fpscr = |
| 540 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 | ||
| 510 | 541 | ||
| 511 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); | 542 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); |
| 512 | 543 | ||
| 513 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 544 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 514 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | 545 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", |
| 515 | name.c_str(), arg, stack_top, priority, processor_id, *out_handle); | 546 | entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle); |
| 516 | 547 | ||
| 517 | return RESULT_SUCCESS; | 548 | return RESULT_SUCCESS; |
| 518 | } | 549 | } |
| @@ -552,7 +583,7 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { | |||
| 552 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); | 583 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); |
| 553 | 584 | ||
| 554 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | 585 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |
| 555 | initial_locked ? "true" : "false", *out_handle); | 586 | initial_locked ? "true" : "false", *out_handle); |
| 556 | 587 | ||
| 557 | return RESULT_SUCCESS; | 588 | return RESULT_SUCCESS; |
| 558 | } | 589 | } |
| @@ -576,7 +607,8 @@ static ResultCode ReleaseMutex(Handle handle) { | |||
| 576 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | 607 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { |
| 577 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); | 608 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); |
| 578 | 609 | ||
| 579 | const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle); | 610 | const SharedPtr<Kernel::Process> process = |
| 611 | Kernel::g_handle_table.Get<Kernel::Process>(process_handle); | ||
| 580 | if (process == nullptr) | 612 | if (process == nullptr) |
| 581 | return ERR_INVALID_HANDLE; | 613 | return ERR_INVALID_HANDLE; |
| 582 | 614 | ||
| @@ -588,7 +620,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | |||
| 588 | static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { | 620 | static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { |
| 589 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); | 621 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); |
| 590 | 622 | ||
| 591 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle); | 623 | const SharedPtr<Kernel::Thread> thread = |
| 624 | Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle); | ||
| 592 | if (thread == nullptr) | 625 | if (thread == nullptr) |
| 593 | return ERR_INVALID_HANDLE; | 626 | return ERR_INVALID_HANDLE; |
| 594 | 627 | ||
| @@ -620,7 +653,7 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max | |||
| 620 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); | 653 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); |
| 621 | 654 | ||
| 622 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", | 655 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", |
| 623 | initial_count, max_count, *out_handle); | 656 | initial_count, max_count, *out_handle); |
| 624 | return RESULT_SUCCESS; | 657 | return RESULT_SUCCESS; |
| 625 | } | 658 | } |
| 626 | 659 | ||
| @@ -640,7 +673,8 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) | |||
| 640 | } | 673 | } |
| 641 | 674 | ||
| 642 | /// Query process memory | 675 | /// Query process memory |
| 643 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) { | 676 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, |
| 677 | Handle process_handle, u32 addr) { | ||
| 644 | using Kernel::Process; | 678 | using Kernel::Process; |
| 645 | Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); | 679 | Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); |
| 646 | if (process == nullptr) | 680 | if (process == nullptr) |
| @@ -649,7 +683,8 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf | |||
| 649 | auto vma = process->vm_manager.FindVMA(addr); | 683 | auto vma = process->vm_manager.FindVMA(addr); |
| 650 | 684 | ||
| 651 | if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) | 685 | if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) |
| 652 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 686 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, |
| 687 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 653 | 688 | ||
| 654 | memory_info->base_address = vma->second.base; | 689 | memory_info->base_address = vma->second.base; |
| 655 | memory_info->permission = static_cast<u32>(vma->second.permissions); | 690 | memory_info->permission = static_cast<u32>(vma->second.permissions); |
| @@ -673,8 +708,8 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | |||
| 673 | SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type)); | 708 | SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type)); |
| 674 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); | 709 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); |
| 675 | 710 | ||
| 676 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 711 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, |
| 677 | reset_type, *out_handle); | 712 | *out_handle); |
| 678 | return RESULT_SUCCESS; | 713 | return RESULT_SUCCESS; |
| 679 | } | 714 | } |
| 680 | 715 | ||
| @@ -719,8 +754,8 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { | |||
| 719 | SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type)); | 754 | SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type)); |
| 720 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); | 755 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); |
| 721 | 756 | ||
| 722 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 757 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, |
| 723 | reset_type, *out_handle); | 758 | *out_handle); |
| 724 | return RESULT_SUCCESS; | 759 | return RESULT_SUCCESS; |
| 725 | } | 760 | } |
| 726 | 761 | ||
| @@ -783,17 +818,19 @@ static void SleepThread(s64 nanoseconds) { | |||
| 783 | static s64 GetSystemTick() { | 818 | static s64 GetSystemTick() { |
| 784 | s64 result = CoreTiming::GetTicks(); | 819 | s64 result = CoreTiming::GetTicks(); |
| 785 | // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. | 820 | // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. |
| 786 | Core::g_app_core->AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b | 821 | Core::g_app_core->AddTicks( |
| 822 | 150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b | ||
| 787 | return result; | 823 | return result; |
| 788 | } | 824 | } |
| 789 | 825 | ||
| 790 | /// Creates a memory block at the specified address with the specified permissions and size | 826 | /// Creates a memory block at the specified address with the specified permissions and size |
| 791 | static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, | 827 | static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, |
| 792 | u32 other_permission) { | 828 | u32 other_permission) { |
| 793 | using Kernel::SharedMemory; | 829 | using Kernel::SharedMemory; |
| 794 | 830 | ||
| 795 | if (size % Memory::PAGE_SIZE != 0) | 831 | if (size % Memory::PAGE_SIZE != 0) |
| 796 | return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 832 | return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, |
| 833 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 797 | 834 | ||
| 798 | SharedPtr<SharedMemory> shared_memory = nullptr; | 835 | SharedPtr<SharedMemory> shared_memory = nullptr; |
| 799 | 836 | ||
| @@ -818,25 +855,29 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||
| 818 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 855 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 819 | 856 | ||
| 820 | if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) { | 857 | if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) { |
| 821 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 858 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, |
| 859 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 822 | } | 860 | } |
| 823 | 861 | ||
| 824 | // When trying to create a memory block with address = 0, | 862 | // When trying to create a memory block with address = 0, |
| 825 | // if the process has the Shared Device Memory flag in the exheader, | 863 | // if the process has the Shared Device Memory flag in the exheader, |
| 826 | // then we have to allocate from the same region as the caller process instead of the BASE region. | 864 | // then we have to allocate from the same region as the caller process instead of the BASE |
| 865 | // region. | ||
| 827 | Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE; | 866 | Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE; |
| 828 | if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem) | 867 | if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem) |
| 829 | region = Kernel::g_current_process->flags.memory_region; | 868 | region = Kernel::g_current_process->flags.memory_region; |
| 830 | 869 | ||
| 831 | shared_memory = SharedMemory::Create(Kernel::g_current_process, size, | 870 | shared_memory = SharedMemory::Create( |
| 832 | static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region); | 871 | Kernel::g_current_process, size, static_cast<MemoryPermission>(my_permission), |
| 872 | static_cast<MemoryPermission>(other_permission), addr, region); | ||
| 833 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); | 873 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); |
| 834 | 874 | ||
| 835 | LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr); | 875 | LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr); |
| 836 | return RESULT_SUCCESS; | 876 | return RESULT_SUCCESS; |
| 837 | } | 877 | } |
| 838 | 878 | ||
| 839 | static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, u32 max_sessions) { | 879 | static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, |
| 880 | u32 max_sessions) { | ||
| 840 | // TODO(Subv): Implement named ports. | 881 | // TODO(Subv): Implement named ports. |
| 841 | ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); | 882 | ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); |
| 842 | 883 | ||
| @@ -845,9 +886,12 @@ static ResultCode CreatePort(Handle* server_port, Handle* client_port, const cha | |||
| 845 | using Kernel::SharedPtr; | 886 | using Kernel::SharedPtr; |
| 846 | 887 | ||
| 847 | auto ports = ServerPort::CreatePortPair(max_sessions); | 888 | auto ports = ServerPort::CreatePortPair(max_sessions); |
| 848 | CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ClientPort>>(ports)))); | 889 | CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create( |
| 849 | // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be created. | 890 | std::move(std::get<SharedPtr<ClientPort>>(ports)))); |
| 850 | CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ServerPort>>(ports)))); | 891 | // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be |
| 892 | // created. | ||
| 893 | CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create( | ||
| 894 | std::move(std::get<SharedPtr<ServerPort>>(ports)))); | ||
| 851 | 895 | ||
| 852 | LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); | 896 | LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); |
| 853 | return RESULT_SUCCESS; | 897 | return RESULT_SUCCESS; |
| @@ -862,9 +906,9 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { | |||
| 862 | case SystemInfoType::REGION_MEMORY_USAGE: | 906 | case SystemInfoType::REGION_MEMORY_USAGE: |
| 863 | switch ((SystemInfoMemUsageRegion)param) { | 907 | switch ((SystemInfoMemUsageRegion)param) { |
| 864 | case SystemInfoMemUsageRegion::ALL: | 908 | case SystemInfoMemUsageRegion::ALL: |
| 865 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used | 909 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used + |
| 866 | + Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used | 910 | Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used + |
| 867 | + Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; | 911 | Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; |
| 868 | break; | 912 | break; |
| 869 | case SystemInfoMemUsageRegion::APPLICATION: | 913 | case SystemInfoMemUsageRegion::APPLICATION: |
| 870 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used; | 914 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used; |
| @@ -912,7 +956,7 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | |||
| 912 | // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure | 956 | // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure |
| 913 | // what's the difference between them. | 957 | // what's the difference between them. |
| 914 | *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; | 958 | *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; |
| 915 | if(*out % Memory::PAGE_SIZE != 0) { | 959 | if (*out % Memory::PAGE_SIZE != 0) { |
| 916 | LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); | 960 | LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); |
| 917 | return ERR_MISALIGNED_SIZE; | 961 | return ERR_MISALIGNED_SIZE; |
| 918 | } | 962 | } |
| @@ -935,12 +979,12 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | |||
| 935 | 979 | ||
| 936 | if (type >= 21 && type <= 23) { | 980 | if (type >= 21 && type <= 23) { |
| 937 | return ResultCode( // 0xE0E01BF4 | 981 | return ResultCode( // 0xE0E01BF4 |
| 938 | ErrorDescription::NotImplemented, ErrorModule::OS, | 982 | ErrorDescription::NotImplemented, ErrorModule::OS, ErrorSummary::InvalidArgument, |
| 939 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 983 | ErrorLevel::Usage); |
| 940 | } else { | 984 | } else { |
| 941 | return ResultCode( // 0xD8E007ED | 985 | return ResultCode( // 0xD8E007ED |
| 942 | ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | 986 | ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, |
| 943 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 987 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 944 | } | 988 | } |
| 945 | break; | 989 | break; |
| 946 | } | 990 | } |
| @@ -949,142 +993,142 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | |||
| 949 | } | 993 | } |
| 950 | 994 | ||
| 951 | namespace { | 995 | namespace { |
| 952 | struct FunctionDef { | 996 | struct FunctionDef { |
| 953 | using Func = void(); | 997 | using Func = void(); |
| 954 | 998 | ||
| 955 | u32 id; | 999 | u32 id; |
| 956 | Func* func; | 1000 | Func* func; |
| 957 | const char* name; | 1001 | const char* name; |
| 958 | }; | 1002 | }; |
| 959 | } | 1003 | } |
| 960 | 1004 | ||
| 961 | static const FunctionDef SVC_Table[] = { | 1005 | static const FunctionDef SVC_Table[] = { |
| 962 | {0x00, nullptr, "Unknown"}, | 1006 | {0x00, nullptr, "Unknown"}, |
| 963 | {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"}, | 1007 | {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"}, |
| 964 | {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"}, | 1008 | {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"}, |
| 965 | {0x03, nullptr, "ExitProcess"}, | 1009 | {0x03, nullptr, "ExitProcess"}, |
| 966 | {0x04, nullptr, "GetProcessAffinityMask"}, | 1010 | {0x04, nullptr, "GetProcessAffinityMask"}, |
| 967 | {0x05, nullptr, "SetProcessAffinityMask"}, | 1011 | {0x05, nullptr, "SetProcessAffinityMask"}, |
| 968 | {0x06, nullptr, "GetProcessIdealProcessor"}, | 1012 | {0x06, nullptr, "GetProcessIdealProcessor"}, |
| 969 | {0x07, nullptr, "SetProcessIdealProcessor"}, | 1013 | {0x07, nullptr, "SetProcessIdealProcessor"}, |
| 970 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, | 1014 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, |
| 971 | {0x09, ExitThread, "ExitThread"}, | 1015 | {0x09, ExitThread, "ExitThread"}, |
| 972 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, | 1016 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, |
| 973 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, | 1017 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, |
| 974 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, | 1018 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, |
| 975 | {0x0D, nullptr, "GetThreadAffinityMask"}, | 1019 | {0x0D, nullptr, "GetThreadAffinityMask"}, |
| 976 | {0x0E, nullptr, "SetThreadAffinityMask"}, | 1020 | {0x0E, nullptr, "SetThreadAffinityMask"}, |
| 977 | {0x0F, nullptr, "GetThreadIdealProcessor"}, | 1021 | {0x0F, nullptr, "GetThreadIdealProcessor"}, |
| 978 | {0x10, nullptr, "SetThreadIdealProcessor"}, | 1022 | {0x10, nullptr, "SetThreadIdealProcessor"}, |
| 979 | {0x11, nullptr, "GetCurrentProcessorNumber"}, | 1023 | {0x11, nullptr, "GetCurrentProcessorNumber"}, |
| 980 | {0x12, nullptr, "Run"}, | 1024 | {0x12, nullptr, "Run"}, |
| 981 | {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"}, | 1025 | {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"}, |
| 982 | {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, | 1026 | {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, |
| 983 | {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"}, | 1027 | {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"}, |
| 984 | {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"}, | 1028 | {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"}, |
| 985 | {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, | 1029 | {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, |
| 986 | {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, | 1030 | {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, |
| 987 | {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, | 1031 | {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, |
| 988 | {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"}, | 1032 | {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"}, |
| 989 | {0x1B, HLE::Wrap<SetTimer>, "SetTimer"}, | 1033 | {0x1B, HLE::Wrap<SetTimer>, "SetTimer"}, |
| 990 | {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"}, | 1034 | {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"}, |
| 991 | {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"}, | 1035 | {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"}, |
| 992 | {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, | 1036 | {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, |
| 993 | {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, | 1037 | {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, |
| 994 | {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"}, | 1038 | {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"}, |
| 995 | {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, | 1039 | {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, |
| 996 | {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"}, | 1040 | {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"}, |
| 997 | {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"}, | 1041 | {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"}, |
| 998 | {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, | 1042 | {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, |
| 999 | {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"}, | 1043 | {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"}, |
| 1000 | {0x26, nullptr, "SignalAndWait"}, | 1044 | {0x26, nullptr, "SignalAndWait"}, |
| 1001 | {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, | 1045 | {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, |
| 1002 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, | 1046 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, |
| 1003 | {0x29, nullptr, "GetHandleInfo"}, | 1047 | {0x29, nullptr, "GetHandleInfo"}, |
| 1004 | {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"}, | 1048 | {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"}, |
| 1005 | {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, | 1049 | {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, |
| 1006 | {0x2C, nullptr, "GetThreadInfo"}, | 1050 | {0x2C, nullptr, "GetThreadInfo"}, |
| 1007 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, | 1051 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, |
| 1008 | {0x2E, nullptr, "SendSyncRequest1"}, | 1052 | {0x2E, nullptr, "SendSyncRequest1"}, |
| 1009 | {0x2F, nullptr, "SendSyncRequest2"}, | 1053 | {0x2F, nullptr, "SendSyncRequest2"}, |
| 1010 | {0x30, nullptr, "SendSyncRequest3"}, | 1054 | {0x30, nullptr, "SendSyncRequest3"}, |
| 1011 | {0x31, nullptr, "SendSyncRequest4"}, | 1055 | {0x31, nullptr, "SendSyncRequest4"}, |
| 1012 | {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, | 1056 | {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, |
| 1013 | {0x33, nullptr, "OpenProcess"}, | 1057 | {0x33, nullptr, "OpenProcess"}, |
| 1014 | {0x34, nullptr, "OpenThread"}, | 1058 | {0x34, nullptr, "OpenThread"}, |
| 1015 | {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, | 1059 | {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, |
| 1016 | {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, | 1060 | {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, |
| 1017 | {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, | 1061 | {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, |
| 1018 | {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, | 1062 | {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, |
| 1019 | {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, | 1063 | {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, |
| 1020 | {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, | 1064 | {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, |
| 1021 | {0x3B, nullptr, "GetThreadContext"}, | 1065 | {0x3B, nullptr, "GetThreadContext"}, |
| 1022 | {0x3C, HLE::Wrap<Break>, "Break"}, | 1066 | {0x3C, HLE::Wrap<Break>, "Break"}, |
| 1023 | {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, | 1067 | {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, |
| 1024 | {0x3E, nullptr, "ControlPerformanceCounter"}, | 1068 | {0x3E, nullptr, "ControlPerformanceCounter"}, |
| 1025 | {0x3F, nullptr, "Unknown"}, | 1069 | {0x3F, nullptr, "Unknown"}, |
| 1026 | {0x40, nullptr, "Unknown"}, | 1070 | {0x40, nullptr, "Unknown"}, |
| 1027 | {0x41, nullptr, "Unknown"}, | 1071 | {0x41, nullptr, "Unknown"}, |
| 1028 | {0x42, nullptr, "Unknown"}, | 1072 | {0x42, nullptr, "Unknown"}, |
| 1029 | {0x43, nullptr, "Unknown"}, | 1073 | {0x43, nullptr, "Unknown"}, |
| 1030 | {0x44, nullptr, "Unknown"}, | 1074 | {0x44, nullptr, "Unknown"}, |
| 1031 | {0x45, nullptr, "Unknown"}, | 1075 | {0x45, nullptr, "Unknown"}, |
| 1032 | {0x46, nullptr, "Unknown"}, | 1076 | {0x46, nullptr, "Unknown"}, |
| 1033 | {0x47, HLE::Wrap<CreatePort>, "CreatePort"}, | 1077 | {0x47, HLE::Wrap<CreatePort>, "CreatePort"}, |
| 1034 | {0x48, nullptr, "CreateSessionToPort"}, | 1078 | {0x48, nullptr, "CreateSessionToPort"}, |
| 1035 | {0x49, nullptr, "CreateSession"}, | 1079 | {0x49, nullptr, "CreateSession"}, |
| 1036 | {0x4A, nullptr, "AcceptSession"}, | 1080 | {0x4A, nullptr, "AcceptSession"}, |
| 1037 | {0x4B, nullptr, "ReplyAndReceive1"}, | 1081 | {0x4B, nullptr, "ReplyAndReceive1"}, |
| 1038 | {0x4C, nullptr, "ReplyAndReceive2"}, | 1082 | {0x4C, nullptr, "ReplyAndReceive2"}, |
| 1039 | {0x4D, nullptr, "ReplyAndReceive3"}, | 1083 | {0x4D, nullptr, "ReplyAndReceive3"}, |
| 1040 | {0x4E, nullptr, "ReplyAndReceive4"}, | 1084 | {0x4E, nullptr, "ReplyAndReceive4"}, |
| 1041 | {0x4F, nullptr, "ReplyAndReceive"}, | 1085 | {0x4F, nullptr, "ReplyAndReceive"}, |
| 1042 | {0x50, nullptr, "BindInterrupt"}, | 1086 | {0x50, nullptr, "BindInterrupt"}, |
| 1043 | {0x51, nullptr, "UnbindInterrupt"}, | 1087 | {0x51, nullptr, "UnbindInterrupt"}, |
| 1044 | {0x52, nullptr, "InvalidateProcessDataCache"}, | 1088 | {0x52, nullptr, "InvalidateProcessDataCache"}, |
| 1045 | {0x53, nullptr, "StoreProcessDataCache"}, | 1089 | {0x53, nullptr, "StoreProcessDataCache"}, |
| 1046 | {0x54, nullptr, "FlushProcessDataCache"}, | 1090 | {0x54, nullptr, "FlushProcessDataCache"}, |
| 1047 | {0x55, nullptr, "StartInterProcessDma"}, | 1091 | {0x55, nullptr, "StartInterProcessDma"}, |
| 1048 | {0x56, nullptr, "StopDma"}, | 1092 | {0x56, nullptr, "StopDma"}, |
| 1049 | {0x57, nullptr, "GetDmaState"}, | 1093 | {0x57, nullptr, "GetDmaState"}, |
| 1050 | {0x58, nullptr, "RestartDma"}, | 1094 | {0x58, nullptr, "RestartDma"}, |
| 1051 | {0x59, nullptr, "Unknown"}, | 1095 | {0x59, nullptr, "Unknown"}, |
| 1052 | {0x5A, nullptr, "Unknown"}, | 1096 | {0x5A, nullptr, "Unknown"}, |
| 1053 | {0x5B, nullptr, "Unknown"}, | 1097 | {0x5B, nullptr, "Unknown"}, |
| 1054 | {0x5C, nullptr, "Unknown"}, | 1098 | {0x5C, nullptr, "Unknown"}, |
| 1055 | {0x5D, nullptr, "Unknown"}, | 1099 | {0x5D, nullptr, "Unknown"}, |
| 1056 | {0x5E, nullptr, "Unknown"}, | 1100 | {0x5E, nullptr, "Unknown"}, |
| 1057 | {0x5F, nullptr, "Unknown"}, | 1101 | {0x5F, nullptr, "Unknown"}, |
| 1058 | {0x60, nullptr, "DebugActiveProcess"}, | 1102 | {0x60, nullptr, "DebugActiveProcess"}, |
| 1059 | {0x61, nullptr, "BreakDebugProcess"}, | 1103 | {0x61, nullptr, "BreakDebugProcess"}, |
| 1060 | {0x62, nullptr, "TerminateDebugProcess"}, | 1104 | {0x62, nullptr, "TerminateDebugProcess"}, |
| 1061 | {0x63, nullptr, "GetProcessDebugEvent"}, | 1105 | {0x63, nullptr, "GetProcessDebugEvent"}, |
| 1062 | {0x64, nullptr, "ContinueDebugEvent"}, | 1106 | {0x64, nullptr, "ContinueDebugEvent"}, |
| 1063 | {0x65, nullptr, "GetProcessList"}, | 1107 | {0x65, nullptr, "GetProcessList"}, |
| 1064 | {0x66, nullptr, "GetThreadList"}, | 1108 | {0x66, nullptr, "GetThreadList"}, |
| 1065 | {0x67, nullptr, "GetDebugThreadContext"}, | 1109 | {0x67, nullptr, "GetDebugThreadContext"}, |
| 1066 | {0x68, nullptr, "SetDebugThreadContext"}, | 1110 | {0x68, nullptr, "SetDebugThreadContext"}, |
| 1067 | {0x69, nullptr, "QueryDebugProcessMemory"}, | 1111 | {0x69, nullptr, "QueryDebugProcessMemory"}, |
| 1068 | {0x6A, nullptr, "ReadProcessMemory"}, | 1112 | {0x6A, nullptr, "ReadProcessMemory"}, |
| 1069 | {0x6B, nullptr, "WriteProcessMemory"}, | 1113 | {0x6B, nullptr, "WriteProcessMemory"}, |
| 1070 | {0x6C, nullptr, "SetHardwareBreakPoint"}, | 1114 | {0x6C, nullptr, "SetHardwareBreakPoint"}, |
| 1071 | {0x6D, nullptr, "GetDebugThreadParam"}, | 1115 | {0x6D, nullptr, "GetDebugThreadParam"}, |
| 1072 | {0x6E, nullptr, "Unknown"}, | 1116 | {0x6E, nullptr, "Unknown"}, |
| 1073 | {0x6F, nullptr, "Unknown"}, | 1117 | {0x6F, nullptr, "Unknown"}, |
| 1074 | {0x70, nullptr, "ControlProcessMemory"}, | 1118 | {0x70, nullptr, "ControlProcessMemory"}, |
| 1075 | {0x71, nullptr, "MapProcessMemory"}, | 1119 | {0x71, nullptr, "MapProcessMemory"}, |
| 1076 | {0x72, nullptr, "UnmapProcessMemory"}, | 1120 | {0x72, nullptr, "UnmapProcessMemory"}, |
| 1077 | {0x73, nullptr, "CreateCodeSet"}, | 1121 | {0x73, nullptr, "CreateCodeSet"}, |
| 1078 | {0x74, nullptr, "RandomStub"}, | 1122 | {0x74, nullptr, "RandomStub"}, |
| 1079 | {0x75, nullptr, "CreateProcess"}, | 1123 | {0x75, nullptr, "CreateProcess"}, |
| 1080 | {0x76, nullptr, "TerminateProcess"}, | 1124 | {0x76, nullptr, "TerminateProcess"}, |
| 1081 | {0x77, nullptr, "SetProcessResourceLimits"}, | 1125 | {0x77, nullptr, "SetProcessResourceLimits"}, |
| 1082 | {0x78, nullptr, "CreateResourceLimit"}, | 1126 | {0x78, nullptr, "CreateResourceLimit"}, |
| 1083 | {0x79, nullptr, "SetResourceLimitValues"}, | 1127 | {0x79, nullptr, "SetResourceLimitValues"}, |
| 1084 | {0x7A, nullptr, "AddCodeSegment"}, | 1128 | {0x7A, nullptr, "AddCodeSegment"}, |
| 1085 | {0x7B, nullptr, "Backdoor"}, | 1129 | {0x7B, nullptr, "Backdoor"}, |
| 1086 | {0x7C, nullptr, "KernelSetState"}, | 1130 | {0x7C, nullptr, "KernelSetState"}, |
| 1087 | {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"}, | 1131 | {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"}, |
| 1088 | }; | 1132 | }; |
| 1089 | 1133 | ||
| 1090 | static const FunctionDef* GetSVCInfo(u32 func_num) { | 1134 | static const FunctionDef* GetSVCInfo(u32 func_num) { |