svc.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cinttypes>
  6. #include <iterator>
  7. #include <mutex>
  8. #include <vector>
  9. #include "common/alignment.h"
  10. #include "common/assert.h"
  11. #include "common/logging/log.h"
  12. #include "common/microprofile.h"
  13. #include "common/string_util.h"
  14. #include "core/arm/exclusive_monitor.h"
  15. #include "core/core.h"
  16. #include "core/core_cpu.h"
  17. #include "core/core_timing.h"
  18. #include "core/hle/kernel/address_arbiter.h"
  19. #include "core/hle/kernel/client_port.h"
  20. #include "core/hle/kernel/client_session.h"
  21. #include "core/hle/kernel/event.h"
  22. #include "core/hle/kernel/handle_table.h"
  23. #include "core/hle/kernel/kernel.h"
  24. #include "core/hle/kernel/mutex.h"
  25. #include "core/hle/kernel/process.h"
  26. #include "core/hle/kernel/resource_limit.h"
  27. #include "core/hle/kernel/scheduler.h"
  28. #include "core/hle/kernel/shared_memory.h"
  29. #include "core/hle/kernel/svc.h"
  30. #include "core/hle/kernel/svc_wrap.h"
  31. #include "core/hle/kernel/thread.h"
  32. #include "core/hle/lock.h"
  33. #include "core/hle/result.h"
  34. #include "core/hle/service/service.h"
  35. namespace Kernel {
  36. namespace {
  37. // Checks if address + size is greater than the given address
  38. // This can return false if the size causes an overflow of a 64-bit type
  39. // or if the given size is zero.
  40. constexpr bool IsValidAddressRange(VAddr address, u64 size) {
  41. return address + size > address;
  42. }
  43. // Checks if a given address range lies within a larger address range.
  44. constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin,
  45. VAddr address_range_end) {
  46. const VAddr end_address = address + size - 1;
  47. return address_range_begin <= address && end_address <= address_range_end - 1;
  48. }
  49. bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) {
  50. return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(),
  51. vm.GetAddressSpaceEndAddress());
  52. }
  53. bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
  54. return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(),
  55. vm.GetNewMapRegionEndAddress());
  56. }
  57. // Helper function that performs the common sanity checks for svcMapMemory
  58. // and svcUnmapMemory. This is doable, as both functions perform their sanitizing
  59. // in the same order.
  60. ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
  61. u64 size) {
  62. if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) {
  63. return ERR_INVALID_ADDRESS;
  64. }
  65. if (size == 0 || !Common::Is4KBAligned(size)) {
  66. return ERR_INVALID_SIZE;
  67. }
  68. if (!IsValidAddressRange(dst_addr, size)) {
  69. return ERR_INVALID_ADDRESS_STATE;
  70. }
  71. if (!IsValidAddressRange(src_addr, size)) {
  72. return ERR_INVALID_ADDRESS_STATE;
  73. }
  74. if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
  75. return ERR_INVALID_ADDRESS_STATE;
  76. }
  77. if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
  78. return ERR_INVALID_MEMORY_RANGE;
  79. }
  80. const VAddr dst_end_address = dst_addr + size;
  81. if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
  82. vm_manager.GetHeapRegionEndAddress() > dst_addr) {
  83. return ERR_INVALID_MEMORY_RANGE;
  84. }
  85. if (dst_end_address > vm_manager.GetMapRegionBaseAddress() &&
  86. vm_manager.GetMapRegionEndAddress() > dst_addr) {
  87. return ERR_INVALID_MEMORY_RANGE;
  88. }
  89. return RESULT_SUCCESS;
  90. }
  91. } // Anonymous namespace
  92. /// Set the process heap to a given Size. It can both extend and shrink the heap.
  93. static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
  94. LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
  95. // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB.
  96. if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) {
  97. return ERR_INVALID_SIZE;
  98. }
  99. auto& process = *Core::CurrentProcess();
  100. const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress();
  101. CASCADE_RESULT(*heap_addr,
  102. process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
  103. return RESULT_SUCCESS;
  104. }
  105. static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
  106. LOG_WARNING(Kernel_SVC,
  107. "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr,
  108. size, state0, state1);
  109. return RESULT_SUCCESS;
  110. }
  111. /// Maps a memory range into a different range.
  112. static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  113. LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
  114. src_addr, size);
  115. auto* const current_process = Core::CurrentProcess();
  116. const auto& vm_manager = current_process->VMManager();
  117. const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
  118. if (result != RESULT_SUCCESS) {
  119. return result;
  120. }
  121. return current_process->MirrorMemory(dst_addr, src_addr, size);
  122. }
  123. /// Unmaps a region that was previously mapped with svcMapMemory
  124. static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  125. LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
  126. src_addr, size);
  127. auto* const current_process = Core::CurrentProcess();
  128. const auto& vm_manager = current_process->VMManager();
  129. const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
  130. if (result != RESULT_SUCCESS) {
  131. return result;
  132. }
  133. return current_process->UnmapMemory(dst_addr, src_addr, size);
  134. }
  135. /// Connect to an OS service given the port name, returns the handle to the port to out
  136. static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
  137. if (!Memory::IsValidVirtualAddress(port_name_address)) {
  138. return ERR_NOT_FOUND;
  139. }
  140. static constexpr std::size_t PortNameMaxLength = 11;
  141. // Read 1 char beyond the max allowed port name to detect names that are too long.
  142. std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
  143. if (port_name.size() > PortNameMaxLength) {
  144. return ERR_PORT_NAME_TOO_LONG;
  145. }
  146. LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
  147. auto& kernel = Core::System::GetInstance().Kernel();
  148. auto it = kernel.FindNamedPort(port_name);
  149. if (!kernel.IsValidNamedPort(it)) {
  150. LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
  151. return ERR_NOT_FOUND;
  152. }
  153. auto client_port = it->second;
  154. SharedPtr<ClientSession> client_session;
  155. CASCADE_RESULT(client_session, client_port->Connect());
  156. // Return the client session
  157. auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  158. CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
  159. return RESULT_SUCCESS;
  160. }
  161. /// Makes a blocking IPC call to an OS service.
  162. static ResultCode SendSyncRequest(Handle handle) {
  163. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  164. SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle);
  165. if (!session) {
  166. LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
  167. return ERR_INVALID_HANDLE;
  168. }
  169. LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
  170. Core::System::GetInstance().PrepareReschedule();
  171. // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
  172. // responds and cause a reschedule.
  173. return session->SendSyncRequest(GetCurrentThread());
  174. }
  175. /// Get the ID for the specified thread.
  176. static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
  177. LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
  178. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  179. const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  180. if (!thread) {
  181. return ERR_INVALID_HANDLE;
  182. }
  183. *thread_id = thread->GetThreadID();
  184. return RESULT_SUCCESS;
  185. }
  186. /// Get the ID of the specified process
  187. static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
  188. LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
  189. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  190. const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
  191. if (!process) {
  192. return ERR_INVALID_HANDLE;
  193. }
  194. *process_id = process->GetProcessID();
  195. return RESULT_SUCCESS;
  196. }
  197. /// Default thread wakeup callback for WaitSynchronization
  198. static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
  199. SharedPtr<WaitObject> object, std::size_t index) {
  200. ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
  201. if (reason == ThreadWakeupReason::Timeout) {
  202. thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
  203. return true;
  204. }
  205. ASSERT(reason == ThreadWakeupReason::Signal);
  206. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  207. thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
  208. return true;
  209. };
  210. /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
  211. static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
  212. s64 nano_seconds) {
  213. LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
  214. handles_address, handle_count, nano_seconds);
  215. if (!Memory::IsValidVirtualAddress(handles_address))
  216. return ERR_INVALID_POINTER;
  217. static constexpr u64 MaxHandles = 0x40;
  218. if (handle_count > MaxHandles)
  219. return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge);
  220. auto* const thread = GetCurrentThread();
  221. using ObjectPtr = Thread::ThreadWaitObjects::value_type;
  222. Thread::ThreadWaitObjects objects(handle_count);
  223. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  224. for (u64 i = 0; i < handle_count; ++i) {
  225. const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
  226. const auto object = handle_table.Get<WaitObject>(handle);
  227. if (object == nullptr) {
  228. return ERR_INVALID_HANDLE;
  229. }
  230. objects[i] = object;
  231. }
  232. // Find the first object that is acquirable in the provided list of objects
  233. auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
  234. return !object->ShouldWait(thread);
  235. });
  236. if (itr != objects.end()) {
  237. // We found a ready object, acquire it and set the result value
  238. WaitObject* object = itr->get();
  239. object->Acquire(thread);
  240. *index = static_cast<s32>(std::distance(objects.begin(), itr));
  241. return RESULT_SUCCESS;
  242. }
  243. // No objects were ready to be acquired, prepare to suspend the thread.
  244. // If a timeout value of 0 was provided, just return the Timeout error code instead of
  245. // suspending the thread.
  246. if (nano_seconds == 0)
  247. return RESULT_TIMEOUT;
  248. for (auto& object : objects)
  249. object->AddWaitingThread(thread);
  250. thread->SetWaitObjects(std::move(objects));
  251. thread->SetStatus(ThreadStatus::WaitSynchAny);
  252. // Create an event to wake the thread up after the specified nanosecond delay has passed
  253. thread->WakeAfterDelay(nano_seconds);
  254. thread->SetWakeupCallback(DefaultThreadWakeupCallback);
  255. Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
  256. return RESULT_TIMEOUT;
  257. }
  258. /// Resumes a thread waiting on WaitSynchronization
  259. static ResultCode CancelSynchronization(Handle thread_handle) {
  260. LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
  261. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  262. const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  263. if (!thread) {
  264. return ERR_INVALID_HANDLE;
  265. }
  266. ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
  267. thread->SetWaitSynchronizationResult(
  268. ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
  269. thread->ResumeFromWait();
  270. return RESULT_SUCCESS;
  271. }
  272. /// Attempts to locks a mutex, creating it if it does not already exist
  273. static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
  274. Handle requesting_thread_handle) {
  275. LOG_TRACE(Kernel_SVC,
  276. "called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, "
  277. "requesting_current_thread_handle=0x{:08X}",
  278. holding_thread_handle, mutex_addr, requesting_thread_handle);
  279. if (Memory::IsKernelVirtualAddress(mutex_addr)) {
  280. return ERR_INVALID_ADDRESS_STATE;
  281. }
  282. if (!Common::IsWordAligned(mutex_addr)) {
  283. return ERR_INVALID_ADDRESS;
  284. }
  285. auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  286. return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
  287. requesting_thread_handle);
  288. }
  289. /// Unlock a mutex
  290. static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
  291. LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
  292. if (Memory::IsKernelVirtualAddress(mutex_addr)) {
  293. return ERR_INVALID_ADDRESS_STATE;
  294. }
  295. if (!Common::IsWordAligned(mutex_addr)) {
  296. return ERR_INVALID_ADDRESS;
  297. }
  298. return Mutex::Release(mutex_addr);
  299. }
  300. enum class BreakType : u32 {
  301. Panic = 0,
  302. AssertionFailed = 1,
  303. PreNROLoad = 3,
  304. PostNROLoad = 4,
  305. PreNROUnload = 5,
  306. PostNROUnload = 6,
  307. };
  308. struct BreakReason {
  309. union {
  310. u32 raw;
  311. BitField<0, 30, BreakType> break_type;
  312. BitField<31, 1, u32> signal_debugger;
  313. };
  314. };
  315. /// Break program execution
  316. static void Break(u32 reason, u64 info1, u64 info2) {
  317. BreakReason break_reason{reason};
  318. switch (break_reason.break_type) {
  319. case BreakType::Panic:
  320. LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}",
  321. info1, info2);
  322. break;
  323. case BreakType::AssertionFailed:
  324. LOG_CRITICAL(Debug_Emulated,
  325. "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
  326. info1, info2);
  327. break;
  328. case BreakType::PreNROLoad:
  329. LOG_WARNING(
  330. Debug_Emulated,
  331. "Signalling debugger, Attempting to load an NRO at 0x{:016X} with size 0x{:016X}",
  332. info1, info2);
  333. break;
  334. case BreakType::PostNROLoad:
  335. LOG_WARNING(Debug_Emulated,
  336. "Signalling debugger, Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
  337. info2);
  338. break;
  339. case BreakType::PreNROUnload:
  340. LOG_WARNING(
  341. Debug_Emulated,
  342. "Signalling debugger, Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}",
  343. info1, info2);
  344. break;
  345. case BreakType::PostNROUnload:
  346. LOG_WARNING(Debug_Emulated,
  347. "Signalling debugger, Unloaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
  348. info2);
  349. break;
  350. default:
  351. LOG_WARNING(
  352. Debug_Emulated,
  353. "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}",
  354. static_cast<u32>(break_reason.break_type.Value()), info1, info2);
  355. break;
  356. }
  357. if (!break_reason.signal_debugger) {
  358. LOG_CRITICAL(
  359. Debug_Emulated,
  360. "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
  361. reason, info1, info2);
  362. ASSERT(false);
  363. Core::CurrentProcess()->PrepareForTermination();
  364. // Kill the current thread
  365. GetCurrentThread()->Stop();
  366. Core::System::GetInstance().PrepareReschedule();
  367. }
  368. }
  369. /// Used to output a message on a debug hardware unit - does nothing on a retail unit
  370. static void OutputDebugString(VAddr address, u64 len) {
  371. if (len == 0) {
  372. return;
  373. }
  374. std::string str(len, '\0');
  375. Memory::ReadBlock(address, str.data(), str.size());
  376. LOG_DEBUG(Debug_Emulated, "{}", str);
  377. }
  378. /// Gets system/memory information for the current process
  379. static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
  380. LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
  381. info_sub_id, handle);
  382. enum class GetInfoType : u64 {
  383. // 1.0.0+
  384. AllowedCpuIdBitmask = 0,
  385. AllowedThreadPrioBitmask = 1,
  386. MapRegionBaseAddr = 2,
  387. MapRegionSize = 3,
  388. HeapRegionBaseAddr = 4,
  389. HeapRegionSize = 5,
  390. TotalMemoryUsage = 6,
  391. TotalHeapUsage = 7,
  392. IsCurrentProcessBeingDebugged = 8,
  393. ResourceHandleLimit = 9,
  394. IdleTickCount = 10,
  395. RandomEntropy = 11,
  396. PerformanceCounter = 0xF0000002,
  397. // 2.0.0+
  398. ASLRRegionBaseAddr = 12,
  399. ASLRRegionSize = 13,
  400. NewMapRegionBaseAddr = 14,
  401. NewMapRegionSize = 15,
  402. // 3.0.0+
  403. IsVirtualAddressMemoryEnabled = 16,
  404. PersonalMmHeapUsage = 17,
  405. TitleId = 18,
  406. // 4.0.0+
  407. PrivilegedProcessId = 19,
  408. // 5.0.0+
  409. UserExceptionContextAddr = 20,
  410. ThreadTickCount = 0xF0000002,
  411. };
  412. const auto* current_process = Core::CurrentProcess();
  413. const auto& vm_manager = current_process->VMManager();
  414. switch (static_cast<GetInfoType>(info_id)) {
  415. case GetInfoType::AllowedCpuIdBitmask:
  416. *result = current_process->GetAllowedProcessorMask();
  417. break;
  418. case GetInfoType::AllowedThreadPrioBitmask:
  419. *result = current_process->GetAllowedThreadPriorityMask();
  420. break;
  421. case GetInfoType::MapRegionBaseAddr:
  422. *result = vm_manager.GetMapRegionBaseAddress();
  423. break;
  424. case GetInfoType::MapRegionSize:
  425. *result = vm_manager.GetMapRegionSize();
  426. break;
  427. case GetInfoType::HeapRegionBaseAddr:
  428. *result = vm_manager.GetHeapRegionBaseAddress();
  429. break;
  430. case GetInfoType::HeapRegionSize:
  431. *result = vm_manager.GetHeapRegionSize();
  432. break;
  433. case GetInfoType::TotalMemoryUsage:
  434. *result = vm_manager.GetTotalMemoryUsage();
  435. break;
  436. case GetInfoType::TotalHeapUsage:
  437. *result = vm_manager.GetTotalHeapUsage();
  438. break;
  439. case GetInfoType::IsCurrentProcessBeingDebugged:
  440. *result = 0;
  441. break;
  442. case GetInfoType::RandomEntropy:
  443. *result = 0;
  444. break;
  445. case GetInfoType::ASLRRegionBaseAddr:
  446. *result = vm_manager.GetASLRRegionBaseAddress();
  447. break;
  448. case GetInfoType::ASLRRegionSize:
  449. *result = vm_manager.GetASLRRegionSize();
  450. break;
  451. case GetInfoType::NewMapRegionBaseAddr:
  452. *result = vm_manager.GetNewMapRegionBaseAddress();
  453. break;
  454. case GetInfoType::NewMapRegionSize:
  455. *result = vm_manager.GetNewMapRegionSize();
  456. break;
  457. case GetInfoType::IsVirtualAddressMemoryEnabled:
  458. *result = current_process->IsVirtualMemoryEnabled();
  459. break;
  460. case GetInfoType::TitleId:
  461. *result = current_process->GetTitleID();
  462. break;
  463. case GetInfoType::PrivilegedProcessId:
  464. LOG_WARNING(Kernel_SVC,
  465. "(STUBBED) Attempted to query privileged process id bounds, returned 0");
  466. *result = 0;
  467. break;
  468. case GetInfoType::UserExceptionContextAddr:
  469. LOG_WARNING(Kernel_SVC,
  470. "(STUBBED) Attempted to query user exception context address, returned 0");
  471. *result = 0;
  472. break;
  473. case GetInfoType::ThreadTickCount: {
  474. constexpr u64 num_cpus = 4;
  475. if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
  476. return ERR_INVALID_COMBINATION_KERNEL;
  477. }
  478. const auto thread =
  479. current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
  480. if (!thread) {
  481. return ERR_INVALID_HANDLE;
  482. }
  483. const auto& system = Core::System::GetInstance();
  484. const auto& scheduler = system.CurrentScheduler();
  485. const auto* const current_thread = scheduler.GetCurrentThread();
  486. const bool same_thread = current_thread == thread;
  487. const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
  488. u64 out_ticks = 0;
  489. if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
  490. const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
  491. out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks);
  492. } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
  493. out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks;
  494. }
  495. *result = out_ticks;
  496. break;
  497. }
  498. default:
  499. UNIMPLEMENTED();
  500. }
  501. return RESULT_SUCCESS;
  502. }
  503. /// Sets the thread activity
  504. static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
  505. LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, unknown);
  506. return RESULT_SUCCESS;
  507. }
  508. /// Gets the thread context
  509. static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
  510. LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
  511. const auto* current_process = Core::CurrentProcess();
  512. const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
  513. if (!thread) {
  514. return ERR_INVALID_HANDLE;
  515. }
  516. if (thread->GetOwnerProcess() != current_process) {
  517. return ERR_INVALID_HANDLE;
  518. }
  519. if (thread == GetCurrentThread()) {
  520. return ERR_ALREADY_REGISTERED;
  521. }
  522. Core::ARM_Interface::ThreadContext ctx = thread->GetContext();
  523. // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
  524. ctx.pstate &= 0xFF0FFE20;
  525. // If 64-bit, we can just write the context registers directly and we're good.
  526. // However, if 32-bit, we have to ensure some registers are zeroed out.
  527. if (!current_process->Is64BitProcess()) {
  528. std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
  529. std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
  530. }
  531. Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
  532. return RESULT_SUCCESS;
  533. }
  534. /// Gets the priority for the specified thread
  535. static ResultCode GetThreadPriority(u32* priority, Handle handle) {
  536. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  537. const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
  538. if (!thread) {
  539. return ERR_INVALID_HANDLE;
  540. }
  541. *priority = thread->GetPriority();
  542. return RESULT_SUCCESS;
  543. }
  544. /// Sets the priority for the specified thread
  545. static ResultCode SetThreadPriority(Handle handle, u32 priority) {
  546. if (priority > THREADPRIO_LOWEST) {
  547. return ERR_INVALID_THREAD_PRIORITY;
  548. }
  549. const auto* const current_process = Core::CurrentProcess();
  550. // Note: The kernel uses the current process's resource limit instead of
  551. // the one from the thread owner's resource limit.
  552. const ResourceLimit& resource_limit = current_process->GetResourceLimit();
  553. if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
  554. return ERR_INVALID_THREAD_PRIORITY;
  555. }
  556. SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
  557. if (!thread) {
  558. return ERR_INVALID_HANDLE;
  559. }
  560. thread->SetPriority(priority);
  561. Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
  562. return RESULT_SUCCESS;
  563. }
  564. /// Get which CPU core is executing the current thread
  565. static u32 GetCurrentProcessorNumber() {
  566. LOG_TRACE(Kernel_SVC, "called");
  567. return GetCurrentThread()->GetProcessorID();
  568. }
  569. static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
  570. u32 permissions) {
  571. LOG_TRACE(Kernel_SVC,
  572. "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
  573. shared_memory_handle, addr, size, permissions);
  574. if (!Common::Is4KBAligned(addr)) {
  575. return ERR_INVALID_ADDRESS;
  576. }
  577. if (size == 0 || !Common::Is4KBAligned(size)) {
  578. return ERR_INVALID_SIZE;
  579. }
  580. if (!IsValidAddressRange(addr, size)) {
  581. return ERR_INVALID_ADDRESS_STATE;
  582. }
  583. const auto permissions_type = static_cast<MemoryPermission>(permissions);
  584. if (permissions_type != MemoryPermission::Read &&
  585. permissions_type != MemoryPermission::ReadWrite) {
  586. LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions);
  587. return ERR_INVALID_MEMORY_PERMISSIONS;
  588. }
  589. auto* const current_process = Core::CurrentProcess();
  590. auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
  591. if (!shared_memory) {
  592. return ERR_INVALID_HANDLE;
  593. }
  594. const auto& vm_manager = current_process->VMManager();
  595. if (!vm_manager.IsWithinASLRRegion(addr, size)) {
  596. return ERR_INVALID_MEMORY_RANGE;
  597. }
  598. return shared_memory->Map(current_process, addr, permissions_type, MemoryPermission::DontCare);
  599. }
  600. static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
  601. LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
  602. shared_memory_handle, addr, size);
  603. if (!Common::Is4KBAligned(addr)) {
  604. return ERR_INVALID_ADDRESS;
  605. }
  606. if (size == 0 || !Common::Is4KBAligned(size)) {
  607. return ERR_INVALID_SIZE;
  608. }
  609. if (!IsValidAddressRange(addr, size)) {
  610. return ERR_INVALID_ADDRESS_STATE;
  611. }
  612. auto* const current_process = Core::CurrentProcess();
  613. auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
  614. if (!shared_memory) {
  615. return ERR_INVALID_HANDLE;
  616. }
  617. const auto& vm_manager = current_process->VMManager();
  618. if (!vm_manager.IsWithinASLRRegion(addr, size)) {
  619. return ERR_INVALID_MEMORY_RANGE;
  620. }
  621. return shared_memory->Unmap(current_process, addr);
  622. }
  623. /// Query process memory
  624. static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
  625. Handle process_handle, u64 addr) {
  626. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  627. SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
  628. if (!process) {
  629. return ERR_INVALID_HANDLE;
  630. }
  631. auto vma = process->VMManager().FindVMA(addr);
  632. memory_info->attributes = 0;
  633. if (vma == process->VMManager().vma_map.end()) {
  634. memory_info->base_address = 0;
  635. memory_info->permission = static_cast<u32>(VMAPermission::None);
  636. memory_info->size = 0;
  637. memory_info->type = static_cast<u32>(MemoryState::Unmapped);
  638. } else {
  639. memory_info->base_address = vma->second.base;
  640. memory_info->permission = static_cast<u32>(vma->second.permissions);
  641. memory_info->size = vma->second.size;
  642. memory_info->type = static_cast<u32>(vma->second.meminfo_state);
  643. }
  644. LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
  645. return RESULT_SUCCESS;
  646. }
  647. /// Query memory
  648. static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) {
  649. LOG_TRACE(Kernel_SVC, "called, addr={:X}", addr);
  650. return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr);
  651. }
  652. /// Exits the current process
  653. static void ExitProcess() {
  654. auto* current_process = Core::CurrentProcess();
  655. LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
  656. ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
  657. "Process has already exited");
  658. current_process->PrepareForTermination();
  659. // Kill the current thread
  660. GetCurrentThread()->Stop();
  661. Core::System::GetInstance().PrepareReschedule();
  662. }
  663. /// Creates a new thread
  664. static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
  665. u32 priority, s32 processor_id) {
  666. if (priority > THREADPRIO_LOWEST) {
  667. return ERR_INVALID_THREAD_PRIORITY;
  668. }
  669. auto* const current_process = Core::CurrentProcess();
  670. const ResourceLimit& resource_limit = current_process->GetResourceLimit();
  671. if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
  672. return ERR_INVALID_THREAD_PRIORITY;
  673. }
  674. if (processor_id == THREADPROCESSORID_DEFAULT) {
  675. // Set the target CPU to the one specified in the process' exheader.
  676. processor_id = current_process->GetDefaultProcessorID();
  677. ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
  678. }
  679. switch (processor_id) {
  680. case THREADPROCESSORID_0:
  681. case THREADPROCESSORID_1:
  682. case THREADPROCESSORID_2:
  683. case THREADPROCESSORID_3:
  684. break;
  685. default:
  686. LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
  687. return ERR_INVALID_PROCESSOR_ID;
  688. }
  689. const std::string name = fmt::format("thread-{:X}", entry_point);
  690. auto& kernel = Core::System::GetInstance().Kernel();
  691. CASCADE_RESULT(SharedPtr<Thread> thread,
  692. Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
  693. *current_process));
  694. const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
  695. if (new_guest_handle.Failed()) {
  696. return new_guest_handle.Code();
  697. }
  698. thread->SetGuestHandle(*new_guest_handle);
  699. *out_handle = *new_guest_handle;
  700. Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
  701. LOG_TRACE(Kernel_SVC,
  702. "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
  703. "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
  704. entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
  705. return RESULT_SUCCESS;
  706. }
  707. /// Starts the thread for the provided handle
  708. static ResultCode StartThread(Handle thread_handle) {
  709. LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
  710. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  711. const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  712. if (!thread) {
  713. return ERR_INVALID_HANDLE;
  714. }
  715. ASSERT(thread->GetStatus() == ThreadStatus::Dormant);
  716. thread->ResumeFromWait();
  717. Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
  718. return RESULT_SUCCESS;
  719. }
  720. /// Called when a thread exits
  721. static void ExitThread() {
  722. LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC());
  723. ExitCurrentThread();
  724. Core::System::GetInstance().PrepareReschedule();
  725. }
  726. /// Sleep the current thread
  727. static void SleepThread(s64 nanoseconds) {
  728. LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
  729. // Don't attempt to yield execution if there are no available threads to run,
  730. // this way we avoid a useless reschedule to the idle thread.
  731. if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
  732. return;
  733. // Sleep current thread and check for next thread to schedule
  734. WaitCurrentThread_Sleep();
  735. // Create an event to wake the thread up after the specified nanosecond delay has passed
  736. GetCurrentThread()->WakeAfterDelay(nanoseconds);
  737. Core::System::GetInstance().PrepareReschedule();
  738. }
  739. /// Wait process wide key atomic
  740. static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
  741. Handle thread_handle, s64 nano_seconds) {
  742. LOG_TRACE(
  743. Kernel_SVC,
  744. "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
  745. mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
  746. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  747. SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  748. ASSERT(thread);
  749. CASCADE_CODE(Mutex::Release(mutex_addr));
  750. SharedPtr<Thread> current_thread = GetCurrentThread();
  751. current_thread->SetCondVarWaitAddress(condition_variable_addr);
  752. current_thread->SetMutexWaitAddress(mutex_addr);
  753. current_thread->SetWaitHandle(thread_handle);
  754. current_thread->SetStatus(ThreadStatus::WaitMutex);
  755. current_thread->InvalidateWakeupCallback();
  756. current_thread->WakeAfterDelay(nano_seconds);
  757. // Note: Deliberately don't attempt to inherit the lock owner's priority.
  758. Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
  759. return RESULT_SUCCESS;
  760. }
  761. /// Signal process wide key
  762. static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
  763. LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
  764. condition_variable_addr, target);
  765. const auto RetrieveWaitingThreads = [](std::size_t core_index,
  766. std::vector<SharedPtr<Thread>>& waiting_threads,
  767. VAddr condvar_addr) {
  768. const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
  769. const auto& thread_list = scheduler.GetThreadList();
  770. for (const auto& thread : thread_list) {
  771. if (thread->GetCondVarWaitAddress() == condvar_addr)
  772. waiting_threads.push_back(thread);
  773. }
  774. };
  775. // Retrieve a list of all threads that are waiting for this condition variable.
  776. std::vector<SharedPtr<Thread>> waiting_threads;
  777. RetrieveWaitingThreads(0, waiting_threads, condition_variable_addr);
  778. RetrieveWaitingThreads(1, waiting_threads, condition_variable_addr);
  779. RetrieveWaitingThreads(2, waiting_threads, condition_variable_addr);
  780. RetrieveWaitingThreads(3, waiting_threads, condition_variable_addr);
  781. // Sort them by priority, such that the highest priority ones come first.
  782. std::sort(waiting_threads.begin(), waiting_threads.end(),
  783. [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
  784. return lhs->GetPriority() < rhs->GetPriority();
  785. });
  786. // Only process up to 'target' threads, unless 'target' is -1, in which case process
  787. // them all.
  788. std::size_t last = waiting_threads.size();
  789. if (target != -1)
  790. last = target;
  791. // If there are no threads waiting on this condition variable, just exit
  792. if (last > waiting_threads.size())
  793. return RESULT_SUCCESS;
  794. for (std::size_t index = 0; index < last; ++index) {
  795. auto& thread = waiting_threads[index];
  796. ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
  797. std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
  798. auto& monitor = Core::System::GetInstance().Monitor();
  799. // Atomically read the value of the mutex.
  800. u32 mutex_val = 0;
  801. do {
  802. monitor.SetExclusive(current_core, thread->GetMutexWaitAddress());
  803. // If the mutex is not yet acquired, acquire it.
  804. mutex_val = Memory::Read32(thread->GetMutexWaitAddress());
  805. if (mutex_val != 0) {
  806. monitor.ClearExclusive();
  807. break;
  808. }
  809. } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
  810. thread->GetWaitHandle()));
  811. if (mutex_val == 0) {
  812. // We were able to acquire the mutex, resume this thread.
  813. ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
  814. thread->ResumeFromWait();
  815. auto* const lock_owner = thread->GetLockOwner();
  816. if (lock_owner != nullptr) {
  817. lock_owner->RemoveMutexWaiter(thread);
  818. }
  819. thread->SetLockOwner(nullptr);
  820. thread->SetMutexWaitAddress(0);
  821. thread->SetCondVarWaitAddress(0);
  822. thread->SetWaitHandle(0);
  823. } else {
  824. // Atomically signal that the mutex now has a waiting thread.
  825. do {
  826. monitor.SetExclusive(current_core, thread->GetMutexWaitAddress());
  827. // Ensure that the mutex value is still what we expect.
  828. u32 value = Memory::Read32(thread->GetMutexWaitAddress());
  829. // TODO(Subv): When this happens, the kernel just clears the exclusive state and
  830. // retries the initial read for this thread.
  831. ASSERT_MSG(mutex_val == value, "Unhandled synchronization primitive case");
  832. } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
  833. mutex_val | Mutex::MutexHasWaitersFlag));
  834. // The mutex is already owned by some other thread, make this thread wait on it.
  835. const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
  836. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  837. auto owner = handle_table.Get<Thread>(owner_handle);
  838. ASSERT(owner);
  839. ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
  840. thread->InvalidateWakeupCallback();
  841. owner->AddMutexWaiter(thread);
  842. Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
  843. }
  844. }
  845. return RESULT_SUCCESS;
  846. }
  847. // Wait for an address (via Address Arbiter)
  848. static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) {
  849. LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}",
  850. address, type, value, timeout);
  851. // If the passed address is a kernel virtual address, return invalid memory state.
  852. if (Memory::IsKernelVirtualAddress(address)) {
  853. return ERR_INVALID_ADDRESS_STATE;
  854. }
  855. // If the address is not properly aligned to 4 bytes, return invalid address.
  856. if (address % sizeof(u32) != 0) {
  857. return ERR_INVALID_ADDRESS;
  858. }
  859. switch (static_cast<AddressArbiter::ArbitrationType>(type)) {
  860. case AddressArbiter::ArbitrationType::WaitIfLessThan:
  861. return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false);
  862. case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
  863. return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true);
  864. case AddressArbiter::ArbitrationType::WaitIfEqual:
  865. return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
  866. default:
  867. return ERR_INVALID_ENUM_VALUE;
  868. }
  869. }
  870. // Signals to an address (via Address Arbiter)
  871. static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) {
  872. LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}",
  873. address, type, value, num_to_wake);
  874. // If the passed address is a kernel virtual address, return invalid memory state.
  875. if (Memory::IsKernelVirtualAddress(address)) {
  876. return ERR_INVALID_ADDRESS_STATE;
  877. }
  878. // If the address is not properly aligned to 4 bytes, return invalid address.
  879. if (address % sizeof(u32) != 0) {
  880. return ERR_INVALID_ADDRESS;
  881. }
  882. switch (static_cast<AddressArbiter::SignalType>(type)) {
  883. case AddressArbiter::SignalType::Signal:
  884. return AddressArbiter::SignalToAddress(address, num_to_wake);
  885. case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
  886. return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
  887. case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
  888. return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
  889. num_to_wake);
  890. default:
  891. return ERR_INVALID_ENUM_VALUE;
  892. }
  893. }
  894. /// This returns the total CPU ticks elapsed since the CPU was powered-on
  895. static u64 GetSystemTick() {
  896. const u64 result{CoreTiming::GetTicks()};
  897. // Advance time to defeat dumb games that busy-wait for the frame to end.
  898. CoreTiming::AddTicks(400);
  899. return result;
  900. }
  901. /// Close a handle
  902. static ResultCode CloseHandle(Handle handle) {
  903. LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
  904. auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  905. return handle_table.Close(handle);
  906. }
  907. /// Reset an event
  908. static ResultCode ResetSignal(Handle handle) {
  909. LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
  910. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  911. auto event = handle_table.Get<Event>(handle);
  912. ASSERT(event != nullptr);
  913. event->Clear();
  914. return RESULT_SUCCESS;
  915. }
  916. /// Creates a TransferMemory object
  917. static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
  918. LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
  919. permissions);
  920. *handle = 0;
  921. return RESULT_SUCCESS;
  922. }
  923. static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
  924. LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
  925. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  926. const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  927. if (!thread) {
  928. return ERR_INVALID_HANDLE;
  929. }
  930. *core = thread->GetIdealCore();
  931. *mask = thread->GetAffinityMask();
  932. return RESULT_SUCCESS;
  933. }
  934. static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
  935. LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
  936. mask, core);
  937. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  938. const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
  939. if (!thread) {
  940. return ERR_INVALID_HANDLE;
  941. }
  942. if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
  943. const u8 default_processor_id = thread->GetOwnerProcess()->GetDefaultProcessorID();
  944. ASSERT(default_processor_id != static_cast<u8>(THREADPROCESSORID_DEFAULT));
  945. // Set the target CPU to the one specified in the process' exheader.
  946. core = default_processor_id;
  947. mask = 1ULL << core;
  948. }
  949. if (mask == 0) {
  950. return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
  951. }
  952. /// This value is used to only change the affinity mask without changing the current ideal core.
  953. static constexpr u32 OnlyChangeMask = static_cast<u32>(-3);
  954. if (core == OnlyChangeMask) {
  955. core = thread->GetIdealCore();
  956. } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
  957. return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
  958. }
  959. // Error out if the input core isn't enabled in the input mask.
  960. if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
  961. return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
  962. }
  963. thread->ChangeCore(core, mask);
  964. return RESULT_SUCCESS;
  965. }
  966. static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
  967. u32 remote_permissions) {
  968. LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
  969. local_permissions, remote_permissions);
  970. // Size must be a multiple of 4KB and be less than or equal to
  971. // approx. 8 GB (actually (1GB - 512B) * 8)
  972. if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
  973. return ERR_INVALID_SIZE;
  974. }
  975. const auto local_perms = static_cast<MemoryPermission>(local_permissions);
  976. if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
  977. return ERR_INVALID_MEMORY_PERMISSIONS;
  978. }
  979. const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
  980. if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
  981. remote_perms != MemoryPermission::DontCare) {
  982. return ERR_INVALID_MEMORY_PERMISSIONS;
  983. }
  984. auto& kernel = Core::System::GetInstance().Kernel();
  985. auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  986. auto shared_mem_handle =
  987. SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
  988. local_perms, remote_perms);
  989. CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
  990. return RESULT_SUCCESS;
  991. }
  992. static ResultCode ClearEvent(Handle handle) {
  993. LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
  994. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  995. SharedPtr<Event> evt = handle_table.Get<Event>(handle);
  996. if (evt == nullptr) {
  997. return ERR_INVALID_HANDLE;
  998. }
  999. evt->Clear();
  1000. return RESULT_SUCCESS;
  1001. }
  1002. static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
  1003. LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
  1004. // This function currently only allows retrieving a process' status.
  1005. enum class InfoType {
  1006. Status,
  1007. };
  1008. const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
  1009. const auto process = handle_table.Get<Process>(process_handle);
  1010. if (!process) {
  1011. return ERR_INVALID_HANDLE;
  1012. }
  1013. const auto info_type = static_cast<InfoType>(type);
  1014. if (info_type != InfoType::Status) {
  1015. return ERR_INVALID_ENUM_VALUE;
  1016. }
  1017. *out = static_cast<u64>(process->GetStatus());
  1018. return RESULT_SUCCESS;
  1019. }
  1020. namespace {
  1021. struct FunctionDef {
  1022. using Func = void();
  1023. u32 id;
  1024. Func* func;
  1025. const char* name;
  1026. };
  1027. } // namespace
  1028. static const FunctionDef SVC_Table[] = {
  1029. {0x00, nullptr, "Unknown"},
  1030. {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"},
  1031. {0x02, nullptr, "SetMemoryPermission"},
  1032. {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"},
  1033. {0x04, SvcWrap<MapMemory>, "MapMemory"},
  1034. {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"},
  1035. {0x06, SvcWrap<QueryMemory>, "QueryMemory"},
  1036. {0x07, SvcWrap<ExitProcess>, "ExitProcess"},
  1037. {0x08, SvcWrap<CreateThread>, "CreateThread"},
  1038. {0x09, SvcWrap<StartThread>, "StartThread"},
  1039. {0x0A, SvcWrap<ExitThread>, "ExitThread"},
  1040. {0x0B, SvcWrap<SleepThread>, "SleepThread"},
  1041. {0x0C, SvcWrap<GetThreadPriority>, "GetThreadPriority"},
  1042. {0x0D, SvcWrap<SetThreadPriority>, "SetThreadPriority"},
  1043. {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
  1044. {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
  1045. {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
  1046. {0x11, nullptr, "SignalEvent"},
  1047. {0x12, SvcWrap<ClearEvent>, "ClearEvent"},
  1048. {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"},
  1049. {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"},
  1050. {0x15, SvcWrap<CreateTransferMemory>, "CreateTransferMemory"},
  1051. {0x16, SvcWrap<CloseHandle>, "CloseHandle"},
  1052. {0x17, SvcWrap<ResetSignal>, "ResetSignal"},
  1053. {0x18, SvcWrap<WaitSynchronization>, "WaitSynchronization"},
  1054. {0x19, SvcWrap<CancelSynchronization>, "CancelSynchronization"},
  1055. {0x1A, SvcWrap<ArbitrateLock>, "ArbitrateLock"},
  1056. {0x1B, SvcWrap<ArbitrateUnlock>, "ArbitrateUnlock"},
  1057. {0x1C, SvcWrap<WaitProcessWideKeyAtomic>, "WaitProcessWideKeyAtomic"},
  1058. {0x1D, SvcWrap<SignalProcessWideKey>, "SignalProcessWideKey"},
  1059. {0x1E, SvcWrap<GetSystemTick>, "GetSystemTick"},
  1060. {0x1F, SvcWrap<ConnectToNamedPort>, "ConnectToNamedPort"},
  1061. {0x20, nullptr, "SendSyncRequestLight"},
  1062. {0x21, SvcWrap<SendSyncRequest>, "SendSyncRequest"},
  1063. {0x22, nullptr, "SendSyncRequestWithUserBuffer"},
  1064. {0x23, nullptr, "SendAsyncRequestWithUserBuffer"},
  1065. {0x24, SvcWrap<GetProcessId>, "GetProcessId"},
  1066. {0x25, SvcWrap<GetThreadId>, "GetThreadId"},
  1067. {0x26, SvcWrap<Break>, "Break"},
  1068. {0x27, SvcWrap<OutputDebugString>, "OutputDebugString"},
  1069. {0x28, nullptr, "ReturnFromException"},
  1070. {0x29, SvcWrap<GetInfo>, "GetInfo"},
  1071. {0x2A, nullptr, "FlushEntireDataCache"},
  1072. {0x2B, nullptr, "FlushDataCache"},
  1073. {0x2C, nullptr, "MapPhysicalMemory"},
  1074. {0x2D, nullptr, "UnmapPhysicalMemory"},
  1075. {0x2E, nullptr, "GetFutureThreadInfo"},
  1076. {0x2F, nullptr, "GetLastThreadInfo"},
  1077. {0x30, nullptr, "GetResourceLimitLimitValue"},
  1078. {0x31, nullptr, "GetResourceLimitCurrentValue"},
  1079. {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
  1080. {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
  1081. {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
  1082. {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
  1083. {0x36, nullptr, "Unknown"},
  1084. {0x37, nullptr, "Unknown"},
  1085. {0x38, nullptr, "Unknown"},
  1086. {0x39, nullptr, "Unknown"},
  1087. {0x3A, nullptr, "Unknown"},
  1088. {0x3B, nullptr, "Unknown"},
  1089. {0x3C, nullptr, "DumpInfo"},
  1090. {0x3D, nullptr, "DumpInfoNew"},
  1091. {0x3E, nullptr, "Unknown"},
  1092. {0x3F, nullptr, "Unknown"},
  1093. {0x40, nullptr, "CreateSession"},
  1094. {0x41, nullptr, "AcceptSession"},
  1095. {0x42, nullptr, "ReplyAndReceiveLight"},
  1096. {0x43, nullptr, "ReplyAndReceive"},
  1097. {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
  1098. {0x45, nullptr, "CreateEvent"},
  1099. {0x46, nullptr, "Unknown"},
  1100. {0x47, nullptr, "Unknown"},
  1101. {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
  1102. {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
  1103. {0x4A, nullptr, "SetUnsafeLimit"},
  1104. {0x4B, nullptr, "CreateCodeMemory"},
  1105. {0x4C, nullptr, "ControlCodeMemory"},
  1106. {0x4D, nullptr, "SleepSystem"},
  1107. {0x4E, nullptr, "ReadWriteRegister"},
  1108. {0x4F, nullptr, "SetProcessActivity"},
  1109. {0x50, SvcWrap<CreateSharedMemory>, "CreateSharedMemory"},
  1110. {0x51, nullptr, "MapTransferMemory"},
  1111. {0x52, nullptr, "UnmapTransferMemory"},
  1112. {0x53, nullptr, "CreateInterruptEvent"},
  1113. {0x54, nullptr, "QueryPhysicalAddress"},
  1114. {0x55, nullptr, "QueryIoMapping"},
  1115. {0x56, nullptr, "CreateDeviceAddressSpace"},
  1116. {0x57, nullptr, "AttachDeviceAddressSpace"},
  1117. {0x58, nullptr, "DetachDeviceAddressSpace"},
  1118. {0x59, nullptr, "MapDeviceAddressSpaceByForce"},
  1119. {0x5A, nullptr, "MapDeviceAddressSpaceAligned"},
  1120. {0x5B, nullptr, "MapDeviceAddressSpace"},
  1121. {0x5C, nullptr, "UnmapDeviceAddressSpace"},
  1122. {0x5D, nullptr, "InvalidateProcessDataCache"},
  1123. {0x5E, nullptr, "StoreProcessDataCache"},
  1124. {0x5F, nullptr, "FlushProcessDataCache"},
  1125. {0x60, nullptr, "DebugActiveProcess"},
  1126. {0x61, nullptr, "BreakDebugProcess"},
  1127. {0x62, nullptr, "TerminateDebugProcess"},
  1128. {0x63, nullptr, "GetDebugEvent"},
  1129. {0x64, nullptr, "ContinueDebugEvent"},
  1130. {0x65, nullptr, "GetProcessList"},
  1131. {0x66, nullptr, "GetThreadList"},
  1132. {0x67, nullptr, "GetDebugThreadContext"},
  1133. {0x68, nullptr, "SetDebugThreadContext"},
  1134. {0x69, nullptr, "QueryDebugProcessMemory"},
  1135. {0x6A, nullptr, "ReadDebugProcessMemory"},
  1136. {0x6B, nullptr, "WriteDebugProcessMemory"},
  1137. {0x6C, nullptr, "SetHardwareBreakPoint"},
  1138. {0x6D, nullptr, "GetDebugThreadParam"},
  1139. {0x6E, nullptr, "Unknown"},
  1140. {0x6F, nullptr, "GetSystemInfo"},
  1141. {0x70, nullptr, "CreatePort"},
  1142. {0x71, nullptr, "ManageNamedPort"},
  1143. {0x72, nullptr, "ConnectToPort"},
  1144. {0x73, nullptr, "SetProcessMemoryPermission"},
  1145. {0x74, nullptr, "MapProcessMemory"},
  1146. {0x75, nullptr, "UnmapProcessMemory"},
  1147. {0x76, nullptr, "QueryProcessMemory"},
  1148. {0x77, nullptr, "MapProcessCodeMemory"},
  1149. {0x78, nullptr, "UnmapProcessCodeMemory"},
  1150. {0x79, nullptr, "CreateProcess"},
  1151. {0x7A, nullptr, "StartProcess"},
  1152. {0x7B, nullptr, "TerminateProcess"},
  1153. {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
  1154. {0x7D, nullptr, "CreateResourceLimit"},
  1155. {0x7E, nullptr, "SetResourceLimitLimitValue"},
  1156. {0x7F, nullptr, "CallSecureMonitor"},
  1157. };
  1158. static const FunctionDef* GetSVCInfo(u32 func_num) {
  1159. if (func_num >= std::size(SVC_Table)) {
  1160. LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
  1161. return nullptr;
  1162. }
  1163. return &SVC_Table[func_num];
  1164. }
  1165. MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
  1166. void CallSVC(u32 immediate) {
  1167. MICROPROFILE_SCOPE(Kernel_SVC);
  1168. // Lock the global kernel mutex when we enter the kernel HLE.
  1169. std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
  1170. const FunctionDef* info = GetSVCInfo(immediate);
  1171. if (info) {
  1172. if (info->func) {
  1173. info->func();
  1174. } else {
  1175. LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
  1176. }
  1177. } else {
  1178. LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
  1179. }
  1180. }
  1181. } // namespace Kernel