svc.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <map>
  5. #include "common/string_util.h"
  6. #include "common/symbols.h"
  7. #include "core/arm/arm_interface.h"
  8. #include "core/mem_map.h"
  9. #include "core/hle/kernel/address_arbiter.h"
  10. #include "core/hle/kernel/event.h"
  11. #include "core/hle/kernel/mutex.h"
  12. #include "core/hle/kernel/semaphore.h"
  13. #include "core/hle/kernel/shared_memory.h"
  14. #include "core/hle/kernel/thread.h"
  15. #include "core/hle/kernel/timer.h"
  16. #include "core/hle/function_wrappers.h"
  17. #include "core/hle/result.h"
  18. #include "core/hle/service/service.h"
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////
  20. // Namespace SVC
  21. using Kernel::SharedPtr;
  22. namespace SVC {
  23. /// An invalid result code that is meant to be overwritten when a thread resumes from waiting
  24. const ResultCode RESULT_INVALID(0xDEADC0DE);
  25. enum ControlMemoryOperation {
  26. MEMORY_OPERATION_HEAP = 0x00000003,
  27. MEMORY_OPERATION_GSP_HEAP = 0x00010003,
  28. };
  29. /// Map application or GSP heap memory
  30. static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
  31. LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
  32. operation, addr0, addr1, size, permissions);
  33. switch (operation) {
  34. // Map normal heap memory
  35. case MEMORY_OPERATION_HEAP:
  36. *out_addr = Memory::MapBlock_Heap(size, operation, permissions);
  37. break;
  38. // Map GSP heap memory
  39. case MEMORY_OPERATION_GSP_HEAP:
  40. *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions);
  41. break;
  42. // Unknown ControlMemory operation
  43. default:
  44. LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
  45. }
  46. return 0;
  47. }
  48. /// Maps a memory block to specified address
  49. static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
  50. using Kernel::SharedMemory;
  51. using Kernel::MemoryPermission;
  52. LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
  53. handle, addr, permissions, other_permissions);
  54. SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
  55. if (shared_memory == nullptr)
  56. return InvalidHandle(ErrorModule::Kernel).raw;
  57. MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions);
  58. switch (permissions_type) {
  59. case MemoryPermission::Read:
  60. case MemoryPermission::Write:
  61. case MemoryPermission::ReadWrite:
  62. case MemoryPermission::Execute:
  63. case MemoryPermission::ReadExecute:
  64. case MemoryPermission::WriteExecute:
  65. case MemoryPermission::ReadWriteExecute:
  66. case MemoryPermission::DontCare:
  67. shared_memory->Map(addr, permissions_type,
  68. static_cast<MemoryPermission>(other_permissions));
  69. break;
  70. default:
  71. LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
  72. }
  73. return 0;
  74. }
  75. /// Connect to an OS service given the port name, returns the handle to the port to out
  76. static Result ConnectToPort(Handle* out, const char* port_name) {
  77. Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
  78. LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
  79. _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!");
  80. *out = service->GetHandle();
  81. return 0;
  82. }
  83. /// Synchronize to an OS service
  84. static Result SendSyncRequest(Handle handle) {
  85. SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
  86. if (session == nullptr) {
  87. return InvalidHandle(ErrorModule::Kernel).raw;
  88. }
  89. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
  90. return session->SyncRequest().Code().raw;
  91. }
  92. /// Close a handle
  93. static Result CloseHandle(Handle handle) {
  94. // ImplementMe
  95. LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
  96. return 0;
  97. }
  98. /// Wait for a handle to synchronize, timeout after the specified nanoseconds
  99. static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
  100. auto object = Kernel::g_handle_table.GetWaitObject(handle);
  101. if (object == nullptr)
  102. return InvalidHandle(ErrorModule::Kernel).raw;
  103. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
  104. object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
  105. // Check for next thread to schedule
  106. if (object->ShouldWait()) {
  107. object->AddWaitingThread(Kernel::GetCurrentThread());
  108. Kernel::WaitCurrentThread_WaitSynchronization(object, false, false);
  109. // Create an event to wake the thread up after the specified nanosecond delay has passed
  110. Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
  111. HLE::Reschedule(__func__);
  112. // NOTE: output of this SVC will be set later depending on how the thread resumes
  113. return RESULT_INVALID.raw;
  114. }
  115. object->Acquire();
  116. return RESULT_SUCCESS.raw;
  117. }
  118. /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
  119. static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
  120. bool wait_thread = !wait_all;
  121. int handle_index = 0;
  122. // Check if 'handles' is invalid
  123. if (handles == nullptr)
  124. return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw;
  125. // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
  126. // this happens, the running application will crash.
  127. _assert_msg_(Kernel, out != nullptr, "invalid output pointer specified!");
  128. // Check if 'handle_count' is invalid
  129. if (handle_count < 0)
  130. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
  131. // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
  132. // necessary
  133. if (handle_count != 0) {
  134. bool selected = false; // True once an object has been selected
  135. for (int i = 0; i < handle_count; ++i) {
  136. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  137. if (object == nullptr)
  138. return InvalidHandle(ErrorModule::Kernel).raw;
  139. // Check if the current thread should wait on this object...
  140. if (object->ShouldWait()) {
  141. // Check we are waiting on all objects...
  142. if (wait_all)
  143. // Wait the thread
  144. wait_thread = true;
  145. } else {
  146. // Do not wait on this object, check if this object should be selected...
  147. if (!wait_all && !selected) {
  148. // Do not wait the thread
  149. wait_thread = false;
  150. handle_index = i;
  151. selected = true;
  152. }
  153. }
  154. }
  155. } else {
  156. // If no handles were passed in, put the thread to sleep only when 'wait_all' is false
  157. // NOTE: This should deadlock the current thread if no timeout was specified
  158. if (!wait_all) {
  159. wait_thread = true;
  160. Kernel::WaitCurrentThread_WaitSynchronization(nullptr, true, wait_all);
  161. }
  162. }
  163. // If thread should wait, then set its state to waiting and then reschedule...
  164. if (wait_thread) {
  165. // Actually wait the current thread on each object if we decided to wait...
  166. for (int i = 0; i < handle_count; ++i) {
  167. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  168. object->AddWaitingThread(Kernel::GetCurrentThread());
  169. Kernel::WaitCurrentThread_WaitSynchronization(object, true, wait_all);
  170. }
  171. // Create an event to wake the thread up after the specified nanosecond delay has passed
  172. Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
  173. HLE::Reschedule(__func__);
  174. // NOTE: output of this SVC will be set later depending on how the thread resumes
  175. return RESULT_INVALID.raw;
  176. }
  177. // Acquire objects if we did not wait...
  178. for (int i = 0; i < handle_count; ++i) {
  179. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  180. // Acquire the object if it is not waiting...
  181. if (!object->ShouldWait()) {
  182. object->Acquire();
  183. // If this was the first non-waiting object and 'wait_all' is false, don't acquire
  184. // any other objects
  185. if (!wait_all)
  186. break;
  187. }
  188. }
  189. // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
  190. // not seem to set it to any meaningful value.
  191. *out = wait_all ? 0 : handle_index;
  192. return RESULT_SUCCESS.raw;
  193. }
  194. /// Create an address arbiter (to allocate access to shared resources)
  195. static Result CreateAddressArbiter(u32* arbiter) {
  196. Handle handle = Kernel::CreateAddressArbiter();
  197. *arbiter = handle;
  198. return 0;
  199. }
  200. /// Arbitrate address
  201. static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
  202. LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter,
  203. address, type, value);
  204. return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
  205. address, value, nanoseconds).raw;
  206. }
  207. /// Used to output a message on a debug hardware unit - does nothing on a retail unit
  208. static void OutputDebugString(const char* string) {
  209. LOG_DEBUG(Debug_Emulated, "%s", string);
  210. }
  211. /// Get resource limit
  212. static Result GetResourceLimit(Handle* resource_limit, Handle process) {
  213. // With regards to proceess values:
  214. // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
  215. // the current KThread.
  216. *resource_limit = 0xDEADBEEF;
  217. LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
  218. return 0;
  219. }
  220. /// Get resource limit current values
  221. static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
  222. s32 name_count) {
  223. LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
  224. resource_limit, names, name_count);
  225. Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
  226. return 0;
  227. }
  228. /// Creates a new thread
  229. static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
  230. using Kernel::Thread;
  231. std::string name;
  232. if (Symbols::HasSymbol(entry_point)) {
  233. TSymbol symbol = Symbols::GetSymbol(entry_point);
  234. name = symbol.name;
  235. } else {
  236. name = Common::StringFromFormat("unknown-%08x", entry_point);
  237. }
  238. ResultVal<SharedPtr<Thread>> thread_res = Kernel::Thread::Create(
  239. name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE);
  240. if (thread_res.Failed())
  241. return thread_res.Code().raw;
  242. SharedPtr<Thread> thread = std::move(*thread_res);
  243. // TODO(yuriks): Create new handle instead of using built-in
  244. Core::g_app_core->SetReg(1, thread->GetHandle());
  245. LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
  246. "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
  247. name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle());
  248. if (THREADPROCESSORID_1 == processor_id) {
  249. LOG_WARNING(Kernel_SVC,
  250. "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling");
  251. }
  252. return 0;
  253. }
  254. /// Called when a thread exits
  255. static void ExitThread() {
  256. LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC());
  257. Kernel::GetCurrentThread()->Stop(__func__);
  258. HLE::Reschedule(__func__);
  259. }
  260. /// Gets the priority for the specified thread
  261. static Result GetThreadPriority(s32* priority, Handle handle) {
  262. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  263. if (thread == nullptr)
  264. return InvalidHandle(ErrorModule::Kernel).raw;
  265. *priority = thread->GetPriority();
  266. return RESULT_SUCCESS.raw;
  267. }
  268. /// Sets the priority for the specified thread
  269. static Result SetThreadPriority(Handle handle, s32 priority) {
  270. SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  271. if (thread == nullptr)
  272. return InvalidHandle(ErrorModule::Kernel).raw;
  273. thread->SetPriority(priority);
  274. return RESULT_SUCCESS.raw;
  275. }
  276. /// Create a mutex
  277. static Result CreateMutex(Handle* mutex, u32 initial_locked) {
  278. *mutex = Kernel::CreateMutex((initial_locked != 0));
  279. LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
  280. initial_locked ? "true" : "false", *mutex);
  281. return 0;
  282. }
  283. /// Release a mutex
  284. static Result ReleaseMutex(Handle handle) {
  285. LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
  286. ResultCode res = Kernel::ReleaseMutex(handle);
  287. return res.raw;
  288. }
  289. /// Get the ID for the specified thread.
  290. static Result GetThreadId(u32* thread_id, Handle handle) {
  291. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
  292. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  293. if (thread == nullptr)
  294. return InvalidHandle(ErrorModule::Kernel).raw;
  295. *thread_id = thread->GetThreadId();
  296. return RESULT_SUCCESS.raw;
  297. }
  298. /// Creates a semaphore
  299. static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) {
  300. ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count);
  301. LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
  302. initial_count, max_count, *semaphore);
  303. return res.raw;
  304. }
  305. /// Releases a certain number of slots in a semaphore
  306. static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) {
  307. LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore);
  308. ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count);
  309. return res.raw;
  310. }
  311. /// Query memory
  312. static Result QueryMemory(void* info, void* out, u32 addr) {
  313. LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
  314. return 0;
  315. }
  316. /// Create an event
  317. static Result CreateEvent(Handle* evt, u32 reset_type) {
  318. *evt = Kernel::CreateEvent((ResetType)reset_type);
  319. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X",
  320. reset_type, *evt);
  321. return 0;
  322. }
  323. /// Duplicates a kernel handle
  324. static Result DuplicateHandle(Handle* out, Handle handle) {
  325. ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle);
  326. if (out_h.Succeeded()) {
  327. *out = *out_h;
  328. LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
  329. }
  330. return out_h.Code().raw;
  331. }
  332. /// Signals an event
  333. static Result SignalEvent(Handle evt) {
  334. LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt);
  335. HLE::Reschedule(__func__);
  336. return Kernel::SignalEvent(evt).raw;
  337. }
  338. /// Clears an event
  339. static Result ClearEvent(Handle evt) {
  340. LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt);
  341. return Kernel::ClearEvent(evt).raw;
  342. }
  343. /// Creates a timer
  344. static Result CreateTimer(Handle* handle, u32 reset_type) {
  345. ResultCode res = Kernel::CreateTimer(handle, static_cast<ResetType>(reset_type));
  346. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X",
  347. reset_type, *handle);
  348. return res.raw;
  349. }
  350. /// Clears a timer
  351. static Result ClearTimer(Handle handle) {
  352. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  353. return Kernel::ClearTimer(handle).raw;
  354. }
  355. /// Starts a timer
  356. static Result SetTimer(Handle handle, s64 initial, s64 interval) {
  357. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  358. return Kernel::SetTimer(handle, initial, interval).raw;
  359. }
  360. /// Cancels a timer
  361. static Result CancelTimer(Handle handle) {
  362. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  363. return Kernel::CancelTimer(handle).raw;
  364. }
  365. /// Sleep the current thread
  366. static void SleepThread(s64 nanoseconds) {
  367. LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
  368. // Sleep current thread and check for next thread to schedule
  369. Kernel::WaitCurrentThread_Sleep();
  370. // Create an event to wake the thread up after the specified nanosecond delay has passed
  371. Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds);
  372. HLE::Reschedule(__func__);
  373. }
  374. /// This returns the total CPU ticks elapsed since the CPU was powered-on
  375. static s64 GetSystemTick() {
  376. return (s64)Core::g_app_core->GetTicks();
  377. }
  378. /// Creates a memory block at the specified address with the specified permissions and size
  379. static Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 my_permission,
  380. u32 other_permission) {
  381. using Kernel::SharedMemory;
  382. // TODO(Subv): Implement this function
  383. ResultVal<SharedPtr<SharedMemory>> shared_memory_res = SharedMemory::Create();
  384. if (shared_memory_res.Failed())
  385. return shared_memory_res.Code().raw;
  386. ResultVal<Handle> handle_res = Kernel::g_handle_table.Create(*shared_memory_res);
  387. if (handle_res.Failed())
  388. return handle_res.Code().raw;
  389. *memblock = *handle_res;
  390. LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
  391. return 0;
  392. }
  393. const HLE::FunctionDef SVC_Table[] = {
  394. {0x00, nullptr, "Unknown"},
  395. {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
  396. {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
  397. {0x03, nullptr, "ExitProcess"},
  398. {0x04, nullptr, "GetProcessAffinityMask"},
  399. {0x05, nullptr, "SetProcessAffinityMask"},
  400. {0x06, nullptr, "GetProcessIdealProcessor"},
  401. {0x07, nullptr, "SetProcessIdealProcessor"},
  402. {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
  403. {0x09, ExitThread, "ExitThread"},
  404. {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
  405. {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
  406. {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
  407. {0x0D, nullptr, "GetThreadAffinityMask"},
  408. {0x0E, nullptr, "SetThreadAffinityMask"},
  409. {0x0F, nullptr, "GetThreadIdealProcessor"},
  410. {0x10, nullptr, "SetThreadIdealProcessor"},
  411. {0x11, nullptr, "GetCurrentProcessorNumber"},
  412. {0x12, nullptr, "Run"},
  413. {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
  414. {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
  415. {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"},
  416. {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"},
  417. {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
  418. {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
  419. {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
  420. {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"},
  421. {0x1B, HLE::Wrap<SetTimer>, "SetTimer"},
  422. {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"},
  423. {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"},
  424. {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"},
  425. {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
  426. {0x20, nullptr, "UnmapMemoryBlock"},
  427. {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
  428. {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
  429. {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
  430. {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
  431. {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
  432. {0x26, nullptr, "SignalAndWait"},
  433. {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
  434. {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
  435. {0x29, nullptr, "GetHandleInfo"},
  436. {0x2A, nullptr, "GetSystemInfo"},
  437. {0x2B, nullptr, "GetProcessInfo"},
  438. {0x2C, nullptr, "GetThreadInfo"},
  439. {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
  440. {0x2E, nullptr, "SendSyncRequest1"},
  441. {0x2F, nullptr, "SendSyncRequest2"},
  442. {0x30, nullptr, "SendSyncRequest3"},
  443. {0x31, nullptr, "SendSyncRequest4"},
  444. {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
  445. {0x33, nullptr, "OpenProcess"},
  446. {0x34, nullptr, "OpenThread"},
  447. {0x35, nullptr, "GetProcessId"},
  448. {0x36, nullptr, "GetProcessIdOfThread"},
  449. {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
  450. {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
  451. {0x39, nullptr, "GetResourceLimitLimitValues"},
  452. {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
  453. {0x3B, nullptr, "GetThreadContext"},
  454. {0x3C, nullptr, "Break"},
  455. {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
  456. {0x3E, nullptr, "ControlPerformanceCounter"},
  457. {0x3F, nullptr, "Unknown"},
  458. {0x40, nullptr, "Unknown"},
  459. {0x41, nullptr, "Unknown"},
  460. {0x42, nullptr, "Unknown"},
  461. {0x43, nullptr, "Unknown"},
  462. {0x44, nullptr, "Unknown"},
  463. {0x45, nullptr, "Unknown"},
  464. {0x46, nullptr, "Unknown"},
  465. {0x47, nullptr, "CreatePort"},
  466. {0x48, nullptr, "CreateSessionToPort"},
  467. {0x49, nullptr, "CreateSession"},
  468. {0x4A, nullptr, "AcceptSession"},
  469. {0x4B, nullptr, "ReplyAndReceive1"},
  470. {0x4C, nullptr, "ReplyAndReceive2"},
  471. {0x4D, nullptr, "ReplyAndReceive3"},
  472. {0x4E, nullptr, "ReplyAndReceive4"},
  473. {0x4F, nullptr, "ReplyAndReceive"},
  474. {0x50, nullptr, "BindInterrupt"},
  475. {0x51, nullptr, "UnbindInterrupt"},
  476. {0x52, nullptr, "InvalidateProcessDataCache"},
  477. {0x53, nullptr, "StoreProcessDataCache"},
  478. {0x54, nullptr, "FlushProcessDataCache"},
  479. {0x55, nullptr, "StartInterProcessDma"},
  480. {0x56, nullptr, "StopDma"},
  481. {0x57, nullptr, "GetDmaState"},
  482. {0x58, nullptr, "RestartDma"},
  483. {0x59, nullptr, "Unknown"},
  484. {0x5A, nullptr, "Unknown"},
  485. {0x5B, nullptr, "Unknown"},
  486. {0x5C, nullptr, "Unknown"},
  487. {0x5D, nullptr, "Unknown"},
  488. {0x5E, nullptr, "Unknown"},
  489. {0x5F, nullptr, "Unknown"},
  490. {0x60, nullptr, "DebugActiveProcess"},
  491. {0x61, nullptr, "BreakDebugProcess"},
  492. {0x62, nullptr, "TerminateDebugProcess"},
  493. {0x63, nullptr, "GetProcessDebugEvent"},
  494. {0x64, nullptr, "ContinueDebugEvent"},
  495. {0x65, nullptr, "GetProcessList"},
  496. {0x66, nullptr, "GetThreadList"},
  497. {0x67, nullptr, "GetDebugThreadContext"},
  498. {0x68, nullptr, "SetDebugThreadContext"},
  499. {0x69, nullptr, "QueryDebugProcessMemory"},
  500. {0x6A, nullptr, "ReadProcessMemory"},
  501. {0x6B, nullptr, "WriteProcessMemory"},
  502. {0x6C, nullptr, "SetHardwareBreakPoint"},
  503. {0x6D, nullptr, "GetDebugThreadParam"},
  504. {0x6E, nullptr, "Unknown"},
  505. {0x6F, nullptr, "Unknown"},
  506. {0x70, nullptr, "ControlProcessMemory"},
  507. {0x71, nullptr, "MapProcessMemory"},
  508. {0x72, nullptr, "UnmapProcessMemory"},
  509. {0x73, nullptr, "CreateCodeSet"},
  510. {0x74, nullptr, "RandomStub"},
  511. {0x75, nullptr, "CreateProcess"},
  512. {0x76, nullptr, "TerminateProcess"},
  513. {0x77, nullptr, "SetProcessResourceLimits"},
  514. {0x78, nullptr, "CreateResourceLimit"},
  515. {0x79, nullptr, "SetResourceLimitValues"},
  516. {0x7A, nullptr, "AddCodeSegment"},
  517. {0x7B, nullptr, "Backdoor"},
  518. {0x7C, nullptr, "KernelSetState"},
  519. {0x7D, nullptr, "QueryProcessMemory"},
  520. };
  521. void Register() {
  522. HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
  523. }
  524. } // namespace