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