svc.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cinttypes>
  6. #include <map>
  7. #include "common/logging/log.h"
  8. #include "common/microprofile.h"
  9. #include "common/scope_exit.h"
  10. #include "common/string_util.h"
  11. #include "core/arm/arm_interface.h"
  12. #include "core/core_timing.h"
  13. #include "core/hle/function_wrappers.h"
  14. #include "core/hle/kernel/address_arbiter.h"
  15. #include "core/hle/kernel/client_port.h"
  16. #include "core/hle/kernel/client_session.h"
  17. #include "core/hle/kernel/errors.h"
  18. #include "core/hle/kernel/event.h"
  19. #include "core/hle/kernel/handle_table.h"
  20. #include "core/hle/kernel/memory.h"
  21. #include "core/hle/kernel/mutex.h"
  22. #include "core/hle/kernel/process.h"
  23. #include "core/hle/kernel/resource_limit.h"
  24. #include "core/hle/kernel/semaphore.h"
  25. #include "core/hle/kernel/server_port.h"
  26. #include "core/hle/kernel/server_session.h"
  27. #include "core/hle/kernel/session.h"
  28. #include "core/hle/kernel/shared_memory.h"
  29. #include "core/hle/kernel/thread.h"
  30. #include "core/hle/kernel/timer.h"
  31. #include "core/hle/kernel/vm_manager.h"
  32. #include "core/hle/kernel/wait_object.h"
  33. #include "core/hle/lock.h"
  34. #include "core/hle/result.h"
  35. #include "core/hle/service/service.h"
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////
  37. // Namespace SVC
  38. using Kernel::ERR_INVALID_HANDLE;
  39. using Kernel::Handle;
  40. using Kernel::SharedPtr;
  41. namespace SVC {
  42. enum ControlMemoryOperation {
  43. MEMOP_FREE = 1,
  44. MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel
  45. MEMOP_COMMIT = 3,
  46. MEMOP_MAP = 4,
  47. MEMOP_UNMAP = 5,
  48. MEMOP_PROTECT = 6,
  49. MEMOP_OPERATION_MASK = 0xFF,
  50. MEMOP_REGION_APP = 0x100,
  51. MEMOP_REGION_SYSTEM = 0x200,
  52. MEMOP_REGION_BASE = 0x300,
  53. MEMOP_REGION_MASK = 0xF00,
  54. MEMOP_LINEAR = 0x10000,
  55. };
  56. /// Map application or GSP heap memory
  57. static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size,
  58. u32 permissions) {
  59. using namespace Kernel;
  60. LOG_DEBUG(Kernel_SVC,
  61. "called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X",
  62. operation, addr0, addr1, size, permissions);
  63. if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
  64. return ERR_MISALIGNED_ADDRESS;
  65. }
  66. if ((size & Memory::PAGE_MASK) != 0) {
  67. return ERR_MISALIGNED_SIZE;
  68. }
  69. u32 region = operation & MEMOP_REGION_MASK;
  70. operation &= ~MEMOP_REGION_MASK;
  71. if (region != 0) {
  72. LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X",
  73. region);
  74. }
  75. if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) {
  76. return ERR_INVALID_COMBINATION;
  77. }
  78. VMAPermission vma_permissions = (VMAPermission)permissions;
  79. auto& process = *g_current_process;
  80. switch (operation & MEMOP_OPERATION_MASK) {
  81. case MEMOP_FREE: {
  82. // TODO(Subv): What happens if an application tries to FREE a block of memory that has a
  83. // SharedMemory pointing to it?
  84. if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
  85. ResultCode result = process.HeapFree(addr0, size);
  86. if (result.IsError())
  87. return result;
  88. } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
  89. ResultCode result = process.LinearFree(addr0, size);
  90. if (result.IsError())
  91. return result;
  92. } else {
  93. return ERR_INVALID_ADDRESS;
  94. }
  95. *out_addr = addr0;
  96. break;
  97. }
  98. case MEMOP_COMMIT: {
  99. if (operation & MEMOP_LINEAR) {
  100. CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions));
  101. } else {
  102. CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
  103. }
  104. break;
  105. }
  106. case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is
  107. // implemented
  108. {
  109. CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
  110. break;
  111. }
  112. case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is
  113. // implemented
  114. {
  115. ResultCode result = process.HeapFree(addr0, size);
  116. if (result.IsError())
  117. return result;
  118. break;
  119. }
  120. case MEMOP_PROTECT: {
  121. ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
  122. if (result.IsError())
  123. return result;
  124. break;
  125. }
  126. default:
  127. LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
  128. return ERR_INVALID_COMBINATION;
  129. }
  130. process.vm_manager.LogLayout(Log::Level::Trace);
  131. return RESULT_SUCCESS;
  132. }
  133. /// Maps a memory block to specified address
  134. static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permissions,
  135. u32 other_permissions) {
  136. using Kernel::SharedMemory;
  137. using Kernel::MemoryPermission;
  138. LOG_TRACE(Kernel_SVC,
  139. "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
  140. handle, addr, permissions, other_permissions);
  141. SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
  142. if (shared_memory == nullptr)
  143. return ERR_INVALID_HANDLE;
  144. MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions);
  145. switch (permissions_type) {
  146. case MemoryPermission::Read:
  147. case MemoryPermission::Write:
  148. case MemoryPermission::ReadWrite:
  149. case MemoryPermission::Execute:
  150. case MemoryPermission::ReadExecute:
  151. case MemoryPermission::WriteExecute:
  152. case MemoryPermission::ReadWriteExecute:
  153. case MemoryPermission::DontCare:
  154. return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
  155. static_cast<MemoryPermission>(other_permissions));
  156. default:
  157. LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
  158. }
  159. return Kernel::ERR_INVALID_COMBINATION;
  160. }
  161. static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) {
  162. using Kernel::SharedMemory;
  163. LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr);
  164. // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
  165. SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
  166. if (shared_memory == nullptr)
  167. return ERR_INVALID_HANDLE;
  168. return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
  169. }
  170. /// Connect to an OS service given the port name, returns the handle to the port to out
  171. static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) {
  172. if (port_name == nullptr)
  173. return Kernel::ERR_NOT_FOUND;
  174. if (std::strlen(port_name) > 11)
  175. return Kernel::ERR_PORT_NAME_TOO_LONG;
  176. LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
  177. auto it = Service::g_kernel_named_ports.find(port_name);
  178. if (it == Service::g_kernel_named_ports.end()) {
  179. LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name);
  180. return Kernel::ERR_NOT_FOUND;
  181. }
  182. auto client_port = it->second;
  183. SharedPtr<Kernel::ClientSession> client_session;
  184. CASCADE_RESULT(client_session, client_port->Connect());
  185. // Return the client session
  186. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session));
  187. return RESULT_SUCCESS;
  188. }
  189. /// Makes a blocking IPC call to an OS service.
  190. static ResultCode SendSyncRequest(Kernel::Handle handle) {
  191. SharedPtr<Kernel::ClientSession> session =
  192. Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
  193. if (session == nullptr) {
  194. return ERR_INVALID_HANDLE;
  195. }
  196. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
  197. Core::System::GetInstance().PrepareReschedule();
  198. // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
  199. // responds and cause a reschedule.
  200. return session->SendSyncRequest(Kernel::GetCurrentThread());
  201. }
  202. /// Close a handle
  203. static ResultCode CloseHandle(Kernel::Handle handle) {
  204. LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle);
  205. return Kernel::g_handle_table.Close(handle);
  206. }
  207. /// Wait for a handle to synchronize, timeout after the specified nanoseconds
  208. static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) {
  209. auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
  210. Kernel::Thread* thread = Kernel::GetCurrentThread();
  211. if (object == nullptr)
  212. return ERR_INVALID_HANDLE;
  213. LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
  214. object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
  215. if (object->ShouldWait(thread)) {
  216. if (nano_seconds == 0)
  217. return Kernel::RESULT_TIMEOUT;
  218. thread->wait_objects = {object};
  219. object->AddWaitingThread(thread);
  220. thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
  221. // Create an event to wake the thread up after the specified nanosecond delay has passed
  222. thread->WakeAfterDelay(nano_seconds);
  223. thread->wakeup_callback = [](ThreadWakeupReason reason,
  224. Kernel::SharedPtr<Kernel::Thread> thread,
  225. Kernel::SharedPtr<Kernel::WaitObject> object) {
  226. ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
  227. if (reason == ThreadWakeupReason::Timeout) {
  228. thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
  229. return;
  230. }
  231. ASSERT(reason == ThreadWakeupReason::Signal);
  232. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  233. // WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
  234. // don't have to do anything else here.
  235. };
  236. Core::System::GetInstance().PrepareReschedule();
  237. // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread
  238. // resumes due to a signal in its wait objects.
  239. // Otherwise we retain the default value of timeout.
  240. return Kernel::RESULT_TIMEOUT;
  241. }
  242. object->Acquire(thread);
  243. return RESULT_SUCCESS;
  244. }
  245. /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
  246. static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count,
  247. bool wait_all, s64 nano_seconds) {
  248. Kernel::Thread* thread = Kernel::GetCurrentThread();
  249. // Check if 'handles' is invalid
  250. if (handles == nullptr)
  251. return Kernel::ERR_INVALID_POINTER;
  252. // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
  253. // this happens, the running application will crash.
  254. ASSERT_MSG(out != nullptr, "invalid output pointer specified!");
  255. // Check if 'handle_count' is invalid
  256. if (handle_count < 0)
  257. return Kernel::ERR_OUT_OF_RANGE;
  258. using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>;
  259. std::vector<ObjectPtr> objects(handle_count);
  260. for (int i = 0; i < handle_count; ++i) {
  261. auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
  262. if (object == nullptr)
  263. return ERR_INVALID_HANDLE;
  264. objects[i] = object;
  265. }
  266. if (wait_all) {
  267. bool all_available =
  268. std::all_of(objects.begin(), objects.end(),
  269. [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); });
  270. if (all_available) {
  271. // We can acquire all objects right now, do so.
  272. for (auto& object : objects)
  273. object->Acquire(thread);
  274. // Note: In this case, the `out` parameter is not set,
  275. // and retains whatever value it had before.
  276. return RESULT_SUCCESS;
  277. }
  278. // Not all objects were available right now, prepare to suspend the thread.
  279. // If a timeout value of 0 was provided, just return the Timeout error code instead of
  280. // suspending the thread.
  281. if (nano_seconds == 0)
  282. return Kernel::RESULT_TIMEOUT;
  283. // Put the thread to sleep
  284. thread->status = THREADSTATUS_WAIT_SYNCH_ALL;
  285. // Add the thread to each of the objects' waiting threads.
  286. for (auto& object : objects) {
  287. object->AddWaitingThread(thread);
  288. }
  289. thread->wait_objects = std::move(objects);
  290. // Create an event to wake the thread up after the specified nanosecond delay has passed
  291. thread->WakeAfterDelay(nano_seconds);
  292. thread->wakeup_callback = [](ThreadWakeupReason reason,
  293. Kernel::SharedPtr<Kernel::Thread> thread,
  294. Kernel::SharedPtr<Kernel::WaitObject> object) {
  295. ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ALL);
  296. if (reason == ThreadWakeupReason::Timeout) {
  297. thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
  298. return;
  299. }
  300. ASSERT(reason == ThreadWakeupReason::Signal);
  301. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  302. // The wait_all case does not update the output index.
  303. };
  304. Core::System::GetInstance().PrepareReschedule();
  305. // This value gets set to -1 by default in this case, it is not modified after this.
  306. *out = -1;
  307. // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to
  308. // a signal in one of its wait objects.
  309. return Kernel::RESULT_TIMEOUT;
  310. } else {
  311. // Find the first object that is acquirable in the provided list of objects
  312. auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
  313. return !object->ShouldWait(thread);
  314. });
  315. if (itr != objects.end()) {
  316. // We found a ready object, acquire it and set the result value
  317. Kernel::WaitObject* object = itr->get();
  318. object->Acquire(thread);
  319. *out = static_cast<s32>(std::distance(objects.begin(), itr));
  320. return RESULT_SUCCESS;
  321. }
  322. // No objects were ready to be acquired, prepare to suspend the thread.
  323. // If a timeout value of 0 was provided, just return the Timeout error code instead of
  324. // suspending the thread.
  325. if (nano_seconds == 0)
  326. return Kernel::RESULT_TIMEOUT;
  327. // Put the thread to sleep
  328. thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
  329. // Add the thread to each of the objects' waiting threads.
  330. for (size_t i = 0; i < objects.size(); ++i) {
  331. Kernel::WaitObject* object = objects[i].get();
  332. object->AddWaitingThread(thread);
  333. }
  334. thread->wait_objects = std::move(objects);
  335. // Note: If no handles and no timeout were given, then the thread will deadlock, this is
  336. // consistent with hardware behavior.
  337. // Create an event to wake the thread up after the specified nanosecond delay has passed
  338. thread->WakeAfterDelay(nano_seconds);
  339. thread->wakeup_callback = [](ThreadWakeupReason reason,
  340. Kernel::SharedPtr<Kernel::Thread> thread,
  341. Kernel::SharedPtr<Kernel::WaitObject> object) {
  342. ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
  343. if (reason == ThreadWakeupReason::Timeout) {
  344. thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
  345. return;
  346. }
  347. ASSERT(reason == ThreadWakeupReason::Signal);
  348. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  349. thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
  350. };
  351. Core::System::GetInstance().PrepareReschedule();
  352. // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
  353. // signal in one of its wait objects.
  354. // Otherwise we retain the default value of timeout, and -1 in the out parameter
  355. *out = -1;
  356. return Kernel::RESULT_TIMEOUT;
  357. }
  358. }
  359. /// In a single operation, sends a IPC reply and waits for a new request.
  360. static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count,
  361. Kernel::Handle reply_target) {
  362. // 'handles' has to be a valid pointer even if 'handle_count' is 0.
  363. if (handles == nullptr)
  364. return Kernel::ERR_INVALID_POINTER;
  365. // Check if 'handle_count' is invalid
  366. if (handle_count < 0)
  367. return Kernel::ERR_OUT_OF_RANGE;
  368. using ObjectPtr = SharedPtr<Kernel::WaitObject>;
  369. std::vector<ObjectPtr> objects(handle_count);
  370. for (int i = 0; i < handle_count; ++i) {
  371. auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
  372. if (object == nullptr)
  373. return ERR_INVALID_HANDLE;
  374. objects[i] = object;
  375. }
  376. // We are also sending a command reply.
  377. // Do not send a reply if the command id in the command buffer is 0xFFFF.
  378. u32* cmd_buff = Kernel::GetCommandBuffer();
  379. IPC::Header header{cmd_buff[0]};
  380. if (reply_target != 0 && header.command_id != 0xFFFF) {
  381. auto session = Kernel::g_handle_table.Get<Kernel::ServerSession>(reply_target);
  382. if (session == nullptr)
  383. return ERR_INVALID_HANDLE;
  384. auto request_thread = std::move(session->currently_handling);
  385. // Mark the request as "handled".
  386. session->currently_handling = nullptr;
  387. // Error out if there's no request thread or the session was closed.
  388. // TODO(Subv): Is the same error code (ClosedByRemote) returned for both of these cases?
  389. if (request_thread == nullptr || session->parent->client == nullptr) {
  390. *index = -1;
  391. return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
  392. }
  393. // TODO(Subv): Perform IPC translation from the current thread to request_thread.
  394. // Note: The scheduler is not invoked here.
  395. request_thread->ResumeFromWait();
  396. }
  397. if (handle_count == 0) {
  398. *index = 0;
  399. // The kernel uses this value as a placeholder for the real error, and returns it when we
  400. // pass no handles and do not perform any reply.
  401. if (reply_target == 0 || header.command_id == 0xFFFF)
  402. return ResultCode(0xE7E3FFFF);
  403. return RESULT_SUCCESS;
  404. }
  405. auto thread = Kernel::GetCurrentThread();
  406. // Find the first object that is acquirable in the provided list of objects
  407. auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
  408. return !object->ShouldWait(thread);
  409. });
  410. if (itr != objects.end()) {
  411. // We found a ready object, acquire it and set the result value
  412. Kernel::WaitObject* object = itr->get();
  413. object->Acquire(thread);
  414. *index = static_cast<s32>(std::distance(objects.begin(), itr));
  415. if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
  416. auto server_session = static_cast<Kernel::ServerSession*>(object);
  417. if (server_session->parent->client == nullptr)
  418. return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
  419. // TODO(Subv): Perform IPC translation from the ServerSession to the current thread.
  420. }
  421. return RESULT_SUCCESS;
  422. }
  423. // No objects were ready to be acquired, prepare to suspend the thread.
  424. // Put the thread to sleep
  425. thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
  426. // Add the thread to each of the objects' waiting threads.
  427. for (size_t i = 0; i < objects.size(); ++i) {
  428. Kernel::WaitObject* object = objects[i].get();
  429. object->AddWaitingThread(thread);
  430. }
  431. thread->wait_objects = std::move(objects);
  432. thread->wakeup_callback = [](ThreadWakeupReason reason,
  433. Kernel::SharedPtr<Kernel::Thread> thread,
  434. Kernel::SharedPtr<Kernel::WaitObject> object) {
  435. ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
  436. ASSERT(reason == ThreadWakeupReason::Signal);
  437. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  438. thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
  439. // TODO(Subv): Perform IPC translation upon wakeup.
  440. };
  441. Core::System::GetInstance().PrepareReschedule();
  442. // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
  443. // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error.
  444. // By default the index is set to -1.
  445. *index = -1;
  446. return RESULT_SUCCESS;
  447. }
  448. /// Create an address arbiter (to allocate access to shared resources)
  449. static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) {
  450. using Kernel::AddressArbiter;
  451. SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create();
  452. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter)));
  453. LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle);
  454. return RESULT_SUCCESS;
  455. }
  456. /// Arbitrate address
  457. static ResultCode ArbitrateAddress(Kernel::Handle handle, u32 address, u32 type, u32 value,
  458. s64 nanoseconds) {
  459. using Kernel::AddressArbiter;
  460. LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle,
  461. address, type, value);
  462. SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle);
  463. if (arbiter == nullptr)
  464. return ERR_INVALID_HANDLE;
  465. auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), address, value,
  466. nanoseconds);
  467. // TODO(Subv): Identify in which specific cases this call should cause a reschedule.
  468. Core::System::GetInstance().PrepareReschedule();
  469. return res;
  470. }
  471. static void Break(u8 break_reason) {
  472. LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
  473. std::string reason_str;
  474. switch (break_reason) {
  475. case 0:
  476. reason_str = "PANIC";
  477. break;
  478. case 1:
  479. reason_str = "ASSERT";
  480. break;
  481. case 2:
  482. reason_str = "USER";
  483. break;
  484. default:
  485. reason_str = "UNKNOWN";
  486. break;
  487. }
  488. LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str());
  489. }
  490. /// Used to output a message on a debug hardware unit - does nothing on a retail unit
  491. static void OutputDebugString(const char* string, int len) {
  492. LOG_DEBUG(Debug_Emulated, "%.*s", len, string);
  493. }
  494. /// Get resource limit
  495. static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handle process_handle) {
  496. LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
  497. SharedPtr<Kernel::Process> process =
  498. Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
  499. if (process == nullptr)
  500. return ERR_INVALID_HANDLE;
  501. CASCADE_RESULT(*resource_limit, Kernel::g_handle_table.Create(process->resource_limit));
  502. return RESULT_SUCCESS;
  503. }
  504. /// Get resource limit current values
  505. static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle,
  506. u32* names, u32 name_count) {
  507. LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
  508. resource_limit_handle, names, name_count);
  509. SharedPtr<Kernel::ResourceLimit> resource_limit =
  510. Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
  511. if (resource_limit == nullptr)
  512. return ERR_INVALID_HANDLE;
  513. for (unsigned int i = 0; i < name_count; ++i)
  514. values[i] = resource_limit->GetCurrentResourceValue(names[i]);
  515. return RESULT_SUCCESS;
  516. }
  517. /// Get resource limit max values
  518. static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle,
  519. u32* names, u32 name_count) {
  520. LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
  521. resource_limit_handle, names, name_count);
  522. SharedPtr<Kernel::ResourceLimit> resource_limit =
  523. Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
  524. if (resource_limit == nullptr)
  525. return ERR_INVALID_HANDLE;
  526. for (unsigned int i = 0; i < name_count; ++i)
  527. values[i] = resource_limit->GetMaxResourceValue(names[i]);
  528. return RESULT_SUCCESS;
  529. }
  530. /// Creates a new thread
  531. static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 entry_point, u32 arg,
  532. u32 stack_top, s32 processor_id) {
  533. using Kernel::Thread;
  534. std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point);
  535. if (priority > THREADPRIO_LOWEST) {
  536. return Kernel::ERR_OUT_OF_RANGE;
  537. }
  538. using Kernel::ResourceLimit;
  539. Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit;
  540. if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) {
  541. return Kernel::ERR_NOT_AUTHORIZED;
  542. }
  543. switch (processor_id) {
  544. case THREADPROCESSORID_ALL:
  545. case THREADPROCESSORID_DEFAULT:
  546. case THREADPROCESSORID_0:
  547. case THREADPROCESSORID_1:
  548. break;
  549. default:
  550. // TODO(bunnei): Implement support for other processor IDs
  551. ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
  552. break;
  553. }
  554. if (processor_id == THREADPROCESSORID_ALL) {
  555. LOG_INFO(Kernel_SVC,
  556. "Newly created thread is allowed to be run in any Core, unimplemented.");
  557. }
  558. if (processor_id == THREADPROCESSORID_DEFAULT &&
  559. Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1) {
  560. LOG_WARNING(
  561. Kernel_SVC,
  562. "Newly created thread is allowed to be run in the SysCore (Core1), unimplemented.");
  563. }
  564. if (processor_id == THREADPROCESSORID_1) {
  565. LOG_ERROR(Kernel_SVC,
  566. "Newly created thread must run in the SysCore (Core1), unimplemented.");
  567. }
  568. CASCADE_RESULT(SharedPtr<Thread> thread,
  569. Kernel::Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
  570. Kernel::g_current_process));
  571. thread->context.fpscr =
  572. FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
  573. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread)));
  574. Core::System::GetInstance().PrepareReschedule();
  575. LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
  576. "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X",
  577. entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle);
  578. return RESULT_SUCCESS;
  579. }
  580. /// Called when a thread exits
  581. static void ExitThread() {
  582. LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC());
  583. Kernel::ExitCurrentThread();
  584. Core::System::GetInstance().PrepareReschedule();
  585. }
  586. /// Gets the priority for the specified thread
  587. static ResultCode GetThreadPriority(u32* priority, Kernel::Handle handle) {
  588. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  589. if (thread == nullptr)
  590. return ERR_INVALID_HANDLE;
  591. *priority = thread->GetPriority();
  592. return RESULT_SUCCESS;
  593. }
  594. /// Sets the priority for the specified thread
  595. static ResultCode SetThreadPriority(Kernel::Handle handle, u32 priority) {
  596. if (priority > THREADPRIO_LOWEST) {
  597. return Kernel::ERR_OUT_OF_RANGE;
  598. }
  599. SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  600. if (thread == nullptr)
  601. return ERR_INVALID_HANDLE;
  602. using Kernel::ResourceLimit;
  603. // Note: The kernel uses the current process's resource limit instead of
  604. // the one from the thread owner's resource limit.
  605. Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit;
  606. if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) {
  607. return Kernel::ERR_NOT_AUTHORIZED;
  608. }
  609. thread->SetPriority(priority);
  610. thread->UpdatePriority();
  611. // Update the mutexes that this thread is waiting for
  612. for (auto& mutex : thread->pending_mutexes)
  613. mutex->UpdatePriority();
  614. Core::System::GetInstance().PrepareReschedule();
  615. return RESULT_SUCCESS;
  616. }
  617. /// Create a mutex
  618. static ResultCode CreateMutex(Kernel::Handle* out_handle, u32 initial_locked) {
  619. using Kernel::Mutex;
  620. SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
  621. mutex->name = Common::StringFromFormat("mutex-%08x", Core::CPU().GetReg(14));
  622. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
  623. LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
  624. initial_locked ? "true" : "false", *out_handle);
  625. return RESULT_SUCCESS;
  626. }
  627. /// Release a mutex
  628. static ResultCode ReleaseMutex(Kernel::Handle handle) {
  629. using Kernel::Mutex;
  630. LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
  631. SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle);
  632. if (mutex == nullptr)
  633. return ERR_INVALID_HANDLE;
  634. mutex->Release();
  635. return RESULT_SUCCESS;
  636. }
  637. /// Get the ID of the specified process
  638. static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) {
  639. LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
  640. const SharedPtr<Kernel::Process> process =
  641. Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
  642. if (process == nullptr)
  643. return ERR_INVALID_HANDLE;
  644. *process_id = process->process_id;
  645. return RESULT_SUCCESS;
  646. }
  647. /// Get the ID of the process that owns the specified thread
  648. static ResultCode GetProcessIdOfThread(u32* process_id, Kernel::Handle thread_handle) {
  649. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
  650. const SharedPtr<Kernel::Thread> thread =
  651. Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
  652. if (thread == nullptr)
  653. return ERR_INVALID_HANDLE;
  654. const SharedPtr<Kernel::Process> process = thread->owner_process;
  655. ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
  656. *process_id = process->process_id;
  657. return RESULT_SUCCESS;
  658. }
  659. /// Get the ID for the specified thread.
  660. static ResultCode GetThreadId(u32* thread_id, Kernel::Handle handle) {
  661. LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
  662. const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
  663. if (thread == nullptr)
  664. return ERR_INVALID_HANDLE;
  665. *thread_id = thread->GetThreadId();
  666. return RESULT_SUCCESS;
  667. }
  668. /// Creates a semaphore
  669. static ResultCode CreateSemaphore(Kernel::Handle* out_handle, s32 initial_count, s32 max_count) {
  670. using Kernel::Semaphore;
  671. CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count));
  672. semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::CPU().GetReg(14));
  673. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore)));
  674. LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
  675. initial_count, max_count, *out_handle);
  676. return RESULT_SUCCESS;
  677. }
  678. /// Releases a certain number of slots in a semaphore
  679. static ResultCode ReleaseSemaphore(s32* count, Kernel::Handle handle, s32 release_count) {
  680. using Kernel::Semaphore;
  681. LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle);
  682. SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle);
  683. if (semaphore == nullptr)
  684. return ERR_INVALID_HANDLE;
  685. CASCADE_RESULT(*count, semaphore->Release(release_count));
  686. return RESULT_SUCCESS;
  687. }
  688. /// Query process memory
  689. static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
  690. Kernel::Handle process_handle, u32 addr) {
  691. using Kernel::Process;
  692. Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
  693. if (process == nullptr)
  694. return ERR_INVALID_HANDLE;
  695. auto vma = process->vm_manager.FindVMA(addr);
  696. if (vma == Kernel::g_current_process->vm_manager.vma_map.end())
  697. return Kernel::ERR_INVALID_ADDRESS;
  698. memory_info->base_address = vma->second.base;
  699. memory_info->permission = static_cast<u32>(vma->second.permissions);
  700. memory_info->size = vma->second.size;
  701. memory_info->state = static_cast<u32>(vma->second.meminfo_state);
  702. page_info->flags = 0;
  703. LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr);
  704. return RESULT_SUCCESS;
  705. }
  706. /// Query memory
  707. static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) {
  708. return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
  709. }
  710. /// Create an event
  711. static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) {
  712. using Kernel::Event;
  713. SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type));
  714. evt->name = Common::StringFromFormat("event-%08x", Core::CPU().GetReg(14));
  715. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt)));
  716. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
  717. *out_handle);
  718. return RESULT_SUCCESS;
  719. }
  720. /// Duplicates a kernel handle
  721. static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) {
  722. CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle));
  723. LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
  724. return RESULT_SUCCESS;
  725. }
  726. /// Signals an event
  727. static ResultCode SignalEvent(Kernel::Handle handle) {
  728. using Kernel::Event;
  729. LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
  730. SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle);
  731. if (evt == nullptr)
  732. return ERR_INVALID_HANDLE;
  733. evt->Signal();
  734. return RESULT_SUCCESS;
  735. }
  736. /// Clears an event
  737. static ResultCode ClearEvent(Kernel::Handle handle) {
  738. using Kernel::Event;
  739. LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
  740. SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle);
  741. if (evt == nullptr)
  742. return ERR_INVALID_HANDLE;
  743. evt->Clear();
  744. return RESULT_SUCCESS;
  745. }
  746. /// Creates a timer
  747. static ResultCode CreateTimer(Kernel::Handle* out_handle, u32 reset_type) {
  748. using Kernel::Timer;
  749. SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type));
  750. timer->name = Common::StringFromFormat("timer-%08x", Core::CPU().GetReg(14));
  751. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer)));
  752. LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
  753. *out_handle);
  754. return RESULT_SUCCESS;
  755. }
  756. /// Clears a timer
  757. static ResultCode ClearTimer(Kernel::Handle handle) {
  758. using Kernel::Timer;
  759. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  760. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  761. if (timer == nullptr)
  762. return ERR_INVALID_HANDLE;
  763. timer->Clear();
  764. return RESULT_SUCCESS;
  765. }
  766. /// Starts a timer
  767. static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) {
  768. using Kernel::Timer;
  769. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  770. if (initial < 0 || interval < 0) {
  771. return Kernel::ERR_OUT_OF_RANGE_KERNEL;
  772. }
  773. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  774. if (timer == nullptr)
  775. return ERR_INVALID_HANDLE;
  776. timer->Set(initial, interval);
  777. return RESULT_SUCCESS;
  778. }
  779. /// Cancels a timer
  780. static ResultCode CancelTimer(Kernel::Handle handle) {
  781. using Kernel::Timer;
  782. LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
  783. SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
  784. if (timer == nullptr)
  785. return ERR_INVALID_HANDLE;
  786. timer->Cancel();
  787. return RESULT_SUCCESS;
  788. }
  789. /// Sleep the current thread
  790. static void SleepThread(s64 nanoseconds) {
  791. LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
  792. // Don't attempt to yield execution if there are no available threads to run,
  793. // this way we avoid a useless reschedule to the idle thread.
  794. if (nanoseconds == 0 && !Kernel::HaveReadyThreads())
  795. return;
  796. // Sleep current thread and check for next thread to schedule
  797. Kernel::WaitCurrentThread_Sleep();
  798. // Create an event to wake the thread up after the specified nanosecond delay has passed
  799. Kernel::GetCurrentThread()->WakeAfterDelay(nanoseconds);
  800. Core::System::GetInstance().PrepareReschedule();
  801. }
  802. /// This returns the total CPU ticks elapsed since the CPU was powered-on
  803. static s64 GetSystemTick() {
  804. s64 result = CoreTiming::GetTicks();
  805. // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
  806. CoreTiming::AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
  807. return result;
  808. }
  809. /// Creates a memory block at the specified address with the specified permissions and size
  810. static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 size,
  811. u32 my_permission, u32 other_permission) {
  812. using Kernel::SharedMemory;
  813. if (size % Memory::PAGE_SIZE != 0)
  814. return Kernel::ERR_MISALIGNED_SIZE;
  815. SharedPtr<SharedMemory> shared_memory = nullptr;
  816. using Kernel::MemoryPermission;
  817. auto VerifyPermissions = [](MemoryPermission permission) {
  818. // SharedMemory blocks can not be created with Execute permissions
  819. switch (permission) {
  820. case MemoryPermission::None:
  821. case MemoryPermission::Read:
  822. case MemoryPermission::Write:
  823. case MemoryPermission::ReadWrite:
  824. case MemoryPermission::DontCare:
  825. return true;
  826. default:
  827. return false;
  828. }
  829. };
  830. if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
  831. !VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
  832. return Kernel::ERR_INVALID_COMBINATION;
  833. // TODO(Subv): Processes with memory type APPLICATION are not allowed
  834. // to create memory blocks with addr = 0, any attempts to do so
  835. // should return error 0xD92007EA.
  836. if ((addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) &&
  837. addr != 0) {
  838. return Kernel::ERR_INVALID_ADDRESS;
  839. }
  840. // When trying to create a memory block with address = 0,
  841. // if the process has the Shared Device Memory flag in the exheader,
  842. // then we have to allocate from the same region as the caller process instead of the BASE
  843. // region.
  844. Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
  845. if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
  846. region = Kernel::g_current_process->flags.memory_region;
  847. shared_memory = SharedMemory::Create(
  848. Kernel::g_current_process, size, static_cast<MemoryPermission>(my_permission),
  849. static_cast<MemoryPermission>(other_permission), addr, region);
  850. CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
  851. LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
  852. return RESULT_SUCCESS;
  853. }
  854. static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port,
  855. const char* name, u32 max_sessions) {
  856. // TODO(Subv): Implement named ports.
  857. ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
  858. using Kernel::ServerPort;
  859. using Kernel::ClientPort;
  860. auto ports = ServerPort::CreatePortPair(max_sessions);
  861. CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(
  862. std::move(std::get<SharedPtr<ClientPort>>(ports))));
  863. // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be
  864. // created.
  865. CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(
  866. std::move(std::get<SharedPtr<ServerPort>>(ports))));
  867. LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions);
  868. return RESULT_SUCCESS;
  869. }
  870. static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) {
  871. using Kernel::ClientPort;
  872. SharedPtr<ClientPort> client_port = Kernel::g_handle_table.Get<ClientPort>(client_port_handle);
  873. if (client_port == nullptr)
  874. return ERR_INVALID_HANDLE;
  875. CASCADE_RESULT(auto session, client_port->Connect());
  876. CASCADE_RESULT(*out_client_session, Kernel::g_handle_table.Create(std::move(session)));
  877. return RESULT_SUCCESS;
  878. }
  879. static ResultCode CreateSession(Handle* server_session, Handle* client_session) {
  880. auto sessions = Kernel::ServerSession::CreateSessionPair();
  881. auto& server = std::get<SharedPtr<Kernel::ServerSession>>(sessions);
  882. CASCADE_RESULT(*server_session, Kernel::g_handle_table.Create(std::move(server)));
  883. auto& client = std::get<SharedPtr<Kernel::ClientSession>>(sessions);
  884. CASCADE_RESULT(*client_session, Kernel::g_handle_table.Create(std::move(client)));
  885. LOG_TRACE(Kernel_SVC, "called");
  886. return RESULT_SUCCESS;
  887. }
  888. static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) {
  889. using Kernel::ServerPort;
  890. SharedPtr<ServerPort> server_port = Kernel::g_handle_table.Get<ServerPort>(server_port_handle);
  891. if (server_port == nullptr)
  892. return ERR_INVALID_HANDLE;
  893. CASCADE_RESULT(auto session, server_port->Accept());
  894. CASCADE_RESULT(*out_server_session, Kernel::g_handle_table.Create(std::move(session)));
  895. return RESULT_SUCCESS;
  896. }
  897. static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
  898. using Kernel::MemoryRegion;
  899. LOG_TRACE(Kernel_SVC, "called type=%u param=%d", type, param);
  900. switch ((SystemInfoType)type) {
  901. case SystemInfoType::REGION_MEMORY_USAGE:
  902. switch ((SystemInfoMemUsageRegion)param) {
  903. case SystemInfoMemUsageRegion::ALL:
  904. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used +
  905. Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used +
  906. Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
  907. break;
  908. case SystemInfoMemUsageRegion::APPLICATION:
  909. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used;
  910. break;
  911. case SystemInfoMemUsageRegion::SYSTEM:
  912. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used;
  913. break;
  914. case SystemInfoMemUsageRegion::BASE:
  915. *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
  916. break;
  917. default:
  918. LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param=%d", param);
  919. *out = 0;
  920. break;
  921. }
  922. break;
  923. case SystemInfoType::KERNEL_ALLOCATED_PAGES:
  924. LOG_ERROR(Kernel_SVC, "unimplemented GetSystemInfo type=2 param=%d", param);
  925. *out = 0;
  926. break;
  927. case SystemInfoType::KERNEL_SPAWNED_PIDS:
  928. *out = 5;
  929. break;
  930. default:
  931. LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=%u param=%d", type, param);
  932. *out = 0;
  933. break;
  934. }
  935. // This function never returns an error, even if invalid parameters were passed.
  936. return RESULT_SUCCESS;
  937. }
  938. static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 type) {
  939. LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
  940. using Kernel::Process;
  941. Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
  942. if (process == nullptr)
  943. return ERR_INVALID_HANDLE;
  944. switch (type) {
  945. case 0:
  946. case 2:
  947. // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
  948. // what's the difference between them.
  949. *out = process->heap_used + process->linear_heap_used + process->misc_memory_used;
  950. if (*out % Memory::PAGE_SIZE != 0) {
  951. LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
  952. return Kernel::ERR_MISALIGNED_SIZE;
  953. }
  954. break;
  955. case 1:
  956. case 3:
  957. case 4:
  958. case 5:
  959. case 6:
  960. case 7:
  961. case 8:
  962. // These are valid, but not implemented yet
  963. LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type);
  964. break;
  965. case 20:
  966. *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase();
  967. break;
  968. case 21:
  969. case 22:
  970. case 23:
  971. // These return a different error value than higher invalid values
  972. LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type);
  973. return Kernel::ERR_NOT_IMPLEMENTED;
  974. default:
  975. LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type);
  976. return Kernel::ERR_INVALID_ENUM_VALUE;
  977. }
  978. return RESULT_SUCCESS;
  979. }
  980. namespace {
  981. struct FunctionDef {
  982. using Func = void();
  983. u32 id;
  984. Func* func;
  985. const char* name;
  986. };
  987. } // namespace
  988. static const FunctionDef SVC_Table[] = {
  989. {0x00, nullptr, "Unknown"},
  990. {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
  991. {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
  992. {0x03, nullptr, "ExitProcess"},
  993. {0x04, nullptr, "GetProcessAffinityMask"},
  994. {0x05, nullptr, "SetProcessAffinityMask"},
  995. {0x06, nullptr, "GetProcessIdealProcessor"},
  996. {0x07, nullptr, "SetProcessIdealProcessor"},
  997. {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
  998. {0x09, ExitThread, "ExitThread"},
  999. {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
  1000. {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
  1001. {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
  1002. {0x0D, nullptr, "GetThreadAffinityMask"},
  1003. {0x0E, nullptr, "SetThreadAffinityMask"},
  1004. {0x0F, nullptr, "GetThreadIdealProcessor"},
  1005. {0x10, nullptr, "SetThreadIdealProcessor"},
  1006. {0x11, nullptr, "GetCurrentProcessorNumber"},
  1007. {0x12, nullptr, "Run"},
  1008. {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
  1009. {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
  1010. {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"},
  1011. {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"},
  1012. {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
  1013. {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
  1014. {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
  1015. {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"},
  1016. {0x1B, HLE::Wrap<SetTimer>, "SetTimer"},
  1017. {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"},
  1018. {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"},
  1019. {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"},
  1020. {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
  1021. {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"},
  1022. {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
  1023. {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
  1024. {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
  1025. {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
  1026. {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
  1027. {0x26, nullptr, "SignalAndWait"},
  1028. {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
  1029. {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
  1030. {0x29, nullptr, "GetHandleInfo"},
  1031. {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"},
  1032. {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"},
  1033. {0x2C, nullptr, "GetThreadInfo"},
  1034. {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
  1035. {0x2E, nullptr, "SendSyncRequest1"},
  1036. {0x2F, nullptr, "SendSyncRequest2"},
  1037. {0x30, nullptr, "SendSyncRequest3"},
  1038. {0x31, nullptr, "SendSyncRequest4"},
  1039. {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
  1040. {0x33, nullptr, "OpenProcess"},
  1041. {0x34, nullptr, "OpenThread"},
  1042. {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"},
  1043. {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"},
  1044. {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
  1045. {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
  1046. {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"},
  1047. {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
  1048. {0x3B, nullptr, "GetThreadContext"},
  1049. {0x3C, HLE::Wrap<Break>, "Break"},
  1050. {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
  1051. {0x3E, nullptr, "ControlPerformanceCounter"},
  1052. {0x3F, nullptr, "Unknown"},
  1053. {0x40, nullptr, "Unknown"},
  1054. {0x41, nullptr, "Unknown"},
  1055. {0x42, nullptr, "Unknown"},
  1056. {0x43, nullptr, "Unknown"},
  1057. {0x44, nullptr, "Unknown"},
  1058. {0x45, nullptr, "Unknown"},
  1059. {0x46, nullptr, "Unknown"},
  1060. {0x47, HLE::Wrap<CreatePort>, "CreatePort"},
  1061. {0x48, HLE::Wrap<CreateSessionToPort>, "CreateSessionToPort"},
  1062. {0x49, HLE::Wrap<CreateSession>, "CreateSession"},
  1063. {0x4A, HLE::Wrap<AcceptSession>, "AcceptSession"},
  1064. {0x4B, nullptr, "ReplyAndReceive1"},
  1065. {0x4C, nullptr, "ReplyAndReceive2"},
  1066. {0x4D, nullptr, "ReplyAndReceive3"},
  1067. {0x4E, nullptr, "ReplyAndReceive4"},
  1068. {0x4F, HLE::Wrap<ReplyAndReceive>, "ReplyAndReceive"},
  1069. {0x50, nullptr, "BindInterrupt"},
  1070. {0x51, nullptr, "UnbindInterrupt"},
  1071. {0x52, nullptr, "InvalidateProcessDataCache"},
  1072. {0x53, nullptr, "StoreProcessDataCache"},
  1073. {0x54, nullptr, "FlushProcessDataCache"},
  1074. {0x55, nullptr, "StartInterProcessDma"},
  1075. {0x56, nullptr, "StopDma"},
  1076. {0x57, nullptr, "GetDmaState"},
  1077. {0x58, nullptr, "RestartDma"},
  1078. {0x59, nullptr, "Unknown"},
  1079. {0x5A, nullptr, "Unknown"},
  1080. {0x5B, nullptr, "Unknown"},
  1081. {0x5C, nullptr, "Unknown"},
  1082. {0x5D, nullptr, "Unknown"},
  1083. {0x5E, nullptr, "Unknown"},
  1084. {0x5F, nullptr, "Unknown"},
  1085. {0x60, nullptr, "DebugActiveProcess"},
  1086. {0x61, nullptr, "BreakDebugProcess"},
  1087. {0x62, nullptr, "TerminateDebugProcess"},
  1088. {0x63, nullptr, "GetProcessDebugEvent"},
  1089. {0x64, nullptr, "ContinueDebugEvent"},
  1090. {0x65, nullptr, "GetProcessList"},
  1091. {0x66, nullptr, "GetThreadList"},
  1092. {0x67, nullptr, "GetDebugThreadContext"},
  1093. {0x68, nullptr, "SetDebugThreadContext"},
  1094. {0x69, nullptr, "QueryDebugProcessMemory"},
  1095. {0x6A, nullptr, "ReadProcessMemory"},
  1096. {0x6B, nullptr, "WriteProcessMemory"},
  1097. {0x6C, nullptr, "SetHardwareBreakPoint"},
  1098. {0x6D, nullptr, "GetDebugThreadParam"},
  1099. {0x6E, nullptr, "Unknown"},
  1100. {0x6F, nullptr, "Unknown"},
  1101. {0x70, nullptr, "ControlProcessMemory"},
  1102. {0x71, nullptr, "MapProcessMemory"},
  1103. {0x72, nullptr, "UnmapProcessMemory"},
  1104. {0x73, nullptr, "CreateCodeSet"},
  1105. {0x74, nullptr, "RandomStub"},
  1106. {0x75, nullptr, "CreateProcess"},
  1107. {0x76, nullptr, "TerminateProcess"},
  1108. {0x77, nullptr, "SetProcessResourceLimits"},
  1109. {0x78, nullptr, "CreateResourceLimit"},
  1110. {0x79, nullptr, "SetResourceLimitValues"},
  1111. {0x7A, nullptr, "AddCodeSegment"},
  1112. {0x7B, nullptr, "Backdoor"},
  1113. {0x7C, nullptr, "KernelSetState"},
  1114. {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"},
  1115. };
  1116. static const FunctionDef* GetSVCInfo(u32 func_num) {
  1117. if (func_num >= ARRAY_SIZE(SVC_Table)) {
  1118. LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
  1119. return nullptr;
  1120. }
  1121. return &SVC_Table[func_num];
  1122. }
  1123. MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
  1124. void CallSVC(u32 immediate) {
  1125. MICROPROFILE_SCOPE(Kernel_SVC);
  1126. // Lock the global kernel mutex when we enter the kernel HLE.
  1127. std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
  1128. const FunctionDef* info = GetSVCInfo(immediate);
  1129. if (info) {
  1130. if (info->func) {
  1131. info->func();
  1132. } else {
  1133. LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
  1134. }
  1135. }
  1136. }
  1137. } // namespace SVC