summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/common_paths.h2
-rw-r--r--src/common/file_util.cpp4
-rw-r--r--src/common/file_util.h2
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/arm/interpreter/armemu.cpp301
-rw-r--r--src/core/file_sys/archive_savedata.cpp33
-rw-r--r--src/core/file_sys/archive_savedata.h31
-rw-r--r--src/core/file_sys/archive_sdmc.cpp83
-rw-r--r--src/core/file_sys/archive_sdmc.h66
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp33
-rw-r--r--src/core/file_sys/archive_systemsavedata.h33
-rw-r--r--src/core/file_sys/directory_sdmc.cpp88
-rw-r--r--src/core/file_sys/directory_sdmc.h55
-rw-r--r--src/core/file_sys/disk_archive.cpp167
-rw-r--r--src/core/file_sys/disk_archive.h101
-rw-r--r--src/core/file_sys/file_backend.h5
-rw-r--r--src/core/file_sys/file_romfs.h2
-rw-r--r--src/core/file_sys/file_sdmc.cpp110
-rw-r--r--src/core/file_sys/file_sdmc.h75
-rw-r--r--src/core/hle/kernel/kernel.cpp1
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/shared_memory.h14
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/fs/archive.cpp60
-rw-r--r--src/core/hle/service/fs/archive.h6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp42
-rw-r--r--src/core/hle/service/gsp_gpu.cpp26
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/loader/loader.cpp1
-rw-r--r--src/core/loader/ncch.cpp4
-rw-r--r--src/core/loader/ncch.h6
31 files changed, 766 insertions, 607 deletions
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 42e1a29c1..966402a3d 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -40,7 +40,9 @@
40#define MAPS_DIR "maps" 40#define MAPS_DIR "maps"
41#define CACHE_DIR "cache" 41#define CACHE_DIR "cache"
42#define SDMC_DIR "sdmc" 42#define SDMC_DIR "sdmc"
43#define SAVEDATA_DIR "savedata"
43#define SYSDATA_DIR "sysdata" 44#define SYSDATA_DIR "sysdata"
45#define SYSSAVEDATA_DIR "syssavedata"
44#define SHADERCACHE_DIR "shader_cache" 46#define SHADERCACHE_DIR "shader_cache"
45#define STATESAVES_DIR "state_saves" 47#define STATESAVES_DIR "state_saves"
46#define SCREENSHOTS_DIR "screenShots" 48#define SCREENSHOTS_DIR "screenShots"
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 88c46c117..20c680571 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -676,7 +676,9 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
676 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 676 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
677 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 677 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
678 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 678 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
679 paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
679 paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; 680 paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
681 paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP;
680 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 682 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
681 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 683 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
682 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 684 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
@@ -718,6 +720,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
718 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 720 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
719 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 721 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
720 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 722 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
723 paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
724 paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP;
721 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 725 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
722 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 726 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
723 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 727 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
diff --git a/src/common/file_util.h b/src/common/file_util.h
index a9d48cfe8..b1a60fb81 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -27,7 +27,9 @@ enum {
27 D_STATESAVES_IDX, 27 D_STATESAVES_IDX,
28 D_SCREENSHOTS_IDX, 28 D_SCREENSHOTS_IDX,
29 D_SDMC_IDX, 29 D_SDMC_IDX,
30 D_SAVEDATA_IDX,
30 D_SYSDATA_IDX, 31 D_SYSDATA_IDX,
32 D_SYSSAVEDATA_IDX,
31 D_HIRESTEXTURES_IDX, 33 D_HIRESTEXTURES_IDX,
32 D_DUMP_IDX, 34 D_DUMP_IDX,
33 D_DUMPFRAMES_IDX, 35 D_DUMPFRAMES_IDX,
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 198e4afd3..3381524e3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -18,11 +18,12 @@ set(SRCS
18 arm/skyeye_common/vfp/vfpinstr.cpp 18 arm/skyeye_common/vfp/vfpinstr.cpp
19 arm/skyeye_common/vfp/vfpsingle.cpp 19 arm/skyeye_common/vfp/vfpsingle.cpp
20 file_sys/archive_romfs.cpp 20 file_sys/archive_romfs.cpp
21 file_sys/archive_savedata.cpp
21 file_sys/archive_sdmc.cpp 22 file_sys/archive_sdmc.cpp
23 file_sys/archive_systemsavedata.cpp
24 file_sys/disk_archive.cpp
22 file_sys/file_romfs.cpp 25 file_sys/file_romfs.cpp
23 file_sys/file_sdmc.cpp
24 file_sys/directory_romfs.cpp 26 file_sys/directory_romfs.cpp
25 file_sys/directory_sdmc.cpp
26 hle/kernel/address_arbiter.cpp 27 hle/kernel/address_arbiter.cpp
27 hle/kernel/event.cpp 28 hle/kernel/event.cpp
28 hle/kernel/kernel.cpp 29 hle/kernel/kernel.cpp
@@ -99,13 +100,14 @@ set(HEADERS
99 arm/arm_interface.h 100 arm/arm_interface.h
100 file_sys/archive_backend.h 101 file_sys/archive_backend.h
101 file_sys/archive_romfs.h 102 file_sys/archive_romfs.h
103 file_sys/archive_savedata.h
102 file_sys/archive_sdmc.h 104 file_sys/archive_sdmc.h
105 file_sys/archive_systemsavedata.h
106 file_sys/disk_archive.h
103 file_sys/file_backend.h 107 file_sys/file_backend.h
104 file_sys/file_romfs.h 108 file_sys/file_romfs.h
105 file_sys/file_sdmc.h
106 file_sys/directory_backend.h 109 file_sys/directory_backend.h
107 file_sys/directory_romfs.h 110 file_sys/directory_romfs.h
108 file_sys/directory_sdmc.h
109 hle/kernel/address_arbiter.h 111 hle/kernel/address_arbiter.h
110 hle/kernel/event.h 112 hle/kernel/event.h
111 hle/kernel/kernel.h 113 hle/kernel/kernel.h
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 0d1b2e60e..63cfd03c6 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -1356,7 +1356,13 @@ mainswitch:
1356 } 1356 }
1357 break; 1357 break;
1358 1358
1359 case 0x04: /* SUB reg */ 1359 case 0x04: /* SUB reg */
1360 // Signifies UMAAL
1361 if (state->is_v6 && BITS(4, 7) == 0x09) {
1362 if (handle_v6_insn(state, instr))
1363 break;
1364 }
1365
1360#ifdef MODET 1366#ifdef MODET
1361 if (BITS (4, 7) == 0xB) { 1367 if (BITS (4, 7) == 0xB) {
1362 /* STRH immediate offset, no write-back, down, post indexed. */ 1368 /* STRH immediate offset, no write-back, down, post indexed. */
@@ -3103,12 +3109,18 @@ mainswitch:
3103 state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); 3109 state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
3104 break; 3110 break;
3105 } else if ((instr & 0x70) == 0x50) { //pkhtb 3111 } else if ((instr & 0x70) == 0x50) { //pkhtb
3106 u8 idest = BITS(12, 15); 3112 const u8 rd_idx = BITS(12, 15);
3107 u8 rfis = BITS(16, 19); 3113 const u8 rn_idx = BITS(16, 19);
3108 u8 rlast = BITS(0, 3); 3114 const u8 rm_idx = BITS(0, 3);
3109 u8 ishi = BITS(7, 11); 3115 const u8 imm5 = BITS(7, 11);
3110 if (ishi == 0)ishi = 0x20; 3116
3111 state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); 3117 ARMword val;
3118 if (imm5 >= 32)
3119 val = (state->Reg[rm_idx] >> 31);
3120 else
3121 val = (state->Reg[rm_idx] >> imm5);
3122
3123 state->Reg[rd_idx] = (val & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000);
3112 break; 3124 break;
3113 } else if (BIT (4)) { 3125 } else if (BIT (4)) {
3114#ifdef MODE32 3126#ifdef MODE32
@@ -5674,8 +5686,24 @@ L_stm_s_takeabort:
5674 case 0x03: 5686 case 0x03:
5675 printf ("Unhandled v6 insn: ldr\n"); 5687 printf ("Unhandled v6 insn: ldr\n");
5676 break; 5688 break;
5677 case 0x04: 5689 case 0x04: // UMAAL
5678 printf ("Unhandled v6 insn: umaal\n"); 5690 {
5691 const u8 rm_idx = BITS(8, 11);
5692 const u8 rn_idx = BITS(0, 3);
5693 const u8 rd_lo_idx = BITS(12, 15);
5694 const u8 rd_hi_idx = BITS(16, 19);
5695
5696 const u32 rm_val = state->Reg[rm_idx];
5697 const u32 rn_val = state->Reg[rn_idx];
5698 const u32 rd_lo_val = state->Reg[rd_lo_idx];
5699 const u32 rd_hi_val = state->Reg[rd_hi_idx];
5700
5701 const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val;
5702
5703 state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF);
5704 state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF);
5705 return 1;
5706 }
5679 break; 5707 break;
5680 case 0x06: 5708 case 0x06:
5681 printf ("Unhandled v6 insn: mls/str\n"); 5709 printf ("Unhandled v6 insn: mls/str\n");
@@ -5796,83 +5824,102 @@ L_stm_s_takeabort:
5796 case 0x3f: 5824 case 0x3f:
5797 printf ("Unhandled v6 insn: rbit\n"); 5825 printf ("Unhandled v6 insn: rbit\n");
5798 break; 5826 break;
5799 case 0x61: 5827 case 0x61: // SSUB16, SADD16, SSAX, and SASX
5800 if ((instr & 0xFF0) == 0xf70) { //ssub16 5828 if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 ||
5801 u8 tar = BITS(12, 15); 5829 (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30)
5802 u8 src1 = BITS(16, 19); 5830 {
5803 u8 src2 = BITS(0, 3); 5831 const u8 rd_idx = BITS(12, 15);
5804 s16 a1 = (state->Reg[src1] & 0xFFFF); 5832 const u8 rm_idx = BITS(0, 3);
5805 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5833 const u8 rn_idx = BITS(16, 19);
5806 s16 b1 = (state->Reg[src2] & 0xFFFF); 5834 const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
5807 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5835 const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF);
5808 state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10); 5836 const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
5809 return 1; 5837 const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF);
5810 } else if ((instr & 0xFF0) == 0xf10) { //sadd16 5838
5811 u8 tar = BITS(12, 15); 5839 s32 lo_result;
5812 u8 src1 = BITS(16, 19); 5840 s32 hi_result;
5813 u8 src2 = BITS(0, 3); 5841
5814 s16 a1 = (state->Reg[src1] & 0xFFFF); 5842 // SSUB16
5815 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5843 if ((instr & 0xFF0) == 0xf70) {
5816 s16 b1 = (state->Reg[src2] & 0xFFFF); 5844 lo_result = (rn_lo - rm_lo);
5817 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5845 hi_result = (rn_hi - rm_hi);
5818 state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2) & 0xFFFF) << 0x10); 5846 }
5819 return 1; 5847 // SADD16
5820 } else if ((instr & 0xFF0) == 0xf50) { //ssax 5848 else if ((instr & 0xFF0) == 0xf10) {
5821 u8 tar = BITS(12, 15); 5849 lo_result = (rn_lo + rm_lo);
5822 u8 src1 = BITS(16, 19); 5850 hi_result = (rn_hi + rm_hi);
5823 u8 src2 = BITS(0, 3); 5851 }
5824 s16 a1 = (state->Reg[src1] & 0xFFFF); 5852 // SSAX
5825 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5853 else if ((instr & 0xFF0) == 0xf50) {
5826 s16 b1 = (state->Reg[src2] & 0xFFFF); 5854 lo_result = (rn_lo + rm_hi);
5827 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5855 hi_result = (rn_hi - rm_lo);
5828 state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10); 5856 }
5829 return 1; 5857 // SASX
5830 } else if ((instr & 0xFF0) == 0xf30) { //sasx 5858 else {
5831 u8 tar = BITS(12, 15); 5859 lo_result = (rn_lo - rm_hi);
5832 u8 src1 = BITS(16, 19); 5860 hi_result = (rn_hi + rm_lo);
5833 u8 src2 = BITS(0, 3); 5861 }
5834 s16 a1 = (state->Reg[src1] & 0xFFFF); 5862
5835 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5863 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5836 s16 b1 = (state->Reg[src2] & 0xFFFF); 5864
5837 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5865 if (lo_result >= 0) {
5838 state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); 5866 state->Cpsr |= (1 << 16);
5867 state->Cpsr |= (1 << 17);
5868 } else {
5869 state->Cpsr &= ~(1 << 16);
5870 state->Cpsr &= ~(1 << 17);
5871 }
5872
5873 if (hi_result >= 0) {
5874 state->Cpsr |= (1 << 18);
5875 state->Cpsr |= (1 << 19);
5876 } else {
5877 state->Cpsr &= ~(1 << 18);
5878 state->Cpsr &= ~(1 << 19);
5879 }
5839 return 1; 5880 return 1;
5840 } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n"); 5881 } else {
5882 printf("Unhandled v6 insn: %08x", BITS(20, 27));
5883 }
5841 break; 5884 break;
5842 case 0x62: 5885 case 0x62: // QSUB16 and QADD16
5843 if ((instr & 0xFF0) == 0xf70) { //QSUB16 5886 if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) {
5844 u8 tar = BITS(12, 15); 5887 const u8 rd_idx = BITS(12, 15);
5845 u8 src1 = BITS(16, 19); 5888 const u8 rn_idx = BITS(16, 19);
5846 u8 src2 = BITS(0, 3); 5889 const u8 rm_idx = BITS(0, 3);
5847 s16 a1 = (state->Reg[src1] & 0xFFFF); 5890 const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
5848 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5891 const s16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF);
5849 s16 b1 = (state->Reg[src2] & 0xFFFF); 5892 const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
5850 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5893 const s16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF);
5851 s32 res1 = (a1 - b1); 5894
5852 s32 res2 = (a2 - b2); 5895 s32 lo_result;
5853 if (res1 > 0x7FFF) res1 = 0x7FFF; 5896 s32 hi_result;
5854 if (res2 > 0x7FFF) res2 = 0x7FFF; 5897
5855 if (res1 < 0x7FFF) res1 = -0x8000; 5898 // QSUB16
5856 if (res2 < 0x7FFF) res2 = -0x8000; 5899 if ((instr & 0xFF0) == 0xf70) {
5857 state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); 5900 lo_result = (rn_lo - rm_lo);
5858 return 1; 5901 hi_result = (rn_hi - rm_hi);
5859 } else if ((instr & 0xFF0) == 0xf10) { //QADD16 5902 }
5860 u8 tar = BITS(12, 15); 5903 else { // QADD16
5861 u8 src1 = BITS(16, 19); 5904 lo_result = (rn_lo + rm_lo);
5862 u8 src2 = BITS(0, 3); 5905 hi_result = (rn_hi + rm_hi);
5863 s16 a1 = (state->Reg[src1] & 0xFFFF); 5906 }
5864 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5907
5865 s16 b1 = (state->Reg[src2] & 0xFFFF); 5908 if (lo_result > 0x7FFF)
5866 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5909 lo_result = 0x7FFF;
5867 s32 res1 = (a1 + b1); 5910 else if (lo_result < -0x8000)
5868 s32 res2 = (a2 + b2); 5911 lo_result = -0x8000;
5869 if (res1 > 0x7FFF) res1 = 0x7FFF; 5912
5870 if (res2 > 0x7FFF) res2 = 0x7FFF; 5913 if (hi_result > 0x7FFF)
5871 if (res1 < 0x7FFF) res1 = -0x8000; 5914 hi_result = 0x7FFF;
5872 if (res2 < 0x7FFF) res2 = -0x8000; 5915 else if (hi_result < -0x8000)
5873 state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); 5916 hi_result = -0x8000;
5917
5918 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5874 return 1; 5919 return 1;
5875 } else printf ("Unhandled v6 insn: qadd16/qsub16\n"); 5920 } else {
5921 printf("Unhandled v6 insn: %08x", BITS(20, 27));
5922 }
5876 break; 5923 break;
5877 case 0x63: 5924 case 0x63:
5878 printf ("Unhandled v6 insn: shadd/shsub\n"); 5925 printf ("Unhandled v6 insn: shadd/shsub\n");
@@ -5922,11 +5969,29 @@ L_stm_s_takeabort:
5922 b2 = ((u8)(from >> 8) + (u8)(to >> 8)); 5969 b2 = ((u8)(from >> 8) + (u8)(to >> 8));
5923 b3 = ((u8)(from >> 16) + (u8)(to >> 16)); 5970 b3 = ((u8)(from >> 16) + (u8)(to >> 16));
5924 b4 = ((u8)(from >> 24) + (u8)(to >> 24)); 5971 b4 = ((u8)(from >> 24) + (u8)(to >> 24));
5925 if (b1 & 0xffffff00) state->Cpsr |= (1 << 16); 5972
5926 if (b2 & 0xffffff00) state->Cpsr |= (1 << 17); 5973 if (b1 & 0xffffff00)
5927 if (b3 & 0xffffff00) state->Cpsr |= (1 << 18); 5974 state->Cpsr |= (1 << 16);
5928 if (b4 & 0xffffff00) state->Cpsr |= (1 << 19); 5975 else
5976 state->Cpsr &= ~(1 << 16);
5977
5978 if (b2 & 0xffffff00)
5979 state->Cpsr |= (1 << 17);
5980 else
5981 state->Cpsr &= ~(1 << 17);
5982
5983 if (b3 & 0xffffff00)
5984 state->Cpsr |= (1 << 18);
5985 else
5986 state->Cpsr &= ~(1 << 18);
5987
5988
5989 if (b4 & 0xffffff00)
5990 state->Cpsr |= (1 << 19);
5991 else
5992 state->Cpsr &= ~(1 << 19);
5929 } 5993 }
5994
5930 state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); 5995 state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24);
5931 return 1; 5996 return 1;
5932 } 5997 }
@@ -6041,7 +6106,7 @@ L_stm_s_takeabort:
6041 break; 6106 break;
6042 } 6107 }
6043 6108
6044 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); 6109 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
6045 if (Rm & 0x80) 6110 if (Rm & 0x80)
6046 Rm |= 0xffffff00; 6111 Rm |= 0xffffff00;
6047 6112
@@ -6050,11 +6115,12 @@ L_stm_s_takeabort:
6050 state->Reg[BITS(12, 15)] = Rm; 6115 state->Reg[BITS(12, 15)] = Rm;
6051 else 6116 else
6052 /* SXTAB */ 6117 /* SXTAB */
6053 state->Reg[BITS(12, 15)] += Rm; 6118 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm;
6054 6119
6055 return 1; 6120 return 1;
6056 } 6121 }
6057 case 0x6b: { 6122 case 0x6b:
6123 {
6058 ARMword Rm; 6124 ARMword Rm;
6059 int ror = -1; 6125 int ror = -1;
6060 6126
@@ -6072,10 +6138,10 @@ L_stm_s_takeabort:
6072 ror = 24; 6138 ror = 24;
6073 break; 6139 break;
6074 6140
6075 case 0xf3: 6141 case 0xf3: // REV
6076 DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); 6142 DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24);
6077 return 1; 6143 return 1;
6078 case 0xfb: 6144 case 0xfb: // REV16
6079 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); 6145 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8);
6080 return 1; 6146 return 1;
6081 default: 6147 default:
@@ -6085,7 +6151,7 @@ L_stm_s_takeabort:
6085 if (ror == -1) 6151 if (ror == -1)
6086 break; 6152 break;
6087 6153
6088 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); 6154 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
6089 if (Rm & 0x8000) 6155 if (Rm & 0x8000)
6090 Rm |= 0xffff0000; 6156 Rm |= 0xffff0000;
6091 6157
@@ -6148,18 +6214,27 @@ L_stm_s_takeabort:
6148 //ichfly 6214 //ichfly
6149 //USAT16 6215 //USAT16
6150 { 6216 {
6151 u8 tar = BITS(12, 15); 6217 const u8 rd_idx = BITS(12, 15);
6152 u8 src = BITS(0, 3); 6218 const u8 rn_idx = BITS(0, 3);
6153 u8 val = BITS(16, 19); 6219 const u8 num_bits = BITS(16, 19);
6154 s16 a1 = (state->Reg[src]); 6220 const s16 max = 0xFFFF >> (16 - num_bits);
6155 s16 a2 = (state->Reg[src] >> 0x10); 6221 s16 rn_lo = (state->Reg[rn_idx]);
6156 s16 max = 0xFFFF >> (16 - val); 6222 s16 rn_hi = (state->Reg[rn_idx] >> 16);
6157 if (max < a1) a1 = max; 6223
6158 if (max < a2) a2 = max; 6224 if (max < rn_lo)
6159 u32 temp2 = ((u32)(a2)) << 0x10; 6225 rn_lo = max;
6160 state->Reg[tar] = (a1 & 0xFFFF) | (temp2); 6226 else if (rn_lo < 0)
6227 rn_lo = 0;
6228
6229 if (max < rn_hi)
6230 rn_hi = max;
6231 else if (rn_hi < 0)
6232 rn_hi = 0;
6233
6234 state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF);
6235 return 1;
6161 } 6236 }
6162 return 1; 6237
6163 default: 6238 default:
6164 break; 6239 break;
6165 } 6240 }
@@ -6172,7 +6247,7 @@ L_stm_s_takeabort:
6172 break; 6247 break;
6173 } 6248 }
6174 6249
6175 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); 6250 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
6176 6251
6177 if (BITS(16, 19) == 0xf) 6252 if (BITS(16, 19) == 0xf)
6178 /* UXTB */ 6253 /* UXTB */
@@ -6202,9 +6277,13 @@ L_stm_s_takeabort:
6202 ror = 24; 6277 ror = 24;
6203 break; 6278 break;
6204 6279
6205 case 0xfb: 6280 case 0xfb: // REVSH
6206 printf("Unhandled v6 insn: revsh\n"); 6281 {
6207 return 0; 6282 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8);
6283 if (DEST & 0x8000)
6284 DEST |= 0xffff0000;
6285 return 1;
6286 }
6208 default: 6287 default:
6209 break; 6288 break;
6210 } 6289 }
@@ -6212,13 +6291,13 @@ L_stm_s_takeabort:
6212 if (ror == -1) 6291 if (ror == -1)
6213 break; 6292 break;
6214 6293
6215 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); 6294 Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
6216 6295
6217 /* UXT */ 6296 /* UXT */
6218 /* state->Reg[BITS (12, 15)] = Rm; */ 6297 /* state->Reg[BITS (12, 15)] = Rm; */
6219 /* dyf add */ 6298 /* dyf add */
6220 if (BITS(16, 19) == 0xf) { 6299 if (BITS(16, 19) == 0xf) {
6221 state->Reg[BITS(12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF; 6300 state->Reg[BITS(12, 15)] = Rm;
6222 } 6301 }
6223 else { 6302 else {
6224 /* UXTAH */ 6303 /* UXTAH */
@@ -6226,7 +6305,7 @@ L_stm_s_takeabort:
6226 // printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] 6305 // printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)]
6227 // , Rm, BITS(10, 11)); 6306 // , Rm, BITS(10, 11));
6228 // printf("icounter is %lld\n", state->NumInstrs); 6307 // printf("icounter is %lld\n", state->NumInstrs);
6229 state->Reg[BITS(12, 15)] = (state->Reg[BITS(16, 19)] >> (8 * (BITS(10, 11)))) + Rm; 6308 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm;
6230 // printf("rd is %x\n", state->Reg[BITS (12, 15)]); 6309 // printf("rd is %x\n", state->Reg[BITS (12, 15)]);
6231 // exit(-1); 6310 // exit(-1);
6232 } 6311 }
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
new file mode 100644
index 000000000..2414564e4
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_savedata.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)
20 : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) {
21 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
22}
23
24bool Archive_SaveData::Initialize() {
25 if (!FileUtil::CreateFullPath(mount_point)) {
26 LOG_ERROR(Service_FS, "Unable to create SaveData path.");
27 return false;
28 }
29
30 return true;
31}
32
33} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
new file mode 100644
index 000000000..d394ad37e
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.h
@@ -0,0 +1,31 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SaveData archive
18class Archive_SaveData final : public DiskArchive {
19public:
20 Archive_SaveData(const std::string& mount_point, u64 program_id);
21
22 /**
23 * Initialize the archive.
24 * @return true if it initialized successfully
25 */
26 bool Initialize();
27
28 std::string GetName() const override { return "SaveData"; }
29};
30
31} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 9d58668e0..dccdf7f67 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -8,8 +8,7 @@
8#include "common/file_util.h" 8#include "common/file_util.h"
9 9
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory_sdmc.h" 11#include "core/file_sys/disk_archive.h"
12#include "core/file_sys/file_sdmc.h"
13#include "core/settings.h" 12#include "core/settings.h"
14 13
15//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -17,18 +16,10 @@
17 16
18namespace FileSys { 17namespace FileSys {
19 18
20Archive_SDMC::Archive_SDMC(const std::string& mount_point) { 19Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {
21 this->mount_point = mount_point;
22 LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); 20 LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());
23} 21}
24 22
25Archive_SDMC::~Archive_SDMC() {
26}
27
28/**
29 * Initialize the archive.
30 * @return true if it initialized successfully
31 */
32bool Archive_SDMC::Initialize() { 23bool Archive_SDMC::Initialize() {
33 if (!Settings::values.use_virtual_sd) { 24 if (!Settings::values.use_virtual_sd) {
34 LOG_WARNING(Service_FS, "SDMC disabled by config."); 25 LOG_WARNING(Service_FS, "SDMC disabled by config.");
@@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() {
43 return true; 34 return true;
44} 35}
45 36
46/**
47 * Open a file specified by its path, using the specified mode
48 * @param path Path relative to the archive
49 * @param mode Mode to open the file with
50 * @return Opened file, or nullptr
51 */
52std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
53 LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);
54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open())
56 return nullptr;
57 return std::unique_ptr<FileBackend>(file);
58}
59
60/**
61 * Delete a file specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the file could be deleted
64 */
65bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
66 return FileUtil::Delete(GetMountPoint() + path.AsString());
67}
68
69bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
70 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
71}
72
73/**
74 * Delete a directory specified by its path
75 * @param path Path relative to the archive
76 * @return Whether the directory could be deleted
77 */
78bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
79 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
80}
81
82/**
83 * Create a directory specified by its path
84 * @param path Path relative to the archive
85 * @return Whether the directory could be created
86 */
87bool Archive_SDMC::CreateDirectory(const Path& path) const {
88 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
89}
90
91bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
92 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
93}
94
95/**
96 * Open a directory specified by its path
97 * @param path Path relative to the archive
98 * @return Opened directory, or nullptr
99 */
100std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const {
101 LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
102 Directory_SDMC* directory = new Directory_SDMC(this, path);
103 if (!directory->Open())
104 return nullptr;
105 return std::unique_ptr<DirectoryBackend>(directory);
106}
107
108/**
109 * Getter for the path used for this Archive
110 * @return Mount point of that passthrough archive
111 */
112std::string Archive_SDMC::GetMountPoint() const {
113 return mount_point;
114}
115
116} // namespace FileSys 37} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 059045245..c84c6948e 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -6,7 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/file_sys/archive_backend.h" 9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,10 +15,9 @@
15namespace FileSys { 15namespace FileSys {
16 16
17/// File system interface to the SDMC archive 17/// File system interface to the SDMC archive
18class Archive_SDMC final : public ArchiveBackend { 18class Archive_SDMC final : public DiskArchive {
19public: 19public:
20 Archive_SDMC(const std::string& mount_point); 20 Archive_SDMC(const std::string& mount_point);
21 ~Archive_SDMC() override;
22 21
23 /** 22 /**
24 * Initialize the archive. 23 * Initialize the archive.
@@ -27,67 +26,6 @@ public:
27 bool Initialize(); 26 bool Initialize();
28 27
29 std::string GetName() const override { return "SDMC"; } 28 std::string GetName() const override { return "SDMC"; }
30
31 /**
32 * Open a file specified by its path, using the specified mode
33 * @param path Path relative to the archive
34 * @param mode Mode to open the file with
35 * @return Opened file, or nullptr
36 */
37 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
38
39 /**
40 * Delete a file specified by its path
41 * @param path Path relative to the archive
42 * @return Whether the file could be deleted
43 */
44 bool DeleteFile(const FileSys::Path& path) const override;
45
46 /**
47 * Rename a File specified by its path
48 * @param src_path Source path relative to the archive
49 * @param dest_path Destination path relative to the archive
50 * @return Whether rename succeeded
51 */
52 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
53
54 /**
55 * Delete a directory specified by its path
56 * @param path Path relative to the archive
57 * @return Whether the directory could be deleted
58 */
59 bool DeleteDirectory(const FileSys::Path& path) const override;
60
61 /**
62 * Create a directory specified by its path
63 * @param path Path relative to the archive
64 * @return Whether the directory could be created
65 */
66 bool CreateDirectory(const Path& path) const override;
67
68 /**
69 * Rename a Directory specified by its path
70 * @param src_path Source path relative to the archive
71 * @param dest_path Destination path relative to the archive
72 * @return Whether rename succeeded
73 */
74 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
75
76 /**
77 * Open a directory specified by its path
78 * @param path Path relative to the archive
79 * @return Opened directory, or nullptr
80 */
81 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
82
83 /**
84 * Getter for the path used for this Archive
85 * @return Mount point of that passthrough archive
86 */
87 std::string GetMountPoint() const;
88
89private:
90 std::string mount_point;
91}; 29};
92 30
93} // namespace FileSys 31} // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
new file mode 100644
index 000000000..dc2c23b41
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_systemsavedata.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point)
20 : DiskArchive(mount_point) {
21 LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str());
22}
23
24bool Archive_SystemSaveData::Initialize() {
25 if (!FileUtil::CreateFullPath(mount_point)) {
26 LOG_ERROR(Service_FS, "Unable to create SystemSaveData path.");
27 return false;
28 }
29
30 return true;
31}
32
33} // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
new file mode 100644
index 000000000..360ed1e13
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SystemSaveData archive
18/// TODO(Subv): This archive should point to a location in the NAND,
19/// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High>
20class Archive_SystemSaveData final : public DiskArchive {
21public:
22 Archive_SystemSaveData(const std::string& mount_point);
23
24 /**
25 * Initialize the archive.
26 * @return true if it initialized successfully
27 */
28 bool Initialize();
29
30 std::string GetName() const override { return "SystemSaveData"; }
31};
32
33} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
deleted file mode 100644
index 519787641..000000000
--- a/src/core/file_sys/directory_sdmc.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../usr/bin can give the emulated program your installed programs.
22 this->path = archive->GetMountPoint() + path.AsString();
23
24}
25
26Directory_SDMC::~Directory_SDMC() {
27 Close();
28}
29
30bool Directory_SDMC::Open() {
31 if (!FileUtil::IsDirectory(path))
32 return false;
33 FileUtil::ScanDirectoryTree(path, directory);
34 children_iterator = directory.children.begin();
35 return true;
36}
37
38/**
39 * List files contained in the directory
40 * @param count Number of entries to return at once in entries
41 * @param entries Buffer to read data into
42 * @return Number of entries listed
43 */
44u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
45 u32 entries_read = 0;
46
47 while (entries_read < count && children_iterator != directory.children.cend()) {
48 const FileUtil::FSTEntry& file = *children_iterator;
49 const std::string& filename = file.virtualName;
50 Entry& entry = entries[entries_read];
51
52 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
53
54 // TODO(Link Mauve): use a proper conversion to UTF-16.
55 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
56 entry.filename[j] = filename[j];
57 if (!filename[j])
58 break;
59 }
60
61 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
62
63 entry.is_directory = file.isDirectory;
64 entry.is_hidden = (filename[0] == '.');
65 entry.is_read_only = 0;
66 entry.file_size = file.size;
67
68 // We emulate a SD card where the archive bit has never been cleared, as it would be on
69 // most user SD cards.
70 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
71 // file bit.
72 entry.is_archive = !file.isDirectory;
73
74 ++entries_read;
75 ++children_iterator;
76 }
77 return entries_read;
78}
79
80/**
81 * Close the directory
82 * @return true if the directory closed correctly
83 */
84bool Directory_SDMC::Close() const {
85 return true;
86}
87
88} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
deleted file mode 100644
index 407a256ef..000000000
--- a/src/core/file_sys/directory_sdmc.h
+++ /dev/null
@@ -1,55 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_backend.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class Directory_SDMC final : public DirectoryBackend {
20public:
21 Directory_SDMC();
22 Directory_SDMC(const Archive_SDMC* archive, const Path& path);
23 ~Directory_SDMC() override;
24
25 /**
26 * Open the directory
27 * @return true if the directory opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * List files contained in the directory
33 * @param count Number of entries to return at once in entries
34 * @param entries Buffer to read data into
35 * @return Number of entries listed
36 */
37 u32 Read(const u32 count, Entry* entries) override;
38
39 /**
40 * Close the directory
41 * @return true if the directory closed correctly
42 */
43 bool Close() const override;
44
45private:
46 std::string path;
47 u32 total_entries_in_directory;
48 FileUtil::FSTEntry directory;
49
50 // We need to remember the last entry we returned, so a subsequent call to Read will continue
51 // from the next one. This iterator will always point to the next unread entry.
52 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
53};
54
55} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
new file mode 100644
index 000000000..eabf58057
--- /dev/null
+++ b/src/core/file_sys/disk_archive.cpp
@@ -0,0 +1,167 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/disk_archive.h"
11#include "core/settings.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
19 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
20 DiskFile* file = new DiskFile(this, path, mode);
21 if (!file->Open())
22 return nullptr;
23 return std::unique_ptr<FileBackend>(file);
24}
25
26bool DiskArchive::DeleteFile(const FileSys::Path& path) const {
27 return FileUtil::Delete(GetMountPoint() + path.AsString());
28}
29
30bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
31 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
32}
33
34bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const {
35 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
36}
37
38bool DiskArchive::CreateDirectory(const Path& path) const {
39 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
40}
41
42bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
43 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
44}
45
46std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const {
47 LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
48 DiskDirectory* directory = new DiskDirectory(this, path);
49 if (!directory->Open())
50 return nullptr;
51 return std::unique_ptr<DirectoryBackend>(directory);
52}
53
54////////////////////////////////////////////////////////////////////////////////////////////////////
55
56DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) {
57 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
58 // the root directory we set while opening the archive.
59 // For example, opening /../../etc/passwd can give the emulated program your users list.
60 this->path = archive->GetMountPoint() + path.AsString();
61 this->mode.hex = mode.hex;
62 this->archive = archive;
63}
64
65bool DiskFile::Open() {
66 if (!mode.create_flag && !FileUtil::Exists(path)) {
67 LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
68 return false;
69 }
70
71 std::string mode_string;
72 if (mode.create_flag)
73 mode_string = "w+";
74 else if (mode.write_flag)
75 mode_string = "r+"; // Files opened with Write access can be read from
76 else if (mode.read_flag)
77 mode_string = "r";
78
79 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
80 mode_string += "b";
81
82 file = new FileUtil::IOFile(path, mode_string.c_str());
83 return true;
84}
85
86size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
87 file->Seek(offset, SEEK_SET);
88 return file->ReadBytes(buffer, length);
89}
90
91size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
92 file->Seek(offset, SEEK_SET);
93 size_t written = file->WriteBytes(buffer, length);
94 if (flush)
95 file->Flush();
96 return written;
97}
98
99size_t DiskFile::GetSize() const {
100 return static_cast<size_t>(file->GetSize());
101}
102
103bool DiskFile::SetSize(const u64 size) const {
104 file->Resize(size);
105 file->Flush();
106 return true;
107}
108
109bool DiskFile::Close() const {
110 return file->Close();
111}
112
113////////////////////////////////////////////////////////////////////////////////////////////////////
114
115DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) {
116 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
117 // the root directory we set while opening the archive.
118 // For example, opening /../../usr/bin can give the emulated program your installed programs.
119 this->path = archive->GetMountPoint() + path.AsString();
120 this->archive = archive;
121}
122
123bool DiskDirectory::Open() {
124 if (!FileUtil::IsDirectory(path))
125 return false;
126 FileUtil::ScanDirectoryTree(path, directory);
127 children_iterator = directory.children.begin();
128 return true;
129}
130
131u32 DiskDirectory::Read(const u32 count, Entry* entries) {
132 u32 entries_read = 0;
133
134 while (entries_read < count && children_iterator != directory.children.cend()) {
135 const FileUtil::FSTEntry& file = *children_iterator;
136 const std::string& filename = file.virtualName;
137 Entry& entry = entries[entries_read];
138
139 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
140
141 // TODO(Link Mauve): use a proper conversion to UTF-16.
142 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
143 entry.filename[j] = filename[j];
144 if (!filename[j])
145 break;
146 }
147
148 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
149
150 entry.is_directory = file.isDirectory;
151 entry.is_hidden = (filename[0] == '.');
152 entry.is_read_only = 0;
153 entry.file_size = file.size;
154
155 // We emulate a SD card where the archive bit has never been cleared, as it would be on
156 // most user SD cards.
157 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
158 // file bit.
159 entry.is_archive = !file.isDirectory;
160
161 ++entries_read;
162 ++children_iterator;
163 }
164 return entries_read;
165}
166
167} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
new file mode 100644
index 000000000..778c83953
--- /dev/null
+++ b/src/core/file_sys/disk_archive.h
@@ -0,0 +1,101 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/**
18 * Helper which implements a backend accessing the host machine's filesystem.
19 * This should be subclassed by concrete archive types, which will provide the
20 * base directory on the host filesystem and override any required functionality.
21 */
22class DiskArchive : public ArchiveBackend {
23public:
24 DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
25
26 virtual std::string GetName() const = 0;
27 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
28 bool DeleteFile(const FileSys::Path& path) const override;
29 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
30 bool DeleteDirectory(const FileSys::Path& path) const override;
31 bool CreateDirectory(const Path& path) const override;
32 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
33 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
34
35 /**
36 * Getter for the path used for this Archive
37 * @return Mount point of that passthrough archive
38 */
39 const std::string& GetMountPoint() const {
40 return mount_point;
41 }
42
43protected:
44 std::string mount_point;
45};
46
47class DiskFile : public FileBackend {
48public:
49 DiskFile();
50 DiskFile(const DiskArchive* archive, const Path& path, const Mode mode);
51
52 ~DiskFile() override {
53 Close();
54 }
55
56 bool Open() override;
57 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
58 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
59 size_t GetSize() const override;
60 bool SetSize(const u64 size) const override;
61 bool Close() const override;
62
63 void Flush() const override {
64 file->Flush();
65 }
66
67protected:
68 const DiskArchive* archive;
69 std::string path;
70 Mode mode;
71 FileUtil::IOFile* file;
72};
73
74class DiskDirectory : public DirectoryBackend {
75public:
76 DiskDirectory();
77 DiskDirectory(const DiskArchive* archive, const Path& path);
78
79 ~DiskDirectory() override {
80 Close();
81 }
82
83 bool Open() override;
84 u32 Read(const u32 count, Entry* entries) override;
85
86 bool Close() const override {
87 return true;
88 }
89
90protected:
91 const DiskArchive* archive;
92 std::string path;
93 u32 total_entries_in_directory;
94 FileUtil::FSTEntry directory;
95
96 // We need to remember the last entry we returned, so a subsequent call to Read will continue
97 // from the next one. This iterator will always point to the next unread entry.
98 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
99};
100
101} // namespace FileSys
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 1b81d5fe9..539ec7314 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -61,6 +61,11 @@ public:
61 * @return true if the file closed correctly 61 * @return true if the file closed correctly
62 */ 62 */
63 virtual bool Close() const = 0; 63 virtual bool Close() const = 0;
64
65 /**
66 * Flushes the file
67 */
68 virtual void Flush() const = 0;
64}; 69};
65 70
66} // namespace FileSys 71} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h
index 09fa2e7e3..32fa6b6d3 100644
--- a/src/core/file_sys/file_romfs.h
+++ b/src/core/file_sys/file_romfs.h
@@ -64,6 +64,8 @@ public:
64 */ 64 */
65 bool Close() const override; 65 bool Close() const override;
66 66
67 void Flush() const override { }
68
67private: 69private:
68 const Archive_RomFS* archive; 70 const Archive_RomFS* archive;
69}; 71};
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
deleted file mode 100644
index 46c29900b..000000000
--- a/src/core/file_sys/file_sdmc.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../etc/passwd can give the emulated program your users list.
22 this->path = archive->GetMountPoint() + path.AsString();
23 this->mode.hex = mode.hex;
24}
25
26File_SDMC::~File_SDMC() {
27 Close();
28}
29
30/**
31 * Open the file
32 * @return true if the file opened correctly
33 */
34bool File_SDMC::Open() {
35 if (!mode.create_flag && !FileUtil::Exists(path)) {
36 LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
37 return false;
38 }
39
40 std::string mode_string;
41 if (mode.create_flag)
42 mode_string = "w+";
43 else if (mode.write_flag)
44 mode_string = "r+"; // Files opened with Write access can be read from
45 else if (mode.read_flag)
46 mode_string = "r";
47
48 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
49 mode_string += "b";
50
51 file = new FileUtil::IOFile(path, mode_string.c_str());
52 return true;
53}
54
55/**
56 * Read data from the file
57 * @param offset Offset in bytes to start reading data from
58 * @param length Length in bytes of data to read from file
59 * @param buffer Buffer to read data into
60 * @return Number of bytes read
61 */
62size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
63 file->Seek(offset, SEEK_SET);
64 return file->ReadBytes(buffer, length);
65}
66
67/**
68 * Write data to the file
69 * @param offset Offset in bytes to start writing data to
70 * @param length Length in bytes of data to write to file
71 * @param flush The flush parameters (0 == do not flush)
72 * @param buffer Buffer to read data from
73 * @return Number of bytes written
74 */
75size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
76 file->Seek(offset, SEEK_SET);
77 size_t written = file->WriteBytes(buffer, length);
78 if (flush)
79 file->Flush();
80 return written;
81}
82
83/**
84 * Get the size of the file in bytes
85 * @return Size of the file in bytes
86 */
87size_t File_SDMC::GetSize() const {
88 return static_cast<size_t>(file->GetSize());
89}
90
91/**
92 * Set the size of the file in bytes
93 * @param size New size of the file
94 * @return true if successful
95 */
96bool File_SDMC::SetSize(const u64 size) const {
97 file->Resize(size);
98 file->Flush();
99 return true;
100}
101
102/**
103 * Close the file
104 * @return true if the file closed correctly
105 */
106bool File_SDMC::Close() const {
107 return file->Close();
108}
109
110} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h
deleted file mode 100644
index e01548598..000000000
--- a/src/core/file_sys/file_sdmc.h
+++ /dev/null
@@ -1,75 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_backend.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class File_SDMC final : public FileBackend {
20public:
21 File_SDMC();
22 File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
23 ~File_SDMC() override;
24
25 /**
26 * Open the file
27 * @return true if the file opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * Read data from the file
33 * @param offset Offset in bytes to start reading data from
34 * @param length Length in bytes of data to read from file
35 * @param buffer Buffer to read data into
36 * @return Number of bytes read
37 */
38 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
39
40 /**
41 * Write data to the file
42 * @param offset Offset in bytes to start writing data to
43 * @param length Length in bytes of data to write to file
44 * @param flush The flush parameters (0 == do not flush)
45 * @param buffer Buffer to read data from
46 * @return Number of bytes written
47 */
48 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
49
50 /**
51 * Get the size of the file in bytes
52 * @return Size of the file in bytes
53 */
54 size_t GetSize() const override;
55
56 /**
57 * Set the size of the file in bytes
58 * @param size New size of the file
59 * @return true if successful
60 */
61 bool SetSize(const u64 size) const override;
62
63 /**
64 * Close the file
65 * @return true if the file closed correctly
66 */
67 bool Close() const override;
68
69private:
70 std::string path;
71 Mode mode;
72 FileUtil::IOFile* file;
73};
74
75} // namespace FileSys
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 929422b36..6a690e915 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -14,6 +14,7 @@ namespace Kernel {
14 14
15Handle g_main_thread = 0; 15Handle g_main_thread = 0;
16ObjectPool g_object_pool; 16ObjectPool g_object_pool;
17u64 g_program_id = 0;
17 18
18ObjectPool::ObjectPool() { 19ObjectPool::ObjectPool() {
19 next_id = INITIAL_NEXT_ID; 20 next_id = INITIAL_NEXT_ID;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7e0f15c84..7123485be 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -151,6 +151,12 @@ private:
151extern ObjectPool g_object_pool; 151extern ObjectPool g_object_pool;
152extern Handle g_main_thread; 152extern Handle g_main_thread;
153 153
154/// The ID code of the currently running game
155/// TODO(Subv): This variable should not be here,
156/// we need a way to store information about the currently loaded application
157/// for later query during runtime, maybe using the LDR service?
158extern u64 g_program_id;
159
154/// Initialize the kernel 160/// Initialize the kernel
155void Init(); 161void Init();
156 162
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 304cf5b67..bb778ec26 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -12,11 +12,15 @@ namespace Kernel {
12 12
13/// Permissions for mapped shared memory blocks 13/// Permissions for mapped shared memory blocks
14enum class MemoryPermission : u32 { 14enum class MemoryPermission : u32 {
15 None = 0, 15 None = 0,
16 Read = (1u << 0), 16 Read = (1u << 0),
17 Write = (1u << 1), 17 Write = (1u << 1),
18 ReadWrite = (Read | Write), 18 ReadWrite = (Read | Write),
19 DontCare = (1u << 28) 19 Execute = (1u << 2),
20 ReadExecute = (Read | Execute),
21 WriteExecute = (Write | Execute),
22 ReadWriteExecute = (Read | Write | Execute),
23 DontCare = (1u << 28)
20}; 24};
21 25
22/** 26/**
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 15c4a2677..14d2be4a2 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -17,6 +17,8 @@
17/// Detailed description of the error. This listing is likely incomplete. 17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 { 18enum class ErrorDescription : u32 {
19 Success = 0, 19 Success = 0,
20 FS_NotFound = 100,
21 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
20 InvalidSection = 1000, 22 InvalidSection = 1000,
21 TooLarge = 1001, 23 TooLarge = 1001,
22 NotAuthorized = 1002, 24 NotAuthorized = 1002,
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index caf82d556..5ab82729c 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -9,6 +9,7 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/math_util.h" 10#include "common/math_util.h"
11 11
12#include "core/file_sys/archive_savedata.h"
12#include "core/file_sys/archive_backend.h" 13#include "core/file_sys/archive_backend.h"
13#include "core/file_sys/archive_sdmc.h" 14#include "core/file_sys/archive_sdmc.h"
14#include "core/file_sys/directory_backend.h" 15#include "core/file_sys/directory_backend.h"
@@ -135,6 +136,13 @@ public:
135 break; 136 break;
136 } 137 }
137 138
139 case FileCommand::Flush:
140 {
141 LOG_TRACE(Service_FS, "Flush");
142 backend->Flush();
143 break;
144 }
145
138 // Unknown command... 146 // Unknown command...
139 default: 147 default:
140 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); 148 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
@@ -220,9 +228,18 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) {
220 228
221 auto itr = id_code_map.find(id_code); 229 auto itr = id_code_map.find(id_code);
222 if (itr == id_code_map.end()) { 230 if (itr == id_code_map.end()) {
231 if (id_code == ArchiveIdCode::SaveData) {
232 // When a SaveData archive is created for the first time, it is not yet formatted
233 // and the save file/directory structure expected by the game has not yet been initialized.
234 // Returning the NotFormatted error code will signal the game to provision the SaveData archive
235 // with the files and folders that it expects.
236 // The FormatSaveData service call will create the SaveData archive when it is called.
237 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
238 ErrorSummary::InvalidState, ErrorLevel::Status);
239 }
223 // TODO: Verify error against hardware 240 // TODO: Verify error against hardware
224 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, 241 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
225 ErrorSummary::NotFound, ErrorLevel::Permanent); 242 ErrorSummary::NotFound, ErrorLevel::Permanent);
226 } 243 }
227 244
228 // This should never even happen in the first place with 64-bit handles, 245 // This should never even happen in the first place with 64-bit handles,
@@ -260,8 +277,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy
260 277
261 std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); 278 std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode);
262 if (backend == nullptr) { 279 if (backend == nullptr) {
263 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, 280 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
264 ErrorSummary::NotFound, ErrorLevel::Permanent); 281 ErrorSummary::NotFound, ErrorLevel::Status);
265 } 282 }
266 283
267 auto file = std::make_unique<File>(std::move(backend), path); 284 auto file = std::make_unique<File>(std::move(backend), path);
@@ -366,6 +383,28 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F
366 return MakeResult<Handle>(handle); 383 return MakeResult<Handle>(handle);
367} 384}
368 385
386ResultCode FormatSaveData() {
387 // TODO(Subv): Actually wipe the savedata folder after creating or opening it
388
389 // Do not create the archive again if it already exists
390 if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end())
391 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code
392
393 // Create the SaveData archive
394 std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX);
395 auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory,
396 Kernel::g_program_id);
397
398 if (savedata_archive->Initialize()) {
399 CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData);
400 return RESULT_SUCCESS;
401 } else {
402 LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s",
403 savedata_archive->GetMountPoint().c_str());
404 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code
405 }
406}
407
369/// Initialize archives 408/// Initialize archives
370void ArchiveInit() { 409void ArchiveInit() {
371 next_handle = 1; 410 next_handle = 1;
@@ -375,11 +414,20 @@ void ArchiveInit() {
375 // archive type is SDMC, so it is the only one getting exposed. 414 // archive type is SDMC, so it is the only one getting exposed.
376 415
377 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); 416 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
378 auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); 417 auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
379 if (archive->Initialize()) 418 if (sdmc_archive->Initialize())
380 CreateArchive(std::move(archive), ArchiveIdCode::SDMC); 419 CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);
381 else 420 else
382 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 421 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
422
423 std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX);
424 auto systemsavedata_archive = std::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory);
425 if (systemsavedata_archive->Initialize()) {
426 CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData);
427 } else {
428 LOG_ERROR(Service_FS, "Can't instantiate SystemSaveData archive with path %s",
429 systemsavedata_directory.c_str());
430 }
383} 431}
384 432
385/// Shutdown archives 433/// Shutdown archives
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index a38de92e3..a128276b6 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -109,6 +109,12 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons
109 */ 109 */
110ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); 110ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
111 111
112/**
113 * Creates a blank SaveData archive.
114 * @return ResultCode 0 on success or the corresponding code on error
115 */
116ResultCode FormatSaveData();
117
112/// Initialize archives 118/// Initialize archives
113void ArchiveInit(); 119void ArchiveInit();
114 120
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 0f75d5e3a..f99d84b2f 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -3,11 +3,11 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
6#include "common/file_util.h"
6#include "common/scope_exit.h" 7#include "common/scope_exit.h"
7
8#include "common/string_util.h" 8#include "common/string_util.h"
9#include "core/hle/service/fs/archive.h"
10#include "core/hle/result.h" 9#include "core/hle/result.h"
10#include "core/hle/service/fs/archive.h"
11#include "core/hle/service/fs/fs_user.h" 11#include "core/hle/service/fs/fs_user.h"
12#include "core/settings.h" 12#include "core/settings.h"
13 13
@@ -50,9 +50,7 @@ static void Initialize(Service::Interface* self) {
50static void OpenFile(Service::Interface* self) { 50static void OpenFile(Service::Interface* self) {
51 u32* cmd_buff = Kernel::GetCommandBuffer(); 51 u32* cmd_buff = Kernel::GetCommandBuffer();
52 52
53 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to 53 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
54 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
55 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
56 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); 54 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
57 u32 filename_size = cmd_buff[5]; 55 u32 filename_size = cmd_buff[5];
58 FileSys::Mode mode; mode.hex = cmd_buff[6]; 56 FileSys::Mode mode; mode.hex = cmd_buff[6];
@@ -398,6 +396,36 @@ static void IsSdmcDetected(Service::Interface* self) {
398 LOG_DEBUG(Service_FS, "called"); 396 LOG_DEBUG(Service_FS, "called");
399} 397}
400 398
399/**
400 * FS_User::FormatSaveData service function
401 * Inputs:
402 * Outputs:
403 * 1 : Result of function, 0 on success, otherwise error code
404 */
405static void FormatSaveData(Service::Interface* self) {
406 u32* cmd_buff = Kernel::GetCommandBuffer();
407 LOG_DEBUG(Service_FS, "(STUBBED)");
408
409 // TODO(Subv): Find out what the inputs and outputs of this function are
410
411 cmd_buff[1] = FormatSaveData().raw;
412}
413
414/**
415 * FS_User::FormatThisUserSaveData service function
416 * Inputs:
417 * Outputs:
418 * 1 : Result of function, 0 on success, otherwise error code
419 */
420static void FormatThisUserSaveData(Service::Interface* self) {
421 u32* cmd_buff = Kernel::GetCommandBuffer();
422 LOG_DEBUG(Service_FS, "(STUBBED)");
423
424 // TODO(Subv): Find out what the inputs and outputs of this function are
425
426 cmd_buff[1] = FormatSaveData().raw;
427}
428
401const FSUserInterface::FunctionInfo FunctionTable[] = { 429const FSUserInterface::FunctionInfo FunctionTable[] = {
402 {0x000100C6, nullptr, "Dummy1"}, 430 {0x000100C6, nullptr, "Dummy1"},
403 {0x040100C4, nullptr, "Control"}, 431 {0x040100C4, nullptr, "Control"},
@@ -415,7 +443,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
415 {0x080C00C2, OpenArchive, "OpenArchive"}, 443 {0x080C00C2, OpenArchive, "OpenArchive"},
416 {0x080D0144, nullptr, "ControlArchive"}, 444 {0x080D0144, nullptr, "ControlArchive"},
417 {0x080E0080, CloseArchive, "CloseArchive"}, 445 {0x080E0080, CloseArchive, "CloseArchive"},
418 {0x080F0180, nullptr, "FormatThisUserSaveData"}, 446 {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"},
419 {0x08100200, nullptr, "CreateSystemSaveData"}, 447 {0x08100200, nullptr, "CreateSystemSaveData"},
420 {0x08110040, nullptr, "DeleteSystemSaveData"}, 448 {0x08110040, nullptr, "DeleteSystemSaveData"},
421 {0x08120080, nullptr, "GetFreeBytes"}, 449 {0x08120080, nullptr, "GetFreeBytes"},
@@ -476,7 +504,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
476 {0x08490040, nullptr, "GetArchiveResource"}, 504 {0x08490040, nullptr, "GetArchiveResource"},
477 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, 505 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
478 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, 506 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
479 {0x084C0242, nullptr, "FormatSaveData"}, 507 {0x084C0242, FormatSaveData, "FormatSaveData"},
480 {0x084D0102, nullptr, "GetLegacySubBannerData"}, 508 {0x084D0102, nullptr, "GetLegacySubBannerData"},
481 {0x084E0342, nullptr, "UpdateSha256Context"}, 509 {0x084E0342, nullptr, "UpdateSha256Context"},
482 {0x084F0102, nullptr, "ReadSpecialFile"}, 510 {0x084F0102, nullptr, "ReadSpecialFile"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index db8027142..8c9ad2712 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -145,6 +145,30 @@ static void SetBufferSwap(Service::Interface* self) {
145} 145}
146 146
147/** 147/**
148 * GSP_GPU::FlushDataCache service function
149 *
150 * This Function is a no-op, We aren't emulating the CPU cache any time soon.
151 *
152 * Inputs:
153 * 1 : Address
154 * 2 : Size
155 * 3 : Value 0, some descriptor for the KProcess Handle
156 * 4 : KProcess handle
157 * Outputs:
158 * 1 : Result of function, 0 on success, otherwise error code
159 */
160static void FlushDataCache(Service::Interface* self) {
161 u32* cmd_buff = Kernel::GetCommandBuffer();
162 u32 address = cmd_buff[1];
163 u32 size = cmd_buff[2];
164 u32 process = cmd_buff[4];
165
166 // TODO(purpasmart96): Verify return header on HW
167
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169}
170
171/**
148 * GSP_GPU::RegisterInterruptRelayQueue service function 172 * GSP_GPU::RegisterInterruptRelayQueue service function
149 * Inputs: 173 * Inputs:
150 * 1 : "Flags" field, purpose is unknown 174 * 1 : "Flags" field, purpose is unknown
@@ -335,7 +359,7 @@ const Interface::FunctionInfo FunctionTable[] = {
335 {0x00050200, SetBufferSwap, "SetBufferSwap"}, 359 {0x00050200, SetBufferSwap, "SetBufferSwap"},
336 {0x00060082, nullptr, "SetCommandList"}, 360 {0x00060082, nullptr, "SetCommandList"},
337 {0x000700C2, nullptr, "RequestDma"}, 361 {0x000700C2, nullptr, "RequestDma"},
338 {0x00080082, nullptr, "FlushDataCache"}, 362 {0x00080082, FlushDataCache, "FlushDataCache"},
339 {0x00090082, nullptr, "InvalidateDataCache"}, 363 {0x00090082, nullptr, "InvalidateDataCache"},
340 {0x000A0044, nullptr, "RegisterInterruptEvents"}, 364 {0x000A0044, nullptr, "RegisterInterruptEvents"},
341 {0x000B0040, nullptr, "SetLcdForceBlack"}, 365 {0x000B0040, nullptr, "SetLcdForceBlack"},
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 15cc240f4..47e9bf77e 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -64,6 +64,10 @@ static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other
64 case Kernel::MemoryPermission::Read: 64 case Kernel::MemoryPermission::Read:
65 case Kernel::MemoryPermission::Write: 65 case Kernel::MemoryPermission::Write:
66 case Kernel::MemoryPermission::ReadWrite: 66 case Kernel::MemoryPermission::ReadWrite:
67 case Kernel::MemoryPermission::Execute:
68 case Kernel::MemoryPermission::ReadExecute:
69 case Kernel::MemoryPermission::WriteExecute:
70 case Kernel::MemoryPermission::ReadWriteExecute:
67 case Kernel::MemoryPermission::DontCare: 71 case Kernel::MemoryPermission::DontCare:
68 Kernel::MapSharedMemory(handle, addr, permissions_type, 72 Kernel::MapSharedMemory(handle, addr, permissions_type,
69 static_cast<Kernel::MemoryPermission>(other_permissions)); 73 static_cast<Kernel::MemoryPermission>(other_permissions));
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 463dacca3..480274d23 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -74,6 +74,7 @@ ResultStatus LoadFile(const std::string& filename) {
74 74
75 // Load application and RomFS 75 // Load application and RomFS
76 if (ResultStatus::Success == app_loader.Load()) { 76 if (ResultStatus::Success == app_loader.Load()) {
77 Kernel::g_program_id = app_loader.GetProgramId();
77 Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); 78 Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
78 return ResultStatus::Success; 79 return ResultStatus::Success;
79 } 80 }
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index ba9ba00c0..4d23656ec 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -315,4 +315,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
315 return ResultStatus::Error; 315 return ResultStatus::Error;
316} 316}
317 317
318u64 AppLoader_NCCH::GetProgramId() const {
319 return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]);
320}
321
318} // namespace Loader 322} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 03116add8..2fe2a7d82 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -191,6 +191,12 @@ public:
191 */ 191 */
192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; 192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
193 193
194 /*
195 * Gets the program id from the NCCH header
196 * @return u64 Program id
197 */
198 u64 GetProgramId() const;
199
194private: 200private:
195 201
196 /** 202 /**