svc.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  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/logging/log.h"
  6. #include "common/microprofile.h"
  7. #include "common/string_util.h"
  8. #include "common/symbols.h"
  9. #include "core/core_timing.h"
  10. #include "core/arm/arm_interface.h"
  11. #include "core/hle/kernel/address_arbiter.h"
  12. #include "core/hle/kernel/event.h"
  13. #include "core/hle/kernel/memory.h"
  14. #include "core/hle/kernel/mutex.h"
  15. #include "core/hle/kernel/process.h"
  16. #include "core/hle/kernel/resource_limit.h"
  17. #include "core/hle/kernel/semaphore.h"
  18. #include "core/hle/kernel/shared_memory.h"
  19. #include "core/hle/kernel/thread.h"
  20. #include "core/hle/kernel/timer.h"
  21. #include "core/hle/kernel/vm_manager.h"
  22. #include "core/hle/function_wrappers.h"
  23. #include "core/hle/result.h"
  24. #include "core/hle/service/service.h"
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////
  26. // Namespace SVC
  27. using Kernel::SharedPtr;
  28. using Kernel::ERR_INVALID_HANDLE;
  29. namespace SVC {
  30. const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
  31. ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA
  32. const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
  33. ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
  34. const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1
  35. ErrorDescription::MisalignedAddress, ErrorModule::OS,
  36. ErrorSummary::InvalidArgument, ErrorLevel::Usage};
  37. const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2
  38. ErrorDescription::MisalignedSize, ErrorModule::OS,
  39. ErrorSummary::InvalidArgument, ErrorLevel::Usage};
  40. const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE
  41. ErrorDescription::InvalidCombination, ErrorModule::OS,
  42. ErrorSummary::InvalidArgument, ErrorLevel::Usage};
  43. enum ControlMemoryOperation {
  44. MEMOP_FREE = 1,
  45. MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel
  46. MEMOP_COMMIT = 3,
  47. MEMOP_MAP = 4,
  48. MEMOP_UNMAP = 5,
  49. MEMOP_PROTECT = 6,
  50. MEMOP_OPERATION_MASK = 0xFF,
  51. MEMOP_REGION_APP = 0x100,
  52. MEMOP_REGION_SYSTEM = 0x200,
  53. MEMOP_REGION_BASE = 0x300,
  54. MEMOP_REGION_MASK = 0xF00,
  55. MEMOP_LINEAR = 0x10000,
  56. };
  57. /// Map application or GSP heap memory
  58. static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
  59. using namespace Kernel;
  60. LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X",
  61. operation, addr0, addr1, size, permissions);
  62. if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
  63. return ERR_MISALIGNED_ADDRESS;
  64. }
  65. if ((size & Memory::PAGE_MASK) != 0) {
  66. return ERR_MISALIGNED_SIZE;
  67. }
  68. u32 region = operation & MEMOP_REGION_MASK;
  69. operation &= ~MEMOP_REGION_MASK;
  70. if (region != 0) {
  71. LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region);
  72. }
  73. if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) {
  74. return ERR_INVALID_COMBINATION;
  75. }
  76. VMAPermission vma_permissions = (VMAPermission)permissions;
  77. auto& process = *g_current_process;
  78. switch (operation & MEMOP_OPERATION_MASK) {
  79. case MEMOP_FREE:
  80. {
  81. // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it?
  82. if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
  83. ResultCode result = process.HeapFree(addr0, size);
  84. if (result.IsError()) return result;
  85. } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
  86. ResultCode result = process.LinearFree(addr0, size);
  87. if (result.IsError()) return result;
  88. } else {
  89. return ERR_INVALID_ADDRESS;
  90. }
  91. *out_addr = addr0;
  92. break;
  93. }
  94. case MEMOP_COMMIT:
  95. {
  96. if (operation & MEMOP_LINEAR) {
  97. CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions));
  98. } else {
  99. CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
  100. }
  101. break;
  102. }
  103. case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
  104. {
  105. CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
  106. break;
  107. }
  108. case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
  109. {
  110. ResultCode result = process.HeapFree(addr0, size);
  111. if (result.IsError()) return result;
  112. break;
  113. }
  114. case MEMOP_PROTECT:
  115. {
  116. ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
  117. if (result.IsError()) return result;
  118. break;
  119. }
  120. default:
  121. LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
  122. return ERR_INVALID_COMBINATION;
  123. }
  124. process.vm_manager.LogLayout(Log::Level::Trace);
  125. return RESULT_SUCCESS;
  126. }
  127. /// Maps a memory block to specified address
  128. static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
  129. using Kernel::SharedMemory;
  130. using Kernel::MemoryPermission;
  131. LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
  132. handle, addr, permissions, other_permissions);
  133. SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
  134. if (shared_memory == nullptr)
  135. return ERR_INVALID_HANDLE;
  136. MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions);
  137. switch (permissions_type) {
  138. case MemoryPermission::Read:
  139. case MemoryPermission::Write:
  140. case MemoryPermission::ReadWrite:
  141. case MemoryPermission::Execute:
  142. case MemoryPermission::ReadExecute:
  143. case MemoryPermission::WriteExecute:
  144. case MemoryPermission::ReadWriteExecute:
  145. case MemoryPermission::DontCare:
  146. return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
  147. static_cast<MemoryPermission>(other_permissions));
  148. default:
  149. LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
  150. }
  151. return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  152. }
  153. static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
  154. using Kernel::SharedMemory;
  155. LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr);
  156. // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
  157. SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
  158. if (shared_memory == nullptr)
  159. return ERR_INVALID_HANDLE;
  160. return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
  161. }
  162. /// Connect to an OS service given the port name, returns the handle to the port to out
  163. static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
  164. if (port_name == nullptr)
  165. return ERR_NOT_FOUND;
  166. if (std::strlen(port_name) > 11)
  167. return ERR_PORT_NAME_TOO_LONG;
  168. LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
  169. auto it = Service::g_kernel_named_ports.find(port_name);
  170. if (it == Service::g_kernel_named_ports.end()) {
  171. LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name);
  172. return ERR_NOT_FOUND;
  173. }
  174. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second));
  175. return RESULT_SUCCESS;
  176. }
  177. /// Synchronize to an OS service
  178. static ResultCode SendSyncRequest(Handle handle) {
  179. SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
  180. if (session == nullptr) {
  181. return ERR_INVALID_HANDLE;
  182. }
  183. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
  184. return session->SyncRequest().Code();
  185. }
  186. /// Close a handle
  187. static ResultCode CloseHandle(Handle handle) {
  188. LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle);
  189. return Kernel::g_handle_table.Close(handle);
  190. }
  191. /// Wait for a handle to synchronize, timeout after the specified nanoseconds
  192. static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
  193. auto object = Kernel::g_handle_table.GetWaitObject(handle);
  194. Kernel::Thread* thread = Kernel::GetCurrentThread();
  195. thread->waitsynch_waited = false;
  196. if (object == nullptr)
  197. return ERR_INVALID_HANDLE;
  198. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
  199. object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
  200. HLE::Reschedule(__func__);
  201. // Check for next thread to schedule
  202. if (object->ShouldWait()) {
  203. object->AddWaitingThread(thread);
  204. Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false);
  205. // Create an event to wake the thread up after the specified nanosecond delay has passed
  206. thread->WakeAfterDelay(nano_seconds);
  207. // NOTE: output of this SVC will be set later depending on how the thread resumes
  208. return HLE::RESULT_INVALID;
  209. }
  210. object->Acquire();
  211. return RESULT_SUCCESS;
  212. }
  213. /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
  214. static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
  215. bool wait_thread = !wait_all;
  216. int handle_index = 0;
  217. Kernel::Thread* thread = Kernel::GetCurrentThread();
  218. bool was_waiting = thread->waitsynch_waited;
  219. thread->waitsynch_waited = false;
  220. // Check if 'handles' is invalid
  221. if (handles == nullptr)
  222. return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
  223. // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
  224. // this happens, the running application will crash.
  225. ASSERT_MSG(out != nullptr, "invalid output pointer specified!");
  226. // Check if 'handle_count' is invalid
  227. if (handle_count < 0)
  228. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  229. // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
  230. // necessary
  231. if (handle_count != 0) {
  232. bool selected = false; // True once an object has been selected
  233. Kernel::SharedPtr<Kernel::WaitObject> wait_object;
  234. for (int i = 0; i < handle_count; ++i) {
  235. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  236. if (object == nullptr)
  237. return ERR_INVALID_HANDLE;
  238. // Check if the current thread should wait on this object...
  239. if (object->ShouldWait()) {
  240. // Check we are waiting on all objects...
  241. if (wait_all)
  242. // Wait the thread
  243. wait_thread = true;
  244. } else {
  245. // Do not wait on this object, check if this object should be selected...
  246. if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
  247. // Do not wait the thread
  248. wait_thread = false;
  249. handle_index = i;
  250. wait_object = object;
  251. selected = true;
  252. }
  253. }
  254. }
  255. } else {
  256. // If no handles were passed in, put the thread to sleep only when 'wait_all' is false
  257. // NOTE: This should deadlock the current thread if no timeout was specified
  258. if (!wait_all) {
  259. wait_thread = true;
  260. }
  261. }
  262. HLE::Reschedule(__func__);
  263. // If thread should wait, then set its state to waiting and then reschedule...
  264. if (wait_thread) {
  265. // Actually wait the current thread on each object if we decided to wait...
  266. std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
  267. wait_objects.reserve(handle_count);
  268. for (int i = 0; i < handle_count; ++i) {
  269. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  270. object->AddWaitingThread(Kernel::GetCurrentThread());
  271. wait_objects.push_back(object);
  272. }
  273. Kernel::WaitCurrentThread_WaitSynchronization(std::move(wait_objects), true, wait_all);
  274. // Create an event to wake the thread up after the specified nanosecond delay has passed
  275. Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
  276. // NOTE: output of this SVC will be set later depending on how the thread resumes
  277. return HLE::RESULT_INVALID;
  278. }
  279. // Acquire objects if we did not wait...
  280. for (int i = 0; i < handle_count; ++i) {
  281. auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
  282. // Acquire the object if it is not waiting...
  283. if (!object->ShouldWait()) {
  284. object->Acquire();
  285. // If this was the first non-waiting object and 'wait_all' is false, don't acquire
  286. // any other objects
  287. if (!wait_all)
  288. break;
  289. }
  290. }
  291. // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
  292. // not seem to set it to any meaningful value.
  293. *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
  294. return RESULT_SUCCESS;
  295. }
  296. /// Create an address arbiter (to allocate access to shared resources)
  297. static ResultCode CreateAddressArbiter(Handle* out_handle) {
  298. using Kernel::AddressArbiter;
  299. SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create();
  300. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter)));
  301. LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle);
  302. return RESULT_SUCCESS;
  303. }
  304. /// Arbitrate address
  305. static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) {
  306. using Kernel::AddressArbiter;
  307. LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle,
  308. address, type, value);
  309. SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle);
  310. if (arbiter == nullptr)
  311. return ERR_INVALID_HANDLE;
  312. auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type),
  313. address, value, nanoseconds);
  314. return res;
  315. }
  316. static void Break(u8 break_reason) {
  317. LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
  318. std::string reason_str;
  319. switch (break_reason) {
  320. case 0: reason_str = "PANIC"; break;
  321. case 1: reason_str = "ASSERT"; break;
  322. case 2: reason_str = "USER"; break;
  323. default: reason_str = "UNKNOWN"; break;
  324. }
  325. LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str());
  326. }
  327. /// Used to output a message on a debug hardware unit - does nothing on a retail unit
  328. static void OutputDebugString(const char* string) {
  329. LOG_DEBUG(Debug_Emulated, "%s", string);
  330. }
  331. /// Get resource limit
  332. static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
  333. LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
  334. SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
  335. if (process == nullptr)
  336. return ERR_INVALID_HANDLE;
  337. CASCADE_RESULT(*resource_limit, Kernel::g_handle_table.Create(process->resource_limit));
  338. return RESULT_SUCCESS;
  339. }
  340. /// Get resource limit current values
  341. static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names,
  342. u32 name_count) {
  343. LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
  344. resource_limit_handle, names, name_count);
  345. SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
  346. if (resource_limit == nullptr)
  347. return ERR_INVALID_HANDLE;
  348. for (unsigned int i = 0; i < name_count; ++i)
  349. values[i] = resource_limit->GetCurrentResourceValue(names[i]);
  350. return RESULT_SUCCESS;
  351. }
  352. /// Get resource limit max values
  353. static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
  354. u32 name_count) {
  355. LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
  356. resource_limit_handle, names, name_count);
  357. SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
  358. if (resource_limit == nullptr)
  359. return ERR_INVALID_HANDLE;
  360. for (unsigned int i = 0; i < name_count; ++i)
  361. values[i] = resource_limit->GetMaxResourceValue(names[i]);
  362. return RESULT_SUCCESS;
  363. }
  364. /// Creates a new thread
  365. static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
  366. using Kernel::Thread;
  367. std::string name;
  368. if (Symbols::HasSymbol(entry_point)) {
  369. TSymbol symbol = Symbols::GetSymbol(entry_point);
  370. name = symbol.name;
  371. } else {
  372. name = Common::StringFromFormat("unknown-%08x", entry_point);
  373. }
  374. // TODO(bunnei): Implement resource limits to return an error code instead of the below assert.
  375. // The error code should be: Description::NotAuthorized, Module::OS, Summary::WrongArgument,
  376. // Level::Permanent
  377. ASSERT_MSG(priority >= THREADPRIO_USERLAND_MAX, "Unexpected thread priority!");
  378. if (priority > THREADPRIO_LOWEST) {
  379. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS,
  380. ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  381. }
  382. switch (processor_id) {
  383. case THREADPROCESSORID_ALL:
  384. case THREADPROCESSORID_DEFAULT:
  385. case THREADPROCESSORID_0:
  386. case THREADPROCESSORID_1:
  387. break;
  388. default:
  389. // TODO(bunnei): Implement support for other processor IDs
  390. ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
  391. break;
  392. }
  393. if (processor_id == THREADPROCESSORID_1 || processor_id == THREADPROCESSORID_ALL ||
  394. (processor_id == THREADPROCESSORID_DEFAULT && Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1)) {
  395. LOG_WARNING(Kernel_SVC, "Newly created thread is allowed to be run in the SysCore, unimplemented.");
  396. }
  397. CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(
  398. name, entry_point, priority, arg, processor_id, stack_top));
  399. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread)));
  400. LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
  401. "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
  402. name.c_str(), arg, stack_top, priority, processor_id, *out_handle);
  403. return RESULT_SUCCESS;
  404. }
  405. /// Called when a thread exits
  406. static void ExitThread() {
  407. LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC());
  408. Kernel::GetCurrentThread()->Stop();
  409. }
  410. /// Gets the priority for the specified thread
  411. static ResultCode GetThreadPriority(s32* priority, Handle handle) {
  412. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  413. if (thread == nullptr)
  414. return ERR_INVALID_HANDLE;
  415. *priority = thread->GetPriority();
  416. return RESULT_SUCCESS;
  417. }
  418. /// Sets the priority for the specified thread
  419. static ResultCode SetThreadPriority(Handle handle, s32 priority) {
  420. SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  421. if (thread == nullptr)
  422. return ERR_INVALID_HANDLE;
  423. thread->SetPriority(priority);
  424. return RESULT_SUCCESS;
  425. }
  426. /// Create a mutex
  427. static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
  428. using Kernel::Mutex;
  429. SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
  430. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
  431. LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
  432. initial_locked ? "true" : "false", *out_handle);
  433. return RESULT_SUCCESS;
  434. }
  435. /// Release a mutex
  436. static ResultCode ReleaseMutex(Handle handle) {
  437. using Kernel::Mutex;
  438. LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
  439. SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle);
  440. if (mutex == nullptr)
  441. return ERR_INVALID_HANDLE;
  442. mutex->Release();
  443. return RESULT_SUCCESS;
  444. }
  445. /// Get the ID of the specified process
  446. static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
  447. LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
  448. const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
  449. if (process == nullptr)
  450. return ERR_INVALID_HANDLE;
  451. *process_id = process->process_id;
  452. return RESULT_SUCCESS;
  453. }
  454. /// Get the ID of the process that owns the specified thread
  455. static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
  456. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
  457. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
  458. if (thread == nullptr)
  459. return ERR_INVALID_HANDLE;
  460. const SharedPtr<Kernel::Process> process = thread->owner_process;
  461. ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
  462. *process_id = process->process_id;
  463. return RESULT_SUCCESS;
  464. }
  465. /// Get the ID for the specified thread.
  466. static ResultCode GetThreadId(u32* thread_id, Handle handle) {
  467. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
  468. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  469. if (thread == nullptr)
  470. return ERR_INVALID_HANDLE;
  471. *thread_id = thread->GetThreadId();
  472. return RESULT_SUCCESS;
  473. }
  474. /// Creates a semaphore
  475. static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
  476. using Kernel::Semaphore;
  477. CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count));
  478. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore)));
  479. LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
  480. initial_count, max_count, *out_handle);
  481. return RESULT_SUCCESS;
  482. }
  483. /// Releases a certain number of slots in a semaphore
  484. static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
  485. using Kernel::Semaphore;
  486. LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle);
  487. SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle);
  488. if (semaphore == nullptr)
  489. return ERR_INVALID_HANDLE;
  490. CASCADE_RESULT(*count, semaphore->Release(release_count));
  491. return RESULT_SUCCESS;
  492. }
  493. /// Query process memory
  494. static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) {
  495. using Kernel::Process;
  496. Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
  497. if (process == nullptr)
  498. return ERR_INVALID_HANDLE;
  499. auto vma = process->vm_manager.FindVMA(addr);
  500. if (vma == Kernel::g_current_process->vm_manager.vma_map.end())
  501. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  502. memory_info->base_address = vma->second.base;
  503. memory_info->permission = static_cast<u32>(vma->second.permissions);
  504. memory_info->size = vma->second.size;
  505. memory_info->state = static_cast<u32>(vma->second.meminfo_state);
  506. page_info->flags = 0;
  507. LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr);
  508. return RESULT_SUCCESS;
  509. }
  510. /// Query memory
  511. static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) {
  512. return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
  513. }
  514. /// Create an event
  515. static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
  516. using Kernel::Event;
  517. SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type));
  518. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt)));
  519. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X",
  520. reset_type, *out_handle);
  521. return RESULT_SUCCESS;
  522. }
  523. /// Duplicates a kernel handle
  524. static ResultCode DuplicateHandle(Handle* out, Handle handle) {
  525. CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle));
  526. LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
  527. return RESULT_SUCCESS;
  528. }
  529. /// Signals an event
  530. static ResultCode SignalEvent(Handle handle) {
  531. using Kernel::Event;
  532. LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
  533. SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle);
  534. if (evt == nullptr)
  535. return ERR_INVALID_HANDLE;
  536. evt->Signal();
  537. return RESULT_SUCCESS;
  538. }
  539. /// Clears an event
  540. static ResultCode ClearEvent(Handle handle) {
  541. using Kernel::Event;
  542. LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
  543. SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle);
  544. if (evt == nullptr)
  545. return ERR_INVALID_HANDLE;
  546. evt->Clear();
  547. return RESULT_SUCCESS;
  548. }
  549. /// Creates a timer
  550. static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
  551. using Kernel::Timer;
  552. SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type));
  553. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer)));
  554. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X",
  555. reset_type, *out_handle);
  556. return RESULT_SUCCESS;
  557. }
  558. /// Clears a timer
  559. static ResultCode ClearTimer(Handle handle) {
  560. using Kernel::Timer;
  561. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  562. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  563. if (timer == nullptr)
  564. return ERR_INVALID_HANDLE;
  565. timer->Clear();
  566. return RESULT_SUCCESS;
  567. }
  568. /// Starts a timer
  569. static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
  570. using Kernel::Timer;
  571. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  572. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  573. if (timer == nullptr)
  574. return ERR_INVALID_HANDLE;
  575. timer->Set(initial, interval);
  576. return RESULT_SUCCESS;
  577. }
  578. /// Cancels a timer
  579. static ResultCode CancelTimer(Handle handle) {
  580. using Kernel::Timer;
  581. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  582. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  583. if (timer == nullptr)
  584. return ERR_INVALID_HANDLE;
  585. timer->Cancel();
  586. return RESULT_SUCCESS;
  587. }
  588. /// Sleep the current thread
  589. static void SleepThread(s64 nanoseconds) {
  590. LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
  591. // Sleep current thread and check for next thread to schedule
  592. Kernel::WaitCurrentThread_Sleep();
  593. // Create an event to wake the thread up after the specified nanosecond delay has passed
  594. Kernel::GetCurrentThread()->WakeAfterDelay(nanoseconds);
  595. }
  596. /// This returns the total CPU ticks elapsed since the CPU was powered-on
  597. static s64 GetSystemTick() {
  598. s64 result = CoreTiming::GetTicks();
  599. // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
  600. Core::g_app_core->AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
  601. return result;
  602. }
  603. /// Creates a memory block at the specified address with the specified permissions and size
  604. static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
  605. u32 other_permission) {
  606. using Kernel::SharedMemory;
  607. if (size % Memory::PAGE_SIZE != 0)
  608. return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  609. SharedPtr<SharedMemory> shared_memory = nullptr;
  610. using Kernel::MemoryPermission;
  611. auto VerifyPermissions = [](MemoryPermission permission) {
  612. // SharedMemory blocks can not be created with Execute permissions
  613. switch (permission) {
  614. case MemoryPermission::None:
  615. case MemoryPermission::Read:
  616. case MemoryPermission::Write:
  617. case MemoryPermission::ReadWrite:
  618. case MemoryPermission::DontCare:
  619. return true;
  620. default:
  621. return false;
  622. }
  623. };
  624. if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
  625. !VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
  626. return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
  627. ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  628. if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) {
  629. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  630. }
  631. // When trying to create a memory block with address = 0,
  632. // if the process has the Shared Device Memory flag in the exheader,
  633. // then we have to allocate from the same region as the caller process instead of the BASE region.
  634. Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
  635. if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
  636. region = Kernel::g_current_process->flags.memory_region;
  637. shared_memory = SharedMemory::Create(Kernel::g_current_process, size,
  638. static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region);
  639. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
  640. LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
  641. return RESULT_SUCCESS;
  642. }
  643. static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
  644. using Kernel::MemoryRegion;
  645. LOG_TRACE(Kernel_SVC, "called type=%u param=%d", type, param);
  646. switch ((SystemInfoType)type) {
  647. case SystemInfoType::REGION_MEMORY_USAGE:
  648. switch ((SystemInfoMemUsageRegion)param) {
  649. case SystemInfoMemUsageRegion::ALL:
  650. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used
  651. + Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used
  652. + Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
  653. break;
  654. case SystemInfoMemUsageRegion::APPLICATION:
  655. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used;
  656. break;
  657. case SystemInfoMemUsageRegion::SYSTEM:
  658. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used;
  659. break;
  660. case SystemInfoMemUsageRegion::BASE:
  661. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
  662. break;
  663. default:
  664. LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param=%d", param);
  665. *out = 0;
  666. break;
  667. }
  668. break;
  669. case SystemInfoType::KERNEL_ALLOCATED_PAGES:
  670. LOG_ERROR(Kernel_SVC, "unimplemented GetSystemInfo type=2 param=%d", param);
  671. *out = 0;
  672. break;
  673. case SystemInfoType::KERNEL_SPAWNED_PIDS:
  674. *out = 5;
  675. break;
  676. default:
  677. LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=%u param=%d", type, param);
  678. *out = 0;
  679. break;
  680. }
  681. // This function never returns an error, even if invalid parameters were passed.
  682. return RESULT_SUCCESS;
  683. }
  684. static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
  685. LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
  686. using Kernel::Process;
  687. Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
  688. if (process == nullptr)
  689. return ERR_INVALID_HANDLE;
  690. switch (type) {
  691. case 0:
  692. case 2:
  693. // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
  694. // what's the difference between them.
  695. *out = process->heap_used + process->linear_heap_used + process->misc_memory_used;
  696. if(*out % Memory::PAGE_SIZE != 0) {
  697. LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
  698. return ERR_MISALIGNED_SIZE;
  699. }
  700. break;
  701. case 1:
  702. case 3:
  703. case 4:
  704. case 5:
  705. case 6:
  706. case 7:
  707. case 8:
  708. // These are valid, but not implemented yet
  709. LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type);
  710. break;
  711. case 20:
  712. *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase();
  713. break;
  714. default:
  715. LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type);
  716. if (type >= 21 && type <= 23) {
  717. return ResultCode( // 0xE0E01BF4
  718. ErrorDescription::NotImplemented, ErrorModule::OS,
  719. ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  720. } else {
  721. return ResultCode( // 0xD8E007ED
  722. ErrorDescription::InvalidEnumValue, ErrorModule::Kernel,
  723. ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
  724. }
  725. break;
  726. }
  727. return RESULT_SUCCESS;
  728. }
  729. namespace {
  730. struct FunctionDef {
  731. using Func = void();
  732. u32 id;
  733. Func* func;
  734. const char* name;
  735. };
  736. }
  737. static const FunctionDef SVC_Table[] = {
  738. {0x00, nullptr, "Unknown"},
  739. {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
  740. {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
  741. {0x03, nullptr, "ExitProcess"},
  742. {0x04, nullptr, "GetProcessAffinityMask"},
  743. {0x05, nullptr, "SetProcessAffinityMask"},
  744. {0x06, nullptr, "GetProcessIdealProcessor"},
  745. {0x07, nullptr, "SetProcessIdealProcessor"},
  746. {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
  747. {0x09, ExitThread, "ExitThread"},
  748. {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
  749. {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
  750. {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
  751. {0x0D, nullptr, "GetThreadAffinityMask"},
  752. {0x0E, nullptr, "SetThreadAffinityMask"},
  753. {0x0F, nullptr, "GetThreadIdealProcessor"},
  754. {0x10, nullptr, "SetThreadIdealProcessor"},
  755. {0x11, nullptr, "GetCurrentProcessorNumber"},
  756. {0x12, nullptr, "Run"},
  757. {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
  758. {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
  759. {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"},
  760. {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"},
  761. {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
  762. {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
  763. {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
  764. {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"},
  765. {0x1B, HLE::Wrap<SetTimer>, "SetTimer"},
  766. {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"},
  767. {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"},
  768. {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"},
  769. {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
  770. {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"},
  771. {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
  772. {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
  773. {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
  774. {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
  775. {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
  776. {0x26, nullptr, "SignalAndWait"},
  777. {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
  778. {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
  779. {0x29, nullptr, "GetHandleInfo"},
  780. {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"},
  781. {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"},
  782. {0x2C, nullptr, "GetThreadInfo"},
  783. {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
  784. {0x2E, nullptr, "SendSyncRequest1"},
  785. {0x2F, nullptr, "SendSyncRequest2"},
  786. {0x30, nullptr, "SendSyncRequest3"},
  787. {0x31, nullptr, "SendSyncRequest4"},
  788. {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
  789. {0x33, nullptr, "OpenProcess"},
  790. {0x34, nullptr, "OpenThread"},
  791. {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"},
  792. {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"},
  793. {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
  794. {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
  795. {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"},
  796. {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
  797. {0x3B, nullptr, "GetThreadContext"},
  798. {0x3C, HLE::Wrap<Break>, "Break"},
  799. {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
  800. {0x3E, nullptr, "ControlPerformanceCounter"},
  801. {0x3F, nullptr, "Unknown"},
  802. {0x40, nullptr, "Unknown"},
  803. {0x41, nullptr, "Unknown"},
  804. {0x42, nullptr, "Unknown"},
  805. {0x43, nullptr, "Unknown"},
  806. {0x44, nullptr, "Unknown"},
  807. {0x45, nullptr, "Unknown"},
  808. {0x46, nullptr, "Unknown"},
  809. {0x47, nullptr, "CreatePort"},
  810. {0x48, nullptr, "CreateSessionToPort"},
  811. {0x49, nullptr, "CreateSession"},
  812. {0x4A, nullptr, "AcceptSession"},
  813. {0x4B, nullptr, "ReplyAndReceive1"},
  814. {0x4C, nullptr, "ReplyAndReceive2"},
  815. {0x4D, nullptr, "ReplyAndReceive3"},
  816. {0x4E, nullptr, "ReplyAndReceive4"},
  817. {0x4F, nullptr, "ReplyAndReceive"},
  818. {0x50, nullptr, "BindInterrupt"},
  819. {0x51, nullptr, "UnbindInterrupt"},
  820. {0x52, nullptr, "InvalidateProcessDataCache"},
  821. {0x53, nullptr, "StoreProcessDataCache"},
  822. {0x54, nullptr, "FlushProcessDataCache"},
  823. {0x55, nullptr, "StartInterProcessDma"},
  824. {0x56, nullptr, "StopDma"},
  825. {0x57, nullptr, "GetDmaState"},
  826. {0x58, nullptr, "RestartDma"},
  827. {0x59, nullptr, "Unknown"},
  828. {0x5A, nullptr, "Unknown"},
  829. {0x5B, nullptr, "Unknown"},
  830. {0x5C, nullptr, "Unknown"},
  831. {0x5D, nullptr, "Unknown"},
  832. {0x5E, nullptr, "Unknown"},
  833. {0x5F, nullptr, "Unknown"},
  834. {0x60, nullptr, "DebugActiveProcess"},
  835. {0x61, nullptr, "BreakDebugProcess"},
  836. {0x62, nullptr, "TerminateDebugProcess"},
  837. {0x63, nullptr, "GetProcessDebugEvent"},
  838. {0x64, nullptr, "ContinueDebugEvent"},
  839. {0x65, nullptr, "GetProcessList"},
  840. {0x66, nullptr, "GetThreadList"},
  841. {0x67, nullptr, "GetDebugThreadContext"},
  842. {0x68, nullptr, "SetDebugThreadContext"},
  843. {0x69, nullptr, "QueryDebugProcessMemory"},
  844. {0x6A, nullptr, "ReadProcessMemory"},
  845. {0x6B, nullptr, "WriteProcessMemory"},
  846. {0x6C, nullptr, "SetHardwareBreakPoint"},
  847. {0x6D, nullptr, "GetDebugThreadParam"},
  848. {0x6E, nullptr, "Unknown"},
  849. {0x6F, nullptr, "Unknown"},
  850. {0x70, nullptr, "ControlProcessMemory"},
  851. {0x71, nullptr, "MapProcessMemory"},
  852. {0x72, nullptr, "UnmapProcessMemory"},
  853. {0x73, nullptr, "CreateCodeSet"},
  854. {0x74, nullptr, "RandomStub"},
  855. {0x75, nullptr, "CreateProcess"},
  856. {0x76, nullptr, "TerminateProcess"},
  857. {0x77, nullptr, "SetProcessResourceLimits"},
  858. {0x78, nullptr, "CreateResourceLimit"},
  859. {0x79, nullptr, "SetResourceLimitValues"},
  860. {0x7A, nullptr, "AddCodeSegment"},
  861. {0x7B, nullptr, "Backdoor"},
  862. {0x7C, nullptr, "KernelSetState"},
  863. {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"},
  864. };
  865. static const FunctionDef* GetSVCInfo(u32 func_num) {
  866. if (func_num >= ARRAY_SIZE(SVC_Table)) {
  867. LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
  868. return nullptr;
  869. }
  870. return &SVC_Table[func_num];
  871. }
  872. MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
  873. void CallSVC(u32 immediate) {
  874. MICROPROFILE_SCOPE(Kernel_SVC);
  875. const FunctionDef* info = GetSVCInfo(immediate);
  876. if (info) {
  877. if (info->func) {
  878. info->func();
  879. } else {
  880. LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
  881. }
  882. }
  883. }
  884. } // namespace