apt.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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/kernel/event.h"
  9. #include "core/hle/kernel/mutex.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/kernel/shared_memory.h"
  12. #include "core/hle/service/apt/apt.h"
  13. #include "core/hle/service/apt/apt_a.h"
  14. #include "core/hle/service/apt/apt_s.h"
  15. #include "core/hle/service/apt/apt_u.h"
  16. #include "core/hle/service/apt/bcfnt/bcfnt.h"
  17. #include "core/hle/service/fs/archive.h"
  18. #include "core/hle/service/ptm/ptm.h"
  19. #include "core/hle/service/service.h"
  20. namespace Service {
  21. namespace APT {
  22. /// Handle to shared memory region designated to for shared system font
  23. static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
  24. static bool shared_font_relocated = false;
  25. static Kernel::SharedPtr<Kernel::Mutex> lock;
  26. static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
  27. static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
  28. static u32 cpu_percent; ///< CPU time available to the running application
  29. // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
  30. static u8 unknown_ns_state_field;
  31. static ScreencapPostPermission screen_capture_post_permission;
  32. /// Parameter data to be returned in the next call to Glance/ReceiveParameter
  33. static MessageParameter next_parameter;
  34. void SendParameter(const MessageParameter& parameter) {
  35. next_parameter = parameter;
  36. // Signal the event to let the application know that a new parameter is ready to be read
  37. parameter_event->Signal();
  38. }
  39. void Initialize(Service::Interface* self) {
  40. u32* cmd_buff = Kernel::GetCommandBuffer();
  41. u32 app_id = cmd_buff[1];
  42. u32 flags = cmd_buff[2];
  43. cmd_buff[2] = IPC::CopyHandleDesc(2);
  44. cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
  45. cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
  46. // TODO(bunnei): Check if these events are cleared every time Initialize is called.
  47. notification_event->Clear();
  48. parameter_event->Clear();
  49. ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
  50. lock->Release();
  51. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  52. LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
  53. }
  54. void GetSharedFont(Service::Interface* self) {
  55. u32* cmd_buff = Kernel::GetCommandBuffer();
  56. if (!shared_font_mem) {
  57. LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
  58. cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
  59. cmd_buff[1] = -1; // TODO: Find the right error code
  60. return;
  61. }
  62. // The shared font has to be relocated to the new address before being passed to the
  63. // application.
  64. VAddr target_address =
  65. Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
  66. if (!shared_font_relocated) {
  67. BCFNT::RelocateSharedFont(shared_font_mem, target_address);
  68. shared_font_relocated = true;
  69. }
  70. cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
  71. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  72. // Since the SharedMemory interface doesn't provide the address at which the memory was
  73. // allocated, the real APT service calculates this address by scanning the entire address space
  74. // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font.
  75. cmd_buff[2] = target_address;
  76. cmd_buff[3] = IPC::CopyHandleDesc();
  77. cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
  78. }
  79. void NotifyToWait(Service::Interface* self) {
  80. u32* cmd_buff = Kernel::GetCommandBuffer();
  81. u32 app_id = cmd_buff[1];
  82. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  83. LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
  84. }
  85. void GetLockHandle(Service::Interface* self) {
  86. u32* cmd_buff = Kernel::GetCommandBuffer();
  87. // Bits [0:2] are the applet type (System, Library, etc)
  88. // Bit 5 tells the application that there's a pending APT parameter,
  89. // this will cause the app to wait until parameter_event is signaled.
  90. u32 applet_attributes = cmd_buff[1];
  91. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  92. cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
  93. cmd_buff[3] = 0; // Least significant bit = power button state
  94. cmd_buff[4] = IPC::CopyHandleDesc();
  95. cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom();
  96. LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5],
  97. applet_attributes);
  98. }
  99. void Enable(Service::Interface* self) {
  100. u32* cmd_buff = Kernel::GetCommandBuffer();
  101. u32 attributes = cmd_buff[1];
  102. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  103. parameter_event->Signal(); // Let the application know that it has been started
  104. LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
  105. }
  106. void GetAppletManInfo(Service::Interface* self) {
  107. u32* cmd_buff = Kernel::GetCommandBuffer();
  108. u32 unk = cmd_buff[1];
  109. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  110. cmd_buff[2] = 0;
  111. cmd_buff[3] = 0;
  112. cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
  113. cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
  114. LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
  115. }
  116. void IsRegistered(Service::Interface* self) {
  117. u32* cmd_buff = Kernel::GetCommandBuffer();
  118. u32 app_id = cmd_buff[1];
  119. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  120. // TODO(Subv): An application is considered "registered" if it has already called APT::Enable
  121. // handle this properly once we implement multiprocess support.
  122. cmd_buff[2] = 0; // Set to not registered by default
  123. if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) {
  124. cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0;
  125. } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) {
  126. cmd_buff[2] = 1; // Set to registered
  127. }
  128. LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
  129. }
  130. void InquireNotification(Service::Interface* self) {
  131. u32* cmd_buff = Kernel::GetCommandBuffer();
  132. u32 app_id = cmd_buff[1];
  133. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  134. cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
  135. LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
  136. }
  137. void SendParameter(Service::Interface* self) {
  138. u32* cmd_buff = Kernel::GetCommandBuffer();
  139. u32 src_app_id = cmd_buff[1];
  140. u32 dst_app_id = cmd_buff[2];
  141. u32 signal_type = cmd_buff[3];
  142. u32 buffer_size = cmd_buff[4];
  143. u32 value = cmd_buff[5];
  144. u32 handle = cmd_buff[6];
  145. u32 size = cmd_buff[7];
  146. u32 buffer = cmd_buff[8];
  147. std::shared_ptr<HLE::Applets::Applet> dest_applet =
  148. HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
  149. if (dest_applet == nullptr) {
  150. LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
  151. cmd_buff[1] = -1; // TODO(Subv): Find the right error code
  152. return;
  153. }
  154. MessageParameter param;
  155. param.destination_id = dst_app_id;
  156. param.sender_id = src_app_id;
  157. param.object = Kernel::g_handle_table.GetGeneric(handle);
  158. param.signal = signal_type;
  159. param.buffer.resize(buffer_size);
  160. Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size());
  161. cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
  162. LOG_WARNING(
  163. Service_APT,
  164. "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
  165. "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
  166. src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
  167. }
  168. void ReceiveParameter(Service::Interface* self) {
  169. u32* cmd_buff = Kernel::GetCommandBuffer();
  170. u32 app_id = cmd_buff[1];
  171. u32 buffer_size = cmd_buff[2];
  172. VAddr buffer = cmd_buff[0x104 >> 2];
  173. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  174. cmd_buff[2] = next_parameter.sender_id;
  175. cmd_buff[3] = next_parameter.signal; // Signal type
  176. cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
  177. cmd_buff[5] = 0x10;
  178. cmd_buff[6] = 0;
  179. if (next_parameter.object != nullptr)
  180. cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
  181. cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
  182. cmd_buff[8] = buffer;
  183. Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
  184. LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
  185. }
  186. void GlanceParameter(Service::Interface* self) {
  187. u32* cmd_buff = Kernel::GetCommandBuffer();
  188. u32 app_id = cmd_buff[1];
  189. u32 buffer_size = cmd_buff[2];
  190. VAddr buffer = cmd_buff[0x104 >> 2];
  191. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  192. cmd_buff[2] = next_parameter.sender_id;
  193. cmd_buff[3] = next_parameter.signal; // Signal type
  194. cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
  195. cmd_buff[5] = 0x10;
  196. cmd_buff[6] = 0;
  197. if (next_parameter.object != nullptr)
  198. cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
  199. cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
  200. cmd_buff[8] = buffer;
  201. Memory::WriteBlock(buffer, next_parameter.buffer.data(),
  202. std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
  203. LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
  204. }
  205. void CancelParameter(Service::Interface* self) {
  206. u32* cmd_buff = Kernel::GetCommandBuffer();
  207. u32 flag1 = cmd_buff[1];
  208. u32 unk = cmd_buff[2];
  209. u32 flag2 = cmd_buff[3];
  210. u32 app_id = cmd_buff[4];
  211. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  212. cmd_buff[2] = 1; // Set to Success
  213. LOG_WARNING(Service_APT,
  214. "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1,
  215. unk, flag2, app_id);
  216. }
  217. void PrepareToStartApplication(Service::Interface* self) {
  218. u32* cmd_buff = Kernel::GetCommandBuffer();
  219. u32 title_info1 = cmd_buff[1];
  220. u32 title_info2 = cmd_buff[2];
  221. u32 title_info3 = cmd_buff[3];
  222. u32 title_info4 = cmd_buff[4];
  223. u32 flags = cmd_buff[5];
  224. if (flags & 0x00000100) {
  225. unknown_ns_state_field = 1;
  226. }
  227. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  228. LOG_WARNING(Service_APT,
  229. "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
  230. "title_info4=0x%08X, flags=0x%08X",
  231. title_info1, title_info2, title_info3, title_info4, flags);
  232. }
  233. void StartApplication(Service::Interface* self) {
  234. u32* cmd_buff = Kernel::GetCommandBuffer();
  235. u32 buffer1_size = cmd_buff[1];
  236. u32 buffer2_size = cmd_buff[2];
  237. u32 flag = cmd_buff[3];
  238. u32 size1 = cmd_buff[4];
  239. u32 buffer1_ptr = cmd_buff[5];
  240. u32 size2 = cmd_buff[6];
  241. u32 buffer2_ptr = cmd_buff[7];
  242. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  243. LOG_WARNING(Service_APT,
  244. "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
  245. "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
  246. buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
  247. }
  248. void AppletUtility(Service::Interface* self) {
  249. u32* cmd_buff = Kernel::GetCommandBuffer();
  250. // These are from 3dbrew - I'm not really sure what they're used for.
  251. u32 command = cmd_buff[1];
  252. u32 buffer1_size = cmd_buff[2];
  253. u32 buffer2_size = cmd_buff[3];
  254. u32 buffer1_addr = cmd_buff[5];
  255. u32 buffer2_addr = cmd_buff[65];
  256. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  257. LOG_WARNING(Service_APT,
  258. "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
  259. "buffer1_addr=0x%08X, buffer2_addr=0x%08X",
  260. command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr);
  261. }
  262. void SetAppCpuTimeLimit(Service::Interface* self) {
  263. u32* cmd_buff = Kernel::GetCommandBuffer();
  264. u32 value = cmd_buff[1];
  265. cpu_percent = cmd_buff[2];
  266. if (value != 1) {
  267. LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
  268. }
  269. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  270. LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value);
  271. }
  272. void GetAppCpuTimeLimit(Service::Interface* self) {
  273. u32* cmd_buff = Kernel::GetCommandBuffer();
  274. u32 value = cmd_buff[1];
  275. if (value != 1) {
  276. LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
  277. }
  278. cmd_buff[1] = RESULT_SUCCESS.raw; // No error
  279. cmd_buff[2] = cpu_percent;
  280. LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
  281. }
  282. void PrepareToStartLibraryApplet(Service::Interface* self) {
  283. u32* cmd_buff = Kernel::GetCommandBuffer();
  284. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  285. auto applet = HLE::Applets::Applet::Get(applet_id);
  286. if (applet) {
  287. LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
  288. cmd_buff[1] = RESULT_SUCCESS.raw;
  289. } else {
  290. cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
  291. }
  292. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  293. }
  294. void PreloadLibraryApplet(Service::Interface* self) {
  295. u32* cmd_buff = Kernel::GetCommandBuffer();
  296. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  297. auto applet = HLE::Applets::Applet::Get(applet_id);
  298. if (applet) {
  299. LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
  300. cmd_buff[1] = RESULT_SUCCESS.raw;
  301. } else {
  302. cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
  303. }
  304. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  305. }
  306. void StartLibraryApplet(Service::Interface* self) {
  307. u32* cmd_buff = Kernel::GetCommandBuffer();
  308. AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
  309. std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
  310. LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
  311. if (applet == nullptr) {
  312. LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
  313. cmd_buff[1] = -1; // TODO(Subv): Find the right error code
  314. return;
  315. }
  316. size_t buffer_size = cmd_buff[2];
  317. VAddr buffer_addr = cmd_buff[6];
  318. AppletStartupParameter parameter;
  319. parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
  320. parameter.buffer.resize(buffer_size);
  321. Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size());
  322. cmd_buff[1] = applet->Start(parameter).raw;
  323. }
  324. void CancelLibraryApplet(Service::Interface* self) {
  325. u32* cmd_buff = Kernel::GetCommandBuffer();
  326. u32 exiting = cmd_buff[1] & 0xFF;
  327. cmd_buff[1] = 1; // TODO: Find the return code meaning
  328. LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting);
  329. }
  330. void SetScreenCapPostPermission(Service::Interface* self) {
  331. u32* cmd_buff = Kernel::GetCommandBuffer();
  332. screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF);
  333. cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
  334. cmd_buff[1] = RESULT_SUCCESS.raw;
  335. LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
  336. screen_capture_post_permission);
  337. }
  338. void GetScreenCapPostPermission(Service::Interface* self) {
  339. u32* cmd_buff = Kernel::GetCommandBuffer();
  340. cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
  341. cmd_buff[1] = RESULT_SUCCESS.raw;
  342. cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
  343. LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
  344. screen_capture_post_permission);
  345. }
  346. void GetAppletInfo(Service::Interface* self) {
  347. u32* cmd_buff = Kernel::GetCommandBuffer();
  348. auto app_id = static_cast<AppletId>(cmd_buff[1]);
  349. if (auto applet = HLE::Applets::Applet::Get(app_id)) {
  350. // TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
  351. cmd_buff[1] = RESULT_SUCCESS.raw;
  352. cmd_buff[4] = static_cast<u32>(Service::FS::MediaType::NAND);
  353. cmd_buff[5] = 1; // Registered
  354. cmd_buff[6] = 1; // Loaded
  355. cmd_buff[7] = 0; // Applet Attributes
  356. } else {
  357. cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
  358. ErrorSummary::NotFound, ErrorLevel::Status)
  359. .raw;
  360. }
  361. LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id);
  362. }
  363. void GetStartupArgument(Service::Interface* self) {
  364. u32* cmd_buff = Kernel::GetCommandBuffer();
  365. u32 parameter_size = cmd_buff[1];
  366. StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]);
  367. if (parameter_size >= 0x300) {
  368. LOG_ERROR(
  369. Service_APT,
  370. "Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x",
  371. parameter_size);
  372. return;
  373. }
  374. u32 addr = cmd_buff[65];
  375. if (addr && parameter_size) {
  376. Memory::ZeroBlock(addr, parameter_size);
  377. }
  378. LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x",
  379. startup_argument_type, parameter_size);
  380. cmd_buff[1] = RESULT_SUCCESS.raw;
  381. cmd_buff[2] = 0;
  382. }
  383. void CheckNew3DSApp(Service::Interface* self) {
  384. u32* cmd_buff = Kernel::GetCommandBuffer();
  385. if (unknown_ns_state_field) {
  386. cmd_buff[1] = RESULT_SUCCESS.raw;
  387. cmd_buff[2] = 0;
  388. } else {
  389. PTM::CheckNew3DS(self);
  390. }
  391. cmd_buff[0] = IPC::MakeHeader(0x101, 2, 0);
  392. LOG_WARNING(Service_APT, "(STUBBED) called");
  393. }
  394. void CheckNew3DS(Service::Interface* self) {
  395. u32* cmd_buff = Kernel::GetCommandBuffer();
  396. PTM::CheckNew3DS(self);
  397. cmd_buff[0] = IPC::MakeHeader(0x102, 2, 0);
  398. LOG_WARNING(Service_APT, "(STUBBED) called");
  399. }
  400. void Init() {
  401. AddService(new APT_A_Interface);
  402. AddService(new APT_S_Interface);
  403. AddService(new APT_U_Interface);
  404. HLE::Applets::Init();
  405. // Load the shared system font (if available).
  406. // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
  407. // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
  408. // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file
  409. // "shared_font.bin" in the Citra "sysdata" directory.
  410. std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT;
  411. FileUtil::CreateFullPath(filepath); // Create path if not already created
  412. FileUtil::IOFile file(filepath, "rb");
  413. if (file.IsOpen()) {
  414. // Create shared font memory object
  415. using Kernel::MemoryPermission;
  416. shared_font_mem =
  417. Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
  418. MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
  419. Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
  420. // Read shared font data
  421. file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
  422. } else {
  423. LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
  424. shared_font_mem = nullptr;
  425. }
  426. lock = Kernel::Mutex::Create(false, "APT_U:Lock");
  427. cpu_percent = 0;
  428. unknown_ns_state_field = 0;
  429. screen_capture_post_permission =
  430. ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
  431. // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
  432. notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
  433. parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start");
  434. next_parameter.signal = static_cast<u32>(SignalType::Wakeup);
  435. next_parameter.destination_id = 0x300;
  436. }
  437. void Shutdown() {
  438. shared_font_mem = nullptr;
  439. shared_font_relocated = false;
  440. lock = nullptr;
  441. notification_event = nullptr;
  442. parameter_event = nullptr;
  443. next_parameter.object = nullptr;
  444. HLE::Applets::Shutdown();
  445. }
  446. } // namespace APT
  447. } // namespace Service