diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 48 | ||||
| -rw-r--r-- | src/core/arm/interpreter/armemu.cpp | 232 | ||||
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 19 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.cpp | 11 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.h | 8 | ||||
| -rw-r--r-- | src/core/file_sys/disk_archive.cpp | 21 | ||||
| -rw-r--r-- | src/core/file_sys/disk_archive.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 21 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp | 64 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 3 | ||||
| -rw-r--r-- | src/core/loader/3dsx.cpp | 4 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 6 |
19 files changed, 449 insertions, 106 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 68012bffd..84b4a38f0 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -1266,6 +1266,13 @@ typedef struct _smla_inst { | |||
| 1266 | unsigned int Rn; | 1266 | unsigned int Rn; |
| 1267 | } smla_inst; | 1267 | } smla_inst; |
| 1268 | 1268 | ||
| 1269 | typedef struct umaal_inst { | ||
| 1270 | unsigned int Rn; | ||
| 1271 | unsigned int Rm; | ||
| 1272 | unsigned int RdHi; | ||
| 1273 | unsigned int RdLo; | ||
| 1274 | } umaal_inst; | ||
| 1275 | |||
| 1269 | typedef struct _umlal_inst { | 1276 | typedef struct _umlal_inst { |
| 1270 | unsigned int S; | 1277 | unsigned int S; |
| 1271 | unsigned int Rm; | 1278 | unsigned int Rm; |
| @@ -3010,7 +3017,26 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) { UN | |||
| 3010 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); } | 3017 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); } |
| 3011 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); } | 3018 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); } |
| 3012 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); } | 3019 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); } |
| 3013 | ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UMAAL"); } | 3020 | ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) |
| 3021 | { | ||
| 3022 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst)); | ||
| 3023 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 3024 | |||
| 3025 | inst_base->cond = BITS(inst, 28, 31); | ||
| 3026 | inst_base->idx = index; | ||
| 3027 | inst_base->br = NON_BRANCH; | ||
| 3028 | inst_base->load_r15 = 0; | ||
| 3029 | |||
| 3030 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 3031 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 3032 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 3033 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 3034 | |||
| 3035 | if (CHECK_RM || CHECK_RN) | ||
| 3036 | inst_base->load_r15 = 1; | ||
| 3037 | |||
| 3038 | return inst_base; | ||
| 3039 | } | ||
| 3014 | ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) | 3040 | ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) |
| 3015 | { | 3041 | { |
| 3016 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | 3042 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); |
| @@ -6374,6 +6400,26 @@ unsigned InterpreterMainLoop(ARMul_State* state) | |||
| 6374 | UHSUB8_INST: | 6400 | UHSUB8_INST: |
| 6375 | UHSUBADDX_INST: | 6401 | UHSUBADDX_INST: |
| 6376 | UMAAL_INST: | 6402 | UMAAL_INST: |
| 6403 | { | ||
| 6404 | INC_ICOUNTER; | ||
| 6405 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | ||
| 6406 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 6407 | |||
| 6408 | const u32 rm = RM; | ||
| 6409 | const u32 rn = RN; | ||
| 6410 | const u32 rd_lo = RDLO; | ||
| 6411 | const u32 rd_hi = RDHI; | ||
| 6412 | |||
| 6413 | const u64 result = (rm * rn) + rd_lo + rd_hi; | ||
| 6414 | |||
| 6415 | RDLO = (result & 0xFFFFFFFF); | ||
| 6416 | RDHI = ((result >> 32) & 0xFFFFFFFF); | ||
| 6417 | } | ||
| 6418 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6419 | INC_PC(sizeof(umaal_inst)); | ||
| 6420 | FETCH_INST; | ||
| 6421 | GOTO_NEXT_INST; | ||
| 6422 | } | ||
| 6377 | UMLAL_INST: | 6423 | UMLAL_INST: |
| 6378 | { | 6424 | { |
| 6379 | INC_ICOUNTER; | 6425 | INC_ICOUNTER; |
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 07d205755..610e04f10 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp | |||
| @@ -5681,11 +5681,8 @@ L_stm_s_takeabort: | |||
| 5681 | /* Attempt to emulate an ARMv6 instruction. | 5681 | /* Attempt to emulate an ARMv6 instruction. |
| 5682 | Returns non-zero upon success. */ | 5682 | Returns non-zero upon success. */ |
| 5683 | 5683 | ||
| 5684 | static int | 5684 | static int handle_v6_insn(ARMul_State* state, ARMword instr) { |
| 5685 | handle_v6_insn (ARMul_State * state, ARMword instr) { | 5685 | switch (BITS(20, 27)) { |
| 5686 | ARMword lhs, temp; | ||
| 5687 | |||
| 5688 | switch (BITS (20, 27)) { | ||
| 5689 | case 0x03: | 5686 | case 0x03: |
| 5690 | printf ("Unhandled v6 insn: ldr\n"); | 5687 | printf ("Unhandled v6 insn: ldr\n"); |
| 5691 | break; | 5688 | break; |
| @@ -5719,7 +5716,7 @@ L_stm_s_takeabort: | |||
| 5719 | /* strex */ | 5716 | /* strex */ |
| 5720 | u32 l = LHSReg; | 5717 | u32 l = LHSReg; |
| 5721 | u32 r = RHSReg; | 5718 | u32 r = RHSReg; |
| 5722 | lhs = LHS; | 5719 | u32 lhs = LHS; |
| 5723 | 5720 | ||
| 5724 | bool enter = false; | 5721 | bool enter = false; |
| 5725 | 5722 | ||
| @@ -5744,7 +5741,7 @@ L_stm_s_takeabort: | |||
| 5744 | case 0x19: | 5741 | case 0x19: |
| 5745 | /* ldrex */ | 5742 | /* ldrex */ |
| 5746 | if (BITS(4, 7) == 0x9) { | 5743 | if (BITS(4, 7) == 0x9) { |
| 5747 | lhs = LHS; | 5744 | u32 lhs = LHS; |
| 5748 | 5745 | ||
| 5749 | state->currentexaddr = lhs; | 5746 | state->currentexaddr = lhs; |
| 5750 | state->currentexval = ARMul_ReadWord(state, lhs); | 5747 | state->currentexval = ARMul_ReadWord(state, lhs); |
| @@ -5763,7 +5760,7 @@ L_stm_s_takeabort: | |||
| 5763 | case 0x1c: | 5760 | case 0x1c: |
| 5764 | if (BITS(4, 7) == 0x9) { | 5761 | if (BITS(4, 7) == 0x9) { |
| 5765 | /* strexb */ | 5762 | /* strexb */ |
| 5766 | lhs = LHS; | 5763 | u32 lhs = LHS; |
| 5767 | 5764 | ||
| 5768 | bool enter = false; | 5765 | bool enter = false; |
| 5769 | 5766 | ||
| @@ -5793,11 +5790,11 @@ L_stm_s_takeabort: | |||
| 5793 | case 0x1d: | 5790 | case 0x1d: |
| 5794 | if ((BITS(4, 7)) == 0x9) { | 5791 | if ((BITS(4, 7)) == 0x9) { |
| 5795 | /* ldrexb */ | 5792 | /* ldrexb */ |
| 5796 | temp = LHS; | 5793 | u32 lhs = LHS; |
| 5797 | LoadByte(state, instr, temp, LUNSIGNED); | 5794 | LoadByte(state, instr, lhs, LUNSIGNED); |
| 5798 | 5795 | ||
| 5799 | state->currentexaddr = temp; | 5796 | state->currentexaddr = lhs; |
| 5800 | state->currentexval = (u32)ARMul_ReadByte(state, temp); | 5797 | state->currentexval = (u32)ARMul_ReadByte(state, lhs); |
| 5801 | 5798 | ||
| 5802 | //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); | 5799 | //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); |
| 5803 | //printf("ldrexb\n"); | 5800 | //printf("ldrexb\n"); |
| @@ -5827,9 +5824,9 @@ L_stm_s_takeabort: | |||
| 5827 | case 0x3f: | 5824 | case 0x3f: |
| 5828 | printf ("Unhandled v6 insn: rbit\n"); | 5825 | printf ("Unhandled v6 insn: rbit\n"); |
| 5829 | break; | 5826 | break; |
| 5830 | case 0x61: // SSUB16, SADD16, SSAX, and SASX | 5827 | case 0x61: // SADD16, SASX, SSAX, and SSUB16 |
| 5831 | if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 || | 5828 | if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || |
| 5832 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30) | 5829 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) |
| 5833 | { | 5830 | { |
| 5834 | const u8 rd_idx = BITS(12, 15); | 5831 | const u8 rd_idx = BITS(12, 15); |
| 5835 | const u8 rm_idx = BITS(0, 3); | 5832 | const u8 rm_idx = BITS(0, 3); |
| @@ -5842,25 +5839,25 @@ L_stm_s_takeabort: | |||
| 5842 | s32 lo_result; | 5839 | s32 lo_result; |
| 5843 | s32 hi_result; | 5840 | s32 hi_result; |
| 5844 | 5841 | ||
| 5845 | // SSUB16 | ||
| 5846 | if ((instr & 0xFF0) == 0xf70) { | ||
| 5847 | lo_result = (rn_lo - rm_lo); | ||
| 5848 | hi_result = (rn_hi - rm_hi); | ||
| 5849 | } | ||
| 5850 | // SADD16 | 5842 | // SADD16 |
| 5851 | else if ((instr & 0xFF0) == 0xf10) { | 5843 | if ((instr & 0xFF0) == 0xf10) { |
| 5852 | lo_result = (rn_lo + rm_lo); | 5844 | lo_result = (rn_lo + rm_lo); |
| 5853 | hi_result = (rn_hi + rm_hi); | 5845 | hi_result = (rn_hi + rm_hi); |
| 5854 | } | 5846 | } |
| 5847 | // SASX | ||
| 5848 | else if ((instr & 0xFF0) == 0xf30) { | ||
| 5849 | lo_result = (rn_lo - rm_hi); | ||
| 5850 | hi_result = (rn_hi + rm_lo); | ||
| 5851 | } | ||
| 5855 | // SSAX | 5852 | // SSAX |
| 5856 | else if ((instr & 0xFF0) == 0xf50) { | 5853 | else if ((instr & 0xFF0) == 0xf50) { |
| 5857 | lo_result = (rn_lo + rm_hi); | 5854 | lo_result = (rn_lo + rm_hi); |
| 5858 | hi_result = (rn_hi - rm_lo); | 5855 | hi_result = (rn_hi - rm_lo); |
| 5859 | } | 5856 | } |
| 5860 | // SASX | 5857 | // SSUB16 |
| 5861 | else { | 5858 | else { |
| 5862 | lo_result = (rn_lo - rm_hi); | 5859 | lo_result = (rn_lo - rm_lo); |
| 5863 | hi_result = (rn_hi + rm_lo); | 5860 | hi_result = (rn_hi - rm_hi); |
| 5864 | } | 5861 | } |
| 5865 | 5862 | ||
| 5866 | state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | 5863 | state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); |
| @@ -5881,12 +5878,87 @@ L_stm_s_takeabort: | |||
| 5881 | state->Cpsr &= ~(1 << 19); | 5878 | state->Cpsr &= ~(1 << 19); |
| 5882 | } | 5879 | } |
| 5883 | return 1; | 5880 | return 1; |
| 5884 | } else { | 5881 | } |
| 5885 | printf("Unhandled v6 insn: %08x", BITS(20, 27)); | 5882 | // SADD8/SSUB8 |
| 5883 | else if ((instr & 0xFF0) == 0xf90 || (instr & 0xFF0) == 0xff0) | ||
| 5884 | { | ||
| 5885 | const u8 rd_idx = BITS(12, 15); | ||
| 5886 | const u8 rm_idx = BITS(0, 3); | ||
| 5887 | const u8 rn_idx = BITS(16, 19); | ||
| 5888 | const u32 rm_val = state->Reg[rm_idx]; | ||
| 5889 | const u32 rn_val = state->Reg[rn_idx]; | ||
| 5890 | |||
| 5891 | u8 lo_val1; | ||
| 5892 | u8 lo_val2; | ||
| 5893 | u8 hi_val1; | ||
| 5894 | u8 hi_val2; | ||
| 5895 | |||
| 5896 | // SADD8 | ||
| 5897 | if ((instr & 0xFF0) == 0xf90) { | ||
| 5898 | lo_val1 = (u8)((rn_val & 0xFF) + (rm_val & 0xFF)); | ||
| 5899 | lo_val2 = (u8)(((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF)); | ||
| 5900 | hi_val1 = (u8)(((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF)); | ||
| 5901 | hi_val2 = (u8)(((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF)); | ||
| 5902 | |||
| 5903 | if (lo_val1 & 0x80) | ||
| 5904 | state->Cpsr |= (1 << 16); | ||
| 5905 | else | ||
| 5906 | state->Cpsr &= ~(1 << 16); | ||
| 5907 | |||
| 5908 | if (lo_val2 & 0x80) | ||
| 5909 | state->Cpsr |= (1 << 17); | ||
| 5910 | else | ||
| 5911 | state->Cpsr &= ~(1 << 17); | ||
| 5912 | |||
| 5913 | if (hi_val1 & 0x80) | ||
| 5914 | state->Cpsr |= (1 << 18); | ||
| 5915 | else | ||
| 5916 | state->Cpsr &= ~(1 << 18); | ||
| 5917 | |||
| 5918 | if (hi_val2 & 0x80) | ||
| 5919 | state->Cpsr |= (1 << 19); | ||
| 5920 | else | ||
| 5921 | state->Cpsr &= ~(1 << 19); | ||
| 5922 | } | ||
| 5923 | // SSUB8 | ||
| 5924 | else { | ||
| 5925 | lo_val1 = (u8)((rn_val & 0xFF) - (rm_val & 0xFF)); | ||
| 5926 | lo_val2 = (u8)(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); | ||
| 5927 | hi_val1 = (u8)(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); | ||
| 5928 | hi_val2 = (u8)(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); | ||
| 5929 | |||
| 5930 | if (!(lo_val1 & 0x80)) | ||
| 5931 | state->Cpsr |= (1 << 16); | ||
| 5932 | else | ||
| 5933 | state->Cpsr &= ~(1 << 16); | ||
| 5934 | |||
| 5935 | if (!(lo_val2 & 0x80)) | ||
| 5936 | state->Cpsr |= (1 << 17); | ||
| 5937 | else | ||
| 5938 | state->Cpsr &= ~(1 << 17); | ||
| 5939 | |||
| 5940 | if (!(hi_val1 & 0x80)) | ||
| 5941 | state->Cpsr |= (1 << 18); | ||
| 5942 | else | ||
| 5943 | state->Cpsr &= ~(1 << 18); | ||
| 5944 | |||
| 5945 | if (!(hi_val2 & 0x80)) | ||
| 5946 | state->Cpsr |= (1 << 19); | ||
| 5947 | else | ||
| 5948 | state->Cpsr &= ~(1 << 19); | ||
| 5949 | } | ||
| 5950 | |||
| 5951 | state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24); | ||
| 5952 | return 1; | ||
| 5953 | } | ||
| 5954 | else { | ||
| 5955 | printf("Unhandled v6 insn: %08x", instr); | ||
| 5886 | } | 5956 | } |
| 5887 | break; | 5957 | break; |
| 5888 | case 0x62: // QSUB16 and QADD16 | 5958 | case 0x62: // QADD16, QASX, QSAX, and QSUB16 |
| 5889 | if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { | 5959 | if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || |
| 5960 | (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) | ||
| 5961 | { | ||
| 5890 | const u8 rd_idx = BITS(12, 15); | 5962 | const u8 rd_idx = BITS(12, 15); |
| 5891 | const u8 rn_idx = BITS(16, 19); | 5963 | const u8 rn_idx = BITS(16, 19); |
| 5892 | const u8 rm_idx = BITS(0, 3); | 5964 | const u8 rm_idx = BITS(0, 3); |
| @@ -5898,15 +5970,26 @@ L_stm_s_takeabort: | |||
| 5898 | s32 lo_result; | 5970 | s32 lo_result; |
| 5899 | s32 hi_result; | 5971 | s32 hi_result; |
| 5900 | 5972 | ||
| 5973 | // QADD16 | ||
| 5974 | if ((instr & 0xFF0) == 0xf10) { | ||
| 5975 | lo_result = (rn_lo + rm_lo); | ||
| 5976 | hi_result = (rn_hi + rm_hi); | ||
| 5977 | } | ||
| 5978 | // QASX | ||
| 5979 | else if ((instr & 0xFF0) == 0xf30) { | ||
| 5980 | lo_result = (rn_lo - rm_hi); | ||
| 5981 | hi_result = (rn_hi + rm_lo); | ||
| 5982 | } | ||
| 5983 | // QSAX | ||
| 5984 | else if ((instr & 0xFF0) == 0xf50) { | ||
| 5985 | lo_result = (rn_lo + rm_hi); | ||
| 5986 | hi_result = (rn_hi - rm_lo); | ||
| 5987 | } | ||
| 5901 | // QSUB16 | 5988 | // QSUB16 |
| 5902 | if ((instr & 0xFF0) == 0xf70) { | 5989 | else { |
| 5903 | lo_result = (rn_lo - rm_lo); | 5990 | lo_result = (rn_lo - rm_lo); |
| 5904 | hi_result = (rn_hi - rm_hi); | 5991 | hi_result = (rn_hi - rm_hi); |
| 5905 | } | 5992 | } |
| 5906 | else { // QADD16 | ||
| 5907 | lo_result = (rn_lo + rm_lo); | ||
| 5908 | hi_result = (rn_hi + rm_hi); | ||
| 5909 | } | ||
| 5910 | 5993 | ||
| 5911 | if (lo_result > 0x7FFF) | 5994 | if (lo_result > 0x7FFF) |
| 5912 | lo_result = 0x7FFF; | 5995 | lo_result = 0x7FFF; |
| @@ -6081,22 +6164,28 @@ L_stm_s_takeabort: | |||
| 6081 | //ichfly | 6164 | //ichfly |
| 6082 | //SSAT16 | 6165 | //SSAT16 |
| 6083 | { | 6166 | { |
| 6084 | u8 tar = BITS(12, 15); | 6167 | const u8 rd_idx = BITS(12, 15); |
| 6085 | u8 src = BITS(0, 3); | 6168 | const u8 rn_idx = BITS(0, 3); |
| 6086 | u8 val = BITS(16, 19) + 1; | 6169 | const u8 num_bits = BITS(16, 19) + 1; |
| 6087 | s16 a1 = (state->Reg[src]); | 6170 | const s16 min = -(0x8000 >> (16 - num_bits)); |
| 6088 | s16 a2 = (state->Reg[src] >> 0x10); | 6171 | const s16 max = (0x7FFF >> (16 - num_bits)); |
| 6089 | s16 min = (s16)(0x8000 >> (16 - val)); | 6172 | s16 rn_lo = (state->Reg[rn_idx]); |
| 6090 | s16 max = 0x7FFF >> (16 - val); | 6173 | s16 rn_hi = (state->Reg[rn_idx] >> 16); |
| 6091 | if (min > a1) a1 = min; | 6174 | |
| 6092 | if (max < a1) a1 = max; | 6175 | if (rn_lo > max) |
| 6093 | if (min > a2) a2 = min; | 6176 | rn_lo = max; |
| 6094 | if (max < a2) a2 = max; | 6177 | else if (rn_lo < min) |
| 6095 | u32 temp2 = ((u32)(a2)) << 0x10; | 6178 | rn_lo = min; |
| 6096 | state->Reg[tar] = (a1 & 0xFFFF) | (temp2); | 6179 | |
| 6180 | if (rn_hi > max) | ||
| 6181 | rn_hi = max; | ||
| 6182 | else if (rn_hi < min) | ||
| 6183 | rn_hi = min; | ||
| 6184 | |||
| 6185 | state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); | ||
| 6186 | return 1; | ||
| 6097 | } | 6187 | } |
| 6098 | 6188 | ||
| 6099 | return 1; | ||
| 6100 | default: | 6189 | default: |
| 6101 | break; | 6190 | break; |
| 6102 | } | 6191 | } |
| @@ -6109,7 +6198,7 @@ L_stm_s_takeabort: | |||
| 6109 | break; | 6198 | break; |
| 6110 | } | 6199 | } |
| 6111 | 6200 | ||
| 6112 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; | 6201 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); |
| 6113 | if (Rm & 0x80) | 6202 | if (Rm & 0x80) |
| 6114 | Rm |= 0xffffff00; | 6203 | Rm |= 0xffffff00; |
| 6115 | 6204 | ||
| @@ -6154,7 +6243,7 @@ L_stm_s_takeabort: | |||
| 6154 | if (ror == -1) | 6243 | if (ror == -1) |
| 6155 | break; | 6244 | break; |
| 6156 | 6245 | ||
| 6157 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; | 6246 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); |
| 6158 | if (Rm & 0x8000) | 6247 | if (Rm & 0x8000) |
| 6159 | Rm |= 0xffff0000; | 6248 | Rm |= 0xffff0000; |
| 6160 | 6249 | ||
| @@ -6250,7 +6339,7 @@ L_stm_s_takeabort: | |||
| 6250 | break; | 6339 | break; |
| 6251 | } | 6340 | } |
| 6252 | 6341 | ||
| 6253 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; | 6342 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); |
| 6254 | 6343 | ||
| 6255 | if (BITS(16, 19) == 0xf) | 6344 | if (BITS(16, 19) == 0xf) |
| 6256 | /* UXTB */ | 6345 | /* UXTB */ |
| @@ -6294,7 +6383,7 @@ L_stm_s_takeabort: | |||
| 6294 | if (ror == -1) | 6383 | if (ror == -1) |
| 6295 | break; | 6384 | break; |
| 6296 | 6385 | ||
| 6297 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; | 6386 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); |
| 6298 | 6387 | ||
| 6299 | /* UXT */ | 6388 | /* UXT */ |
| 6300 | /* state->Reg[BITS (12, 15)] = Rm; */ | 6389 | /* state->Reg[BITS (12, 15)] = Rm; */ |
| @@ -6317,11 +6406,14 @@ L_stm_s_takeabort: | |||
| 6317 | } | 6406 | } |
| 6318 | case 0x70: | 6407 | case 0x70: |
| 6319 | // ichfly | 6408 | // ichfly |
| 6320 | // SMUAD, SMUSD, SMLAD | 6409 | // SMUAD, SMUSD, SMLAD, and SMLSD |
| 6321 | if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || (instr & 0xd0) == 0x10) { | 6410 | if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || |
| 6411 | (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50) | ||
| 6412 | { | ||
| 6322 | const u8 rd_idx = BITS(16, 19); | 6413 | const u8 rd_idx = BITS(16, 19); |
| 6323 | const u8 rn_idx = BITS(0, 3); | 6414 | const u8 rn_idx = BITS(0, 3); |
| 6324 | const u8 rm_idx = BITS(8, 11); | 6415 | const u8 rm_idx = BITS(8, 11); |
| 6416 | const u8 ra_idx = BITS(12, 15); | ||
| 6325 | const bool do_swap = (BIT(5) == 1); | 6417 | const bool do_swap = (BIT(5) == 1); |
| 6326 | 6418 | ||
| 6327 | u32 rm_val = state->Reg[rm_idx]; | 6419 | u32 rm_val = state->Reg[rm_idx]; |
| @@ -6344,13 +6436,14 @@ L_stm_s_takeabort: | |||
| 6344 | state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); | 6436 | state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); |
| 6345 | } | 6437 | } |
| 6346 | // SMLAD | 6438 | // SMLAD |
| 6347 | else { | 6439 | else if ((instr & 0xd0) == 0x10) { |
| 6348 | const u8 ra_idx = BITS(12, 15); | ||
| 6349 | state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; | 6440 | state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; |
| 6350 | } | 6441 | } |
| 6442 | // SMLSD | ||
| 6443 | else { | ||
| 6444 | state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx]; | ||
| 6445 | } | ||
| 6351 | return 1; | 6446 | return 1; |
| 6352 | } else { | ||
| 6353 | printf ("Unhandled v6 insn: smlsd\n"); | ||
| 6354 | } | 6447 | } |
| 6355 | break; | 6448 | break; |
| 6356 | case 0x74: | 6449 | case 0x74: |
| @@ -6360,7 +6453,30 @@ L_stm_s_takeabort: | |||
| 6360 | printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); | 6453 | printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); |
| 6361 | break; | 6454 | break; |
| 6362 | case 0x78: | 6455 | case 0x78: |
| 6363 | printf ("Unhandled v6 insn: usad/usada8\n"); | 6456 | if (BITS(20, 24) == 0x18) |
| 6457 | { | ||
| 6458 | const u8 rm_idx = BITS(8, 11); | ||
| 6459 | const u8 rn_idx = BITS(0, 3); | ||
| 6460 | const u8 rd_idx = BITS(16, 19); | ||
| 6461 | |||
| 6462 | const u32 rm_val = state->Reg[rm_idx]; | ||
| 6463 | const u32 rn_val = state->Reg[rn_idx]; | ||
| 6464 | |||
| 6465 | const u8 diff1 = (u8)std::labs((rn_val & 0xFF) - (rm_val & 0xFF)); | ||
| 6466 | const u8 diff2 = (u8)std::labs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); | ||
| 6467 | const u8 diff3 = (u8)std::labs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); | ||
| 6468 | const u8 diff4 = (u8)std::labs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); | ||
| 6469 | |||
| 6470 | u32 finalDif = (diff1 + diff2 + diff3 + diff4); | ||
| 6471 | |||
| 6472 | // Op is USADA8 if true. | ||
| 6473 | const u8 ra_idx = BITS(12, 15); | ||
| 6474 | if (ra_idx != 15) | ||
| 6475 | finalDif += state->Reg[ra_idx]; | ||
| 6476 | |||
| 6477 | state->Reg[rd_idx] = finalDif; | ||
| 6478 | return 1; | ||
| 6479 | } | ||
| 6364 | break; | 6480 | break; |
| 6365 | case 0x7a: | 6481 | case 0x7a: |
| 6366 | printf ("Unhandled v6 insn: usbfx\n"); | 6482 | printf ("Unhandled v6 insn: usbfx\n"); |
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 065b22e5d..eb1fdaa1f 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -143,7 +143,16 @@ public: | |||
| 143 | case Char: | 143 | case Char: |
| 144 | return std::vector<u8>(string.begin(), string.end()); | 144 | return std::vector<u8>(string.begin(), string.end()); |
| 145 | case Wchar: | 145 | case Wchar: |
| 146 | return std::vector<u8>(u16str.begin(), u16str.end()); | 146 | { |
| 147 | // use two u8 for each character of u16str | ||
| 148 | std::vector<u8> to_return(u16str.size() * 2); | ||
| 149 | for (size_t i = 0; i < u16str.size(); ++i) { | ||
| 150 | u16 tmp_char = u16str.at(i); | ||
| 151 | to_return[i*2] = (tmp_char & 0xFF00) >> 8; | ||
| 152 | to_return[i*2 + 1] = (tmp_char & 0x00FF); | ||
| 153 | } | ||
| 154 | return to_return; | ||
| 155 | } | ||
| 147 | case Empty: | 156 | case Empty: |
| 148 | return {}; | 157 | return {}; |
| 149 | default: | 158 | default: |
| @@ -200,6 +209,14 @@ public: | |||
| 200 | virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; | 209 | virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; |
| 201 | 210 | ||
| 202 | /** | 211 | /** |
| 212 | * Create a file specified by its path | ||
| 213 | * @param path Path relative to the Archive | ||
| 214 | * @param size The size of the new file, filled with zeroes | ||
| 215 | * @return File creation result code | ||
| 216 | */ | ||
| 217 | virtual ResultCode CreateFile(const Path& path, u32 size) const = 0; | ||
| 218 | |||
| 219 | /** | ||
| 203 | * Create a directory specified by its path | 220 | * Create a directory specified by its path |
| 204 | * @param path Path relative to the archive | 221 | * @param path Path relative to the archive |
| 205 | * @return Whether the directory could be created | 222 | * @return Whether the directory could be created |
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 6ef6ea2fb..ced0794ef 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/make_unique.h" | ||
| 8 | 9 | ||
| 9 | #include "core/file_sys/archive_romfs.h" | 10 | #include "core/file_sys/archive_romfs.h" |
| 10 | #include "core/file_sys/directory_romfs.h" | 11 | #include "core/file_sys/directory_romfs.h" |
| @@ -29,7 +30,7 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { | |||
| 29 | * @return Opened file, or nullptr | 30 | * @return Opened file, or nullptr |
| 30 | */ | 31 | */ |
| 31 | std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { | 32 | std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { |
| 32 | return std::make_unique<File_RomFS>(this); | 33 | return Common::make_unique<File_RomFS>(this); |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | /** | 36 | /** |
| @@ -57,6 +58,12 @@ bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const { | |||
| 57 | return false; | 58 | return false; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 61 | ResultCode Archive_RomFS::CreateFile(const Path& path, u32 size) const { | ||
| 62 | LOG_WARNING(Service_FS, "Attempted to create a file in ROMFS."); | ||
| 63 | // TODO: Verify error code | ||
| 64 | return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||
| 65 | } | ||
| 66 | |||
| 60 | /** | 67 | /** |
| 61 | * Create a directory specified by its path | 68 | * Create a directory specified by its path |
| 62 | * @param path Path relative to the archive | 69 | * @param path Path relative to the archive |
| @@ -78,7 +85,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys | |||
| 78 | * @return Opened directory, or nullptr | 85 | * @return Opened directory, or nullptr |
| 79 | */ | 86 | */ |
| 80 | std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { | 87 | std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { |
| 81 | return std::make_unique<Directory_RomFS>(); | 88 | return Common::make_unique<Directory_RomFS>(); |
| 82 | } | 89 | } |
| 83 | 90 | ||
| 84 | } // namespace FileSys | 91 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 564c23f70..2fafd0d2a 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -54,6 +54,14 @@ public: | |||
| 54 | bool DeleteDirectory(const FileSys::Path& path) const override; | 54 | bool DeleteDirectory(const FileSys::Path& path) const override; |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | * Create a file specified by its path | ||
| 58 | * @param path Path relative to the Archive | ||
| 59 | * @param size The size of the new file, filled with zeroes | ||
| 60 | * @return File creation result code | ||
| 61 | */ | ||
| 62 | ResultCode CreateFile(const Path& path, u32 size) const override; | ||
| 63 | |||
| 64 | /** | ||
| 57 | * Create a directory specified by its path | 65 | * Create a directory specified by its path |
| 58 | * @param path Path relative to the archive | 66 | * @param path Path relative to the archive |
| 59 | * @return Whether the directory could be created | 67 | * @return Whether the directory could be created |
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index fc9ee4acf..1689a1a91 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -35,6 +35,27 @@ bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const { | |||
| 35 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | 35 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { | ||
| 39 | std::string full_path = GetMountPoint() + path.AsString(); | ||
| 40 | |||
| 41 | if (FileUtil::Exists(full_path)) | ||
| 42 | return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info); | ||
| 43 | |||
| 44 | if (size == 0) { | ||
| 45 | FileUtil::CreateEmptyFile(full_path); | ||
| 46 | return RESULT_SUCCESS; | ||
| 47 | } | ||
| 48 | |||
| 49 | FileUtil::IOFile file(full_path, "wb"); | ||
| 50 | // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) | ||
| 51 | // We do this by seeking to the right size, then writing a single null byte. | ||
| 52 | if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) | ||
| 53 | return RESULT_SUCCESS; | ||
| 54 | |||
| 55 | return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, ErrorLevel::Info); | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 38 | bool DiskArchive::CreateDirectory(const Path& path) const { | 59 | bool DiskArchive::CreateDirectory(const Path& path) const { |
| 39 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | 60 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); |
| 40 | } | 61 | } |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index 73fce2fce..c1784e870 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -28,6 +28,7 @@ public: | |||
| 28 | bool DeleteFile(const FileSys::Path& path) 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; | 29 | bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; |
| 30 | bool DeleteDirectory(const FileSys::Path& path) const override; | 30 | bool DeleteDirectory(const FileSys::Path& path) const override; |
| 31 | ResultCode CreateFile(const Path& path, u32 size) const override; | ||
| 31 | bool CreateDirectory(const Path& path) const override; | 32 | bool CreateDirectory(const Path& path) const override; |
| 32 | bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | 33 | 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 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index dca87d93a..32258d5a0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -14,6 +14,10 @@ typedef s32 Result; | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | // From kernel.h. Declarations duplicated here to avoid a circular header dependency. | ||
| 18 | class Thread; | ||
| 19 | Thread* GetCurrentThread(); | ||
| 20 | |||
| 17 | enum KernelHandle { | 21 | enum KernelHandle { |
| 18 | CurrentThread = 0xFFFF8000, | 22 | CurrentThread = 0xFFFF8000, |
| 19 | CurrentProcess = 0xFFFF8001, | 23 | CurrentProcess = 0xFFFF8001, |
| @@ -81,6 +85,10 @@ public: | |||
| 81 | 85 | ||
| 82 | template <class T> | 86 | template <class T> |
| 83 | T* Get(Handle handle) { | 87 | T* Get(Handle handle) { |
| 88 | if (handle == CurrentThread) { | ||
| 89 | return reinterpret_cast<T*>(GetCurrentThread()); | ||
| 90 | } | ||
| 91 | |||
| 84 | if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { | 92 | if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { |
| 85 | if (handle != 0) { | 93 | if (handle != 0) { |
| 86 | LOG_ERROR(Kernel, "Bad object handle %08x", handle); | 94 | LOG_ERROR(Kernel, "Bad object handle %08x", handle); |
| @@ -99,6 +107,10 @@ public: | |||
| 99 | // ONLY use this when you know the handle is valid. | 107 | // ONLY use this when you know the handle is valid. |
| 100 | template <class T> | 108 | template <class T> |
| 101 | T *GetFast(Handle handle) { | 109 | T *GetFast(Handle handle) { |
| 110 | if (handle == CurrentThread) { | ||
| 111 | return reinterpret_cast<T*>(GetCurrentThread()); | ||
| 112 | } | ||
| 113 | |||
| 102 | const Handle realHandle = handle - HANDLE_OFFSET; | 114 | const Handle realHandle = handle - HANDLE_OFFSET; |
| 103 | _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); | 115 | _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); |
| 104 | return static_cast<T*>(pool[realHandle]); | 116 | return static_cast<T*>(pool[realHandle]); |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 1572e8ab2..b81d0b26a 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -20,8 +20,8 @@ public: | |||
| 20 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; } | 20 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; } |
| 21 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; } | 21 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; } |
| 22 | 22 | ||
| 23 | u32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have |
| 24 | u32 available_count; ///< Number of free slots left in the semaphore | 24 | s32 available_count; ///< Number of free slots left in the semaphore |
| 25 | std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore | 25 | std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore |
| 26 | std::string name; ///< Name of semaphore (optional) | 26 | std::string name; ///< Name of semaphore (optional) |
| 27 | 27 | ||
| @@ -49,8 +49,8 @@ public: | |||
| 49 | 49 | ||
| 50 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 50 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 51 | 51 | ||
| 52 | ResultCode CreateSemaphore(Handle* handle, u32 initial_count, | 52 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, |
| 53 | u32 max_count, const std::string& name) { | 53 | s32 max_count, const std::string& name) { |
| 54 | 54 | ||
| 55 | if (initial_count > max_count) | 55 | if (initial_count > max_count) |
| 56 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 56 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 934499e7b..8644ecf0c 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h | |||
| @@ -18,7 +18,7 @@ namespace Kernel { | |||
| 18 | * @param name Optional name of semaphore | 18 | * @param name Optional name of semaphore |
| 19 | * @return ResultCode of the error | 19 | * @return ResultCode of the error |
| 20 | */ | 20 | */ |
| 21 | ResultCode CreateSemaphore(Handle* handle, u32 initial_count, u32 max_count, const std::string& name = "Unknown"); | 21 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | * Releases a certain number of slots from a semaphore. | 24 | * Releases a certain number of slots from a semaphore. |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a47bde9dd..c6a8dc7b9 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -83,8 +83,7 @@ static Thread* current_thread; | |||
| 83 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup | 83 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup |
| 84 | static u32 next_thread_id; ///< The next available thread id | 84 | static u32 next_thread_id; ///< The next available thread id |
| 85 | 85 | ||
| 86 | /// Gets the current thread | 86 | Thread* GetCurrentThread() { |
| 87 | inline Thread* GetCurrentThread() { | ||
| 88 | return current_thread; | 87 | return current_thread; |
| 89 | } | 88 | } |
| 90 | 89 | ||
| @@ -148,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) { | |||
| 148 | } | 147 | } |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | /// Verify that a thread has not been released from waiting | 150 | /// Check if a thread is blocking on a specified wait type |
| 152 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | 151 | static bool CheckWaitType(const Thread* thread, WaitType type) { |
| 153 | _dbg_assert_(Kernel, thread != nullptr); | 152 | return (type == thread->wait_type) && (thread->IsWaiting()); |
| 154 | return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting()); | ||
| 155 | } | 153 | } |
| 156 | 154 | ||
| 157 | /// Verify that a thread has not been released from waiting (with wait address) | 155 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 158 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | 156 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { |
| 159 | _dbg_assert_(Kernel, thread != nullptr); | 157 | return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); |
| 160 | return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address); | 158 | } |
| 159 | |||
| 160 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | ||
| 161 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | ||
| 162 | return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address); | ||
| 161 | } | 163 | } |
| 162 | 164 | ||
| 163 | /// Stops the current thread | 165 | /// Stops the current thread |
| @@ -172,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) { | |||
| 172 | thread->status = THREADSTATUS_DORMANT; | 174 | thread->status = THREADSTATUS_DORMANT; |
| 173 | for (Handle waiting_handle : thread->waiting_threads) { | 175 | for (Handle waiting_handle : thread->waiting_threads) { |
| 174 | Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); | 176 | Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); |
| 175 | if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | 177 | |
| 178 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | ||
| 176 | ResumeThreadFromWait(waiting_handle); | 179 | ResumeThreadFromWait(waiting_handle); |
| 177 | } | ||
| 178 | } | 180 | } |
| 179 | thread->waiting_threads.clear(); | 181 | thread->waiting_threads.clear(); |
| 180 | 182 | ||
| @@ -210,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||
| 210 | for (Handle handle : thread_queue) { | 212 | for (Handle handle : thread_queue) { |
| 211 | Thread* thread = g_object_pool.Get<Thread>(handle); | 213 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 212 | 214 | ||
| 213 | if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) | 215 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 214 | continue; | 216 | continue; |
| 215 | 217 | ||
| 216 | if (thread == nullptr) | 218 | if (thread == nullptr) |
| @@ -235,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) { | |||
| 235 | for (Handle handle : thread_queue) { | 237 | for (Handle handle : thread_queue) { |
| 236 | Thread* thread = g_object_pool.Get<Thread>(handle); | 238 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 237 | 239 | ||
| 238 | if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) | 240 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 239 | ResumeThreadFromWait(handle); | 241 | ResumeThreadFromWait(handle); |
| 240 | } | 242 | } |
| 241 | } | 243 | } |
| @@ -306,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) { | |||
| 306 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); | 308 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); |
| 307 | if (thread) { | 309 | if (thread) { |
| 308 | thread->status &= ~THREADSTATUS_WAIT; | 310 | thread->status &= ~THREADSTATUS_WAIT; |
| 311 | thread->wait_handle = 0; | ||
| 312 | thread->wait_type = WAITTYPE_NONE; | ||
| 309 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 313 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 310 | ChangeReadyState(thread, true); | 314 | ChangeReadyState(thread, true); |
| 311 | } | 315 | } |
| @@ -469,19 +473,27 @@ void Reschedule() { | |||
| 469 | Thread* prev = GetCurrentThread(); | 473 | Thread* prev = GetCurrentThread(); |
| 470 | Thread* next = NextThread(); | 474 | Thread* next = NextThread(); |
| 471 | HLE::g_reschedule = false; | 475 | HLE::g_reschedule = false; |
| 472 | if (next > 0) { | ||
| 473 | LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 474 | 476 | ||
| 477 | if (next != nullptr) { | ||
| 478 | LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 475 | SwitchContext(next); | 479 | SwitchContext(next); |
| 480 | } else { | ||
| 481 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | ||
| 476 | 482 | ||
| 477 | // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep | 483 | for (Handle handle : thread_queue) { |
| 478 | // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. | 484 | Thread* thread = g_object_pool.Get<Thread>(handle); |
| 479 | // This results in the current thread yielding on a VBLANK once, and then it will be | 485 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", |
| 480 | // immediately placed back in the queue for execution. | 486 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); |
| 481 | if (prev->wait_type == WAITTYPE_VBLANK) { | ||
| 482 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 483 | } | 487 | } |
| 484 | } | 488 | } |
| 489 | |||
| 490 | // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put | ||
| 491 | // to sleep. So, we'll just immediately set it to "ready" again after an attempted context | ||
| 492 | // switch has occurred. This results in the current thread yielding on a sleep once, and then it | ||
| 493 | // will immediately be placed back in the queue for execution. | ||
| 494 | |||
| 495 | if (CheckWaitType(prev, WAITTYPE_SLEEP)) | ||
| 496 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 485 | } | 497 | } |
| 486 | 498 | ||
| 487 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | 499 | ResultCode GetThreadId(u32* thread_id, Handle handle) { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 34333ef6e..9396b6b26 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -40,7 +40,6 @@ enum WaitType { | |||
| 40 | WAITTYPE_SEMA, | 40 | WAITTYPE_SEMA, |
| 41 | WAITTYPE_EVENT, | 41 | WAITTYPE_EVENT, |
| 42 | WAITTYPE_THREADEND, | 42 | WAITTYPE_THREADEND, |
| 43 | WAITTYPE_VBLANK, | ||
| 44 | WAITTYPE_MUTEX, | 43 | WAITTYPE_MUTEX, |
| 45 | WAITTYPE_SYNCH, | 44 | WAITTYPE_SYNCH, |
| 46 | WAITTYPE_ARB, | 45 | WAITTYPE_ARB, |
| @@ -78,6 +77,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); | |||
| 78 | /// Arbitrate all threads currently waiting... | 77 | /// Arbitrate all threads currently waiting... |
| 79 | void ArbitrateAllThreads(u32 arbiter, u32 address); | 78 | void ArbitrateAllThreads(u32 arbiter, u32 address); |
| 80 | 79 | ||
| 80 | /// Gets the current thread | ||
| 81 | Thread* GetCurrentThread(); | ||
| 82 | |||
| 81 | /// Gets the current thread handle | 83 | /// Gets the current thread handle |
| 82 | Handle GetCurrentThreadHandle(); | 84 | Handle GetCurrentThreadHandle(); |
| 83 | 85 | ||
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index d92444160..e2a59a069 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/make_unique.h" | ||
| 10 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 11 | 12 | ||
| 12 | #include "core/file_sys/archive_savedata.h" | 13 | #include "core/file_sys/archive_savedata.h" |
| @@ -260,7 +261,7 @@ ResultCode CloseArchive(ArchiveHandle handle) { | |||
| 260 | // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in | 261 | // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in |
| 261 | // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 | 262 | // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 |
| 262 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { | 263 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { |
| 263 | auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); | 264 | auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code)); |
| 264 | 265 | ||
| 265 | bool inserted = result.second; | 266 | bool inserted = result.second; |
| 266 | _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); | 267 | _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); |
| @@ -281,7 +282,7 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 281 | ErrorSummary::NotFound, ErrorLevel::Status); | 282 | ErrorSummary::NotFound, ErrorLevel::Status); |
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | auto file = std::make_unique<File>(std::move(backend), path); | 285 | auto file = Common::make_unique<File>(std::move(backend), path); |
| 285 | Handle handle = Kernel::g_object_pool.Create(file.release()); | 286 | Handle handle = Kernel::g_object_pool.Create(file.release()); |
| 286 | return MakeResult<Handle>(handle); | 287 | return MakeResult<Handle>(handle); |
| 287 | } | 288 | } |
| @@ -329,6 +330,14 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 329 | ErrorSummary::Canceled, ErrorLevel::Status); | 330 | ErrorSummary::Canceled, ErrorLevel::Status); |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 333 | ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size) { | ||
| 334 | Archive* archive = GetArchive(archive_handle); | ||
| 335 | if (archive == nullptr) | ||
| 336 | return InvalidHandle(ErrorModule::FS); | ||
| 337 | |||
| 338 | return archive->backend->CreateFile(path, file_size); | ||
| 339 | } | ||
| 340 | |||
| 332 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 341 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 333 | Archive* archive = GetArchive(archive_handle); | 342 | Archive* archive = GetArchive(archive_handle); |
| 334 | if (archive == nullptr) | 343 | if (archive == nullptr) |
| @@ -378,7 +387,7 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||
| 378 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 387 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 379 | } | 388 | } |
| 380 | 389 | ||
| 381 | auto directory = std::make_unique<Directory>(std::move(backend), path); | 390 | auto directory = Common::make_unique<Directory>(std::move(backend), path); |
| 382 | Handle handle = Kernel::g_object_pool.Create(directory.release()); | 391 | Handle handle = Kernel::g_object_pool.Create(directory.release()); |
| 383 | return MakeResult<Handle>(handle); | 392 | return MakeResult<Handle>(handle); |
| 384 | } | 393 | } |
| @@ -392,7 +401,7 @@ ResultCode FormatSaveData() { | |||
| 392 | 401 | ||
| 393 | // Create the SaveData archive | 402 | // Create the SaveData archive |
| 394 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | 403 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); |
| 395 | auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory, | 404 | auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory, |
| 396 | Kernel::g_program_id); | 405 | Kernel::g_program_id); |
| 397 | 406 | ||
| 398 | if (savedata_archive->Initialize()) { | 407 | if (savedata_archive->Initialize()) { |
| @@ -414,14 +423,14 @@ void ArchiveInit() { | |||
| 414 | // archive type is SDMC, so it is the only one getting exposed. | 423 | // archive type is SDMC, so it is the only one getting exposed. |
| 415 | 424 | ||
| 416 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | 425 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); |
| 417 | auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); | 426 | auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory); |
| 418 | if (sdmc_archive->Initialize()) | 427 | if (sdmc_archive->Initialize()) |
| 419 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); | 428 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 420 | else | 429 | else |
| 421 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 430 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 422 | 431 | ||
| 423 | std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX); | 432 | std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX); |
| 424 | auto systemsavedata_archive = std::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory); | 433 | auto systemsavedata_archive = Common::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory); |
| 425 | if (systemsavedata_archive->Initialize()) { | 434 | if (systemsavedata_archive->Initialize()) { |
| 426 | CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData); | 435 | CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData); |
| 427 | } else { | 436 | } else { |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index df04bdb6b..b39bc41b6 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -83,6 +83,15 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil | |||
| 83 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | 83 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 84 | 84 | ||
| 85 | /** | 85 | /** |
| 86 | * Create a File in an Archive | ||
| 87 | * @param archive_handle Handle to an open Archive object | ||
| 88 | * @param path Path to the File inside of the Archive | ||
| 89 | * @param file_size The size of the new file, filled with zeroes | ||
| 90 | * @return File creation result code | ||
| 91 | */ | ||
| 92 | ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size); | ||
| 93 | |||
| 94 | /** | ||
| 86 | * Create a Directory from an Archive | 95 | * Create a Directory from an Archive |
| 87 | * @param archive_handle Handle to an open Archive object | 96 | * @param archive_handle Handle to an open Archive object |
| 88 | * @param path Path to the Directory inside of the Archive | 97 | * @param path Path to the Directory inside of the Archive |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 8d11e64b5..5e9b85cc7 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -226,6 +226,35 @@ static void DeleteDirectory(Service::Interface* self) { | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | /* | 228 | /* |
| 229 | * FS_User::CreateFile service function | ||
| 230 | * Inputs: | ||
| 231 | * 0 : Command header 0x08080202 | ||
| 232 | * 2 : Archive handle lower word | ||
| 233 | * 3 : Archive handle upper word | ||
| 234 | * 4 : File path string type | ||
| 235 | * 5 : File path string size | ||
| 236 | * 7 : File size (filled with zeroes) | ||
| 237 | * 10: File path string data | ||
| 238 | * Outputs: | ||
| 239 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 240 | */ | ||
| 241 | static void CreateFile(Service::Interface* self) { | ||
| 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 243 | |||
| 244 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||
| 245 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||
| 246 | u32 filename_size = cmd_buff[5]; | ||
| 247 | u32 file_size = cmd_buff[7]; | ||
| 248 | u32 filename_ptr = cmd_buff[10]; | ||
| 249 | |||
| 250 | FileSys::Path file_path(filename_type, filename_size, filename_ptr); | ||
| 251 | |||
| 252 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str()); | ||
| 253 | |||
| 254 | cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw; | ||
| 255 | } | ||
| 256 | |||
| 257 | /* | ||
| 229 | * FS_User::CreateDirectory service function | 258 | * FS_User::CreateDirectory service function |
| 230 | * Inputs: | 259 | * Inputs: |
| 231 | * 2 : Archive handle lower word | 260 | * 2 : Archive handle lower word |
| @@ -397,16 +426,44 @@ static void IsSdmcDetected(Service::Interface* self) { | |||
| 397 | } | 426 | } |
| 398 | 427 | ||
| 399 | /** | 428 | /** |
| 400 | * FS_User::FormatSaveData service function | 429 | * FS_User::FormatSaveData service function, |
| 430 | * formats the SaveData specified by the input path. | ||
| 401 | * Inputs: | 431 | * Inputs: |
| 432 | * 0 : 0x084C0242 | ||
| 433 | * 1 : Archive ID | ||
| 434 | * 2 : Archive low path type | ||
| 435 | * 3 : Archive low path size | ||
| 436 | * 10 : (LowPathSize << 14) | 2 | ||
| 437 | * 11 : Archive low path | ||
| 402 | * Outputs: | 438 | * Outputs: |
| 403 | * 1 : Result of function, 0 on success, otherwise error code | 439 | * 1 : Result of function, 0 on success, otherwise error code |
| 404 | */ | 440 | */ |
| 405 | static void FormatSaveData(Service::Interface* self) { | 441 | static void FormatSaveData(Service::Interface* self) { |
| 442 | // TODO(Subv): Find out what the other inputs and outputs of this function are | ||
| 406 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 443 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 407 | LOG_DEBUG(Service_FS, "(STUBBED)"); | 444 | LOG_DEBUG(Service_FS, "(STUBBED)"); |
| 408 | 445 | ||
| 409 | // TODO(Subv): Find out what the inputs and outputs of this function are | 446 | auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); |
| 447 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); | ||
| 448 | u32 archivename_size = cmd_buff[3]; | ||
| 449 | u32 archivename_ptr = cmd_buff[11]; | ||
| 450 | FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); | ||
| 451 | |||
| 452 | LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); | ||
| 453 | |||
| 454 | if (archive_id != FS::ArchiveIdCode::SaveData) { | ||
| 455 | // TODO(Subv): What should happen if somebody attempts to format a different archive? | ||
| 456 | LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]); | ||
| 457 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 458 | return; | ||
| 459 | } | ||
| 460 | |||
| 461 | if (archive_path.GetType() != FileSys::LowPathType::Empty) { | ||
| 462 | // TODO(Subv): Implement formatting the SaveData of other games | ||
| 463 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||
| 464 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 465 | return; | ||
| 466 | } | ||
| 410 | 467 | ||
| 411 | cmd_buff[1] = FormatSaveData().raw; | 468 | cmd_buff[1] = FormatSaveData().raw; |
| 412 | } | 469 | } |
| @@ -414,6 +471,7 @@ static void FormatSaveData(Service::Interface* self) { | |||
| 414 | /** | 471 | /** |
| 415 | * FS_User::FormatThisUserSaveData service function | 472 | * FS_User::FormatThisUserSaveData service function |
| 416 | * Inputs: | 473 | * Inputs: |
| 474 | * 0: 0x080F0180 | ||
| 417 | * Outputs: | 475 | * Outputs: |
| 418 | * 1 : Result of function, 0 on success, otherwise error code | 476 | * 1 : Result of function, 0 on success, otherwise error code |
| 419 | */ | 477 | */ |
| @@ -436,7 +494,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 436 | {0x08050244, RenameFile, "RenameFile"}, | 494 | {0x08050244, RenameFile, "RenameFile"}, |
| 437 | {0x08060142, DeleteDirectory, "DeleteDirectory"}, | 495 | {0x08060142, DeleteDirectory, "DeleteDirectory"}, |
| 438 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, | 496 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, |
| 439 | {0x08080202, nullptr, "CreateFile"}, | 497 | {0x08080202, CreateFile, "CreateFile"}, |
| 440 | {0x08090182, CreateDirectory, "CreateDirectory"}, | 498 | {0x08090182, CreateDirectory, "CreateDirectory"}, |
| 441 | {0x080A0244, RenameDirectory, "RenameDirectory"}, | 499 | {0x080A0244, RenameDirectory, "RenameDirectory"}, |
| 442 | {0x080B0102, OpenDirectory, "OpenDirectory"}, | 500 | {0x080B0102, OpenDirectory, "OpenDirectory"}, |
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 10c157ba6..1f841078a 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 4d39e7d0b..c98168e51 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) { | |||
| 352 | static void SleepThread(s64 nanoseconds) { | 352 | static void SleepThread(s64 nanoseconds) { |
| 353 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); | 353 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); |
| 354 | 354 | ||
| 355 | // Check for next thread to schedule | 355 | // Sleep current thread and check for next thread to schedule |
| 356 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | ||
| 356 | HLE::Reschedule(__func__); | 357 | HLE::Reschedule(__func__); |
| 357 | } | 358 | } |
| 358 | 359 | ||
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 5a4f7e7d9..4d072871a 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -223,9 +223,7 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 223 | LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); | 223 | LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); |
| 224 | FileUtil::IOFile file(filename, "rb"); | 224 | FileUtil::IOFile file(filename, "rb"); |
| 225 | if (file.IsOpen()) { | 225 | if (file.IsOpen()) { |
| 226 | 226 | THREEDSXReader::Load3DSXFile(filename, 0x00100000); | |
| 227 | THREEDSXReader reader; | ||
| 228 | reader.Load3DSXFile(filename, 0x00100000); | ||
| 229 | Kernel::LoadExec(0x00100000); | 227 | Kernel::LoadExec(0x00100000); |
| 230 | } else { | 228 | } else { |
| 231 | return ResultStatus::Error; | 229 | return ResultStatus::Error; |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 74a29ac61..87580cb2a 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <string> |
| 6 | |||
| 7 | #include "common/make_unique.h" | ||
| 6 | 8 | ||
| 7 | #include "core/file_sys/archive_romfs.h" | 9 | #include "core/file_sys/archive_romfs.h" |
| 8 | #include "core/loader/3dsx.h" | 10 | #include "core/loader/3dsx.h" |
| @@ -75,7 +77,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 75 | // Load application and RomFS | 77 | // Load application and RomFS |
| 76 | if (ResultStatus::Success == app_loader.Load()) { | 78 | if (ResultStatus::Success == app_loader.Load()) { |
| 77 | Kernel::g_program_id = app_loader.GetProgramId(); | 79 | Kernel::g_program_id = app_loader.GetProgramId(); |
| 78 | Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); | 80 | Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); |
| 79 | return ResultStatus::Success; | 81 | return ResultStatus::Success; |
| 80 | } | 82 | } |
| 81 | break; | 83 | break; |