apt.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/common_paths.h"
  5. #include "common/file_util.h"
  6. #include "common/logging/log.h"
  7. #include "core/hle/applets/applet.h"
  8. #include "core/hle/service/service.h"
  9. #include "core/hle/service/apt/apt.h"
  10. #include "core/hle/service/apt/apt_a.h"
  11. #include "core/hle/service/apt/apt_s.h"
  12. #include "core/hle/service/apt/apt_u.h"
  13. #include "core/hle/hle.h"
  14. #include "core/hle/kernel/event.h"
  15. #include "core/hle/kernel/mutex.h"
  16. #include "core/hle/kernel/process.h"
  17. #include "core/hle/kernel/shared_memory.h"
  18. #include "core/hle/kernel/thread.h"
  19. namespace Service {
  20. namespace APT {
  21. // Address used for shared font (as observed on HW)
  22. // TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via
  23. // https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any
  24. // address other than 0x18000000 due to internal pointers in the shared font dump that would need to
  25. // be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then
  26. // correctly mapping it in Citra, however we still do not understand how the mapping is determined.
  27. static const VAddr SHARED_FONT_VADDR = 0x18000000;
  28. /// Handle to shared memory region designated to for shared system font
  29. static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
  30. static Kernel::SharedPtr<Kernel::Mutex> lock;
  31. static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
  32. static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
  33. static std::shared_ptr<std::vector<u8>> shared_font;
  34. static u32 cpu_percent; ///< CPU time available to the running application
  35. /// Parameter data to be returned in the next call to Glance/ReceiveParameter
  36. static MessageParameter next_parameter;
  37. void SendParameter(const MessageParameter& parameter) {
  38. next_parameter = parameter;
  39. // Signal the event to let the application know that a new parameter is ready to be read
  40. parameter_event->Signal();
  41. }
  42. void Initialize(Service::Interface* self) {
  43. u32* cmd_buff = Kernel::GetCommandBuffer();
  44. u32 app_id = cmd_buff[1];
  45. u32 flags = cmd_buff[2];
  46. cmd_buff[2] = IPC::MoveHandleDesc(2);
  47. cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
  48. cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
  49. // TODO(bunnei): Check if these events are cleared every time Initialize is called.
  50. notification_event->Clear();
  51. parameter_event->Clear();
  52. ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
  53. lock->Release();
  54. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  55. LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
  56. }
  57. void GetSharedFont(Service::Interface* self) {
  58. u32* cmd_buff = Kernel::GetCommandBuffer();
  59. if (shared_font != nullptr) {
  60. // TODO(yuriks): This is a hack to keep this working right now even with our completely
  61. // broken shared memory system.
  62. shared_font_mem->fixed_address = SHARED_FONT_VADDR;
  63. Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->fixed_address,
  64. shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared);
  65. cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
  66. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  67. cmd_buff[2] = SHARED_FONT_VADDR;
  68. cmd_buff[3] = IPC::MoveHandleDesc();
  69. cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
  70. } else {
  71. cmd_buff[0] = IPC::MakeHeader(0x44, 1, 0);
  72. cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
  73. LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
  74. }
  75. }
  76. void NotifyToWait(Service::Interface* self) {
  77. u32* cmd_buff = Kernel::GetCommandBuffer();
  78. u32 app_id = cmd_buff[1];
  79. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  80. LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
  81. }
  82. void GetLockHandle(Service::Interface* self) {
  83. u32* cmd_buff = Kernel::GetCommandBuffer();
  84. // Bits [0:2] are the applet type (System, Library, etc)
  85. // Bit 5 tells the application that there's a pending APT parameter,
  86. // this will cause the app to wait until parameter_event is signaled.
  87. u32 applet_attributes = cmd_buff[1];
  88. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  89. cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
  90. cmd_buff[3] = 0; // Least significant bit = power button state
  91. cmd_buff[4] = IPC::CopyHandleDesc();
  92. cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom();
  93. LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], applet_attributes);
  94. }
  95. void Enable(Service::Interface* self) {
  96. u32* cmd_buff = Kernel::GetCommandBuffer();
  97. u32 attributes = cmd_buff[1];
  98. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  99. parameter_event->Signal(); // Let the application know that it has been started
  100. LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
  101. }
  102. void GetAppletManInfo(Service::Interface* self) {
  103. u32* cmd_buff = Kernel::GetCommandBuffer();
  104. u32 unk = cmd_buff[1];
  105. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  106. cmd_buff[2] = 0;
  107. cmd_buff[3] = 0;
  108. cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
  109. cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
  110. LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
  111. }
  112. void IsRegistered(Service::Interface* self) {
  113. u32* cmd_buff = Kernel::GetCommandBuffer();
  114. u32 app_id = cmd_buff[1];
  115. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  116. // TODO(Subv): An application is considered "registered" if it has already called APT::Enable
  117. // handle this properly once we implement multiprocess support.
  118. cmd_buff[2] = 0; // Set to not registered by default
  119. if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) {
  120. cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0;
  121. } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) {
  122. cmd_buff[2] = 1; // Set to registered
  123. }
  124. LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
  125. }
  126. void InquireNotification(Service::Interface* self) {
  127. u32* cmd_buff = Kernel::GetCommandBuffer();
  128. u32 app_id = cmd_buff[1];
  129. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  130. cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
  131. LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
  132. }
  133. void SendParameter(Service::Interface* self) {
  134. u32* cmd_buff = Kernel::GetCommandBuffer();
  135. u32 src_app_id = cmd_buff[1];
  136. u32 dst_app_id = cmd_buff[2];
  137. u32 signal_type = cmd_buff[3];
  138. u32 buffer_size = cmd_buff[4];
  139. u32 value = cmd_buff[5];
  140. u32 handle = cmd_buff[6];
  141. u32 size = cmd_buff[7];
  142. u32 buffer = cmd_buff[8];
  143. std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
  144. if (dest_applet == nullptr) {
  145. LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
  146. cmd_buff[1] = -1; // TODO(Subv): Find the right error code
  147. return;
  148. }
  149. MessageParameter param;
  150. param.buffer_size = buffer_size;
  151. param.destination_id = dst_app_id;
  152. param.sender_id = src_app_id;
  153. param.object = Kernel::g_handle_table.GetGeneric(handle);
  154. param.signal = signal_type;
  155. param.data = Memory::GetPointer(buffer);
  156. cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
  157. LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
  158. "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
  159. src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
  160. }
  161. void ReceiveParameter(Service::Interface* self) {
  162. u32* cmd_buff = Kernel::GetCommandBuffer();
  163. u32 app_id = cmd_buff[1];
  164. u32 buffer_size = cmd_buff[2];
  165. VAddr buffer = cmd_buff[0x104 >> 2];
  166. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  167. cmd_buff[2] = next_parameter.sender_id;
  168. cmd_buff[3] = next_parameter.signal; // Signal type
  169. cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
  170. cmd_buff[5] = 0x10;
  171. cmd_buff[6] = 0;
  172. if (next_parameter.object != nullptr)
  173. cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
  174. cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
  175. cmd_buff[8] = buffer;
  176. if (next_parameter.data)
  177. memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
  178. LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
  179. }
  180. void GlanceParameter(Service::Interface* self) {
  181. u32* cmd_buff = Kernel::GetCommandBuffer();
  182. u32 app_id = cmd_buff[1];
  183. u32 buffer_size = cmd_buff[2];
  184. VAddr buffer = cmd_buff[0x104 >> 2];
  185. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  186. cmd_buff[2] = next_parameter.sender_id;
  187. cmd_buff[3] = next_parameter.signal; // Signal type
  188. cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
  189. cmd_buff[5] = 0x10;
  190. cmd_buff[6] = 0;
  191. if (next_parameter.object != nullptr)
  192. cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
  193. cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
  194. cmd_buff[8] = buffer;
  195. if (next_parameter.data)
  196. memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
  197. LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
  198. }
  199. void CancelParameter(Service::Interface* self) {
  200. u32* cmd_buff = Kernel::GetCommandBuffer();
  201. u32 flag1 = cmd_buff[1];
  202. u32 unk = cmd_buff[2];
  203. u32 flag2 = cmd_buff[3];
  204. u32 app_id = cmd_buff[4];
  205. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  206. cmd_buff[2] = 1; // Set to Success
  207. LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X",
  208. flag1, unk, flag2, app_id);
  209. }
  210. void PrepareToStartApplication(Service::Interface* self) {
  211. u32* cmd_buff = Kernel::GetCommandBuffer();
  212. u32 title_info1 = cmd_buff[1];
  213. u32 title_info2 = cmd_buff[2];
  214. u32 title_info3 = cmd_buff[3];
  215. u32 title_info4 = cmd_buff[4];
  216. u32 flags = cmd_buff[5];
  217. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  218. LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
  219. "title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags);
  220. }
  221. void StartApplication(Service::Interface* self) {
  222. u32* cmd_buff = Kernel::GetCommandBuffer();
  223. u32 buffer1_size = cmd_buff[1];
  224. u32 buffer2_size = cmd_buff[2];
  225. u32 flag = cmd_buff[3];
  226. u32 size1 = cmd_buff[4];
  227. u32 buffer1_ptr = cmd_buff[5];
  228. u32 size2 = cmd_buff[6];
  229. u32 buffer2_ptr = cmd_buff[7];
  230. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  231. LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
  232. "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
  233. buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
  234. }
  235. void AppletUtility(Service::Interface* self) {
  236. u32* cmd_buff = Kernel::GetCommandBuffer();
  237. // These are from 3dbrew - I'm not really sure what they're used for.
  238. u32 command = cmd_buff[1];
  239. u32 buffer1_size = cmd_buff[2];
  240. u32 buffer2_size = cmd_buff[3];
  241. u32 buffer1_addr = cmd_buff[5];
  242. u32 buffer2_addr = cmd_buff[65];
  243. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  244. LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
  245. "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
  246. buffer1_addr, buffer2_addr);
  247. }
  248. void SetAppCpuTimeLimit(Service::Interface* self) {
  249. u32* cmd_buff = Kernel::GetCommandBuffer();
  250. u32 value = cmd_buff[1];
  251. cpu_percent = cmd_buff[2];
  252. if (value != 1) {
  253. LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
  254. }
  255. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  256. LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value);
  257. }
  258. void GetAppCpuTimeLimit(Service::Interface* self) {
  259. u32* cmd_buff = Kernel::GetCommandBuffer();
  260. u32 value = cmd_buff[1];
  261. if (value != 1) {
  262. LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
  263. }
  264. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  265. cmd_buff[2] = cpu_percent;
  266. LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
  267. }
  268. void PrepareToStartLibraryApplet(Service::Interface* self) {
  269. u32* cmd_buff = Kernel::GetCommandBuffer();
  270. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  271. auto applet = HLE::Applets::Applet::Get(applet_id);
  272. if (applet) {
  273. LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
  274. cmd_buff[1] = RESULT_SUCCESS.raw;
  275. } else {
  276. cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
  277. }
  278. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  279. }
  280. void PreloadLibraryApplet(Service::Interface* self) {
  281. u32* cmd_buff = Kernel::GetCommandBuffer();
  282. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  283. auto applet = HLE::Applets::Applet::Get(applet_id);
  284. if (applet) {
  285. LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
  286. cmd_buff[1] = RESULT_SUCCESS.raw;
  287. } else {
  288. cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
  289. }
  290. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  291. }
  292. void StartLibraryApplet(Service::Interface* self) {
  293. u32* cmd_buff = Kernel::GetCommandBuffer();
  294. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  295. std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
  296. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  297. if (applet == nullptr) {
  298. LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
  299. cmd_buff[1] = -1; // TODO(Subv): Find the right error code
  300. return;
  301. }
  302. AppletStartupParameter parameter;
  303. parameter.buffer_size = cmd_buff[2];
  304. parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
  305. parameter.data = Memory::GetPointer(cmd_buff[6]);
  306. cmd_buff[1] = applet->Start(parameter).raw;
  307. }
  308. void Init() {
  309. AddService(new APT_A_Interface);
  310. AddService(new APT_S_Interface);
  311. AddService(new APT_U_Interface);
  312. HLE::Applets::Init();
  313. // Load the shared system font (if available).
  314. // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
  315. // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
  316. // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file
  317. // "shared_font.bin" in the Citra "sysdata" directory.
  318. std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT;
  319. FileUtil::CreateFullPath(filepath); // Create path if not already created
  320. FileUtil::IOFile file(filepath, "rb");
  321. if (file.IsOpen()) {
  322. // Read shared font data
  323. shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
  324. file.ReadBytes(shared_font->data(), shared_font->size());
  325. // Create shared font memory object
  326. using Kernel::MemoryPermission;
  327. shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
  328. MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
  329. } else {
  330. LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
  331. shared_font_mem = nullptr;
  332. }
  333. lock = Kernel::Mutex::Create(false, "APT_U:Lock");
  334. cpu_percent = 0;
  335. // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
  336. notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
  337. parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
  338. next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
  339. next_parameter.destination_id = 0x300;
  340. }
  341. void Shutdown() {
  342. shared_font = nullptr;
  343. shared_font_mem = nullptr;
  344. lock = nullptr;
  345. notification_event = nullptr;
  346. parameter_event = nullptr;
  347. next_parameter.object = nullptr;
  348. HLE::Applets::Shutdown();
  349. }
  350. } // namespace APT
  351. } // namespace Service