diff options
| author | 2018-09-19 19:53:11 +0800 | |
|---|---|---|
| committer | 2018-09-19 19:53:11 +0800 | |
| commit | c8f9bbbf859c0e38cf691b64c67761382fcebfc2 (patch) | |
| tree | 99529c2277a6b740a6e278985c5147fa649c5497 /src/core/hle/kernel/svc.cpp | |
| parent | Add 1D sampler for TLDS - TexelFetch (Mario Rabbids) (diff) | |
| parent | Merge pull request #1348 from ogniK5377/GetImageSize (diff) | |
| download | yuzu-c8f9bbbf859c0e38cf691b64c67761382fcebfc2.tar.gz yuzu-c8f9bbbf859c0e38cf691b64c67761382fcebfc2.tar.xz yuzu-c8f9bbbf859c0e38cf691b64c67761382fcebfc2.zip | |
Merge branch 'master' into tlds
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f500fd2e7..371fc439e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -35,10 +35,21 @@ | |||
| 35 | #include "core/hle/service/service.h" | 35 | #include "core/hle/service/service.h" |
| 36 | 36 | ||
| 37 | namespace Kernel { | 37 | namespace Kernel { |
| 38 | namespace { | ||
| 39 | constexpr bool Is4KBAligned(VAddr address) { | ||
| 40 | return (address & 0xFFF) == 0; | ||
| 41 | } | ||
| 42 | } // Anonymous namespace | ||
| 38 | 43 | ||
| 39 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 44 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 40 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 45 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 41 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 46 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); |
| 47 | |||
| 48 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. | ||
| 49 | if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { | ||
| 50 | return ERR_INVALID_SIZE; | ||
| 51 | } | ||
| 52 | |||
| 42 | auto& process = *Core::CurrentProcess(); | 53 | auto& process = *Core::CurrentProcess(); |
| 43 | CASCADE_RESULT(*heap_addr, | 54 | CASCADE_RESULT(*heap_addr, |
| 44 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); | 55 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); |
| @@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state | |||
| 56 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 67 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 57 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 68 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 58 | src_addr, size); | 69 | src_addr, size); |
| 70 | |||
| 71 | if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||
| 72 | return ERR_INVALID_ADDRESS; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 76 | return ERR_INVALID_SIZE; | ||
| 77 | } | ||
| 78 | |||
| 59 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); | 79 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); |
| 60 | } | 80 | } |
| 61 | 81 | ||
| @@ -63,6 +83,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | |||
| 63 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 83 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 64 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 84 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 65 | src_addr, size); | 85 | src_addr, size); |
| 86 | |||
| 87 | if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||
| 88 | return ERR_INVALID_ADDRESS; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 92 | return ERR_INVALID_SIZE; | ||
| 93 | } | ||
| 94 | |||
| 66 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); | 95 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); |
| 67 | } | 96 | } |
| 68 | 97 | ||
| @@ -146,7 +175,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | |||
| 146 | 175 | ||
| 147 | /// Default thread wakeup callback for WaitSynchronization | 176 | /// Default thread wakeup callback for WaitSynchronization |
| 148 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, | 177 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, |
| 149 | SharedPtr<WaitObject> object, size_t index) { | 178 | SharedPtr<WaitObject> object, std::size_t index) { |
| 150 | ASSERT(thread->status == ThreadStatus::WaitSynchAny); | 179 | ASSERT(thread->status == ThreadStatus::WaitSynchAny); |
| 151 | 180 | ||
| 152 | if (reason == ThreadWakeupReason::Timeout) { | 181 | if (reason == ThreadWakeupReason::Timeout) { |
| @@ -251,6 +280,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 251 | "requesting_current_thread_handle=0x{:08X}", | 280 | "requesting_current_thread_handle=0x{:08X}", |
| 252 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 281 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 253 | 282 | ||
| 283 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | ||
| 284 | return ERR_INVALID_ADDRESS_STATE; | ||
| 285 | } | ||
| 286 | |||
| 254 | auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); | 287 | auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); |
| 255 | return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, | 288 | return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, |
| 256 | requesting_thread_handle); | 289 | requesting_thread_handle); |
| @@ -260,6 +293,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 260 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | 293 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { |
| 261 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); | 294 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); |
| 262 | 295 | ||
| 296 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | ||
| 297 | return ERR_INVALID_ADDRESS_STATE; | ||
| 298 | } | ||
| 299 | |||
| 263 | return Mutex::Release(mutex_addr); | 300 | return Mutex::Release(mutex_addr); |
| 264 | } | 301 | } |
| 265 | 302 | ||
| @@ -415,35 +452,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 415 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | 452 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", |
| 416 | shared_memory_handle, addr, size, permissions); | 453 | shared_memory_handle, addr, size, permissions); |
| 417 | 454 | ||
| 455 | if (!Is4KBAligned(addr)) { | ||
| 456 | return ERR_INVALID_ADDRESS; | ||
| 457 | } | ||
| 458 | |||
| 459 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 460 | return ERR_INVALID_SIZE; | ||
| 461 | } | ||
| 462 | |||
| 463 | const auto permissions_type = static_cast<MemoryPermission>(permissions); | ||
| 464 | if (permissions_type != MemoryPermission::Read && | ||
| 465 | permissions_type != MemoryPermission::ReadWrite) { | ||
| 466 | LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); | ||
| 467 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 468 | } | ||
| 469 | |||
| 418 | auto& kernel = Core::System::GetInstance().Kernel(); | 470 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 419 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); | 471 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); |
| 420 | if (!shared_memory) { | 472 | if (!shared_memory) { |
| 421 | return ERR_INVALID_HANDLE; | 473 | return ERR_INVALID_HANDLE; |
| 422 | } | 474 | } |
| 423 | 475 | ||
| 424 | MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); | 476 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, |
| 425 | switch (permissions_type) { | 477 | MemoryPermission::DontCare); |
| 426 | case MemoryPermission::Read: | ||
| 427 | case MemoryPermission::Write: | ||
| 428 | case MemoryPermission::ReadWrite: | ||
| 429 | case MemoryPermission::Execute: | ||
| 430 | case MemoryPermission::ReadExecute: | ||
| 431 | case MemoryPermission::WriteExecute: | ||
| 432 | case MemoryPermission::ReadWriteExecute: | ||
| 433 | case MemoryPermission::DontCare: | ||
| 434 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, | ||
| 435 | MemoryPermission::DontCare); | ||
| 436 | default: | ||
| 437 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); | ||
| 438 | } | ||
| 439 | |||
| 440 | return RESULT_SUCCESS; | ||
| 441 | } | 478 | } |
| 442 | 479 | ||
| 443 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | 480 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { |
| 444 | LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", | 481 | LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", |
| 445 | shared_memory_handle, addr, size); | 482 | shared_memory_handle, addr, size); |
| 446 | 483 | ||
| 484 | if (!Is4KBAligned(addr)) { | ||
| 485 | return ERR_INVALID_ADDRESS; | ||
| 486 | } | ||
| 487 | |||
| 488 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 489 | return ERR_INVALID_SIZE; | ||
| 490 | } | ||
| 491 | |||
| 447 | auto& kernel = Core::System::GetInstance().Kernel(); | 492 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 448 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); | 493 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); |
| 449 | 494 | ||
| @@ -524,7 +569,7 @@ static void ExitProcess() { | |||
| 524 | /// Creates a new thread | 569 | /// Creates a new thread |
| 525 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, | 570 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, |
| 526 | u32 priority, s32 processor_id) { | 571 | u32 priority, s32 processor_id) { |
| 527 | std::string name = fmt::format("unknown-{:X}", entry_point); | 572 | std::string name = fmt::format("thread-{:X}", entry_point); |
| 528 | 573 | ||
| 529 | if (priority > THREADPRIO_LOWEST) { | 574 | if (priority > THREADPRIO_LOWEST) { |
| 530 | return ERR_INVALID_THREAD_PRIORITY; | 575 | return ERR_INVALID_THREAD_PRIORITY; |
| @@ -647,16 +692,17 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 647 | LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", | 692 | LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", |
| 648 | condition_variable_addr, target); | 693 | condition_variable_addr, target); |
| 649 | 694 | ||
| 650 | auto RetrieveWaitingThreads = | 695 | auto RetrieveWaitingThreads = [](std::size_t core_index, |
| 651 | [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { | 696 | std::vector<SharedPtr<Thread>>& waiting_threads, |
| 652 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); | 697 | VAddr condvar_addr) { |
| 653 | auto& thread_list = scheduler->GetThreadList(); | 698 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); |
| 699 | auto& thread_list = scheduler->GetThreadList(); | ||
| 654 | 700 | ||
| 655 | for (auto& thread : thread_list) { | 701 | for (auto& thread : thread_list) { |
| 656 | if (thread->condvar_wait_address == condvar_addr) | 702 | if (thread->condvar_wait_address == condvar_addr) |
| 657 | waiting_threads.push_back(thread); | 703 | waiting_threads.push_back(thread); |
| 658 | } | 704 | } |
| 659 | }; | 705 | }; |
| 660 | 706 | ||
| 661 | // Retrieve a list of all threads that are waiting for this condition variable. | 707 | // Retrieve a list of all threads that are waiting for this condition variable. |
| 662 | std::vector<SharedPtr<Thread>> waiting_threads; | 708 | std::vector<SharedPtr<Thread>> waiting_threads; |
| @@ -672,7 +718,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 672 | 718 | ||
| 673 | // Only process up to 'target' threads, unless 'target' is -1, in which case process | 719 | // Only process up to 'target' threads, unless 'target' is -1, in which case process |
| 674 | // them all. | 720 | // them all. |
| 675 | size_t last = waiting_threads.size(); | 721 | std::size_t last = waiting_threads.size(); |
| 676 | if (target != -1) | 722 | if (target != -1) |
| 677 | last = target; | 723 | last = target; |
| 678 | 724 | ||
| @@ -680,12 +726,12 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 680 | if (last > waiting_threads.size()) | 726 | if (last > waiting_threads.size()) |
| 681 | return RESULT_SUCCESS; | 727 | return RESULT_SUCCESS; |
| 682 | 728 | ||
| 683 | for (size_t index = 0; index < last; ++index) { | 729 | for (std::size_t index = 0; index < last; ++index) { |
| 684 | auto& thread = waiting_threads[index]; | 730 | auto& thread = waiting_threads[index]; |
| 685 | 731 | ||
| 686 | ASSERT(thread->condvar_wait_address == condition_variable_addr); | 732 | ASSERT(thread->condvar_wait_address == condition_variable_addr); |
| 687 | 733 | ||
| 688 | size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); | 734 | std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); |
| 689 | 735 | ||
| 690 | auto& monitor = Core::System::GetInstance().Monitor(); | 736 | auto& monitor = Core::System::GetInstance().Monitor(); |
| 691 | 737 | ||
| @@ -898,12 +944,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 898 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | 944 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, |
| 899 | local_permissions, remote_permissions); | 945 | local_permissions, remote_permissions); |
| 900 | 946 | ||
| 947 | // Size must be a multiple of 4KB and be less than or equal to | ||
| 948 | // approx. 8 GB (actually (1GB - 512B) * 8) | ||
| 949 | if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { | ||
| 950 | return ERR_INVALID_SIZE; | ||
| 951 | } | ||
| 952 | |||
| 953 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); | ||
| 954 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { | ||
| 955 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 956 | } | ||
| 957 | |||
| 958 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); | ||
| 959 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && | ||
| 960 | remote_perms != MemoryPermission::DontCare) { | ||
| 961 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 962 | } | ||
| 963 | |||
| 901 | auto& kernel = Core::System::GetInstance().Kernel(); | 964 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 902 | auto& handle_table = kernel.HandleTable(); | 965 | auto& handle_table = kernel.HandleTable(); |
| 903 | auto shared_mem_handle = | 966 | auto shared_mem_handle = |
| 904 | SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, | 967 | SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, |
| 905 | static_cast<MemoryPermission>(local_permissions), | 968 | local_perms, remote_perms); |
| 906 | static_cast<MemoryPermission>(remote_permissions)); | ||
| 907 | 969 | ||
| 908 | CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); | 970 | CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); |
| 909 | return RESULT_SUCCESS; | 971 | return RESULT_SUCCESS; |