svc.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/logging/log.h"
  5. #include "common/microprofile.h"
  6. #include "core/core_timing.h"
  7. #include "core/hle/function_wrappers.h"
  8. #include "core/hle/kernel/client_port.h"
  9. #include "core/hle/kernel/client_session.h"
  10. #include "core/hle/kernel/handle_table.h"
  11. #include "core/hle/kernel/process.h"
  12. #include "core/hle/kernel/sync_object.h"
  13. #include "core/hle/kernel/thread.h"
  14. #include "core/hle/lock.h"
  15. #include "core/hle/result.h"
  16. #include "core/hle/service/service.h"
  17. ////////////////////////////////////////////////////////////////////////////////////////////////////
  18. // Namespace SVC
  19. using Kernel::ERR_INVALID_HANDLE;
  20. using Kernel::Handle;
  21. using Kernel::SharedPtr;
  22. namespace SVC {
  23. /// Set the process heap to a given Size. It can both extend and shrink the heap.
  24. static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
  25. LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size);
  26. auto& process = *Kernel::g_current_process;
  27. CASCADE_RESULT(*heap_addr, process.HeapAllocate(Memory::HEAP_VADDR, heap_size,
  28. Kernel::VMAPermission::ReadWrite));
  29. return RESULT_SUCCESS;
  30. }
  31. /// Maps a memory range into a different range.
  32. static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  33. LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr,
  34. src_addr, size);
  35. return Kernel::g_current_process->MirrorMemory(dst_addr, src_addr, size);
  36. }
  37. /// Unmaps a region that was previously mapped with svcMapMemory
  38. static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  39. LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr,
  40. src_addr, size);
  41. return Kernel::g_current_process->UnmapMemory(dst_addr, src_addr, size);
  42. }
  43. /// Connect to an OS service given the port name, returns the handle to the port to out
  44. static ResultCode ConnectToPort(Kernel::Handle* out_handle, VAddr port_name_address) {
  45. if (!Memory::IsValidVirtualAddress(port_name_address))
  46. return Kernel::ERR_NOT_FOUND;
  47. static constexpr std::size_t PortNameMaxLength = 11;
  48. // Read 1 char beyond the max allowed port name to detect names that are too long.
  49. std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
  50. if (port_name.size() > PortNameMaxLength)
  51. return Kernel::ERR_PORT_NAME_TOO_LONG;
  52. LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name.c_str());
  53. auto it = Service::g_kernel_named_ports.find(port_name);
  54. if (it == Service::g_kernel_named_ports.end()) {
  55. LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str());
  56. return Kernel::ERR_NOT_FOUND;
  57. }
  58. auto client_port = it->second;
  59. SharedPtr<Kernel::ClientSession> client_session;
  60. CASCADE_RESULT(client_session, client_port->Connect());
  61. // Return the client session
  62. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session));
  63. return RESULT_SUCCESS;
  64. }
  65. /// Makes a blocking IPC call to an OS service.
  66. static ResultCode SendSyncRequest(Kernel::Handle handle) {
  67. SharedPtr<Kernel::SyncObject> session = Kernel::g_handle_table.Get<Kernel::SyncObject>(handle);
  68. if (!session) {
  69. LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);
  70. return ERR_INVALID_HANDLE;
  71. }
  72. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
  73. Core::System::GetInstance().PrepareReschedule();
  74. // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
  75. // responds and cause a reschedule.
  76. return session->SendSyncRequest(Kernel::GetCurrentThread());
  77. }
  78. /// Get the ID for the specified thread.
  79. static ResultCode GetThreadId(u32* thread_id, Kernel::Handle thread_handle) {
  80. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
  81. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
  82. if (!thread) {
  83. return ERR_INVALID_HANDLE;
  84. }
  85. *thread_id = thread->GetThreadId();
  86. return RESULT_SUCCESS;
  87. }
  88. /// Get the ID of the specified process
  89. static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) {
  90. LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
  91. const SharedPtr<Kernel::Process> process =
  92. Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
  93. if (!process) {
  94. return ERR_INVALID_HANDLE;
  95. }
  96. *process_id = process->process_id;
  97. return RESULT_SUCCESS;
  98. }
  99. /// Break program execution
  100. static void Break(u64 unk_0, u64 unk_1, u64 unk_2) {
  101. LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
  102. ASSERT(false);
  103. }
  104. /// Used to output a message on a debug hardware unit - does nothing on a retail unit
  105. static void OutputDebugString(VAddr address, int len) {
  106. std::vector<char> string(len);
  107. Memory::ReadBlock(address, string.data(), len);
  108. LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data());
  109. }
  110. static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
  111. LOG_TRACE(Kernel_SVC, "called, info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, info_sub_id, handle);
  112. if (!handle) {
  113. switch (info_id) {
  114. case 0xB:
  115. *result = 0; // Used for PRNG seed
  116. return RESULT_SUCCESS;
  117. }
  118. }
  119. return RESULT_SUCCESS;
  120. }
  121. /// Gets the priority for the specified thread
  122. static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) {
  123. LOG_TRACE(Kernel_SVC, "called, handle=0x%08X", handle);
  124. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  125. *priority = thread ? thread->GetPriority() : 0;
  126. return RESULT_SUCCESS;
  127. }
  128. /// Query process memory
  129. static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
  130. Kernel::Handle process_handle, u64 addr) {
  131. using Kernel::Process;
  132. Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
  133. if (!process) {
  134. return ERR_INVALID_HANDLE;
  135. }
  136. auto vma = process->vm_manager.FindVMA(addr);
  137. memory_info->attributes = 0;
  138. if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) {
  139. memory_info->base_address = 0;
  140. memory_info->permission = static_cast<u32>(Kernel::VMAPermission::None);
  141. memory_info->size = 0;
  142. memory_info->type = static_cast<u32>(Kernel::MemoryState::Free);
  143. } else {
  144. memory_info->base_address = vma->second.base;
  145. memory_info->permission = static_cast<u32>(vma->second.permissions);
  146. memory_info->size = vma->second.size;
  147. memory_info->type = static_cast<u32>(vma->second.meminfo_state);
  148. }
  149. LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=%llx", process_handle, addr);
  150. return RESULT_SUCCESS;
  151. }
  152. /// Query memory
  153. static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) {
  154. LOG_TRACE(Kernel_SVC, "called, addr=%llx", addr);
  155. return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
  156. }
  157. /// Starts the thread for the provided handle
  158. static ResultCode StartThread(Handle thread_handle) {
  159. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
  160. const SharedPtr<Kernel::Thread> thread =
  161. Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
  162. if (!thread) {
  163. return ERR_INVALID_HANDLE;
  164. }
  165. thread->ResumeFromWait();
  166. return RESULT_SUCCESS;
  167. }
  168. /// Sleep the current thread
  169. static void SleepThread(s64 nanoseconds) {
  170. LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
  171. // Don't attempt to yield execution if there are no available threads to run,
  172. // this way we avoid a useless reschedule to the idle thread.
  173. if (nanoseconds == 0 && !Kernel::HaveReadyThreads())
  174. return;
  175. // Sleep current thread and check for next thread to schedule
  176. Kernel::WaitCurrentThread_Sleep();
  177. // Create an event to wake the thread up after the specified nanosecond delay has passed
  178. Kernel::GetCurrentThread()->WakeAfterDelay(nanoseconds);
  179. Core::System::GetInstance().PrepareReschedule();
  180. }
  181. /// Signal process wide key
  182. static ResultCode SignalProcessWideKey(VAddr address, u32 target) {
  183. LOG_TRACE(Kernel_SVC, "called, address=0x%llx, target=0x%08x", address, target);
  184. return RESULT_SUCCESS;
  185. }
  186. /// Close a handle
  187. static ResultCode CloseHandle(Kernel::Handle handle) {
  188. LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle);
  189. return Kernel::g_handle_table.Close(handle);
  190. }
  191. namespace {
  192. struct FunctionDef {
  193. using Func = void();
  194. u32 id;
  195. Func* func;
  196. const char* name;
  197. };
  198. } // namespace
  199. static const FunctionDef SVC_Table[] = {
  200. {0x00, nullptr, "Unknown"},
  201. {0x01, HLE::Wrap<SetHeapSize>, "svcSetHeapSize"},
  202. {0x02, nullptr, "svcSetMemoryPermission"},
  203. {0x03, nullptr, "svcSetMemoryAttribute"},
  204. {0x04, HLE::Wrap<MapMemory>, "svcMapMemory"},
  205. {0x05, HLE::Wrap<UnmapMemory>, "svcUnmapMemory"},
  206. {0x06, HLE::Wrap<QueryMemory>, "svcQueryMemory"},
  207. {0x07, nullptr, "svcExitProcess"},
  208. {0x08, nullptr, "svcCreateThread"},
  209. {0x09, nullptr, "svcStartThread"},
  210. {0x09, HLE::Wrap<StartThread>, "svcStartThread"},
  211. {0x0A, nullptr, "svcExitThread"},
  212. {0x0B, HLE::Wrap<SleepThread>, "svcSleepThread"},
  213. {0x0C, HLE::Wrap<GetThreadPriority>, "svcGetThreadPriority"},
  214. {0x0D, nullptr, "svcSetThreadPriority"},
  215. {0x0E, nullptr, "svcGetThreadCoreMask"},
  216. {0x0F, nullptr, "svcSetThreadCoreMask"},
  217. {0x10, nullptr, "svcGetCurrentProcessorNumber"},
  218. {0x11, nullptr, "svcSignalEvent"},
  219. {0x12, nullptr, "svcClearEvent"},
  220. {0x13, nullptr, "svcMapSharedMemory"},
  221. {0x14, nullptr, "svcUnmapSharedMemory"},
  222. {0x15, nullptr, "svcCreateTransferMemory"},
  223. {0x16, HLE::Wrap<CloseHandle>, "svcCloseHandle"},
  224. {0x17, nullptr, "svcResetSignal"},
  225. {0x18, nullptr, "svcWaitSynchronization"},
  226. {0x19, nullptr, "svcCancelSynchronization"},
  227. {0x1A, nullptr, "svcLockMutex"},
  228. {0x1B, nullptr, "svcUnlockMutex"},
  229. {0x1C, nullptr, "svcWaitProcessWideKeyAtomic"},
  230. {0x1D, HLE::Wrap<SignalProcessWideKey>, "svcSignalProcessWideKey"},
  231. {0x1E, nullptr, "svcGetSystemTick"},
  232. {0x1F, HLE::Wrap<ConnectToPort>, "svcConnectToPort"},
  233. {0x20, nullptr, "svcSendSyncRequestLight"},
  234. {0x21, HLE::Wrap<SendSyncRequest>, "svcSendSyncRequest"},
  235. {0x22, nullptr, "svcSendSyncRequestWithUserBuffer"},
  236. {0x23, nullptr, "svcSendAsyncRequestWithUserBuffer"},
  237. {0x24, HLE::Wrap<GetProcessId>, "svcGetProcessId"},
  238. {0x25, HLE::Wrap<GetThreadId>, "svcGetThreadId"},
  239. {0x26, HLE::Wrap<Break>, "svcBreak"},
  240. {0x27, HLE::Wrap<OutputDebugString>, "svcOutputDebugString"},
  241. {0x28, nullptr, "svcReturnFromException"},
  242. {0x29, HLE::Wrap<GetInfo>, "svcGetInfo"},
  243. {0x2A, nullptr, "svcFlushEntireDataCache"},
  244. {0x2B, nullptr, "svcFlushDataCache"},
  245. {0x2C, nullptr, "svcMapPhysicalMemory"},
  246. {0x2D, nullptr, "svcUnmapPhysicalMemory"},
  247. {0x2E, nullptr, "Unknown"},
  248. {0x2F, nullptr, "svcGetLastThreadInfo"},
  249. {0x30, nullptr, "svcGetResourceLimitLimitValue"},
  250. {0x31, nullptr, "svcGetResourceLimitCurrentValue"},
  251. {0x32, nullptr, "svcSetThreadActivity"},
  252. {0x33, nullptr, "svcGetThreadContext"},
  253. {0x34, nullptr, "Unknown"},
  254. {0x35, nullptr, "Unknown"},
  255. {0x36, nullptr, "Unknown"},
  256. {0x37, nullptr, "Unknown"},
  257. {0x38, nullptr, "Unknown"},
  258. {0x39, nullptr, "Unknown"},
  259. {0x3A, nullptr, "Unknown"},
  260. {0x3B, nullptr, "Unknown"},
  261. {0x3C, nullptr, "svcDumpInfo"},
  262. {0x3D, nullptr, "Unknown"},
  263. {0x3E, nullptr, "Unknown"},
  264. {0x3F, nullptr, "Unknown"},
  265. {0x40, nullptr, "svcCreateSession"},
  266. {0x41, nullptr, "svcAcceptSession"},
  267. {0x42, nullptr, "svcReplyAndReceiveLight"},
  268. {0x43, nullptr, "svcReplyAndReceive"},
  269. {0x44, nullptr, "svcReplyAndReceiveWithUserBuffer"},
  270. {0x45, nullptr, "svcCreateEvent"},
  271. {0x46, nullptr, "Unknown"},
  272. {0x47, nullptr, "Unknown"},
  273. {0x48, nullptr, "Unknown"},
  274. {0x49, nullptr, "Unknown"},
  275. {0x4A, nullptr, "Unknown"},
  276. {0x4B, nullptr, "Unknown"},
  277. {0x4C, nullptr, "Unknown"},
  278. {0x4D, nullptr, "svcSleepSystem"},
  279. {0x4E, nullptr, "svcReadWriteRegister"},
  280. {0x4F, nullptr, "svcSetProcessActivity"},
  281. {0x50, nullptr, "svcCreateSharedMemory"},
  282. {0x51, nullptr, "svcMapTransferMemory"},
  283. {0x52, nullptr, "svcUnmapTransferMemory"},
  284. {0x53, nullptr, "svcCreateInterruptEvent"},
  285. {0x54, nullptr, "svcQueryPhysicalAddress"},
  286. {0x55, nullptr, "svcQueryIoMapping"},
  287. {0x56, nullptr, "svcCreateDeviceAddressSpace"},
  288. {0x57, nullptr, "svcAttachDeviceAddressSpace"},
  289. {0x58, nullptr, "svcDetachDeviceAddressSpace"},
  290. {0x59, nullptr, "svcMapDeviceAddressSpaceByForce"},
  291. {0x5A, nullptr, "svcMapDeviceAddressSpaceAligned"},
  292. {0x5B, nullptr, "svcMapDeviceAddressSpace"},
  293. {0x5C, nullptr, "svcUnmapDeviceAddressSpace"},
  294. {0x5D, nullptr, "svcInvalidateProcessDataCache"},
  295. {0x5E, nullptr, "svcStoreProcessDataCache"},
  296. {0x5F, nullptr, "svcFlushProcessDataCache"},
  297. {0x60, nullptr, "svcDebugActiveProcess"},
  298. {0x61, nullptr, "svcBreakDebugProcess"},
  299. {0x62, nullptr, "svcTerminateDebugProcess"},
  300. {0x63, nullptr, "svcGetDebugEvent"},
  301. {0x64, nullptr, "svcContinueDebugEvent"},
  302. {0x65, nullptr, "svcGetProcessList"},
  303. {0x66, nullptr, "svcGetThreadList"},
  304. {0x67, nullptr, "svcGetDebugThreadContext"},
  305. {0x68, nullptr, "svcSetDebugThreadContext"},
  306. {0x69, nullptr, "svcQueryDebugProcessMemory"},
  307. {0x6A, nullptr, "svcReadDebugProcessMemory"},
  308. {0x6B, nullptr, "svcWriteDebugProcessMemory"},
  309. {0x6C, nullptr, "svcSetHardwareBreakPoint"},
  310. {0x6D, nullptr, "svcGetDebugThreadParam"},
  311. {0x6E, nullptr, "Unknown"},
  312. {0x6F, nullptr, "Unknown"},
  313. {0x70, nullptr, "svcCreatePort"},
  314. {0x71, nullptr, "svcManageNamedPort"},
  315. {0x72, nullptr, "svcConnectToPort"},
  316. {0x73, nullptr, "svcSetProcessMemoryPermission"},
  317. {0x74, nullptr, "svcMapProcessMemory"},
  318. {0x75, nullptr, "svcUnmapProcessMemory"},
  319. {0x76, nullptr, "svcQueryProcessMemory"},
  320. {0x77, nullptr, "svcMapProcessCodeMemory"},
  321. {0x78, nullptr, "svcUnmapProcessCodeMemory"},
  322. {0x79, nullptr, "svcCreateProcess"},
  323. {0x7A, nullptr, "svcStartProcess"},
  324. {0x7B, nullptr, "svcTerminateProcess"},
  325. {0x7C, nullptr, "svcGetProcessInfo"},
  326. {0x7D, nullptr, "svcCreateResourceLimit"},
  327. {0x7E, nullptr, "svcSetResourceLimitLimitValue"},
  328. {0x7F, nullptr, "svcCallSecureMonitor"},
  329. };
  330. static const FunctionDef* GetSVCInfo(u32 func_num) {
  331. if (func_num >= ARRAY_SIZE(SVC_Table)) {
  332. LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
  333. return nullptr;
  334. }
  335. return &SVC_Table[func_num];
  336. }
  337. MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
  338. void CallSVC(u32 immediate) {
  339. MICROPROFILE_SCOPE(Kernel_SVC);
  340. // Lock the global kernel mutex when we enter the kernel HLE.
  341. std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
  342. const FunctionDef* info = GetSVCInfo(immediate);
  343. if (info) {
  344. if (info->func) {
  345. info->func();
  346. } else {
  347. LOG_CRITICAL(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
  348. }
  349. } else {
  350. LOG_CRITICAL(Kernel_SVC, "unknown SVC function 0x%x", immediate);
  351. }
  352. }
  353. } // namespace SVC