svc.cpp 42 KB

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