aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp48
-rw-r--r--src/core/arm/interpreter/armemu.cpp471
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp7
-rw-r--r--src/core/file_sys/archive_backend.h11
-rw-r--r--src/core/file_sys/archive_romfs.cpp5
-rw-r--r--src/core/file_sys/archive_savedata.cpp33
-rw-r--r--src/core/file_sys/archive_savedata.h31
-rw-r--r--src/core/file_sys/archive_sdmc.cpp83
-rw-r--r--src/core/file_sys/archive_sdmc.h66
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp33
-rw-r--r--src/core/file_sys/archive_systemsavedata.h33
-rw-r--r--src/core/file_sys/directory_sdmc.cpp88
-rw-r--r--src/core/file_sys/directory_sdmc.h55
-rw-r--r--src/core/file_sys/disk_archive.cpp167
-rw-r--r--src/core/file_sys/disk_archive.h101
-rw-r--r--src/core/file_sys/file_backend.h5
-rw-r--r--src/core/file_sys/file_romfs.h2
-rw-r--r--src/core/file_sys/file_sdmc.cpp110
-rw-r--r--src/core/file_sys/file_sdmc.h75
-rw-r--r--src/core/hle/kernel/kernel.cpp1
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/semaphore.cpp8
-rw-r--r--src/core/hle/kernel/semaphore.h2
-rw-r--r--src/core/hle/kernel/shared_memory.h14
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/fs/archive.cpp67
-rw-r--r--src/core/hle/service/fs/archive.h6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp71
-rw-r--r--src/core/hle/service/gsp_gpu.cpp26
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/loader/3dsx.cpp4
-rw-r--r--src/core/loader/loader.cpp7
-rw-r--r--src/core/loader/ncch.cpp4
-rw-r--r--src/core/loader/ncch.h6
35 files changed, 971 insertions, 691 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 198e4afd..3381524e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -18,11 +18,12 @@ set(SRCS
arm/skyeye_common/vfp/vfpinstr.cpp
arm/skyeye_common/vfp/vfpsingle.cpp
file_sys/archive_romfs.cpp
+ file_sys/archive_savedata.cpp
file_sys/archive_sdmc.cpp
+ file_sys/archive_systemsavedata.cpp
+ file_sys/disk_archive.cpp
file_sys/file_romfs.cpp
- file_sys/file_sdmc.cpp
file_sys/directory_romfs.cpp
- file_sys/directory_sdmc.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
@@ -99,13 +100,14 @@ set(HEADERS
arm/arm_interface.h
file_sys/archive_backend.h
file_sys/archive_romfs.h
+ file_sys/archive_savedata.h
file_sys/archive_sdmc.h
+ file_sys/archive_systemsavedata.h
+ file_sys/disk_archive.h
file_sys/file_backend.h
file_sys/file_romfs.h
- file_sys/file_sdmc.h
file_sys/directory_backend.h
file_sys/directory_romfs.h
- file_sys/directory_sdmc.h
hle/kernel/address_arbiter.h
hle/kernel/event.h
hle/kernel/kernel.h
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 68012bff..84b4a38f 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 {
unsigned int Rn;
} smla_inst;
+typedef struct umaal_inst {
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned int RdHi;
+ unsigned int RdLo;
+} umaal_inst;
+
typedef struct _umlal_inst {
unsigned int S;
unsigned int Rm;
@@ -3010,7 +3017,26 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) { UN
ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB16"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUB8"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UHSUBADDX"); }
-ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UMAAL"); }
+ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst));
+ umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+
+ if (CHECK_RM || CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
@@ -6374,6 +6400,26 @@ unsigned InterpreterMainLoop(ARMul_State* state)
UHSUB8_INST:
UHSUBADDX_INST:
UMAAL_INST:
+ {
+ INC_ICOUNTER;
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
+
+ const u32 rm = RM;
+ const u32 rn = RN;
+ const u32 rd_lo = RDLO;
+ const u32 rd_hi = RDHI;
+
+ const u64 result = (rm * rn) + rd_lo + rd_hi;
+
+ RDLO = (result & 0xFFFFFFFF);
+ RDHI = ((result >> 32) & 0xFFFFFFFF);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umaal_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
UMLAL_INST:
{
INC_ICOUNTER;
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index b846fbe9..7a319b63 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -1356,7 +1356,13 @@ mainswitch:
}
break;
- case 0x04: /* SUB reg */
+ case 0x04: /* SUB reg */
+ // Signifies UMAAL
+ if (state->is_v6 && BITS(4, 7) == 0x09) {
+ if (handle_v6_insn(state, instr))
+ break;
+ }
+
#ifdef MODET
if (BITS (4, 7) == 0xB) {
/* STRH immediate offset, no write-back, down, post indexed. */
@@ -3103,12 +3109,18 @@ mainswitch:
state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
break;
} else if ((instr & 0x70) == 0x50) { //pkhtb
- u8 idest = BITS(12, 15);
- u8 rfis = BITS(16, 19);
- u8 rlast = BITS(0, 3);
- u8 ishi = BITS(7, 11);
- if (ishi == 0)ishi = 0x20;
- state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000);
+ const u8 rd_idx = BITS(12, 15);
+ const u8 rn_idx = BITS(16, 19);
+ const u8 rm_idx = BITS(0, 3);
+ const u8 imm5 = BITS(7, 11);
+
+ ARMword val;
+ if (imm5 >= 32)
+ val = (state->Reg[rm_idx] >> 31);
+ else
+ val = (state->Reg[rm_idx] >> imm5);
+
+ state->Reg[rd_idx] = (val & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000);
break;
} else if (BIT (4)) {
#ifdef MODE32
@@ -5669,16 +5681,29 @@ L_stm_s_takeabort:
/* Attempt to emulate an ARMv6 instruction.
Returns non-zero upon success. */
- static int
- handle_v6_insn (ARMul_State * state, ARMword instr) {
- ARMword lhs, temp;
-
- switch (BITS (20, 27)) {
+ static int handle_v6_insn(ARMul_State* state, ARMword instr) {
+ switch (BITS(20, 27)) {
case 0x03:
printf ("Unhandled v6 insn: ldr\n");
break;
- case 0x04:
- printf ("Unhandled v6 insn: umaal\n");
+ case 0x04: // UMAAL
+ {
+ const u8 rm_idx = BITS(8, 11);
+ const u8 rn_idx = BITS(0, 3);
+ const u8 rd_lo_idx = BITS(12, 15);
+ const u8 rd_hi_idx = BITS(16, 19);
+
+ const u32 rm_val = state->Reg[rm_idx];
+ const u32 rn_val = state->Reg[rn_idx];
+ const u32 rd_lo_val = state->Reg[rd_lo_idx];
+ const u32 rd_hi_val = state->Reg[rd_hi_idx];
+
+ const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val;
+
+ state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF);
+ state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF);
+ return 1;
+ }
break;
case 0x06:
printf ("Unhandled v6 insn: mls/str\n");
@@ -5691,7 +5716,7 @@ L_stm_s_takeabort:
/* strex */
u32 l = LHSReg;
u32 r = RHSReg;
- lhs = LHS;
+ u32 lhs = LHS;
bool enter = false;
@@ -5716,7 +5741,7 @@ L_stm_s_takeabort:
case 0x19:
/* ldrex */
if (BITS(4, 7) == 0x9) {
- lhs = LHS;
+ u32 lhs = LHS;
state->currentexaddr = lhs;
state->currentexval = ARMul_ReadWord(state, lhs);
@@ -5735,7 +5760,7 @@ L_stm_s_takeabort:
case 0x1c:
if (BITS(4, 7) == 0x9) {
/* strexb */
- lhs = LHS;
+ u32 lhs = LHS;
bool enter = false;
@@ -5765,11 +5790,11 @@ L_stm_s_takeabort:
case 0x1d:
if ((BITS(4, 7)) == 0x9) {
/* ldrexb */
- temp = LHS;
- LoadByte(state, instr, temp, LUNSIGNED);
+ u32 lhs = LHS;
+ LoadByte(state, instr, lhs, LUNSIGNED);
- state->currentexaddr = temp;
- state->currentexval = (u32)ARMul_ReadByte(state, temp);
+ state->currentexaddr = lhs;
+ state->currentexval = (u32)ARMul_ReadByte(state, lhs);
//state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]);
//printf("ldrexb\n");
@@ -5799,83 +5824,115 @@ L_stm_s_takeabort:
case 0x3f:
printf ("Unhandled v6 insn: rbit\n");
break;
- case 0x61:
- if ((instr & 0xFF0) == 0xf70) { //ssub16
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10);
- return 1;
- } else if ((instr & 0xFF0) == 0xf10) { //sadd16
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2) & 0xFFFF) << 0x10);
- return 1;
- } else if ((instr & 0xFF0) == 0xf50) { //ssax
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10);
- return 1;
- } else if ((instr & 0xFF0) == 0xf30) { //sasx
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10);
+ case 0x61: // SSUB16, SADD16, SSAX, and SASX
+ if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 ||
+ (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30)
+ {
+ const u8 rd_idx = BITS(12, 15);
+ const u8 rm_idx = BITS(0, 3);
+ const u8 rn_idx = BITS(16, 19);
+ const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
+ const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF);
+ const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
+ const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF);
+
+ s32 lo_result;
+ s32 hi_result;
+
+ // SSUB16
+ if ((instr & 0xFF0) == 0xf70) {
+ lo_result = (rn_lo - rm_lo);
+ hi_result = (rn_hi - rm_hi);
+ }
+ // SADD16
+ else if ((instr & 0xFF0) == 0xf10) {
+ lo_result = (rn_lo + rm_lo);
+ hi_result = (rn_hi + rm_hi);
+ }
+ // SSAX
+ else if ((instr & 0xFF0) == 0xf50) {
+ lo_result = (rn_lo + rm_hi);
+ hi_result = (rn_hi - rm_lo);
+ }
+ // SASX
+ else {
+ lo_result = (rn_lo - rm_hi);
+ hi_result = (rn_hi + rm_lo);
+ }
+
+ state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
+
+ if (lo_result >= 0) {
+ state->Cpsr |= (1 << 16);
+ state->Cpsr |= (1 << 17);
+ } else {
+ state->Cpsr &= ~(1 << 16);
+ state->Cpsr &= ~(1 << 17);
+ }
+
+ if (hi_result >= 0) {
+ state->Cpsr |= (1 << 18);
+ state->Cpsr |= (1 << 19);
+ } else {
+ state->Cpsr &= ~(1 << 18);
+ state->Cpsr &= ~(1 << 19);
+ }
return 1;
- } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n");
+ } else {
+ printf("Unhandled v6 insn: %08x", BITS(20, 27));
+ }
break;
- case 0x62:
- if ((instr & 0xFF0) == 0xf70) { //QSUB16
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- s32 res1 = (a1 - b1);
- s32 res2 = (a2 - b2);
- if (res1 > 0x7FFF) res1 = 0x7FFF;
- if (res2 > 0x7FFF) res2 = 0x7FFF;
- if (res1 < 0x7FFF) res1 = -0x8000;
- if (res2 < 0x7FFF) res2 = -0x8000;
- state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10);
- return 1;
- } else if ((instr & 0xFF0) == 0xf10) { //QADD16
- u8 tar = BITS(12, 15);
- u8 src1 = BITS(16, 19);
- u8 src2 = BITS(0, 3);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = (state->Reg[src2] & 0xFFFF);
- s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- s32 res1 = (a1 + b1);
- s32 res2 = (a2 + b2);
- if (res1 > 0x7FFF) res1 = 0x7FFF;
- if (res2 > 0x7FFF) res2 = 0x7FFF;
- if (res1 < 0x7FFF) res1 = -0x8000;
- if (res2 < 0x7FFF) res2 = -0x8000;
- state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10);
+ case 0x62: // QADD16, QASX, QSAX, and QSUB16
+ if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 ||
+ (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70)
+ {
+ const u8 rd_idx = BITS(12, 15);
+ const u8 rn_idx = BITS(16, 19);
+ const u8 rm_idx = BITS(0, 3);
+ const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
+ const s16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF);
+ const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
+ const s16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF);
+
+ s32 lo_result;
+ s32 hi_result;
+
+ // QADD16
+ if ((instr & 0xFF0) == 0xf10) {
+ lo_result = (rn_lo + rm_lo);
+ hi_result = (rn_hi + rm_hi);
+ }
+ // QASX
+ else if ((instr & 0xFF0) == 0xf30) {
+ lo_result = (rn_lo - rm_hi);
+ hi_result = (rn_hi + rm_lo);
+ }
+ // QSAX
+ else if ((instr & 0xFF0) == 0xf50) {
+ lo_result = (rn_lo + rm_hi);
+ hi_result = (rn_hi - rm_lo);
+ }
+ // QSUB16
+ else {
+ lo_result = (rn_lo - rm_lo);
+ hi_result = (rn_hi - rm_hi);
+ }
+
+ if (lo_result > 0x7FFF)
+ lo_result = 0x7FFF;
+ else if (lo_result < -0x8000)
+ lo_result = -0x8000;
+
+ if (hi_result > 0x7FFF)
+ hi_result = 0x7FFF;
+ else if (hi_result < -0x8000)
+ hi_result = -0x8000;
+
+ state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
return 1;
- } else printf ("Unhandled v6 insn: qadd16/qsub16\n");
+ } else {
+ printf("Unhandled v6 insn: %08x", BITS(20, 27));
+ }
break;
case 0x63:
printf ("Unhandled v6 insn: shadd/shsub\n");
@@ -5925,11 +5982,29 @@ L_stm_s_takeabort:
b2 = ((u8)(from >> 8) + (u8)(to >> 8));
b3 = ((u8)(from >> 16) + (u8)(to >> 16));
b4 = ((u8)(from >> 24) + (u8)(to >> 24));
- if (b1 & 0xffffff00) state->Cpsr |= (1 << 16);
- if (b2 & 0xffffff00) state->Cpsr |= (1 << 17);
- if (b3 & 0xffffff00) state->Cpsr |= (1 << 18);
- if (b4 & 0xffffff00) state->Cpsr |= (1 << 19);
+
+ if (b1 & 0xffffff00)
+ state->Cpsr |= (1 << 16);
+ else
+ state->Cpsr &= ~(1 << 16);
+
+ if (b2 & 0xffffff00)
+ state->Cpsr |= (1 << 17);
+ else
+ state->Cpsr &= ~(1 << 17);
+
+ if (b3 & 0xffffff00)
+ state->Cpsr |= (1 << 18);
+ else
+ state->Cpsr &= ~(1 << 18);
+
+
+ if (b4 & 0xffffff00)
+ state->Cpsr |= (1 << 19);
+ else
+ state->Cpsr &= ~(1 << 19);
}
+
state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24);
return 1;
}
@@ -6016,22 +6091,28 @@ L_stm_s_takeabort:
//ichfly
//SSAT16
{
- u8 tar = BITS(12, 15);
- u8 src = BITS(0, 3);
- u8 val = BITS(16, 19) + 1;
- s16 a1 = (state->Reg[src]);
- s16 a2 = (state->Reg[src] >> 0x10);
- s16 min = (s16)(0x8000 >> (16 - val));
- s16 max = 0x7FFF >> (16 - val);
- if (min > a1) a1 = min;
- if (max < a1) a1 = max;
- if (min > a2) a2 = min;
- if (max < a2) a2 = max;
- u32 temp2 = ((u32)(a2)) << 0x10;
- state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
+ const u8 rd_idx = BITS(12, 15);
+ const u8 rn_idx = BITS(0, 3);
+ const u8 num_bits = BITS(16, 19) + 1;
+ const s16 min = -(0x8000 >> (16 - num_bits));
+ const s16 max = (0x7FFF >> (16 - num_bits));
+ s16 rn_lo = (state->Reg[rn_idx]);
+ s16 rn_hi = (state->Reg[rn_idx] >> 16);
+
+ if (rn_lo > max)
+ rn_lo = max;
+ else if (rn_lo < min)
+ rn_lo = min;
+
+ if (rn_hi > max)
+ rn_hi = max;
+ else if (rn_hi < min)
+ rn_hi = min;
+
+ state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16);
+ return 1;
}
- return 1;
default:
break;
}
@@ -6044,7 +6125,7 @@ L_stm_s_takeabort:
break;
}
- Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF);
+ Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
if (Rm & 0x80)
Rm |= 0xffffff00;
@@ -6053,11 +6134,12 @@ L_stm_s_takeabort:
state->Reg[BITS(12, 15)] = Rm;
else
/* SXTAB */
- state->Reg[BITS(12, 15)] += Rm;
+ state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm;
return 1;
}
- case 0x6b: {
+ case 0x6b:
+ {
ARMword Rm;
int ror = -1;
@@ -6075,10 +6157,10 @@ L_stm_s_takeabort:
ror = 24;
break;
- case 0xf3:
+ case 0xf3: // REV
DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24);
return 1;
- case 0xfb:
+ case 0xfb: // REV16
DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8);
return 1;
default:
@@ -6088,7 +6170,7 @@ L_stm_s_takeabort:
if (ror == -1)
break;
- Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF);
+ Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
if (Rm & 0x8000)
Rm |= 0xffff0000;
@@ -6151,18 +6233,27 @@ L_stm_s_takeabort:
//ichfly
//USAT16
{
- u8 tar = BITS(12, 15);
- u8 src = BITS(0, 3);
- u8 val = BITS(16, 19);
- s16 a1 = (state->Reg[src]);
- s16 a2 = (state->Reg[src] >> 0x10);
- s16 max = 0xFFFF >> (16 - val);
- if (max < a1) a1 = max;
- if (max < a2) a2 = max;
- u32 temp2 = ((u32)(a2)) << 0x10;
- state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
+ const u8 rd_idx = BITS(12, 15);
+ const u8 rn_idx = BITS(0, 3);
+ const u8 num_bits = BITS(16, 19);
+ const s16 max = 0xFFFF >> (16 - num_bits);
+ s16 rn_lo = (state->Reg[rn_idx]);
+ s16 rn_hi = (state->Reg[rn_idx] >> 16);
+
+ if (max < rn_lo)
+ rn_lo = max;
+ else if (rn_lo < 0)
+ rn_lo = 0;
+
+ if (max < rn_hi)
+ rn_hi = max;
+ else if (rn_hi < 0)
+ rn_hi = 0;
+
+ state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF);
+ return 1;
}
- return 1;
+
default:
break;
}
@@ -6175,7 +6266,7 @@ L_stm_s_takeabort:
break;
}
- Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF);
+ Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF);
if (BITS(16, 19) == 0xf)
/* UXTB */
@@ -6205,9 +6296,13 @@ L_stm_s_takeabort:
ror = 24;
break;
- case 0xfb:
- printf("Unhandled v6 insn: revsh\n");
- return 0;
+ case 0xfb: // REVSH
+ {
+ DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8);
+ if (DEST & 0x8000)
+ DEST |= 0xffff0000;
+ return 1;
+ }
default:
break;
}
@@ -6215,13 +6310,13 @@ L_stm_s_takeabort:
if (ror == -1)
break;
- Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF);
+ Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF);
/* UXT */
/* state->Reg[BITS (12, 15)] = Rm; */
/* dyf add */
if (BITS(16, 19) == 0xf) {
- state->Reg[BITS(12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF;
+ state->Reg[BITS(12, 15)] = Rm;
}
else {
/* UXTAH */
@@ -6229,7 +6324,7 @@ L_stm_s_takeabort:
// printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)]
// , Rm, BITS(10, 11));
// printf("icounter is %lld\n", state->NumInstrs);
- state->Reg[BITS(12, 15)] = (state->Reg[BITS(16, 19)] >> (8 * (BITS(10, 11)))) + Rm;
+ state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm;
// printf("rd is %x\n", state->Reg[BITS (12, 15)]);
// exit(-1);
}
@@ -6237,45 +6332,46 @@ L_stm_s_takeabort:
return 1;
}
case 0x70:
- if ((instr & 0xf0d0) == 0xf010) { //smuad //ichfly
- u8 tar = BITS(16, 19);
- u8 src1 = BITS(0, 3);
- u8 src2 = BITS(8, 11);
- u8 swap = BIT(5);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
- s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = a1*a2 + b1*b2;
- return 1;
-
- } else if ((instr & 0xf0d0) == 0xf050) { //smusd
- u8 tar = BITS(16, 19);
- u8 src1 = BITS(0, 3);
- u8 src2 = BITS(8, 11);
- u8 swap = BIT(5);
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
- s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = a1*a2 - b1*b2;
- return 1;
- } else if ((instr & 0xd0) == 0x10) { //smlad
- u8 tar = BITS(16, 19);
- u8 src1 = BITS(0, 3);
- u8 src2 = BITS(8, 11);
- u8 src3 = BITS(12, 15);
- u8 swap = BIT(5);
-
- u32 a3 = state->Reg[src3];
-
- s16 a1 = (state->Reg[src1] & 0xFFFF);
- s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
- s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
- s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = a1*a2 + b1*b2 + a3;
+ // ichfly
+ // SMUAD, SMUSD, SMLAD, and SMLSD
+ if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 ||
+ (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50)
+ {
+ const u8 rd_idx = BITS(16, 19);
+ const u8 rn_idx = BITS(0, 3);
+ const u8 rm_idx = BITS(8, 11);
+ const u8 ra_idx = BITS(12, 15);
+ const bool do_swap = (BIT(5) == 1);
+
+ u32 rm_val = state->Reg[rm_idx];
+ const u32 rn_val = state->Reg[rn_idx];
+
+ if (do_swap)
+ rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
+
+ const s16 rm_lo = (rm_val & 0xFFFF);
+ const s16 rm_hi = ((rm_val >> 16) & 0xFFFF);
+ const s16 rn_lo = (rn_val & 0xFFFF);
+ const s16 rn_hi = ((rn_val >> 16) & 0xFFFF);
+
+ // SMUAD
+ if ((instr & 0xf0d0) == 0xf010) {
+ state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi);
+ }
+ // SMUSD
+ else if ((instr & 0xf0d0) == 0xf050) {
+ state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi);
+ }
+ // SMLAD
+ else if ((instr & 0xd0) == 0x10) {
+ state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx];
+ }
+ // SMLSD
+ else {
+ state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx];
+ }
return 1;
- } else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
+ }
break;
case 0x74:
printf ("Unhandled v6 insn: smlald/smlsld\n");
@@ -6284,7 +6380,30 @@ L_stm_s_takeabort:
printf ("Unhandled v6 insn: smmla/smmls/smmul\n");
break;
case 0x78:
- printf ("Unhandled v6 insn: usad/usada8\n");
+ if (BITS(20, 24) == 0x18)
+ {
+ const u8 rm_idx = BITS(8, 11);
+ const u8 rn_idx = BITS(0, 3);
+ const u8 rd_idx = BITS(16, 19);
+
+ const u32 rm_val = state->Reg[rm_idx];
+ const u32 rn_val = state->Reg[rn_idx];
+
+ const u8 diff1 = (u8)std::labs((rn_val & 0xFF) - (rm_val & 0xFF));
+ const u8 diff2 = (u8)std::labs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF));
+ const u8 diff3 = (u8)std::labs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF));
+ const u8 diff4 = (u8)std::labs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF));
+
+ u32 finalDif = (diff1 + diff2 + diff3 + diff4);
+
+ // Op is USADA8 if true.
+ const u8 ra_idx = BITS(12, 15);
+ if (ra_idx != 15)
+ finalDif += state->Reg[ra_idx];
+
+ state->Reg[rd_idx] = finalDif;
+ return 1;
+ }
break;
case 0x7a:
printf ("Unhandled v6 insn: usbfx\n");
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 87190049..6c33d8b7 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -614,7 +614,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
exceptions |= FPSCR_IDC;
if (tm & VFP_NAN)
- vsm.sign = 0;
+ vsm.sign = 1;
if (vsm.exponent >= 127 + 32) {
d = vsm.sign ? 0 : 0xffffffff;
@@ -1148,7 +1148,10 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
/*
* Subtraction is addition with one sign inverted.
*/
- return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
+ if (m != 0x7FC00000) // Only negate if m isn't NaN.
+ m = vfp_single_packed_negate(m);
+
+ return vfp_single_fadd(state, sd, sn, m, fpscr);
}
/*
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 18c31488..d7959b2c 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -143,7 +143,16 @@ public:
case Char:
return std::vector<u8>(string.begin(), string.end());
case Wchar:
- return std::vector<u8>(u16str.begin(), u16str.end());
+ {
+ // use two u8 for each character of u16str
+ std::vector<u8> to_return(u16str.size() * 2);
+ for (size_t i = 0; i < u16str.size(); ++i) {
+ u16 tmp_char = u16str.at(i);
+ to_return[i*2] = (tmp_char & 0xFF00) >> 8;
+ to_return[i*2 + 1] = (tmp_char & 0x00FF);
+ }
+ return to_return;
+ }
case Empty:
return {};
default:
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 0709b62a..1e3e9dc6 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -5,6 +5,7 @@
#include <memory>
#include "common/common_types.h"
+#include "common/make_unique.h"
#include "core/file_sys/archive_romfs.h"
#include "core/file_sys/directory_romfs.h"
@@ -29,7 +30,7 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) {
* @return Opened file, or nullptr
*/
std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const {
- return std::make_unique<File_RomFS>(this);
+ return Common::make_unique<File_RomFS>(this);
}
/**
@@ -78,7 +79,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys
* @return Opened directory, or nullptr
*/
std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const {
- return std::make_unique<Directory_RomFS>();
+ return Common::make_unique<Directory_RomFS>();
}
} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
new file mode 100644
index 00000000..2414564e
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -0,0 +1,33 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/archive_savedata.h"
+#include "core/file_sys/disk_archive.h"
+#include "core/settings.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)
+ : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) {
+ LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
+}
+
+bool Archive_SaveData::Initialize() {
+ if (!FileUtil::CreateFullPath(mount_point)) {
+ LOG_ERROR(Service_FS, "Unable to create SaveData path.");
+ return false;
+ }
+
+ return true;
+}
+
+} // 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 00000000..d394ad37
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.h
@@ -0,0 +1,31 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/disk_archive.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/// File system interface to the SaveData archive
+class Archive_SaveData final : public DiskArchive {
+public:
+ Archive_SaveData(const std::string& mount_point, u64 program_id);
+
+ /**
+ * Initialize the archive.
+ * @return true if it initialized successfully
+ */
+ bool Initialize();
+
+ std::string GetName() const override { return "SaveData"; }
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 9d58668e..dccdf7f6 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -8,8 +8,7 @@
#include "common/file_util.h"
#include "core/file_sys/archive_sdmc.h"
-#include "core/file_sys/directory_sdmc.h"
-#include "core/file_sys/file_sdmc.h"
+#include "core/file_sys/disk_archive.h"
#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -17,18 +16,10 @@
namespace FileSys {
-Archive_SDMC::Archive_SDMC(const std::string& mount_point) {
- this->mount_point = mount_point;
+Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {
LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());
}
-Archive_SDMC::~Archive_SDMC() {
-}
-
-/**
- * Initialize the archive.
- * @return true if it initialized successfully
- */
bool Archive_SDMC::Initialize() {
if (!Settings::values.use_virtual_sd) {
LOG_WARNING(Service_FS, "SDMC disabled by config.");
@@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() {
return true;
}
-/**
- * Open a file specified by its path, using the specified mode
- * @param path Path relative to the archive
- * @param mode Mode to open the file with
- * @return Opened file, or nullptr
- */
-std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
- LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);
- File_SDMC* file = new File_SDMC(this, path, mode);
- if (!file->Open())
- return nullptr;
- return std::unique_ptr<FileBackend>(file);
-}
-
-/**
- * Delete a file specified by its path
- * @param path Path relative to the archive
- * @return Whether the file could be deleted
- */
-bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
- return FileUtil::Delete(GetMountPoint() + path.AsString());
-}
-
-bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
- return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
-}
-
-/**
- * Delete a directory specified by its path
- * @param path Path relative to the archive
- * @return Whether the directory could be deleted
- */
-bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
- return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
-}
-
-/**
- * Create a directory specified by its path
- * @param path Path relative to the archive
- * @return Whether the directory could be created
- */
-bool Archive_SDMC::CreateDirectory(const Path& path) const {
- return FileUtil::CreateDir(GetMountPoint() + path.AsString());
-}
-
-bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
- return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
-}
-
-/**
- * Open a directory specified by its path
- * @param path Path relative to the archive
- * @return Opened directory, or nullptr
- */
-std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const {
- LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
- Directory_SDMC* directory = new Directory_SDMC(this, path);
- if (!directory->Open())
- return nullptr;
- return std::unique_ptr<DirectoryBackend>(directory);
-}
-
-/**
- * Getter for the path used for this Archive
- * @return Mount point of that passthrough archive
- */
-std::string Archive_SDMC::GetMountPoint() const {
- return mount_point;
-}
-
} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 05904524..c84c6948 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -6,7 +6,7 @@
#include "common/common_types.h"
-#include "core/file_sys/archive_backend.h"
+#include "core/file_sys/disk_archive.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,10 +15,9 @@
namespace FileSys {
/// File system interface to the SDMC archive
-class Archive_SDMC final : public ArchiveBackend {
+class Archive_SDMC final : public DiskArchive {
public:
Archive_SDMC(const std::string& mount_point);
- ~Archive_SDMC() override;
/**
* Initialize the archive.
@@ -27,67 +26,6 @@ public:
bool Initialize();
std::string GetName() const override { return "SDMC"; }
-
- /**
- * Open a file specified by its path, using the specified mode
- * @param path Path relative to the archive
- * @param mode Mode to open the file with
- * @return Opened file, or nullptr
- */
- std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
-
- /**
- * Delete a file specified by its path
- * @param path Path relative to the archive
- * @return Whether the file could be deleted
- */
- bool DeleteFile(const FileSys::Path& path) const override;
-
- /**
- * Rename a File specified by its path
- * @param src_path Source path relative to the archive
- * @param dest_path Destination path relative to the archive
- * @return Whether rename succeeded
- */
- bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
-
- /**
- * Delete a directory specified by its path
- * @param path Path relative to the archive
- * @return Whether the directory could be deleted
- */
- bool DeleteDirectory(const FileSys::Path& path) const override;
-
- /**
- * Create a directory specified by its path
- * @param path Path relative to the archive
- * @return Whether the directory could be created
- */
- bool CreateDirectory(const Path& path) const override;
-
- /**
- * Rename a Directory specified by its path
- * @param src_path Source path relative to the archive
- * @param dest_path Destination path relative to the archive
- * @return Whether rename succeeded
- */
- bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
-
- /**
- * Open a directory specified by its path
- * @param path Path relative to the archive
- * @return Opened directory, or nullptr
- */
- std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
-
- /**
- * Getter for the path used for this Archive
- * @return Mount point of that passthrough archive
- */
- std::string GetMountPoint() const;
-
-private:
- std::string mount_point;
};
} // 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 00000000..dc2c23b4
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -0,0 +1,33 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/archive_systemsavedata.h"
+#include "core/file_sys/disk_archive.h"
+#include "core/settings.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point)
+ : DiskArchive(mount_point) {
+ LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str());
+}
+
+bool Archive_SystemSaveData::Initialize() {
+ if (!FileUtil::CreateFullPath(mount_point)) {
+ LOG_ERROR(Service_FS, "Unable to create SystemSaveData path.");
+ return false;
+ }
+
+ return true;
+}
+
+} // 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 00000000..360ed1e1
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -0,0 +1,33 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/disk_archive.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/// File system interface to the SystemSaveData archive
+/// TODO(Subv): This archive should point to a location in the NAND,
+/// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High>
+class Archive_SystemSaveData final : public DiskArchive {
+public:
+ Archive_SystemSaveData(const std::string& mount_point);
+
+ /**
+ * Initialize the archive.
+ * @return true if it initialized successfully
+ */
+ bool Initialize();
+
+ std::string GetName() const override { return "SystemSaveData"; }
+};
+
+} // 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 51978764..00000000
--- a/src/core/file_sys/directory_sdmc.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include <sys/stat.h>
-
-#include "common/common_types.h"
-#include "common/file_util.h"
-
-#include "core/file_sys/directory_sdmc.h"
-#include "core/file_sys/archive_sdmc.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
-
-namespace FileSys {
-
-Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
- // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
- // the root directory we set while opening the archive.
- // For example, opening /../../usr/bin can give the emulated program your installed programs.
- this->path = archive->GetMountPoint() + path.AsString();
-
-}
-
-Directory_SDMC::~Directory_SDMC() {
- Close();
-}
-
-bool Directory_SDMC::Open() {
- if (!FileUtil::IsDirectory(path))
- return false;
- FileUtil::ScanDirectoryTree(path, directory);
- children_iterator = directory.children.begin();
- return true;
-}
-
-/**
- * List files contained in the directory
- * @param count Number of entries to return at once in entries
- * @param entries Buffer to read data into
- * @return Number of entries listed
- */
-u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
- u32 entries_read = 0;
-
- while (entries_read < count && children_iterator != directory.children.cend()) {
- const FileUtil::FSTEntry& file = *children_iterator;
- const std::string& filename = file.virtualName;
- Entry& entry = entries[entries_read];
-
- LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
-
- // TODO(Link Mauve): use a proper conversion to UTF-16.
- for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
- entry.filename[j] = filename[j];
- if (!filename[j])
- break;
- }
-
- FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
-
- entry.is_directory = file.isDirectory;
- entry.is_hidden = (filename[0] == '.');
- entry.is_read_only = 0;
- entry.file_size = file.size;
-
- // We emulate a SD card where the archive bit has never been cleared, as it would be on
- // most user SD cards.
- // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
- // file bit.
- entry.is_archive = !file.isDirectory;
-
- ++entries_read;
- ++children_iterator;
- }
- return entries_read;
-}
-
-/**
- * Close the directory
- * @return true if the directory closed correctly
- */
-bool Directory_SDMC::Close() const {
- return true;
-}
-
-} // 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 407a256e..00000000
--- a/src/core/file_sys/directory_sdmc.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-#include "common/file_util.h"
-
-#include "core/file_sys/directory_backend.h"
-#include "core/file_sys/archive_sdmc.h"
-#include "core/loader/loader.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
-
-namespace FileSys {
-
-class Directory_SDMC final : public DirectoryBackend {
-public:
- Directory_SDMC();
- Directory_SDMC(const Archive_SDMC* archive, const Path& path);
- ~Directory_SDMC() override;
-
- /**
- * Open the directory
- * @return true if the directory opened correctly
- */
- bool Open() override;
-
- /**
- * List files contained in the directory
- * @param count Number of entries to return at once in entries
- * @param entries Buffer to read data into
- * @return Number of entries listed
- */
- u32 Read(const u32 count, Entry* entries) override;
-
- /**
- * Close the directory
- * @return true if the directory closed correctly
- */
- bool Close() const override;
-
-private:
- std::string path;
- u32 total_entries_in_directory;
- FileUtil::FSTEntry directory;
-
- // We need to remember the last entry we returned, so a subsequent call to Read will continue
- // from the next one. This iterator will always point to the next unread entry.
- std::vector<FileUtil::FSTEntry>::iterator children_iterator;
-};
-
-} // 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 00000000..eabf5805
--- /dev/null
+++ b/src/core/file_sys/disk_archive.cpp
@@ -0,0 +1,167 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/disk_archive.h"
+#include "core/settings.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
+ LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
+ DiskFile* file = new DiskFile(this, path, mode);
+ if (!file->Open())
+ return nullptr;
+ return std::unique_ptr<FileBackend>(file);
+}
+
+bool DiskArchive::DeleteFile(const FileSys::Path& path) const {
+ return FileUtil::Delete(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
+ return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
+}
+
+bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const {
+ return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::CreateDirectory(const Path& path) const {
+ return FileUtil::CreateDir(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
+ return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
+}
+
+std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const {
+ LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
+ DiskDirectory* directory = new DiskDirectory(this, path);
+ if (!directory->Open())
+ return nullptr;
+ return std::unique_ptr<DirectoryBackend>(directory);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../etc/passwd can give the emulated program your users list.
+ this->path = archive->GetMountPoint() + path.AsString();
+ this->mode.hex = mode.hex;
+ this->archive = archive;
+}
+
+bool DiskFile::Open() {
+ if (!mode.create_flag && !FileUtil::Exists(path)) {
+ LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
+ return false;
+ }
+
+ std::string mode_string;
+ if (mode.create_flag)
+ mode_string = "w+";
+ else if (mode.write_flag)
+ mode_string = "r+"; // Files opened with Write access can be read from
+ else if (mode.read_flag)
+ mode_string = "r";
+
+ // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
+ mode_string += "b";
+
+ file = new FileUtil::IOFile(path, mode_string.c_str());
+ return true;
+}
+
+size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ return file->ReadBytes(buffer, length);
+}
+
+size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ size_t written = file->WriteBytes(buffer, length);
+ if (flush)
+ file->Flush();
+ return written;
+}
+
+size_t DiskFile::GetSize() const {
+ return static_cast<size_t>(file->GetSize());
+}
+
+bool DiskFile::SetSize(const u64 size) const {
+ file->Resize(size);
+ file->Flush();
+ return true;
+}
+
+bool DiskFile::Close() const {
+ return file->Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../usr/bin can give the emulated program your installed programs.
+ this->path = archive->GetMountPoint() + path.AsString();
+ this->archive = archive;
+}
+
+bool DiskDirectory::Open() {
+ if (!FileUtil::IsDirectory(path))
+ return false;
+ FileUtil::ScanDirectoryTree(path, directory);
+ children_iterator = directory.children.begin();
+ return true;
+}
+
+u32 DiskDirectory::Read(const u32 count, Entry* entries) {
+ u32 entries_read = 0;
+
+ while (entries_read < count && children_iterator != directory.children.cend()) {
+ const FileUtil::FSTEntry& file = *children_iterator;
+ const std::string& filename = file.virtualName;
+ Entry& entry = entries[entries_read];
+
+ LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
+
+ // TODO(Link Mauve): use a proper conversion to UTF-16.
+ for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
+ entry.filename[j] = filename[j];
+ if (!filename[j])
+ break;
+ }
+
+ FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
+
+ entry.is_directory = file.isDirectory;
+ entry.is_hidden = (filename[0] == '.');
+ entry.is_read_only = 0;
+ entry.file_size = file.size;
+
+ // We emulate a SD card where the archive bit has never been cleared, as it would be on
+ // most user SD cards.
+ // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
+ // file bit.
+ entry.is_archive = !file.isDirectory;
+
+ ++entries_read;
+ ++children_iterator;
+ }
+ return entries_read;
+}
+
+} // 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 00000000..778c8395
--- /dev/null
+++ b/src/core/file_sys/disk_archive.h
@@ -0,0 +1,101 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/archive_backend.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/**
+ * Helper which implements a backend accessing the host machine's filesystem.
+ * This should be subclassed by concrete archive types, which will provide the
+ * base directory on the host filesystem and override any required functionality.
+ */
+class DiskArchive : public ArchiveBackend {
+public:
+ DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
+
+ virtual std::string GetName() const = 0;
+ std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
+ bool DeleteFile(const FileSys::Path& path) const override;
+ bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
+ bool DeleteDirectory(const FileSys::Path& path) const override;
+ bool CreateDirectory(const Path& path) const override;
+ bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
+ std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
+
+ /**
+ * Getter for the path used for this Archive
+ * @return Mount point of that passthrough archive
+ */
+ const std::string& GetMountPoint() const {
+ return mount_point;
+ }
+
+protected:
+ std::string mount_point;
+};
+
+class DiskFile : public FileBackend {
+public:
+ DiskFile();
+ DiskFile(const DiskArchive* archive, const Path& path, const Mode mode);
+
+ ~DiskFile() override {
+ Close();
+ }
+
+ bool Open() override;
+ size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
+ size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
+ size_t GetSize() const override;
+ bool SetSize(const u64 size) const override;
+ bool Close() const override;
+
+ void Flush() const override {
+ file->Flush();
+ }
+
+protected:
+ const DiskArchive* archive;
+ std::string path;
+ Mode mode;
+ FileUtil::IOFile* file;
+};
+
+class DiskDirectory : public DirectoryBackend {
+public:
+ DiskDirectory();
+ DiskDirectory(const DiskArchive* archive, const Path& path);
+
+ ~DiskDirectory() override {
+ Close();
+ }
+
+ bool Open() override;
+ u32 Read(const u32 count, Entry* entries) override;
+
+ bool Close() const override {
+ return true;
+ }
+
+protected:
+ const DiskArchive* archive;
+ std::string path;
+ u32 total_entries_in_directory;
+ FileUtil::FSTEntry directory;
+
+ // We need to remember the last entry we returned, so a subsequent call to Read will continue
+ // from the next one. This iterator will always point to the next unread entry.
+ std::vector<FileUtil::FSTEntry>::iterator children_iterator;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 1b81d5fe..539ec731 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -61,6 +61,11 @@ public:
* @return true if the file closed correctly
*/
virtual bool Close() const = 0;
+
+ /**
+ * Flushes the file
+ */
+ virtual void Flush() const = 0;
};
} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h
index 09fa2e7e..32fa6b6d 100644
--- a/src/core/file_sys/file_romfs.h
+++ b/src/core/file_sys/file_romfs.h
@@ -64,6 +64,8 @@ public:
*/
bool Close() const override;
+ void Flush() const override { }
+
private:
const Archive_RomFS* archive;
};
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
deleted file mode 100644
index 46c29900..00000000
--- a/src/core/file_sys/file_sdmc.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include <sys/stat.h>
-
-#include "common/common_types.h"
-#include "common/file_util.h"
-
-#include "core/file_sys/file_sdmc.h"
-#include "core/file_sys/archive_sdmc.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
-
-namespace FileSys {
-
-File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) {
- // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
- // the root directory we set while opening the archive.
- // For example, opening /../../etc/passwd can give the emulated program your users list.
- this->path = archive->GetMountPoint() + path.AsString();
- this->mode.hex = mode.hex;
-}
-
-File_SDMC::~File_SDMC() {
- Close();
-}
-
-/**
- * Open the file
- * @return true if the file opened correctly
- */
-bool File_SDMC::Open() {
- if (!mode.create_flag && !FileUtil::Exists(path)) {
- LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
- return false;
- }
-
- std::string mode_string;
- if (mode.create_flag)
- mode_string = "w+";
- else if (mode.write_flag)
- mode_string = "r+"; // Files opened with Write access can be read from
- else if (mode.read_flag)
- mode_string = "r";
-
- // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
- mode_string += "b";
-
- file = new FileUtil::IOFile(path, mode_string.c_str());
- return true;
-}
-
-/**
- * Read data from the file
- * @param offset Offset in bytes to start reading data from
- * @param length Length in bytes of data to read from file
- * @param buffer Buffer to read data into
- * @return Number of bytes read
- */
-size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
- file->Seek(offset, SEEK_SET);
- return file->ReadBytes(buffer, length);
-}
-
-/**
- * Write data to the file
- * @param offset Offset in bytes to start writing data to
- * @param length Length in bytes of data to write to file
- * @param flush The flush parameters (0 == do not flush)
- * @param buffer Buffer to read data from
- * @return Number of bytes written
- */
-size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
- file->Seek(offset, SEEK_SET);
- size_t written = file->WriteBytes(buffer, length);
- if (flush)
- file->Flush();
- return written;
-}
-
-/**
- * Get the size of the file in bytes
- * @return Size of the file in bytes
- */
-size_t File_SDMC::GetSize() const {
- return static_cast<size_t>(file->GetSize());
-}
-
-/**
- * Set the size of the file in bytes
- * @param size New size of the file
- * @return true if successful
- */
-bool File_SDMC::SetSize(const u64 size) const {
- file->Resize(size);
- file->Flush();
- return true;
-}
-
-/**
- * Close the file
- * @return true if the file closed correctly
- */
-bool File_SDMC::Close() const {
- return file->Close();
-}
-
-} // 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 e0154859..00000000
--- a/src/core/file_sys/file_sdmc.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-#include "common/file_util.h"
-
-#include "core/file_sys/file_backend.h"
-#include "core/file_sys/archive_sdmc.h"
-#include "core/loader/loader.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
-
-namespace FileSys {
-
-class File_SDMC final : public FileBackend {
-public:
- File_SDMC();
- File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
- ~File_SDMC() override;
-
- /**
- * Open the file
- * @return true if the file opened correctly
- */
- bool Open() override;
-
- /**
- * Read data from the file
- * @param offset Offset in bytes to start reading data from
- * @param length Length in bytes of data to read from file
- * @param buffer Buffer to read data into
- * @return Number of bytes read
- */
- size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
-
- /**
- * Write data to the file
- * @param offset Offset in bytes to start writing data to
- * @param length Length in bytes of data to write to file
- * @param flush The flush parameters (0 == do not flush)
- * @param buffer Buffer to read data from
- * @return Number of bytes written
- */
- size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
-
- /**
- * Get the size of the file in bytes
- * @return Size of the file in bytes
- */
- size_t GetSize() const override;
-
- /**
- * Set the size of the file in bytes
- * @param size New size of the file
- * @return true if successful
- */
- bool SetSize(const u64 size) const override;
-
- /**
- * Close the file
- * @return true if the file closed correctly
- */
- bool Close() const override;
-
-private:
- std::string path;
- Mode mode;
- FileUtil::IOFile* file;
-};
-
-} // namespace FileSys
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 929422b3..6a690e91 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -14,6 +14,7 @@ namespace Kernel {
Handle g_main_thread = 0;
ObjectPool g_object_pool;
+u64 g_program_id = 0;
ObjectPool::ObjectPool() {
next_id = INITIAL_NEXT_ID;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 861a8e69..683fffee 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -163,6 +163,12 @@ private:
extern ObjectPool g_object_pool;
extern Handle g_main_thread;
+/// The ID code of the currently running game
+/// TODO(Subv): This variable should not be here,
+/// we need a way to store information about the currently loaded application
+/// for later query during runtime, maybe using the LDR service?
+extern u64 g_program_id;
+
/// Initialize the kernel
void Init();
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 6f56da8a..f955d195 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -20,8 +20,8 @@ public:
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; }
Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; }
- u32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
- u32 available_count; ///< Number of free slots left in the semaphore
+ s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
+ s32 available_count; ///< Number of free slots left in the semaphore
std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
std::string name; ///< Name of semaphore (optional)
@@ -49,8 +49,8 @@ public:
////////////////////////////////////////////////////////////////////////////////////////////////////
-ResultCode CreateSemaphore(Handle* handle, u32 initial_count,
- u32 max_count, const std::string& name) {
+ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
+ s32 max_count, const std::string& name) {
if (initial_count > max_count)
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index f0075fdb..ad474b87 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -18,7 +18,7 @@ namespace Kernel {
* @param name Optional name of semaphore
* @return ResultCode of the error
*/
-ResultCode CreateSemaphore(Handle* handle, u32 initial_count, u32 max_count, const std::string& name = "Unknown");
+ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown");
/**
* Releases a certain number of slots from a semaphore.
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 304cf5b6..bb778ec2 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -12,11 +12,15 @@ namespace Kernel {
/// Permissions for mapped shared memory blocks
enum class MemoryPermission : u32 {
- None = 0,
- Read = (1u << 0),
- Write = (1u << 1),
- ReadWrite = (Read | Write),
- DontCare = (1u << 28)
+ None = 0,
+ Read = (1u << 0),
+ Write = (1u << 1),
+ ReadWrite = (Read | Write),
+ Execute = (1u << 2),
+ ReadExecute = (Read | Execute),
+ WriteExecute = (Write | Execute),
+ ReadWriteExecute = (Read | Write | Execute),
+ DontCare = (1u << 28)
};
/**
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 15c4a267..14d2be4a 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -17,6 +17,8 @@
/// Detailed description of the error. This listing is likely incomplete.
enum class ErrorDescription : u32 {
Success = 0,
+ FS_NotFound = 100,
+ FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
InvalidSection = 1000,
TooLarge = 1001,
NotAuthorized = 1002,
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index caf82d55..510d7320 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -7,8 +7,10 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/make_unique.h"
#include "common/math_util.h"
+#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/archive_sdmc.h"
#include "core/file_sys/directory_backend.h"
@@ -135,6 +137,13 @@ public:
break;
}
+ case FileCommand::Flush:
+ {
+ LOG_TRACE(Service_FS, "Flush");
+ backend->Flush();
+ break;
+ }
+
// Unknown command...
default:
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
@@ -220,9 +229,18 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) {
auto itr = id_code_map.find(id_code);
if (itr == id_code_map.end()) {
+ if (id_code == ArchiveIdCode::SaveData) {
+ // When a SaveData archive is created for the first time, it is not yet formatted
+ // and the save file/directory structure expected by the game has not yet been initialized.
+ // Returning the NotFormatted error code will signal the game to provision the SaveData archive
+ // with the files and folders that it expects.
+ // The FormatSaveData service call will create the SaveData archive when it is called.
+ return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
+ ErrorSummary::InvalidState, ErrorLevel::Status);
+ }
// TODO: Verify error against hardware
return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
- ErrorSummary::NotFound, ErrorLevel::Permanent);
+ ErrorSummary::NotFound, ErrorLevel::Permanent);
}
// This should never even happen in the first place with 64-bit handles,
@@ -243,7 +261,7 @@ ResultCode CloseArchive(ArchiveHandle handle) {
// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) {
- auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code));
+ auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code));
bool inserted = result.second;
_dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code");
@@ -260,11 +278,11 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy
std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode);
if (backend == nullptr) {
- return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
- ErrorSummary::NotFound, ErrorLevel::Permanent);
+ return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
+ ErrorSummary::NotFound, ErrorLevel::Status);
}
- auto file = std::make_unique<File>(std::move(backend), path);
+ auto file = Common::make_unique<File>(std::move(backend), path);
Handle handle = Kernel::g_object_pool.Create(file.release());
return MakeResult<Handle>(handle);
}
@@ -361,11 +379,33 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F
ErrorSummary::NotFound, ErrorLevel::Permanent);
}
- auto directory = std::make_unique<Directory>(std::move(backend), path);
+ auto directory = Common::make_unique<Directory>(std::move(backend), path);
Handle handle = Kernel::g_object_pool.Create(directory.release());
return MakeResult<Handle>(handle);
}
+ResultCode FormatSaveData() {
+ // TODO(Subv): Actually wipe the savedata folder after creating or opening it
+
+ // Do not create the archive again if it already exists
+ if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end())
+ return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code
+
+ // Create the SaveData archive
+ std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX);
+ auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory,
+ Kernel::g_program_id);
+
+ if (savedata_archive->Initialize()) {
+ CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData);
+ return RESULT_SUCCESS;
+ } else {
+ LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s",
+ savedata_archive->GetMountPoint().c_str());
+ return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code
+ }
+}
+
/// Initialize archives
void ArchiveInit() {
next_handle = 1;
@@ -375,11 +415,20 @@ void ArchiveInit() {
// archive type is SDMC, so it is the only one getting exposed.
std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
- auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
- if (archive->Initialize())
- CreateArchive(std::move(archive), ArchiveIdCode::SDMC);
+ auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
+ if (sdmc_archive->Initialize())
+ CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);
else
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
+
+ std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX);
+ auto systemsavedata_archive = Common::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory);
+ if (systemsavedata_archive->Initialize()) {
+ CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData);
+ } else {
+ LOG_ERROR(Service_FS, "Can't instantiate SystemSaveData archive with path %s",
+ systemsavedata_directory.c_str());
+ }
}
/// Shutdown archives
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index a38de92e..a128276b 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
*/
ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
+/**
+ * Creates a blank SaveData archive.
+ * @return ResultCode 0 on success or the corresponding code on error
+ */
+ResultCode FormatSaveData();
+
/// Initialize archives
void ArchiveInit();
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 0f75d5e3..8b908d69 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -3,11 +3,11 @@
// Refer to the license.txt file included.
#include "common/common.h"
+#include "common/file_util.h"
#include "common/scope_exit.h"
-
#include "common/string_util.h"
-#include "core/hle/service/fs/archive.h"
#include "core/hle/result.h"
+#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
#include "core/settings.h"
@@ -50,9 +50,7 @@ static void Initialize(Service::Interface* self) {
static void OpenFile(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
- // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
- Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
+ ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
u32 filename_size = cmd_buff[5];
FileSys::Mode mode; mode.hex = cmd_buff[6];
@@ -398,6 +396,65 @@ static void IsSdmcDetected(Service::Interface* self) {
LOG_DEBUG(Service_FS, "called");
}
+/**
+ * FS_User::FormatSaveData service function,
+ * formats the SaveData specified by the input path.
+ * Inputs:
+ * 0 : 0x084C0242
+ * 1 : Archive ID
+ * 2 : Archive low path type
+ * 3 : Archive low path size
+ * 10 : (LowPathSize << 14) | 2
+ * 11 : Archive low path
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void FormatSaveData(Service::Interface* self) {
+ // TODO(Subv): Find out what the other inputs and outputs of this function are
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ LOG_DEBUG(Service_FS, "(STUBBED)");
+
+ auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
+ auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
+ u32 archivename_size = cmd_buff[3];
+ u32 archivename_ptr = cmd_buff[11];
+ FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
+
+ LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
+
+ if (archive_id != FS::ArchiveIdCode::SaveData) {
+ // TODO(Subv): What should happen if somebody attempts to format a different archive?
+ LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]);
+ cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
+ return;
+ }
+
+ if (archive_path.GetType() != FileSys::LowPathType::Empty) {
+ // TODO(Subv): Implement formatting the SaveData of other games
+ LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
+ cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
+ return;
+ }
+
+ cmd_buff[1] = FormatSaveData().raw;
+}
+
+/**
+ * FS_User::FormatThisUserSaveData service function
+ * Inputs:
+ * 0: 0x080F0180
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void FormatThisUserSaveData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ LOG_DEBUG(Service_FS, "(STUBBED)");
+
+ // TODO(Subv): Find out what the inputs and outputs of this function are
+
+ cmd_buff[1] = FormatSaveData().raw;
+}
+
const FSUserInterface::FunctionInfo FunctionTable[] = {
{0x000100C6, nullptr, "Dummy1"},
{0x040100C4, nullptr, "Control"},
@@ -415,7 +472,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
{0x080C00C2, OpenArchive, "OpenArchive"},
{0x080D0144, nullptr, "ControlArchive"},
{0x080E0080, CloseArchive, "CloseArchive"},
- {0x080F0180, nullptr, "FormatThisUserSaveData"},
+ {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"},
{0x08100200, nullptr, "CreateSystemSaveData"},
{0x08110040, nullptr, "DeleteSystemSaveData"},
{0x08120080, nullptr, "GetFreeBytes"},
@@ -476,7 +533,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
{0x08490040, nullptr, "GetArchiveResource"},
{0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
{0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
- {0x084C0242, nullptr, "FormatSaveData"},
+ {0x084C0242, FormatSaveData, "FormatSaveData"},
{0x084D0102, nullptr, "GetLegacySubBannerData"},
{0x084E0342, nullptr, "UpdateSha256Context"},
{0x084F0102, nullptr, "ReadSpecialFile"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index db802714..8c9ad271 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) {
}
/**
+ * GSP_GPU::FlushDataCache service function
+ *
+ * This Function is a no-op, We aren't emulating the CPU cache any time soon.
+ *
+ * Inputs:
+ * 1 : Address
+ * 2 : Size
+ * 3 : Value 0, some descriptor for the KProcess Handle
+ * 4 : KProcess handle
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void FlushDataCache(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 address = cmd_buff[1];
+ u32 size = cmd_buff[2];
+ u32 process = cmd_buff[4];
+
+ // TODO(purpasmart96): Verify return header on HW
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+}
+
+/**
* GSP_GPU::RegisterInterruptRelayQueue service function
* Inputs:
* 1 : "Flags" field, purpose is unknown
@@ -335,7 +359,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00050200, SetBufferSwap, "SetBufferSwap"},
{0x00060082, nullptr, "SetCommandList"},
{0x000700C2, nullptr, "RequestDma"},
- {0x00080082, nullptr, "FlushDataCache"},
+ {0x00080082, FlushDataCache, "FlushDataCache"},
{0x00090082, nullptr, "InvalidateDataCache"},
{0x000A0044, nullptr, "RegisterInterruptEvents"},
{0x000B0040, nullptr, "SetLcdForceBlack"},
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 15cc240f..47e9bf77 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
case Kernel::MemoryPermission::Read:
case Kernel::MemoryPermission::Write:
case Kernel::MemoryPermission::ReadWrite:
+ case Kernel::MemoryPermission::Execute:
+ case Kernel::MemoryPermission::ReadExecute:
+ case Kernel::MemoryPermission::WriteExecute:
+ case Kernel::MemoryPermission::ReadWriteExecute:
case Kernel::MemoryPermission::DontCare:
Kernel::MapSharedMemory(handle, addr, permissions_type,
static_cast<Kernel::MemoryPermission>(other_permissions));
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 0437e537..3d84fc5d 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)
LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
-
- THREEDSXReader reader;
- reader.Load3DSXFile(filename, 0x00100000);
+ THREEDSXReader::Load3DSXFile(filename, 0x00100000);
Kernel::LoadExec(0x00100000);
} else {
return ResultStatus::Error;
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 463dacca..b3b58da7 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -2,7 +2,9 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#include <memory>
+#include <string>
+
+#include "common/make_unique.h"
#include "core/file_sys/archive_romfs.h"
#include "core/loader/3dsx.h"
@@ -74,7 +76,8 @@ ResultStatus LoadFile(const std::string& filename) {
// Load application and RomFS
if (ResultStatus::Success == app_loader.Load()) {
- Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
+ Kernel::g_program_id = app_loader.GetProgramId();
+ Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
return ResultStatus::Success;
}
break;
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index ba9ba00c..4d23656e 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 {
return ResultStatus::Error;
}
+u64 AppLoader_NCCH::GetProgramId() const {
+ return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]);
+}
+
} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 03116add..2fe2a7d8 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -191,6 +191,12 @@ public:
*/
ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
+ /*
+ * Gets the program id from the NCCH header
+ * @return u64 Program id
+ */
+ u64 GetProgramId() const;
+
private:
/**