summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/citra/default_ini.h2
-rw-r--r--src/citra_qt/bootmanager.cpp21
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp11
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp115
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h2
-rw-r--r--src/core/core.h12
-rw-r--r--src/core/hle/service/apt_u.cpp109
-rw-r--r--src/core/hle/service/frd_u.cpp35
-rw-r--r--src/core/hle/service/frd_u.h27
-rw-r--r--src/core/hle/service/service.cpp2
11 files changed, 238 insertions, 100 deletions
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 7352c70c2..557da881b 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -28,7 +28,7 @@ pad_sright =
[Core]
cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental)
-gpu_refresh_rate = ## 60 (default), 1024 or 2048 may work better on the FastInterpreter
+gpu_refresh_rate = ## 60 (default)
[Data Storage]
use_virtual_sd =
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 8f3799351..20824692d 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -33,19 +33,16 @@ void EmuThread::run()
stop_run = false;
while (!stop_run)
{
- for (int tight_loop = 0; tight_loop < 10000; ++tight_loop)
+ if (cpu_running)
{
- if (cpu_running || exec_cpu_step)
- {
- if (exec_cpu_step)
- exec_cpu_step = false;
-
- Core::SingleStep();
- if (!cpu_running) {
- emit CPUStepped();
- yieldCurrentThread();
- }
- }
+ Core::RunLoop();
+ }
+ else if (exec_cpu_step)
+ {
+ exec_cpu_step = false;
+ Core::SingleStep();
+ emit CPUStepped();
+ yieldCurrentThread();
}
}
render_window->moveContext();
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f67481359..f41d52e80 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRCS
hle/service/dsp_dsp.cpp
hle/service/err_f.cpp
hle/service/fs_user.cpp
+ hle/service/frd_u.cpp
hle/service/gsp_gpu.cpp
hle/service/hid_user.cpp
hle/service/mic_u.cpp
@@ -106,6 +107,7 @@ set(HEADERS
hle/service/dsp_dsp.h
hle/service/err_f.h
hle/service/fs_user.h
+ hle/service/frd_u.h
hle/service/gsp_gpu.h
hle/service/hid_user.h
hle/service/mic_u.h
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 669b612fc..a3ed3e31e 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -60,7 +60,7 @@ void ARM_DynCom::SetPC(u32 pc) {
* @return Returns current PC
*/
u32 ARM_DynCom::GetPC() const {
- return state->pc;
+ return state->Reg[15];
}
/**
@@ -110,9 +110,12 @@ u64 ARM_DynCom::GetTicks() const {
* @param num_instructions Number of instructions to executes
*/
void ARM_DynCom::ExecuteInstructions(int num_instructions) {
- ticks += num_instructions;
state->NumInstrsToExecute = num_instructions;
- InterpreterMainLoop(state.get());
+
+ // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
+ // executing one instruction at a time. Otherwise, if a block is being executed, more
+ // instructions may actually be executed than specified.
+ ticks += InterpreterMainLoop(state.get());
}
/**
@@ -126,7 +129,7 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) {
ctx.sp = state->Reg[13];
ctx.lr = state->Reg[14];
- ctx.pc = state->pc;
+ ctx.pc = state->Reg[15];
ctx.cpsr = state->Cpsr;
ctx.fpscr = state->VFP[1];
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index fe1501b59..f899e2e8a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -3718,7 +3718,7 @@ static bool InAPrivilegedMode(arm_core_t *core)
}
/* r15 = r15 + 8 */
-void InterpreterMainLoop(ARMul_State* state)
+unsigned InterpreterMainLoop(ARMul_State* state)
{
#define CRn inst_cream->crn
#define OPCODE_2 inst_cream->opcode_2
@@ -3747,16 +3747,22 @@ void InterpreterMainLoop(ARMul_State* state)
#endif
#define FETCH_INST if (inst_base->br != NON_BRANCH) \
- goto PROFILING; \
+ goto DISPATCH; \
inst_base = (arm_inst *)&inst_buf[ptr]
#define INC_PC(l) ptr += sizeof(arm_inst) + l
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
// clunky switch statement.
#if defined __GNUC__ || defined __clang__
-#define GOTO_NEXT_INST goto *InstLabel[inst_base->idx]
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ goto *InstLabel[inst_base->idx]
#else
-#define GOTO_NEXT_INST switch(inst_base->idx) { \
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ switch(inst_base->idx) { \
case 0: goto VMLA_INST; \
case 1: goto VMLS_INST; \
case 2: goto VNMLA_INST; \
@@ -4028,20 +4034,15 @@ void InterpreterMainLoop(ARMul_State* state)
unsigned int addr;
unsigned int phys_addr;
unsigned int last_pc = 0;
+ unsigned int num_instrs = 0;
fault_t fault;
static unsigned int last_physical_base = 0, last_logical_base = 0;
int ptr;
+ bool single_step = (cpu->NumInstrsToExecute == 1);
LOAD_NZCVT;
DISPATCH:
{
- if (cpu->NumInstrsToExecute == 0)
- return;
-
- cpu->NumInstrsToExecute--;
-
- //NOTICE_LOG(ARM11, "instr!");
-
if (!cpu->NirqSig) {
if (!(cpu->Cpsr & 0x80)) {
goto END;
@@ -4179,10 +4180,6 @@ void InterpreterMainLoop(ARMul_State* state)
inst_base = (arm_inst *)&inst_buf[ptr];
GOTO_NEXT_INST;
}
- PROFILING:
- {
- goto DISPATCH;
- }
ADC_INST:
{
INC_ICOUNTER;
@@ -4207,7 +4204,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(adc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4241,7 +4238,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(add_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4272,7 +4269,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(and_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4290,11 +4287,11 @@ void InterpreterMainLoop(ARMul_State* state)
}
SET_PC;
INC_PC(sizeof(bbl_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
INC_PC(sizeof(bbl_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BIC_INST:
{
@@ -4322,7 +4319,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(bic_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4358,12 +4355,12 @@ void InterpreterMainLoop(ARMul_State* state)
//DEBUG_MSG;
}
INC_PC(sizeof(blx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
// INC_PC(sizeof(bx_inst));
INC_PC(sizeof(blx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BX_INST:
{
@@ -4376,12 +4373,12 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
INC_PC(sizeof(bx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
// INC_PC(sizeof(bx_inst));
INC_PC(sizeof(bx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BXJ_INST:
CDP_INST:
@@ -4393,7 +4390,8 @@ void InterpreterMainLoop(ARMul_State* state)
#define CP_ACCESS_ALLOW 0
if(CP_ACCESS_ALLOW){
/* undefined instruction here */
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]);
unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst);
@@ -4522,7 +4520,7 @@ void InterpreterMainLoop(ARMul_State* state)
// RD = RM;
if ((inst_cream->Rd == 15)) {
INC_PC(sizeof(mov_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]);
@@ -4558,7 +4556,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(eor_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4717,7 +4715,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (BIT(inst, 15)) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4764,7 +4762,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = value & 0x1;
cpu->Reg[15] &= 0xFFFFFFFE;
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
//}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4794,7 +4792,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = value & 0x1;
cpu->Reg[15] &= 0xFFFFFFFE;
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4848,7 +4846,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4869,7 +4867,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4926,7 +4924,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4953,7 +4951,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4980,7 +4978,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5006,7 +5004,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5031,7 +5029,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5058,7 +5056,7 @@ void InterpreterMainLoop(ARMul_State* state)
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5228,7 +5226,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mla_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5260,7 +5258,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mov_inst));
- goto PROFILING;
+ goto DISPATCH;
}
// return;
}
@@ -5422,7 +5420,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mul_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5451,7 +5449,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mvn_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5483,7 +5481,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(orr_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5575,7 +5573,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(rsb_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5612,7 +5610,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(rsc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5653,7 +5651,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(sbc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -6066,7 +6064,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
//if (BITS(inst_cream->inst, 12, 15) == 15)
- // goto PROFILING;
+ // goto DISPATCH;
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6175,7 +6173,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
//if (BITS(inst_cream->inst, 12, 15) == 15)
- // goto PROFILING;
+ // goto DISPATCH;
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6225,7 +6223,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(sub_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -6449,7 +6447,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
//DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(b_2_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
B_COND_THUMB:
{
@@ -6461,7 +6459,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] += 2;
//DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]);
INC_PC(sizeof(b_cond_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
BL_1_THUMB:
{
@@ -6487,7 +6485,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[14] = tmp;
//DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(bl_2_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
BLX_1_THUMB:
{
@@ -6503,7 +6501,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = 0;
//DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(blx_1_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
UQADD16_INST:
@@ -6532,12 +6530,14 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->AbortAddr = addr;
cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff;
cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
END:
{
SAVE_NZCVT;
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
INIT_INST_LENGTH:
{
@@ -6557,7 +6557,8 @@ void InterpreterMainLoop(ARMul_State* state)
DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]);
DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]);
#endif
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
}
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index d73f8f65f..c65eb23f7 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -4,4 +4,4 @@
#pragma once
-void InterpreterMainLoop(ARMul_State* state);
+unsigned InterpreterMainLoop(ARMul_State* state);
diff --git a/src/core/core.h b/src/core/core.h
index 872dc0cd1..850bb0ab4 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -26,13 +26,13 @@ void Start();
/**
* Run the core CPU loop
- * This function loops for 100 instructions in the CPU before trying to update hardware. This is a
- * little bit faster than SingleStep, and should be pretty much equivalent. The number of
- * instructions chosen is fairly arbitrary, however a large number will more drastically affect the
- * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU
- * for more than 1 instruction to reduce overhead and make it a little bit faster...
+ * This function runs the core for the specified number of CPU instructions before trying to update
+ * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
+ * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
+ * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
+ * requested (e.g. on a thread switch).
*/
-void RunLoop(int tight_loop=100);
+void RunLoop(int tight_loop=1000);
/// Step the CPU one instruction
void SingleStep();
diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp
index 617b6add4..4f41ec5f4 100644
--- a/src/core/hle/service/apt_u.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -15,6 +15,8 @@
namespace APT_U {
+static Handle lock_handle = 0;
+
/// Signals used by APT functions
enum class SignalType : u32 {
None = 0x0,
@@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) {
Kernel::SetEventLocked(cmd_buff[3], true);
Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
+ _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock");
+ Kernel::ReleaseMutex(lock_handle);
+
cmd_buff[1] = 0; // No error
+
DEBUG_LOG(KERNEL, "called");
}
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
+
+ if (0 == lock_handle) {
+ // TODO(bunnei): Verify if this is created here or at application boot?
+ lock_handle = Kernel::CreateMutex(false, "APT_U:Lock");
+ Kernel::ReleaseMutex(lock_handle);
+ }
cmd_buff[1] = 0; // No error
- cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
+
+ // Not sure what these parameters are used for, but retail apps check that they are 0 after
+ // GetLockHandle has been called.
+ cmd_buff[2] = 0;
+ cmd_buff[3] = 0;
+ cmd_buff[4] = 0;
+
+ cmd_buff[5] = lock_handle;
DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
}
@@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) {
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id);
}
+/**
+ * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state,
+ * from the source process which set the parameters. Once finished, NS will clear a flag in the NS
+ * state so that this command will return an error if this command is used again if parameters were
+ * not set again. This is called when the second Initialize event is triggered. It returns a signal
+ * type indicating why it was triggered.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
void ReceiveParameter(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[1];
@@ -66,7 +104,7 @@ void ReceiveParameter(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = 0;
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0x10;
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
cmd_buff[5] = 0;
cmd_buff[6] = 0;
cmd_buff[7] = 0;
@@ -74,35 +112,66 @@ void ReceiveParameter(Service::Interface* self) {
}
/**
-* APT_U::GlanceParameter service function
-* Inputs:
-* 1 : AppID
-* 2 : Parameter buffer size, max size is 0x1000
-* Outputs:
-* 1 : Result of function, 0 on success, otherwise error code
-* 2 : Unknown, for now assume AppID of the process which sent these parameters
-* 3 : Unknown, for now assume Signal type
-* 4 : Actual parameter buffer size, this is <= to the the input size
-* 5 : Value
-* 6 : Handle from the source process which set the parameters, likely used for shared memory
-* 7 : Size
-* 8 : Output parameter buffer ptr
-*/
+ * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter
+ * (except for the word value prior to the output handle), except this will not clear the flag
+ * (except when responseword[3]==8 || responseword[3]==9) in NS state.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
void GlanceParameter(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[1];
u32 buffer_size = cmd_buff[2];
+
cmd_buff[1] = 0; // No error
cmd_buff[2] = 0;
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0;
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
cmd_buff[5] = 0;
cmd_buff[6] = 0;
cmd_buff[7] = 0;
- cmd_buff[8] = 0;
+
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
}
+/**
+ * APT_U::AppletUtility service function
+ * Inputs:
+ * 1 : Unknown, but clearly used for something
+ * 2 : Buffer 1 size (purpose is unknown)
+ * 3 : Buffer 2 size (purpose is unknown)
+ * 5 : Buffer 1 address (purpose is unknown)
+ * 65 : Buffer 2 address (purpose is unknown)
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void AppletUtility(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // These are from 3dbrew - I'm not really sure what they're used for.
+ u32 unk = cmd_buff[1];
+ u32 buffer1_size = cmd_buff[2];
+ u32 buffer2_size = cmd_buff[3];
+ u32 buffer1_addr = cmd_buff[5];
+ u32 buffer2_addr = cmd_buff[65];
+
+ cmd_buff[1] = 0; // No error
+
+ WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
+ "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
+ buffer1_addr, buffer2_addr);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle"},
{0x00020080, Initialize, "Initialize"},
@@ -178,7 +247,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, nullptr, "Reboot"},
{0x004A0040, nullptr, "GetCaptureInfo"},
- {0x004B00C2, nullptr, "AppletUtility"},
+ {0x004B00C2, AppletUtility, "AppletUtility"},
{0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, nullptr, "GetAppletProgramInfo"},
{0x004E0000, nullptr, "HardwareResetAsync"},
@@ -191,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+
+ lock_handle = 0;
}
Interface::~Interface() {
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp
new file mode 100644
index 000000000..58023e536
--- /dev/null
+++ b/src/core/hle/service/frd_u.cpp
@@ -0,0 +1,35 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/frd_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ const Interface::FunctionInfo FunctionTable[] = {
+ {0x00050000, nullptr, "GetFriendKey"},
+ {0x00080000, nullptr, "GetMyPresence"},
+ {0x00100040, nullptr, "GetPassword"},
+ {0x00190042, nullptr, "GetFriendFavoriteGame"},
+ {0x001A00C4, nullptr, "GetFriendInfo"},
+ {0x001B0080, nullptr, "IsOnFriendList"},
+ {0x001C0042, nullptr, "DecodeLocalFriendCode"},
+ {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
+ {0x00320042, nullptr, "SetClientSdkVersion"}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Interface class
+
+ Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+ }
+
+ Interface::~Interface() {
+ }
+
+} // namespace
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h
new file mode 100644
index 000000000..9df8a815a
--- /dev/null
+++ b/src/core/hle/service/frd_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ class Interface : public Service::Interface {
+ public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "frd:u";
+ }
+ };
+
+} // namespace
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index b144a77d4..bb0f80e98 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -12,6 +12,7 @@
#include "core/hle/service/dsp_dsp.h"
#include "core/hle/service/err_f.h"
#include "core/hle/service/fs_user.h"
+#include "core/hle/service/frd_u.h"
#include "core/hle/service/gsp_gpu.h"
#include "core/hle/service/hid_user.h"
#include "core/hle/service/mic_u.h"
@@ -80,6 +81,7 @@ void Init() {
g_manager->AddService(new CFG_U::Interface);
g_manager->AddService(new DSP_DSP::Interface);
g_manager->AddService(new ERR_F::Interface);
+ g_manager->AddService(new FRD_U::Interface);
g_manager->AddService(new FS_User::Interface);
g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface);