fs_user.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/common_types.h"
  6. #include "common/file_util.h"
  7. #include "common/logging/log.h"
  8. #include "common/scope_exit.h"
  9. #include "common/string_util.h"
  10. #include "core/hle/result.h"
  11. #include "core/hle/service/fs/archive.h"
  12. #include "core/hle/service/fs/fs_user.h"
  13. #include "core/settings.h"
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////
  15. // Namespace FS_User
  16. using Kernel::SharedPtr;
  17. using Kernel::Session;
  18. namespace Service {
  19. namespace FS {
  20. static u32 priority = -1; ///< For SetPriority and GetPriority service functions
  21. static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) {
  22. return (u64)low_word | ((u64)high_word << 32);
  23. }
  24. static void Initialize(Service::Interface* self) {
  25. u32* cmd_buff = Kernel::GetCommandBuffer();
  26. // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
  27. // http://3dbrew.org/wiki/FS:Initialize#Request
  28. cmd_buff[1] = RESULT_SUCCESS.raw;
  29. }
  30. /**
  31. * FS_User::OpenFile service function
  32. * Inputs:
  33. * 1 : Transaction
  34. * 2 : Archive handle lower word
  35. * 3 : Archive handle upper word
  36. * 4 : Low path type
  37. * 5 : Low path size
  38. * 6 : Open flags
  39. * 7 : Attributes
  40. * 8 : (LowPathSize << 14) | 2
  41. * 9 : Low path data pointer
  42. * Outputs:
  43. * 1 : Result of function, 0 on success, otherwise error code
  44. * 3 : File handle
  45. */
  46. static void OpenFile(Service::Interface* self) {
  47. u32* cmd_buff = Kernel::GetCommandBuffer();
  48. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  49. auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  50. u32 filename_size = cmd_buff[5];
  51. FileSys::Mode mode; mode.hex = cmd_buff[6];
  52. u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
  53. u32 filename_ptr = cmd_buff[9];
  54. FileSys::Path file_path(filename_type, filename_size, filename_ptr);
  55. LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
  56. ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode);
  57. cmd_buff[1] = file_res.Code().raw;
  58. if (file_res.Succeeded()) {
  59. cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
  60. } else {
  61. cmd_buff[3] = 0;
  62. LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
  63. }
  64. }
  65. /**
  66. * FS_User::OpenFileDirectly service function
  67. * Inputs:
  68. * 1 : Transaction
  69. * 2 : Archive ID
  70. * 3 : Archive low path type
  71. * 4 : Archive low path size
  72. * 5 : File low path type
  73. * 6 : File low path size
  74. * 7 : Flags
  75. * 8 : Attributes
  76. * 9 : (ArchiveLowPathSize << 14) | 0x802
  77. * 10 : Archive low path
  78. * 11 : (FileLowPathSize << 14) | 2
  79. * 12 : File low path
  80. * Outputs:
  81. * 1 : Result of function, 0 on success, otherwise error code
  82. * 3 : File handle
  83. */
  84. static void OpenFileDirectly(Service::Interface* self) {
  85. u32* cmd_buff = Kernel::GetCommandBuffer();
  86. auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[2]);
  87. auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
  88. u32 archivename_size = cmd_buff[4];
  89. auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
  90. u32 filename_size = cmd_buff[6];
  91. FileSys::Mode mode; mode.hex = cmd_buff[7];
  92. u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
  93. u32 archivename_ptr = cmd_buff[10];
  94. u32 filename_ptr = cmd_buff[12];
  95. FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
  96. FileSys::Path file_path(filename_type, filename_size, filename_ptr);
  97. LOG_DEBUG(Service_FS, "archive_id=0x%08X archive_path=%s file_path=%s, mode=%u attributes=%d",
  98. archive_id, archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes);
  99. ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
  100. if (archive_handle.Failed()) {
  101. LOG_ERROR(Service_FS, "failed to get a handle for archive");
  102. cmd_buff[1] = archive_handle.Code().raw;
  103. cmd_buff[3] = 0;
  104. return;
  105. }
  106. SCOPE_EXIT({ CloseArchive(*archive_handle); });
  107. ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode);
  108. cmd_buff[1] = file_res.Code().raw;
  109. if (file_res.Succeeded()) {
  110. cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
  111. } else {
  112. cmd_buff[3] = 0;
  113. LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
  114. }
  115. }
  116. /*
  117. * FS_User::DeleteFile service function
  118. * Inputs:
  119. * 2 : Archive handle lower word
  120. * 3 : Archive handle upper word
  121. * 4 : File path string type
  122. * 5 : File path string size
  123. * 7 : File path string data
  124. * Outputs:
  125. * 1 : Result of function, 0 on success, otherwise error code
  126. */
  127. static void DeleteFile(Service::Interface* self) {
  128. u32* cmd_buff = Kernel::GetCommandBuffer();
  129. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  130. auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  131. u32 filename_size = cmd_buff[5];
  132. u32 filename_ptr = cmd_buff[7];
  133. FileSys::Path file_path(filename_type, filename_size, filename_ptr);
  134. LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
  135. filename_type, filename_size, file_path.DebugStr().c_str());
  136. cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw;
  137. }
  138. /*
  139. * FS_User::RenameFile service function
  140. * Inputs:
  141. * 2 : Source archive handle lower word
  142. * 3 : Source archive handle upper word
  143. * 4 : Source file path type
  144. * 5 : Source file path size
  145. * 6 : Dest archive handle lower word
  146. * 7 : Dest archive handle upper word
  147. * 8 : Dest file path type
  148. * 9 : Dest file path size
  149. * 11: Source file path string data
  150. * 13: Dest file path string
  151. * Outputs:
  152. * 1 : Result of function, 0 on success, otherwise error code
  153. */
  154. static void RenameFile(Service::Interface* self) {
  155. u32* cmd_buff = Kernel::GetCommandBuffer();
  156. ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  157. auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  158. u32 src_filename_size = cmd_buff[5];
  159. ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);;
  160. auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
  161. u32 dest_filename_size = cmd_buff[9];
  162. u32 src_filename_ptr = cmd_buff[11];
  163. u32 dest_filename_ptr = cmd_buff[13];
  164. FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr);
  165. FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr);
  166. LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
  167. src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(),
  168. dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str());
  169. cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw;
  170. }
  171. /*
  172. * FS_User::DeleteDirectory service function
  173. * Inputs:
  174. * 2 : Archive handle lower word
  175. * 3 : Archive handle upper word
  176. * 4 : Directory path string type
  177. * 5 : Directory path string size
  178. * 7 : Directory path string data
  179. * Outputs:
  180. * 1 : Result of function, 0 on success, otherwise error code
  181. */
  182. static void DeleteDirectory(Service::Interface* self) {
  183. u32* cmd_buff = Kernel::GetCommandBuffer();
  184. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  185. auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  186. u32 dirname_size = cmd_buff[5];
  187. u32 dirname_ptr = cmd_buff[7];
  188. FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
  189. LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
  190. dirname_type, dirname_size, dir_path.DebugStr().c_str());
  191. cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
  192. }
  193. /*
  194. * FS_User::CreateFile service function
  195. * Inputs:
  196. * 0 : Command header 0x08080202
  197. * 2 : Archive handle lower word
  198. * 3 : Archive handle upper word
  199. * 4 : File path string type
  200. * 5 : File path string size
  201. * 7 : File size (filled with zeroes)
  202. * 10: File path string data
  203. * Outputs:
  204. * 1 : Result of function, 0 on success, otherwise error code
  205. */
  206. static void CreateFile(Service::Interface* self) {
  207. u32* cmd_buff = Kernel::GetCommandBuffer();
  208. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  209. auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  210. u32 filename_size = cmd_buff[5];
  211. u32 file_size = cmd_buff[7];
  212. u32 filename_ptr = cmd_buff[10];
  213. FileSys::Path file_path(filename_type, filename_size, filename_ptr);
  214. LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str());
  215. cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
  216. }
  217. /*
  218. * FS_User::CreateDirectory service function
  219. * Inputs:
  220. * 2 : Archive handle lower word
  221. * 3 : Archive handle upper word
  222. * 4 : Directory path string type
  223. * 5 : Directory path string size
  224. * 8 : Directory path string data
  225. * Outputs:
  226. * 1 : Result of function, 0 on success, otherwise error code
  227. */
  228. static void CreateDirectory(Service::Interface* self) {
  229. u32* cmd_buff = Kernel::GetCommandBuffer();
  230. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  231. auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  232. u32 dirname_size = cmd_buff[5];
  233. u32 dirname_ptr = cmd_buff[8];
  234. FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
  235. LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
  236. cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw;
  237. }
  238. /*
  239. * FS_User::RenameDirectory service function
  240. * Inputs:
  241. * 2 : Source archive handle lower word
  242. * 3 : Source archive handle upper word
  243. * 4 : Source dir path type
  244. * 5 : Source dir path size
  245. * 6 : Dest archive handle lower word
  246. * 7 : Dest archive handle upper word
  247. * 8 : Dest dir path type
  248. * 9 : Dest dir path size
  249. * 11: Source dir path string data
  250. * 13: Dest dir path string
  251. * Outputs:
  252. * 1 : Result of function, 0 on success, otherwise error code
  253. */
  254. static void RenameDirectory(Service::Interface* self) {
  255. u32* cmd_buff = Kernel::GetCommandBuffer();
  256. ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
  257. auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
  258. u32 src_dirname_size = cmd_buff[5];
  259. ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);
  260. auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
  261. u32 dest_dirname_size = cmd_buff[9];
  262. u32 src_dirname_ptr = cmd_buff[11];
  263. u32 dest_dirname_ptr = cmd_buff[13];
  264. FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr);
  265. FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr);
  266. LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
  267. src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(),
  268. dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str());
  269. cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw;
  270. }
  271. /**
  272. * FS_User::OpenDirectory service function
  273. * Inputs:
  274. * 1 : Archive handle low word
  275. * 2 : Archive handle high word
  276. * 3 : Low path type
  277. * 4 : Low path size
  278. * 7 : (LowPathSize << 14) | 2
  279. * 8 : Low path data pointer
  280. * Outputs:
  281. * 1 : Result of function, 0 on success, otherwise error code
  282. * 3 : Directory handle
  283. */
  284. static void OpenDirectory(Service::Interface* self) {
  285. u32* cmd_buff = Kernel::GetCommandBuffer();
  286. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
  287. auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
  288. u32 dirname_size = cmd_buff[4];
  289. u32 dirname_ptr = cmd_buff[6];
  290. FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
  291. LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
  292. ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path);
  293. cmd_buff[1] = dir_res.Code().raw;
  294. if (dir_res.Succeeded()) {
  295. cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
  296. } else {
  297. LOG_ERROR(Service_FS, "failed to get a handle for directory");
  298. }
  299. }
  300. /**
  301. * FS_User::OpenArchive service function
  302. * Inputs:
  303. * 1 : Archive ID
  304. * 2 : Archive low path type
  305. * 3 : Archive low path size
  306. * 4 : (LowPathSize << 14) | 2
  307. * 5 : Archive low path
  308. * Outputs:
  309. * 1 : Result of function, 0 on success, otherwise error code
  310. * 2 : Archive handle lower word (unused)
  311. * 3 : Archive handle upper word (same as file handle)
  312. */
  313. static void OpenArchive(Service::Interface* self) {
  314. u32* cmd_buff = Kernel::GetCommandBuffer();
  315. auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
  316. auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
  317. u32 archivename_size = cmd_buff[3];
  318. u32 archivename_ptr = cmd_buff[5];
  319. FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
  320. LOG_DEBUG(Service_FS, "archive_id=0x%08X archive_path=%s", archive_id, archive_path.DebugStr().c_str());
  321. ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path);
  322. cmd_buff[1] = handle.Code().raw;
  323. if (handle.Succeeded()) {
  324. cmd_buff[2] = *handle & 0xFFFFFFFF;
  325. cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
  326. } else {
  327. cmd_buff[2] = cmd_buff[3] = 0;
  328. LOG_ERROR(Service_FS, "failed to get a handle for archive");
  329. }
  330. }
  331. /**
  332. * FS_User::CloseArchive service function
  333. * Inputs:
  334. * 0 : 0x080E0080
  335. * 1 : Archive handle low word
  336. * 2 : Archive handle high word
  337. * Outputs:
  338. * 0 : ??? TODO(yuriks): Verify return header
  339. * 1 : Result of function, 0 on success, otherwise error code
  340. */
  341. static void CloseArchive(Service::Interface* self) {
  342. u32* cmd_buff = Kernel::GetCommandBuffer();
  343. ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
  344. cmd_buff[1] = CloseArchive(archive_handle).raw;
  345. }
  346. /*
  347. * FS_User::IsSdmcDetected service function
  348. * Outputs:
  349. * 1 : Result of function, 0 on success, otherwise error code
  350. * 2 : Whether the Sdmc could be detected
  351. */
  352. static void IsSdmcDetected(Service::Interface* self) {
  353. u32* cmd_buff = Kernel::GetCommandBuffer();
  354. cmd_buff[1] = 0;
  355. cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
  356. }
  357. /**
  358. * FS_User::IsSdmcWriteable service function
  359. * Outputs:
  360. * 0 : Command header 0x08180000
  361. * 1 : Result of function, 0 on success, otherwise error code
  362. * 2 : Whether the Sdmc is currently writeable
  363. */
  364. static void IsSdmcWriteable(Service::Interface* self) {
  365. u32* cmd_buff = Kernel::GetCommandBuffer();
  366. cmd_buff[1] = RESULT_SUCCESS.raw;
  367. // If the SD isn't enabled, it can't be writeable...else, stubbed true
  368. cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
  369. LOG_DEBUG(Service_FS, " (STUBBED)");
  370. }
  371. /**
  372. * FS_User::FormatSaveData service function,
  373. * formats the SaveData specified by the input path.
  374. * Inputs:
  375. * 0 : 0x084C0242
  376. * 1 : Archive ID
  377. * 2 : Archive low path type
  378. * 3 : Archive low path size
  379. * 10 : (LowPathSize << 14) | 2
  380. * 11 : Archive low path
  381. * Outputs:
  382. * 1 : Result of function, 0 on success, otherwise error code
  383. */
  384. static void FormatSaveData(Service::Interface* self) {
  385. // TODO(Subv): Find out what the other inputs and outputs of this function are
  386. u32* cmd_buff = Kernel::GetCommandBuffer();
  387. LOG_DEBUG(Service_FS, "(STUBBED)");
  388. auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
  389. auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
  390. u32 archivename_size = cmd_buff[3];
  391. u32 archivename_ptr = cmd_buff[11];
  392. FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
  393. LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
  394. if (archive_id != FS::ArchiveIdCode::SaveData) {
  395. // TODO(Subv): What should happen if somebody attempts to format a different archive?
  396. LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]);
  397. cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
  398. return;
  399. }
  400. if (archive_path.GetType() != FileSys::LowPathType::Empty) {
  401. // TODO(Subv): Implement formatting the SaveData of other games
  402. LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
  403. cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
  404. return;
  405. }
  406. cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw;
  407. }
  408. /**
  409. * FS_User::FormatThisUserSaveData service function
  410. * Inputs:
  411. * 0: 0x080F0180
  412. * Outputs:
  413. * 1 : Result of function, 0 on success, otherwise error code
  414. */
  415. static void FormatThisUserSaveData(Service::Interface* self) {
  416. u32* cmd_buff = Kernel::GetCommandBuffer();
  417. LOG_DEBUG(Service_FS, "(STUBBED)");
  418. // TODO(Subv): Find out what the inputs and outputs of this function are
  419. cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw;
  420. }
  421. /**
  422. * FS_User::CreateExtSaveData service function
  423. * Inputs:
  424. * 0 : 0x08510242
  425. * 1 : Media type (NAND / SDMC)
  426. * 2 : Low word of the saveid to create
  427. * 3 : High word of the saveid to create
  428. * 4 : Unknown
  429. * 5 : Unknown
  430. * 6 : Unknown
  431. * 7 : Unknown
  432. * 8 : Unknown
  433. * 9 : Unknown
  434. * 10: Unknown
  435. * 11: Unknown
  436. * Outputs:
  437. * 1 : Result of function, 0 on success, otherwise error code
  438. */
  439. static void CreateExtSaveData(Service::Interface* self) {
  440. // TODO(Subv): Figure out the other parameters.
  441. u32* cmd_buff = Kernel::GetCommandBuffer();
  442. MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
  443. u32 save_low = cmd_buff[2];
  444. u32 save_high = cmd_buff[3];
  445. LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
  446. "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
  447. "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
  448. cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
  449. cmd_buff[10], cmd_buff[11]);
  450. cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw;
  451. }
  452. /**
  453. * FS_User::DeleteExtSaveData service function
  454. * Inputs:
  455. * 0 : 0x08520100
  456. * 1 : Media type (NAND / SDMC)
  457. * 2 : Low word of the saveid to create
  458. * 3 : High word of the saveid to create
  459. * 4 : Unknown
  460. * Outputs:
  461. * 1 : Result of function, 0 on success, otherwise error code
  462. */
  463. static void DeleteExtSaveData(Service::Interface* self) {
  464. u32* cmd_buff = Kernel::GetCommandBuffer();
  465. MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
  466. u32 save_low = cmd_buff[2];
  467. u32 save_high = cmd_buff[3];
  468. u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
  469. LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
  470. save_low, save_high, cmd_buff[1] & 0xFF, unknown);
  471. cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
  472. }
  473. /**
  474. * FS_User::CardSlotIsInserted service function.
  475. * Inputs:
  476. * 0 : 0x08210000
  477. * Outputs:
  478. * 1 : Result of function, 0 on success, otherwise error code
  479. * 2 : Whether there is a game card inserted into the slot or not.
  480. */
  481. static void CardSlotIsInserted(Service::Interface* self) {
  482. u32* cmd_buff = Kernel::GetCommandBuffer();
  483. cmd_buff[1] = RESULT_SUCCESS.raw;
  484. cmd_buff[2] = 0;
  485. LOG_WARNING(Service_FS, "(STUBBED) called");
  486. }
  487. /**
  488. * FS_User::DeleteSystemSaveData service function.
  489. * Inputs:
  490. * 0 : 0x08570080
  491. * 1 : High word of the SystemSaveData id to delete
  492. * 2 : Low word of the SystemSaveData id to delete
  493. * Outputs:
  494. * 1 : Result of function, 0 on success, otherwise error code
  495. */
  496. static void DeleteSystemSaveData(Service::Interface* self) {
  497. u32* cmd_buff = Kernel::GetCommandBuffer();
  498. u32 savedata_high = cmd_buff[1];
  499. u32 savedata_low = cmd_buff[2];
  500. cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw;
  501. }
  502. /**
  503. * FS_User::CreateSystemSaveData service function.
  504. * Inputs:
  505. * 0 : 0x08560240
  506. * 1 : High word of the SystemSaveData id to create
  507. * 2 : Low word of the SystemSaveData id to create
  508. * 3 : Unknown
  509. * 4 : Unknown
  510. * 5 : Unknown
  511. * 6 : Unknown
  512. * 7 : Unknown
  513. * 8 : Unknown
  514. * 9 : Unknown (Memory address)
  515. * Outputs:
  516. * 1 : Result of function, 0 on success, otherwise error code
  517. */
  518. static void CreateSystemSaveData(Service::Interface* self) {
  519. // TODO(Subv): Figure out the other parameters.
  520. u32* cmd_buff = Kernel::GetCommandBuffer();
  521. u32 savedata_high = cmd_buff[1];
  522. u32 savedata_low = cmd_buff[2];
  523. LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
  524. "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
  525. "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
  526. cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]);
  527. cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw;
  528. }
  529. /**
  530. * FS_User::InitializeWithSdkVersion service function.
  531. * Inputs:
  532. * 0 : 0x08610042
  533. * 1 : Unknown
  534. * 2 : Unknown
  535. * 3 : Unknown
  536. * Outputs:
  537. * 1 : Result of function, 0 on success, otherwise error code
  538. */
  539. static void InitializeWithSdkVersion(Service::Interface* self) {
  540. u32* cmd_buff = Kernel::GetCommandBuffer();
  541. u32 unk1 = cmd_buff[1];
  542. u32 unk2 = cmd_buff[2];
  543. u32 unk3 = cmd_buff[3];
  544. cmd_buff[1] = RESULT_SUCCESS.raw;
  545. LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X",
  546. unk1, unk2, unk3);
  547. }
  548. /**
  549. * FS_User::SetPriority service function.
  550. * Inputs:
  551. * 0 : 0x08620040
  552. * 1 : priority
  553. * Outputs:
  554. * 1 : Result of function, 0 on success, otherwise error code
  555. */
  556. static void SetPriority(Service::Interface* self) {
  557. u32* cmd_buff = Kernel::GetCommandBuffer();
  558. priority = cmd_buff[1];
  559. cmd_buff[1] = RESULT_SUCCESS.raw;
  560. LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
  561. }
  562. /**
  563. * FS_User::GetPriority service function.
  564. * Inputs:
  565. * 0 : 0x08630000
  566. * Outputs:
  567. * 1 : Result of function, 0 on success, otherwise error code
  568. * 2 : priority
  569. */
  570. static void GetPriority(Service::Interface* self) {
  571. u32* cmd_buff = Kernel::GetCommandBuffer();
  572. ASSERT(priority != -1);
  573. cmd_buff[1] = RESULT_SUCCESS.raw;
  574. cmd_buff[2] = priority;
  575. LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
  576. }
  577. const Interface::FunctionInfo FunctionTable[] = {
  578. {0x000100C6, nullptr, "Dummy1"},
  579. {0x040100C4, nullptr, "Control"},
  580. {0x08010002, Initialize, "Initialize"},
  581. {0x080201C2, OpenFile, "OpenFile"},
  582. {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
  583. {0x08040142, DeleteFile, "DeleteFile"},
  584. {0x08050244, RenameFile, "RenameFile"},
  585. {0x08060142, DeleteDirectory, "DeleteDirectory"},
  586. {0x08070142, nullptr, "DeleteDirectoryRecursively"},
  587. {0x08080202, CreateFile, "CreateFile"},
  588. {0x08090182, CreateDirectory, "CreateDirectory"},
  589. {0x080A0244, RenameDirectory, "RenameDirectory"},
  590. {0x080B0102, OpenDirectory, "OpenDirectory"},
  591. {0x080C00C2, OpenArchive, "OpenArchive"},
  592. {0x080D0144, nullptr, "ControlArchive"},
  593. {0x080E0080, CloseArchive, "CloseArchive"},
  594. {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"},
  595. {0x08100200, nullptr, "CreateSystemSaveData"},
  596. {0x08110040, nullptr, "DeleteSystemSaveData"},
  597. {0x08120080, nullptr, "GetFreeBytes"},
  598. {0x08130000, nullptr, "GetCardType"},
  599. {0x08140000, nullptr, "GetSdmcArchiveResource"},
  600. {0x08150000, nullptr, "GetNandArchiveResource"},
  601. {0x08160000, nullptr, "GetSdmcFatfsErro"},
  602. {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
  603. {0x08180000, IsSdmcWriteable, "IsSdmcWritable"},
  604. {0x08190042, nullptr, "GetSdmcCid"},
  605. {0x081A0042, nullptr, "GetNandCid"},
  606. {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
  607. {0x081C0000, nullptr, "GetNandSpeedInfo"},
  608. {0x081D0042, nullptr, "GetSdmcLog"},
  609. {0x081E0042, nullptr, "GetNandLog"},
  610. {0x081F0000, nullptr, "ClearSdmcLog"},
  611. {0x08200000, nullptr, "ClearNandLog"},
  612. {0x08210000, CardSlotIsInserted, "CardSlotIsInserted"},
  613. {0x08220000, nullptr, "CardSlotPowerOn"},
  614. {0x08230000, nullptr, "CardSlotPowerOff"},
  615. {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
  616. {0x08250040, nullptr, "CardNorDirectCommand"},
  617. {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
  618. {0x08270082, nullptr, "CardNorDirectRead"},
  619. {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
  620. {0x08290082, nullptr, "CardNorDirectWrite"},
  621. {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
  622. {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
  623. {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
  624. {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
  625. {0x082E0040, nullptr, "GetProductInfo"},
  626. {0x082F0040, nullptr, "GetProgramLaunchInfo"},
  627. {0x08300182, nullptr, "CreateExtSaveData"},
  628. {0x08310180, nullptr, "CreateSharedExtSaveData"},
  629. {0x08320102, nullptr, "ReadExtSaveDataIcon"},
  630. {0x08330082, nullptr, "EnumerateExtSaveData"},
  631. {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
  632. {0x08350080, nullptr, "DeleteExtSaveData"},
  633. {0x08360080, nullptr, "DeleteSharedExtSaveData"},
  634. {0x08370040, nullptr, "SetCardSpiBaudRate"},
  635. {0x08380040, nullptr, "SetCardSpiBusMode"},
  636. {0x08390000, nullptr, "SendInitializeInfoTo9"},
  637. {0x083A0100, nullptr, "GetSpecialContentIndex"},
  638. {0x083B00C2, nullptr, "GetLegacyRomHeader"},
  639. {0x083C00C2, nullptr, "GetLegacyBannerData"},
  640. {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
  641. {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
  642. {0x083F00C0, nullptr, "GetExtDataBlockSize"},
  643. {0x08400040, nullptr, "AbnegateAccessRight"},
  644. {0x08410000, nullptr, "DeleteSdmcRoot"},
  645. {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
  646. {0x08430000, nullptr, "InitializeCtrFileSystem"},
  647. {0x08440000, nullptr, "CreateSeed"},
  648. {0x084500C2, nullptr, "GetFormatInfo"},
  649. {0x08460102, nullptr, "GetLegacyRomHeader2"},
  650. {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
  651. {0x08480042, nullptr, "GetSdmcCtrRootPath"},
  652. {0x08490040, nullptr, "GetArchiveResource"},
  653. {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
  654. {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
  655. {0x084C0242, FormatSaveData, "FormatSaveData"},
  656. {0x084D0102, nullptr, "GetLegacySubBannerData"},
  657. {0x084E0342, nullptr, "UpdateSha256Context"},
  658. {0x084F0102, nullptr, "ReadSpecialFile"},
  659. {0x08500040, nullptr, "GetSpecialFileSize"},
  660. {0x08510242, CreateExtSaveData, "CreateExtSaveData"},
  661. {0x08520100, DeleteExtSaveData, "DeleteExtSaveData"},
  662. {0x08560240, CreateSystemSaveData, "CreateSystemSaveData"},
  663. {0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"},
  664. {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
  665. {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"},
  666. {0x08620040, SetPriority, "SetPriority"},
  667. {0x08630000, GetPriority, "GetPriority"},
  668. };
  669. ////////////////////////////////////////////////////////////////////////////////////////////////////
  670. // Interface class
  671. Interface::Interface() {
  672. priority = -1;
  673. Register(FunctionTable);
  674. }
  675. } // namespace FS
  676. } // namespace Service