diff options
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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | Archive_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 | |||
| 24 | bool 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 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the SaveData archive | ||
| 18 | class Archive_SaveData final : public DiskArchive { | ||
| 19 | public: | ||
| 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 | ||
| 18 | namespace FileSys { | 17 | namespace FileSys { |
| 19 | 18 | ||
| 20 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) { | 19 | Archive_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 | ||
| 25 | Archive_SDMC::~Archive_SDMC() { | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Initialize the archive. | ||
| 30 | * @return true if it initialized successfully | ||
| 31 | */ | ||
| 32 | bool Archive_SDMC::Initialize() { | 23 | bool 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 | */ | ||
| 52 | std::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 | */ | ||
| 65 | bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const { | ||
| 66 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool 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 | */ | ||
| 78 | bool 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 | */ | ||
| 87 | bool Archive_SDMC::CreateDirectory(const Path& path) const { | ||
| 88 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 89 | } | ||
| 90 | |||
| 91 | bool 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 | */ | ||
| 100 | std::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 | */ | ||
| 112 | std::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 @@ | |||
| 15 | namespace FileSys { | 15 | namespace FileSys { |
| 16 | 16 | ||
| 17 | /// File system interface to the SDMC archive | 17 | /// File system interface to the SDMC archive |
| 18 | class Archive_SDMC final : public ArchiveBackend { | 18 | class Archive_SDMC final : public DiskArchive { |
| 19 | public: | 19 | public: |
| 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 | |||
| 89 | private: | ||
| 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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | Archive_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 | |||
| 24 | bool 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 | |||
| 15 | namespace 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> | ||
| 20 | class Archive_SystemSaveData final : public DiskArchive { | ||
| 21 | public: | ||
| 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 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | Directory_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 | |||
| 26 | Directory_SDMC::~Directory_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool 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 | */ | ||
| 44 | u32 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 | */ | ||
| 84 | bool 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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class Directory_SDMC final : public DirectoryBackend { | ||
| 20 | public: | ||
| 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 | |||
| 45 | private: | ||
| 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 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | std::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 | |||
| 26 | bool DiskArchive::DeleteFile(const FileSys::Path& path) const { | ||
| 27 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool 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 | |||
| 34 | bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const { | ||
| 35 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool DiskArchive::CreateDirectory(const Path& path) const { | ||
| 39 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 40 | } | ||
| 41 | |||
| 42 | bool 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 | |||
| 46 | std::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 | |||
| 56 | DiskFile::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 | |||
| 65 | bool 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 | |||
| 86 | size_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 | |||
| 91 | size_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 | |||
| 99 | size_t DiskFile::GetSize() const { | ||
| 100 | return static_cast<size_t>(file->GetSize()); | ||
| 101 | } | ||
| 102 | |||
| 103 | bool DiskFile::SetSize(const u64 size) const { | ||
| 104 | file->Resize(size); | ||
| 105 | file->Flush(); | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool DiskFile::Close() const { | ||
| 110 | return file->Close(); | ||
| 111 | } | ||
| 112 | |||
| 113 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 114 | |||
| 115 | DiskDirectory::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 | |||
| 123 | bool 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 | |||
| 131 | u32 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 | |||
| 15 | namespace 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 | */ | ||
| 22 | class DiskArchive : public ArchiveBackend { | ||
| 23 | public: | ||
| 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 | |||
| 43 | protected: | ||
| 44 | std::string mount_point; | ||
| 45 | }; | ||
| 46 | |||
| 47 | class DiskFile : public FileBackend { | ||
| 48 | public: | ||
| 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 | |||
| 67 | protected: | ||
| 68 | const DiskArchive* archive; | ||
| 69 | std::string path; | ||
| 70 | Mode mode; | ||
| 71 | FileUtil::IOFile* file; | ||
| 72 | }; | ||
| 73 | |||
| 74 | class DiskDirectory : public DirectoryBackend { | ||
| 75 | public: | ||
| 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 | |||
| 90 | protected: | ||
| 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 | |||
| 67 | private: | 69 | private: |
| 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 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | File_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 | |||
| 26 | File_SDMC::~File_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Open the file | ||
| 32 | * @return true if the file opened correctly | ||
| 33 | */ | ||
| 34 | bool 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 | */ | ||
| 62 | size_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 | */ | ||
| 75 | size_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 | */ | ||
| 87 | size_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 | */ | ||
| 96 | bool 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 | */ | ||
| 106 | bool 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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class File_SDMC final : public FileBackend { | ||
| 20 | public: | ||
| 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 | |||
| 69 | private: | ||
| 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 | ||
| 15 | Handle g_main_thread = 0; | 15 | Handle g_main_thread = 0; |
| 16 | ObjectPool g_object_pool; | 16 | ObjectPool g_object_pool; |
| 17 | u64 g_program_id = 0; | ||
| 17 | 18 | ||
| 18 | ObjectPool::ObjectPool() { | 19 | ObjectPool::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: | |||
| 151 | extern ObjectPool g_object_pool; | 151 | extern ObjectPool g_object_pool; |
| 152 | extern Handle g_main_thread; | 152 | extern 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? | ||
| 158 | extern u64 g_program_id; | ||
| 159 | |||
| 154 | /// Initialize the kernel | 160 | /// Initialize the kernel |
| 155 | void Init(); | 161 | void 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 |
| 14 | enum class MemoryPermission : u32 { | 14 | enum 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. |
| 18 | enum class ErrorDescription : u32 { | 18 | enum 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 | ||
| 386 | ResultCode 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 |
| 370 | void ArchiveInit() { | 409 | void 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 | */ |
| 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | 110 | ResultVal<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 | */ | ||
| 116 | ResultCode FormatSaveData(); | ||
| 117 | |||
| 112 | /// Initialize archives | 118 | /// Initialize archives |
| 113 | void ArchiveInit(); | 119 | void 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) { | |||
| 50 | static void OpenFile(Service::Interface* self) { | 50 | static 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 | */ | ||
| 405 | static 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 | */ | ||
| 420 | static 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 | |||
| 401 | const FSUserInterface::FunctionInfo FunctionTable[] = { | 429 | const 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 | */ | ||
| 160 | static 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 | ||
| 318 | u64 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 | |||
| 194 | private: | 200 | private: |
| 195 | 201 | ||
| 196 | /** | 202 | /** |