summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp38
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h4
-rw-r--r--src/core/gdbstub/gdbstub.cpp170
-rw-r--r--src/core/gdbstub/gdbstub.h9
-rw-r--r--src/core/hle/ipc.h3
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/svc.cpp27
-rw-r--r--src/core/hle/kernel/thread.cpp13
-rw-r--r--src/core/hle/service/am/am.cpp215
-rw-r--r--src/core/hle/service/am/am.h2
-rw-r--r--src/core/hle/service/bcat/bcat.cpp16
-rw-r--r--src/core/hle/service/bcat/bcat.h16
-rw-r--r--src/core/hle/service/bcat/module.cpp53
-rw-r--r--src/core/hle/service/bcat/module.h27
-rw-r--r--src/core/hle/service/hid/hid.cpp30
-rw-r--r--src/core/hle/service/mm/mm_u.cpp50
-rw-r--r--src/core/hle/service/mm/mm_u.h29
-rw-r--r--src/core/hle/service/nfp/nfp.cpp108
-rw-r--r--src/core/hle/service/nifm/nifm.cpp11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp22
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h31
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h47
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp32
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h38
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp2
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/time/time.cpp58
-rw-r--r--src/core/hle/service/time/time.h28
31 files changed, 986 insertions, 131 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 821d2f883..ba5b02174 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -124,6 +124,10 @@ add_library(core STATIC
hle/service/audio/audren_u.h
hle/service/audio/codecctl.cpp
hle/service/audio/codecctl.h
+ hle/service/bcat/module.cpp
+ hle/service/bcat/module.h
+ hle/service/bcat/bcat.cpp
+ hle/service/bcat/bcat.h
hle/service/fatal/fatal.cpp
hle/service/fatal/fatal.h
hle/service/fatal/fatal_p.cpp
@@ -144,6 +148,8 @@ add_library(core STATIC
hle/service/hid/hid.h
hle/service/lm/lm.cpp
hle/service/lm/lm.h
+ hle/service/mm/mm_u.cpp
+ hle/service/mm/mm_u.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
hle/service/nifm/nifm_a.cpp
@@ -171,6 +177,8 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
hle/service/nvdrv/devices/nvhost_gpu.cpp
hle/service/nvdrv/devices/nvhost_gpu.h
+ hle/service/nvdrv/devices/nvhost_nvdec.cpp
+ hle/service/nvdrv/devices/nvhost_nvdec.h
hle/service/nvdrv/devices/nvmap.cpp
hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.cpp
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index c0cc62f03..ce6c5616d 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -35,6 +35,17 @@ LoadDll LoadDll::g_load_dll;
} \
} while (0)
+static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
+ GDBStub::BreakpointAddress bkpt =
+ GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
+ if (GDBStub::IsMemoryBreak() ||
+ (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
+ auto core = static_cast<ARM_Unicorn*>(user_data);
+ core->RecordBreak(bkpt);
+ uc_emu_stop(uc);
+ }
+}
+
static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
@@ -67,6 +78,10 @@ ARM_Unicorn::ARM_Unicorn() {
uc_hook hook{};
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1));
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1));
+ if (GDBStub::IsServerEnabled()) {
+ CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1));
+ last_bkpt_hit = false;
+ }
}
ARM_Unicorn::~ARM_Unicorn() {
@@ -155,7 +170,11 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
}
void ARM_Unicorn::Run() {
- ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
+ if (GDBStub::IsServerEnabled()) {
+ ExecuteInstructions(std::max(4000000, 0));
+ } else {
+ ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
+ }
}
void ARM_Unicorn::Step() {
@@ -168,6 +187,18 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit);
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
CoreTiming::AddTicks(num_instructions);
+ if (GDBStub::IsServerEnabled()) {
+ if (last_bkpt_hit) {
+ uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
+ }
+ Kernel::Thread* thread = Kernel::GetCurrentThread();
+ SaveContext(thread->context);
+ if (last_bkpt_hit) {
+ last_bkpt_hit = false;
+ GDBStub::Break();
+ }
+ GDBStub::SendTrap(thread, 5);
+ }
}
void ARM_Unicorn::SaveContext(ARM_Interface::ThreadContext& ctx) {
@@ -233,3 +264,8 @@ void ARM_Unicorn::PrepareReschedule() {
}
void ARM_Unicorn::ClearInstructionCache() {}
+
+void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
+ last_bkpt = bkpt;
+ last_bkpt_hit = true;
+}
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index b99b58e4c..a482a2aa3 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -7,6 +7,7 @@
#include <unicorn/unicorn.h>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
+#include "core/gdbstub/gdbstub.h"
class ARM_Unicorn final : public ARM_Interface {
public:
@@ -35,7 +36,10 @@ public:
void Step() override;
void ClearInstructionCache() override;
void PageTableChanged() override{};
+ void RecordBreak(GDBStub::BreakpointAddress bkpt);
private:
uc_engine* uc{};
+ GDBStub::BreakpointAddress last_bkpt{};
+ bool last_bkpt_hit;
};
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 6c5a40ba8..2603192fe 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -32,9 +32,13 @@
#include "common/logging/log.h"
#include "common/string_util.h"
+#include "common/swap.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
+#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/scheduler.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@@ -137,15 +141,17 @@ static u8 command_buffer[GDB_BUFFER_SIZE];
static u32 command_length;
static u32 latest_signal = 0;
-static bool step_break = false;
static bool memory_break = false;
+static Kernel::Thread* current_thread = nullptr;
+
// Binding to a port within the reserved ports range (0-1023) requires root permissions,
// so default to a port outside of that range.
static u16 gdbstub_port = 24689;
static bool halt_loop = true;
static bool step_loop = false;
+static bool send_trap = false;
// If set to false, the server will never be started and no
// gdbstub-related functions will be executed.
@@ -165,6 +171,53 @@ static std::map<u64, Breakpoint> breakpoints_execute;
static std::map<u64, Breakpoint> breakpoints_read;
static std::map<u64, Breakpoint> breakpoints_write;
+static Kernel::Thread* FindThreadById(int id) {
+ for (int core = 0; core < Core::NUM_CPU_CORES; core++) {
+ auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
+ for (auto thread : threads) {
+ if (thread->GetThreadId() == id) {
+ current_thread = thread.get();
+ return current_thread;
+ }
+ }
+ }
+ return nullptr;
+}
+
+static u64 RegRead(int id, Kernel::Thread* thread = nullptr) {
+ if (!thread) {
+ return 0;
+ }
+
+ if (id < SP_REGISTER) {
+ return thread->context.cpu_registers[id];
+ } else if (id == SP_REGISTER) {
+ return thread->context.sp;
+ } else if (id == PC_REGISTER) {
+ return thread->context.pc;
+ } else if (id == CPSR_REGISTER) {
+ return thread->context.cpsr;
+ } else {
+ return 0;
+ }
+}
+
+static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) {
+ if (!thread) {
+ return;
+ }
+
+ if (id < SP_REGISTER) {
+ thread->context.cpu_registers[id] = val;
+ } else if (id == SP_REGISTER) {
+ thread->context.sp = val;
+ } else if (id == PC_REGISTER) {
+ thread->context.pc = val;
+ } else if (id == CPSR_REGISTER) {
+ thread->context.cpsr = val;
+ }
+}
+
/**
* Turns hex string character into the equivalent byte.
*
@@ -193,7 +246,7 @@ static u8 NibbleToHex(u8 n) {
if (n < 0xA) {
return '0' + n;
} else {
- return 'A' + n - 0xA;
+ return 'a' + n - 0xA;
}
}
@@ -439,6 +492,8 @@ static void SendReply(const char* reply) {
return;
}
+ NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply);
+
memset(command_buffer, 0, sizeof(command_buffer));
command_length = static_cast<u32>(strlen(reply));
@@ -483,6 +538,22 @@ static void HandleQuery() {
} else if (strncmp(query, "Xfer:features:read:target.xml:",
strlen("Xfer:features:read:target.xml:")) == 0) {
SendReply(target_xml);
+ } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
+ std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR);
+ SendReply(buffer.c_str());
+ } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
+ std::string val = "m";
+ for (int core = 0; core < Core::NUM_CPU_CORES; core++) {
+ auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
+ for (auto thread : threads) {
+ val += fmt::format("{:x}", thread->GetThreadId());
+ val += ",";
+ }
+ }
+ val.pop_back();
+ SendReply(val.c_str());
+ } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) {
+ SendReply("l");
} else {
SendReply("");
}
@@ -490,11 +561,40 @@ static void HandleQuery() {
/// Handle set thread command from gdb client.
static void HandleSetThread() {
- if (memcmp(command_buffer, "Hg0", 3) == 0 || memcmp(command_buffer, "Hc-1", 4) == 0 ||
- memcmp(command_buffer, "Hc0", 4) == 0 || memcmp(command_buffer, "Hc1", 4) == 0) {
- return SendReply("OK");
+ if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) {
+ int thread_id = -1;
+ if (command_buffer[2] != '-') {
+ thread_id = static_cast<int>(HexToInt(
+ command_buffer + 2,
+ command_length - 2 /*strlen(reinterpret_cast<char*>(command_buffer) + 2)*/));
+ }
+ if (thread_id >= 1) {
+ current_thread = FindThreadById(thread_id);
+ }
+ if (!current_thread) {
+ thread_id = 1;
+ current_thread = FindThreadById(thread_id);
+ }
+ if (current_thread) {
+ SendReply("OK");
+ return;
+ }
}
+ SendReply("E01");
+}
+/// Handle thread alive command from gdb client.
+static void HandleThreadAlive() {
+ int thread_id = static_cast<int>(
+ HexToInt(command_buffer + 1,
+ command_length - 1 /*strlen(reinterpret_cast<char*>(command_buffer) + 1)*/));
+ if (thread_id == 0) {
+ thread_id = 1;
+ }
+ if (FindThreadById(thread_id)) {
+ SendReply("OK");
+ return;
+ }
SendReply("E01");
}
@@ -503,15 +603,24 @@ static void HandleSetThread() {
*
* @param signal Signal to be sent to client.
*/
-static void SendSignal(u32 signal) {
+static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
if (gdbserver_socket == -1) {
return;
}
latest_signal = signal;
- std::string buffer = fmt::format("T{:02x}", latest_signal);
- NGLOG_DEBUG(Debug_GDBStub, "Response: {}", buffer);
+ std::string buffer;
+ if (full) {
+ buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER,
+ Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER,
+ Common::swap64(RegRead(SP_REGISTER, thread)));
+ } else {
+ buffer = fmt::format("T{:02x};", latest_signal);
+ }
+
+ buffer += fmt::format("thread:{:x};", thread->GetThreadId());
+
SendReply(buffer.c_str());
}
@@ -527,7 +636,7 @@ static void ReadCommand() {
} else if (c == 0x03) {
NGLOG_INFO(Debug_GDBStub, "gdb: found break command");
halt_loop = true;
- SendSignal(SIGTRAP);
+ SendSignal(current_thread, SIGTRAP);
return;
} else if (c != GDB_STUB_START) {
NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
@@ -598,11 +707,11 @@ static void ReadRegister() {
}
if (id <= SP_REGISTER) {
- LongToGdbHex(reply, Core::CurrentArmInterface().GetReg(static_cast<int>(id)));
+ LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == PC_REGISTER) {
- LongToGdbHex(reply, Core::CurrentArmInterface().GetPC());
+ LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == CPSR_REGISTER) {
- IntToGdbHex(reply, Core::CurrentArmInterface().GetCPSR());
+ IntToGdbHex(reply, (u32)RegRead(id, current_thread));
} else {
return SendReply("E01");
}
@@ -618,16 +727,16 @@ static void ReadRegisters() {
u8* bufptr = buffer;
for (int reg = 0; reg <= SP_REGISTER; reg++) {
- LongToGdbHex(bufptr + reg * 16, Core::CurrentArmInterface().GetReg(reg));
+ LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
}
bufptr += (32 * 16);
- LongToGdbHex(bufptr, Core::CurrentArmInterface().GetPC());
+ LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread));
bufptr += 16;
- IntToGdbHex(bufptr, Core::CurrentArmInterface().GetCPSR());
+ IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
bufptr += 8;
@@ -646,11 +755,11 @@ static void WriteRegister() {
}
if (id <= SP_REGISTER) {
- Core::CurrentArmInterface().SetReg(id, GdbHexToLong(buffer_ptr));
+ RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == PC_REGISTER) {
- Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr));
+ RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == CPSR_REGISTER) {
- Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr));
+ RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
} else {
return SendReply("E01");
}
@@ -667,11 +776,11 @@ static void WriteRegisters() {
for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) {
if (reg <= SP_REGISTER) {
- Core::CurrentArmInterface().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16));
+ RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == PC_REGISTER) {
- Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr + i * 16));
+ RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == CPSR_REGISTER) {
- Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr + i * 16));
+ RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
} else {
UNIMPLEMENTED();
}
@@ -734,7 +843,7 @@ static void WriteMemory() {
void Break(bool is_memory_break) {
if (!halt_loop) {
halt_loop = true;
- SendSignal(SIGTRAP);
+ send_trap = true;
}
memory_break = is_memory_break;
@@ -744,10 +853,10 @@ void Break(bool is_memory_break) {
static void Step() {
step_loop = true;
halt_loop = true;
- step_break = true;
- SendSignal(SIGTRAP);
+ send_trap = true;
}
+/// Tell the CPU if we hit a memory breakpoint.
bool IsMemoryBreak() {
if (IsConnected()) {
return false;
@@ -759,7 +868,6 @@ bool IsMemoryBreak() {
/// Tell the CPU to continue executing.
static void Continue() {
memory_break = false;
- step_break = false;
step_loop = false;
halt_loop = false;
}
@@ -898,7 +1006,7 @@ void HandlePacket() {
HandleSetThread();
break;
case '?':
- SendSignal(latest_signal);
+ SendSignal(current_thread, latest_signal);
break;
case 'k':
Shutdown();
@@ -935,6 +1043,9 @@ void HandlePacket() {
case 'Z':
AddBreakpoint();
break;
+ case 'T':
+ HandleThreadAlive();
+ break;
default:
SendReply("");
break;
@@ -1079,4 +1190,11 @@ bool GetCpuStepFlag() {
void SetCpuStepFlag(bool is_step) {
step_loop = is_step;
}
+
+void SendTrap(Kernel::Thread* thread, int trap) {
+ if (send_trap) {
+ send_trap = false;
+ SendSignal(thread, trap);
+ }
+}
}; // namespace GDBStub
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index 201fca095..f2418c9e4 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -7,6 +7,7 @@
#pragma once
#include "common/common_types.h"
+#include "core/hle/kernel/thread.h"
namespace GDBStub {
@@ -91,4 +92,12 @@ bool GetCpuStepFlag();
* @param is_step
*/
void SetCpuStepFlag(bool is_step);
+
+/**
+ * Send trap signal from thread back to the gdbstub server.
+ *
+ * @param thread Sending thread.
+ * @param trap Trap no.
+ */
+void SendTrap(Kernel::Thread* thread, int trap);
} // namespace GDBStub
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index c9257de77..eaa5395ac 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -29,7 +29,10 @@ enum class ControlCommand : u32 {
};
enum class CommandType : u32 {
+ Invalid = 0,
+ LegacyRequest = 1,
Close = 2,
+ LegacyControl = 3,
Request = 4,
Control = 5,
RequestWithContext = 6,
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 5be20c878..e1b5430bf 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -21,7 +21,9 @@ enum {
// Confirmed Switch OS error codes
MisalignedAddress = 102,
+ InvalidProcessorId = 113,
InvalidHandle = 114,
+ InvalidCombination = 116,
Timeout = 117,
SynchronizationCanceled = 118,
TooLarge = 119,
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 0811a16b8..ec3601e8b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -732,7 +732,7 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
}
static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
- NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:08X}, core=0x{:X}", thread_handle,
+ NGLOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
mask, core);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
@@ -740,6 +740,31 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
return ERR_INVALID_HANDLE;
}
+ if (core == THREADPROCESSORID_DEFAULT) {
+ ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT);
+ // Set the target CPU to the one specified in the process' exheader.
+ core = thread->owner_process->ideal_processor;
+ mask = 1 << core;
+ }
+
+ if (mask == 0) {
+ return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
+ }
+
+ /// This value is used to only change the affinity mask without changing the current ideal core.
+ static constexpr u32 OnlyChangeMask = static_cast<u32>(-3);
+
+ if (core == OnlyChangeMask) {
+ core = thread->ideal_core;
+ } else if (core >= Core::NUM_CPU_CORES && core != -1) {
+ return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
+ }
+
+ // Error out if the input core isn't enabled in the input mask.
+ if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) {
+ return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
+ }
+
thread->ChangeCore(core, mask);
return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 46fcdefb8..cffa7ca83 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -133,8 +133,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
auto lock_owner = thread->lock_owner;
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
- // and don't have a lock owner.
- ASSERT(lock_owner == nullptr);
+ // and don't have a lock owner unless SignalProcessWideKey was called first and the thread
+ // wasn't awakened due to the mutex already being acquired.
+ if (lock_owner) {
+ lock_owner->RemoveMutexWaiter(thread);
+ }
}
if (resume)
@@ -460,13 +463,13 @@ void Thread::UpdatePriority() {
void Thread::ChangeCore(u32 core, u64 mask) {
ideal_core = core;
- mask = mask;
+ affinity_mask = mask;
if (status != THREADSTATUS_READY) {
return;
}
- boost::optional<s32> new_processor_id{GetNextProcessorId(mask)};
+ boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
if (!new_processor_id) {
new_processor_id = processor_id;
@@ -476,7 +479,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
new_processor_id = ideal_core;
}
- ASSERT(new_processor_id < 4);
+ ASSERT(*new_processor_id < 4);
// Add thread to new core's scheduler
auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 6b1d6bf97..b8d6b8d4d 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cinttypes>
+#include <stack>
#include "core/file_sys/filesystem.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
@@ -154,7 +155,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
launchable_event =
- Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent");
+ Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
}
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
@@ -348,19 +349,100 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
+class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
+public:
+ explicit IStorageAccessor(std::vector<u8> buffer)
+ : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
+ static const FunctionInfo functions[] = {
+ {0, &IStorageAccessor::GetSize, "GetSize"},
+ {10, &IStorageAccessor::Write, "Write"},
+ {11, &IStorageAccessor::Read, "Read"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ std::vector<u8> buffer;
+
+ void GetSize(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 4};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(static_cast<u64>(buffer.size()));
+
+ NGLOG_DEBUG(Service_AM, "called");
+ }
+
+ void Write(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const u64 offset{rp.Pop<u64>()};
+ const std::vector<u8> data{ctx.ReadBuffer()};
+
+ ASSERT(offset + data.size() <= buffer.size());
+
+ std::memcpy(&buffer[offset], data.data(), data.size());
+
+ IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
+ rb.Push(RESULT_SUCCESS);
+
+ NGLOG_DEBUG(Service_AM, "called, offset={}", offset);
+ }
+
+ void Read(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const u64 offset{rp.Pop<u64>()};
+ const size_t size{ctx.GetWriteBufferSize()};
+
+ ASSERT(offset + size <= buffer.size());
+
+ ctx.WriteBuffer(buffer.data() + offset, size);
+
+ IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
+ rb.Push(RESULT_SUCCESS);
+
+ NGLOG_DEBUG(Service_AM, "called, offset={}", offset);
+ }
+};
+
+class IStorage final : public ServiceFramework<IStorage> {
+public:
+ explicit IStorage(std::vector<u8> buffer)
+ : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
+ static const FunctionInfo functions[] = {
+ {0, &IStorage::Open, "Open"},
+ {1, nullptr, "OpenTransferStorage"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ std::vector<u8> buffer;
+
+ void Open(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
+
+ NGLOG_DEBUG(Service_AM, "called");
+ }
+};
+
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
{1, nullptr, "IsCompleted"},
- {10, nullptr, "Start"},
+ {10, &ILibraryAppletAccessor::Start, "Start"},
{20, nullptr, "RequestExit"},
{25, nullptr, "Terminate"},
- {30, nullptr, "GetResult"},
+ {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
- {100, nullptr, "PushInData"},
- {101, nullptr, "PopOutData"},
+ {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
+ {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
{102, nullptr, "PushExtraStorage"},
{103, nullptr, "PushInteractiveInData"},
{104, nullptr, "PopInteractiveOutData"},
@@ -388,6 +470,41 @@ private:
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
+ void GetResult(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ NGLOG_WARNING(Service_AM, "(STUBBED) called");
+ }
+
+ void Start(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ NGLOG_WARNING(Service_AM, "(STUBBED) called");
+ }
+
+ void PushInData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
+
+ IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
+ rb.Push(RESULT_SUCCESS);
+
+ NGLOG_DEBUG(Service_AM, "called");
+ }
+
+ void PopOutData(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top()));
+
+ storage_stack.pop();
+
+ NGLOG_DEBUG(Service_AM, "called");
+ }
+
+ std::stack<std::shared_ptr<AM::IStorage>> storage_stack;
Kernel::SharedPtr<Kernel::Event> state_changed_event;
};
@@ -396,7 +513,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
{2, nullptr, "AreAnyLibraryAppletsLeft"},
- {10, nullptr, "CreateStorage"},
+ {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
{11, nullptr, "CreateTransferMemoryStorage"},
{12, nullptr, "CreateHandleStorage"},
};
@@ -412,72 +529,17 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
NGLOG_DEBUG(Service_AM, "called");
}
-class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
-public:
- explicit IStorageAccessor(std::vector<u8> buffer)
- : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
- static const FunctionInfo functions[] = {
- {0, &IStorageAccessor::GetSize, "GetSize"},
- {10, nullptr, "Write"},
- {11, &IStorageAccessor::Read, "Read"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- std::vector<u8> buffer;
-
- void GetSize(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 4};
-
- rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(buffer.size()));
-
- NGLOG_DEBUG(Service_AM, "called");
- }
-
- void Read(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- u64 offset = rp.Pop<u64>();
-
- const size_t size{ctx.GetWriteBufferSize()};
-
- ASSERT(offset + size <= buffer.size());
-
- ctx.WriteBuffer(buffer.data() + offset, size);
-
- IPC::ResponseBuilder rb{ctx, 2};
-
- rb.Push(RESULT_SUCCESS);
-
- NGLOG_DEBUG(Service_AM, "called");
- }
-};
-
-class IStorage final : public ServiceFramework<IStorage> {
-public:
- explicit IStorage(std::vector<u8> buffer)
- : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
- static const FunctionInfo functions[] = {
- {0, &IStorage::Open, "Open"},
- {1, nullptr, "OpenTransferStorage"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- std::vector<u8> buffer;
-
- void Open(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 size{rp.Pop<u64>()};
+ std::vector<u8> buffer(size);
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
+ IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
- NGLOG_DEBUG(Service_AM, "called");
- }
-};
+ NGLOG_DEBUG(Service_AM, "called, size={}", size);
+}
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
static const FunctionInfo functions[] = {
@@ -499,7 +561,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{32, nullptr, "BeginBlockingHomeButton"},
{33, nullptr, "EndBlockingHomeButton"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
- {50, nullptr, "GetPseudoDeviceId"},
+ {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
{65, nullptr, "IsGamePlayRecordingSupported"},
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
@@ -622,6 +684,17 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
+void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(RESULT_SUCCESS);
+
+ // Returns a 128-bit UUID
+ rb.Push<u64>(0);
+ rb.Push<u64>(0);
+
+ NGLOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index ff8eb14d7..1da79fd01 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -121,6 +121,7 @@ public:
private:
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
+ void CreateStorage(Kernel::HLERequestContext& ctx);
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -137,6 +138,7 @@ private:
void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx);
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
void NotifyRunning(Kernel::HLERequestContext& ctx);
+ void GetPseudoDeviceId(Kernel::HLERequestContext& ctx);
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp
new file mode 100644
index 000000000..20ce692dc
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat.cpp
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/bcat/bcat.h"
+
+namespace Service::BCAT {
+
+BCAT::BCAT(std::shared_ptr<Module> module, const char* name)
+ : Module::Interface(std::move(module), name) {
+ static const FunctionInfo functions[] = {
+ {0, &BCAT::CreateBcatService, "CreateBcatService"},
+ };
+ RegisterHandlers(functions);
+}
+} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h
new file mode 100644
index 000000000..6632996a0
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/bcat/module.h"
+
+namespace Service::BCAT {
+
+class BCAT final : public Module::Interface {
+public:
+ explicit BCAT(std::shared_ptr<Module> module, const char* name);
+};
+
+} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
new file mode 100644
index 000000000..52be9db22
--- /dev/null
+++ b/src/core/hle/service/bcat/module.cpp
@@ -0,0 +1,53 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/bcat/bcat.h"
+#include "core/hle/service/bcat/module.h"
+
+namespace Service::BCAT {
+
+class IBcatService final : public ServiceFramework<IBcatService> {
+public:
+ IBcatService() : ServiceFramework("IBcatService") {
+ static const FunctionInfo functions[] = {
+ {10100, nullptr, "RequestSyncDeliveryCache"},
+ {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"},
+ {10200, nullptr, "CancelSyncDeliveryCacheRequest"},
+ {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
+ {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
+ {30100, nullptr, "SetPassphrase"},
+ {30200, nullptr, "RegisterBackgroundDeliveryTask"},
+ {30201, nullptr, "UnregisterBackgroundDeliveryTask"},
+ {30202, nullptr, "BlockDeliveryTask"},
+ {30203, nullptr, "UnblockDeliveryTask"},
+ {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
+ {90200, nullptr, "GetDeliveryList"},
+ {90201, nullptr, "ClearDeliveryCacheStorage"},
+ {90300, nullptr, "GetPushNotificationLog"},
+ };
+ RegisterHandlers(functions);
+ }
+};
+
+void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IBcatService>();
+ NGLOG_DEBUG(Service_BCAT, "called");
+}
+
+Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
+ : ServiceFramework(name), module(std::move(module)) {}
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+ auto module = std::make_shared<Module>();
+ std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager);
+ std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager);
+ std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager);
+ std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager);
+}
+
+} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h
new file mode 100644
index 000000000..8366fb877
--- /dev/null
+++ b/src/core/hle/service/bcat/module.h
@@ -0,0 +1,27 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::BCAT {
+
+class Module final {
+public:
+ class Interface : public ServiceFramework<Interface> {
+ public:
+ Interface(std::shared_ptr<Module> module, const char* name);
+
+ void CreateBcatService(Kernel::HLERequestContext& ctx);
+
+ protected:
+ std::shared_ptr<Module> module;
+ };
+};
+
+/// Registers all BCAT services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace Service::BCAT
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1891255cb..00c5308ba 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -329,6 +329,7 @@ public:
{130, nullptr, "SwapNpadAssignment"},
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
+ {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
{201, &Hid::SendVibrationValue, "SendVibrationValue"},
{202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
@@ -336,12 +337,41 @@ public:
{204, nullptr, "PermitVibration"},
{205, nullptr, "IsVibrationPermitted"},
{206, &Hid::SendVibrationValues, "SendVibrationValues"},
+ {207, nullptr, "SendVibrationGcErmCommand"},
+ {208, nullptr, "GetActualVibrationGcErmCommand"},
+ {209, nullptr, "BeginPermitVibrationSession"},
+ {210, nullptr, "EndPermitVibrationSession"},
{300, nullptr, "ActivateConsoleSixAxisSensor"},
{301, nullptr, "StartConsoleSixAxisSensor"},
{302, nullptr, "StopConsoleSixAxisSensor"},
+ {303, nullptr, "ActivateSevenSixAxisSensor"},
+ {304, nullptr, "StartSevenSixAxisSensor"},
+ {305, nullptr, "StopSevenSixAxisSensor"},
+ {306, nullptr, "InitializeSevenSixAxisSensor"},
+ {307, nullptr, "FinalizeSevenSixAxisSensor"},
+ {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
+ {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
{400, nullptr, "IsUsbFullKeyControllerEnabled"},
{401, nullptr, "EnableUsbFullKeyController"},
{402, nullptr, "IsUsbFullKeyControllerConnected"},
+ {403, nullptr, "HasBattery"},
+ {404, nullptr, "HasLeftRightBattery"},
+ {405, nullptr, "GetNpadInterfaceType"},
+ {406, nullptr, "GetNpadLeftRightInterfaceType"},
+ {500, nullptr, "GetPalmaConnectionHandle"},
+ {501, nullptr, "InitializePalma"},
+ {502, nullptr, "AcquirePalmaOperationCompleteEvent"},
+ {503, nullptr, "GetPalmaOperationInfo"},
+ {504, nullptr, "PlayPalmaActivity"},
+ {505, nullptr, "SetPalmaFrModeType"},
+ {506, nullptr, "ReadPalmaStep"},
+ {507, nullptr, "EnablePalmaStep"},
+ {508, nullptr, "SuspendPalmaStep"},
+ {509, nullptr, "ResetPalmaStep"},
+ {510, nullptr, "ReadPalmaApplicationSection"},
+ {511, nullptr, "WritePalmaApplicationSection"},
+ {512, nullptr, "ReadPalmaUniqueCode"},
+ {513, nullptr, "SetPalmaUniqueCodeInvalid"},
{1000, nullptr, "SetNpadCommunicationMode"},
{1001, nullptr, "GetNpadCommunicationMode"},
};
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
new file mode 100644
index 000000000..b3a85b818
--- /dev/null
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -0,0 +1,50 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/service/mm/mm_u.h"
+
+namespace Service::MM {
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+ std::make_shared<MM_U>()->InstallAsService(service_manager);
+}
+
+void MM_U::Initialize(Kernel::HLERequestContext& ctx) {
+ NGLOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ min = rp.Pop<u32>();
+ max = rp.Pop<u32>();
+ current = min;
+
+ NGLOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void MM_U::Get(Kernel::HLERequestContext& ctx) {
+ NGLOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(current);
+}
+
+MM_U::MM_U() : ServiceFramework("mm:u") {
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"},
+ {2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"},
+ {4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"},
+ {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::MM
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
new file mode 100644
index 000000000..79eeedf9c
--- /dev/null
+++ b/src/core/hle/service/mm/mm_u.h
@@ -0,0 +1,29 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::MM {
+
+class MM_U final : public ServiceFramework<MM_U> {
+public:
+ MM_U();
+ ~MM_U() = default;
+
+private:
+ void Initialize(Kernel::HLERequestContext& ctx);
+ void SetAndWait(Kernel::HLERequestContext& ctx);
+ void Get(Kernel::HLERequestContext& ctx);
+
+ u32 min{0};
+ u32 max{0};
+ u32 current{0};
+};
+
+/// Registers all MM services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace Service::MM
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2af4465de..2a9f84037 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -4,6 +4,8 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/service/hid/hid.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_user.h"
@@ -18,7 +20,7 @@ public:
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, nullptr, "Finalize"},
- {2, nullptr, "ListDevices"},
+ {2, &IUser::ListDevices, "ListDevices"},
{3, nullptr, "StartDetection"},
{4, nullptr, "StopDetection"},
{5, nullptr, "Mount"},
@@ -33,24 +35,116 @@ public:
{14, nullptr, "GetRegisterInfo"},
{15, nullptr, "GetCommonInfo"},
{16, nullptr, "GetModelInfo"},
- {17, nullptr, "AttachActivateEvent"},
- {18, nullptr, "AttachDeactivateEvent"},
- {19, nullptr, "GetState"},
- {20, nullptr, "GetDeviceState"},
- {21, nullptr, "GetNpadId"},
+ {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
+ {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {19, &IUser::GetState, "GetState"},
+ {20, &IUser::GetDeviceState, "GetDeviceState"},
+ {21, &IUser::GetNpadId, "GetNpadId"},
{22, nullptr, "GetApplicationArea2"},
- {23, nullptr, "AttachAvailabilityChangeEvent"},
+ {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
{24, nullptr, "RecreateApplicationArea"},
};
RegisterHandlers(functions);
+
+ activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent");
+ deactivate_event =
+ Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
+ availability_change_event =
+ Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
}
private:
+ enum class State : u32 {
+ NonInitialized = 0,
+ Initialized = 1,
+ };
+
+ enum class DeviceState : u32 {
+ Initialized = 0,
+ };
+
void Initialize(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NFP, "(STUBBED) called");
+
+ state = State::Initialized;
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+
+ void ListDevices(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u32 array_size = rp.Pop<u32>();
+
+ ctx.WriteBuffer(&device_handle, sizeof(device_handle));
+
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0);
+ }
+
+ void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 dev_handle = rp.Pop<u64>();
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(activate_event);
+ }
+
+ void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 dev_handle = rp.Pop<u64>();
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(deactivate_event);
+ }
+
+ void GetState(Kernel::HLERequestContext& ctx) {
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(state));
+ }
+
+ void GetDeviceState(Kernel::HLERequestContext& ctx) {
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(device_state));
+ }
+
+ void GetNpadId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 dev_handle = rp.Pop<u64>();
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(npad_id);
+ }
+
+ void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 dev_handle = rp.Pop<u64>();
+ NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(availability_change_event);
+ }
+
+ const u64 device_handle{0xDEAD};
+ const HID::ControllerID npad_id{HID::Controller_Player1};
+ State state{State::NonInitialized};
+ DeviceState device_state{DeviceState::Initialized};
+ Kernel::SharedPtr<Kernel::Event> activate_event;
+ Kernel::SharedPtr<Kernel::Event> deactivate_event;
+ Kernel::SharedPtr<Kernel::Event> availability_change_event;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index eee92cfcd..62489c7fe 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -38,7 +38,7 @@ public:
{8, nullptr, "SetPriority"},
{9, nullptr, "SetNetworkProfileId"},
{10, nullptr, "SetRejectable"},
- {11, nullptr, "SetConnectionConfirmationOption"},
+ {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"},
{12, nullptr, "SetPersistent"},
{13, nullptr, "SetInstant"},
{14, nullptr, "SetSustainable"},
@@ -67,23 +67,32 @@ private:
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
}
+
void GetResult(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+
void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 2};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event1, event2);
}
+
void Cancel(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+ void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
+ NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
Kernel::SharedPtr<Kernel::Event> event1, event2;
};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index e979b9707..7872d1e09 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -16,7 +16,11 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
case IoctlCommand::IocGetConfigCommand:
return NvOsGetConfigU32(input, output);
case IoctlCommand::IocCtrlEventWaitCommand:
- return IocCtrlEventWait(input, output);
+ return IocCtrlEventWait(input, output, false);
+ case IoctlCommand::IocCtrlEventWaitAsyncCommand:
+ return IocCtrlEventWait(input, output, true);
+ case IoctlCommand::IocCtrlEventRegisterCommand:
+ return IocCtrlEventRegister(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -45,11 +49,13 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
-u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
+ bool is_async) {
IocCtrlEventWaitParams params{};
std::memcpy(&params, input.data(), sizeof(params));
- NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, syncpt_id={} threshold={} timeout={}",
- params.syncpt_id, params.threshold, params.timeout);
+ NGLOG_WARNING(Service_NVDRV,
+ "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}",
+ params.syncpt_id, params.threshold, params.timeout, is_async);
// TODO(Subv): Implement actual syncpt waiting.
params.value = 0;
@@ -57,4 +63,10 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
+u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
+ NGLOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ // TODO(bunnei): Implement this.
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index aa9b5a14b..090261a60 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -134,7 +134,9 @@ private:
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
- u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
+
+ u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index a9538ff43..0abc0de83 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -26,6 +26,10 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
return ZCullGetInfo(input, output);
case IoctlCommand::IocZbcSetTable:
return ZBCSetTable(input, output);
+ case IoctlCommand::IocZbcQueryTable:
+ return ZBCQueryTable(input, output);
+ case IoctlCommand::IocFlushL2:
+ return FlushL2(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -136,4 +140,22 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
+u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
+ NGLOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ IoctlZbcQueryTable params{};
+ std::memcpy(&params, input.data(), input.size());
+ // TODO : To implement properly
+ std::memcpy(output.data(), &params, output.size());
+ return 0;
+}
+
+u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
+ NGLOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ IoctlFlushL2 params{};
+ std::memcpy(&params, input.data(), input.size());
+ // TODO : To implement properly
+ std::memcpy(output.data(), &params, output.size());
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 1d5ba2e67..f09113e67 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -26,6 +26,18 @@ private:
IocZcullGetCtxSizeCommand = 0x80044701,
IocZcullGetInfo = 0x80284702,
IocZbcSetTable = 0x402C4703,
+ IocZbcQueryTable = 0xC0344704,
+ IocFlushL2 = 0x40084707,
+ IocInvalICache = 0x4008470D,
+ IocSetMmudebugMode = 0x4008470E,
+ IocSetSmDebugMode = 0x4010470F,
+ IocWaitForPause = 0xC0084710,
+ IocGetTcpExceptionEnStatus = 0x80084711,
+ IocNumVsms = 0x80084712,
+ IocVsmsMapping = 0xC0044713,
+ IocGetErrorChannelUserData = 0xC008471B,
+ IocGetGpuTime = 0xC010471C,
+ IocGetCpuTimeCorrelationInfo = 0xC108471D,
};
struct IoctlGpuCharacteristics {
@@ -127,12 +139,31 @@ private:
};
static_assert(sizeof(IoctlZbcSetTable) == 44, "IoctlZbcSetTable is incorrect size");
+ struct IoctlZbcQueryTable {
+ u32_le color_ds[4];
+ u32_le color_l2[4];
+ u32_le depth;
+ u32_le ref_cnt;
+ u32_le format;
+ u32_le type;
+ u32_le index_size;
+ };
+ static_assert(sizeof(IoctlZbcQueryTable) == 52, "IoctlZbcQueryTable is incorrect size");
+
+ struct IoctlFlushL2 {
+ u32_le flush; // l2_flush | l2_invalidate << 1 | fb_flush << 2
+ u32_le reserved;
+ };
+ static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
+
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 2ecf818f3..56b5ed60d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -26,11 +26,19 @@ public:
private:
enum class IoctlCommand : u32_le {
IocSetNVMAPfdCommand = 0x40044801,
+ IocAllocGPFIFOCommand = 0x40084805,
IocSetClientDataCommand = 0x40084714,
IocGetClientDataCommand = 0x80084715,
IocZCullBind = 0xc010480b,
IocSetErrorNotifierCommand = 0xC018480C,
IocChannelSetPriorityCommand = 0x4004480D,
+ IocEnableCommand = 0x0000480E,
+ IocDisableCommand = 0x0000480F,
+ IocPreemptCommand = 0x00004810,
+ IocForceResetCommand = 0x00004811,
+ IocEventIdControlCommand = 0x40084812,
+ IocGetErrorNotificationCommand = 0xC0104817,
+ IocAllocGPFIFOExCommand = 0x40204818,
IocAllocGPFIFOEx2Command = 0xC020481A,
IocAllocObjCtxCommand = 0xC0104809,
IocChannelGetWaitbaseCommand = 0xC0080003,
@@ -56,6 +64,12 @@ private:
};
static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
+ struct IoctlAllocGPFIFO {
+ u32_le num_entries;
+ u32_le flags;
+ };
+ static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
+
struct IoctlClientData {
u64_le data;
};
@@ -76,12 +90,45 @@ private:
};
static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
+ struct IoctlChannelSetPriority {
+ u32_le priority;
+ };
+ static_assert(sizeof(IoctlChannelSetPriority) == 4,
+ "IoctlChannelSetPriority is incorrect size");
+
+ struct IoctlEventIdControl {
+ u32_le cmd; // 0=disable, 1=enable, 2=clear
+ u32_le id;
+ };
+ static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
+
+ struct IoctlGetErrorNotification {
+ u64_le timestamp;
+ u32_le info32;
+ u16_le info16;
+ u16_le status; // always 0xFFFF
+ };
+ static_assert(sizeof(IoctlGetErrorNotification) == 16,
+ "IoctlGetErrorNotification is incorrect size");
+
struct IoctlFence {
u32_le id;
u32_le value;
};
static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size");
+ struct IoctlAllocGpfifoEx {
+ u32_le num_entries;
+ u32_le flags;
+ u32_le unk0;
+ u32_le unk1;
+ u32_le unk2;
+ u32_le unk3;
+ u32_le unk4;
+ u32_le unk5;
+ };
+ static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
+
struct IoctlAllocGpfifoEx2 {
u32_le num_entries; // in
u32_le flags; // in
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
new file mode 100644
index 000000000..0b6c22898
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -0,0 +1,32 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
+
+namespace Service::Nvidia::Devices {
+
+u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+ NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
+ command.raw, input.size(), output.size());
+
+ switch (static_cast<IoctlCommand>(command.raw)) {
+ case IoctlCommand::IocSetNVMAPfdCommand:
+ return SetNVMAPfd(input, output);
+ }
+
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
+ return 0;
+}
+
+u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSetNvmapFD params{};
+ std::memcpy(&params, input.data(), input.size());
+ NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+ nvmap_fd = params.nvmap_fd;
+ return 0;
+}
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
new file mode 100644
index 000000000..0192aecdd
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -0,0 +1,38 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service::Nvidia::Devices {
+
+class nvhost_nvdec final : public nvdevice {
+public:
+ nvhost_nvdec() = default;
+ ~nvhost_nvdec() override = default;
+
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+private:
+ enum class IoctlCommand : u32_le {
+ IocSetNVMAPfdCommand = 0x40044801,
+ };
+
+ struct IoctlSetNvmapFD {
+ u32_le nvmap_fd;
+ };
+ static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
+
+ u32_le nvmap_fd{};
+
+ u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+};
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index a6a4ab7d3..cc5cfe34e 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -9,6 +9,7 @@
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
+#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -36,6 +37,7 @@ Module::Module() {
devices["/dev/nvmap"] = nvmap_dev;
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
+ devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
}
u32 Module::Open(std::string device_name) {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 5b91089cf..bdd9eb5a5 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -20,11 +20,13 @@
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/audio/audio.h"
+#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/lm/lm.h"
+#include "core/hle/service/mm/mm_u.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/ns/ns.h"
@@ -183,12 +185,14 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
AM::InstallInterfaces(*sm, nv_flinger);
AOC::InstallInterfaces(*sm);
APM::InstallInterfaces(*sm);
+ BCAT::InstallInterfaces(*sm);
Audio::InstallInterfaces(*sm);
Fatal::InstallInterfaces(*sm);
FileSystem::InstallInterfaces(*sm);
Friend::InstallInterfaces(*sm);
HID::InstallInterfaces(*sm);
LM::InstallInterfaces(*sm);
+ MM::InstallInterfaces(*sm);
NFP::InstallInterfaces(*sm);
NIFM::InstallInterfaces(*sm);
NS::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 2eb37fb42..654012189 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <chrono>
+#include <ctime>
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
@@ -77,7 +78,7 @@ public:
{3, nullptr, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, nullptr, "GetTimeZoneRuleVersion"},
- {100, nullptr, "ToCalendarTime"},
+ {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{200, nullptr, "ToPosixTime"},
{201, nullptr, "ToPosixTimeWithMyRule"},
@@ -86,9 +87,11 @@ public:
}
private:
+ LocationName location_name{"UTC"};
+ TimeZoneRule my_time_zone_rule{};
+
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Time, "(STUBBED) called");
- LocationName location_name{};
+ NGLOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(location_name);
@@ -103,23 +106,70 @@ private:
void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Time, "(STUBBED) called");
+
+ ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule));
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+ void ToCalendarTime(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 posix_time = rp.Pop<u64>();
+
+ NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
+
+ TimeZoneRule time_zone_rule{};
+ auto buffer = ctx.ReadBuffer();
+ std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
+
+ CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
+ CalendarAdditionalInfo additional_info{};
+
+ PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule);
+
+ IPC::ResponseBuilder rb{ctx, 10};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(calendar_time);
+ rb.PushRaw(additional_info);
+ }
+
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u64 posix_time = rp.Pop<u64>();
+ const u64 posix_time = rp.Pop<u64>();
NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
CalendarAdditionalInfo additional_info{};
+
+ PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule);
+
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(calendar_time);
rb.PushRaw(additional_info);
}
+
+ void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
+ CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) {
+ std::time_t t(posix_time);
+ std::tm* tm = std::localtime(&t);
+ if (!tm) {
+ return;
+ }
+ calendar_time.year = tm->tm_year + 1900;
+ calendar_time.month = tm->tm_mon + 1;
+ calendar_time.day = tm->tm_mday;
+ calendar_time.hour = tm->tm_hour;
+ calendar_time.minute = tm->tm_min;
+ calendar_time.second = tm->tm_sec;
+
+ additional_info.day_of_week = tm->tm_wday;
+ additional_info.day_of_year = tm->tm_yday;
+ std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
+ additional_info.utc_offset = 0;
+ }
};
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 12fe1995a..49af38589 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -4,13 +4,13 @@
#pragma once
+#include <array>
#include "core/hle/service/service.h"
namespace Service::Time {
-// TODO(Rozelette) RE this structure
struct LocationName {
- INSERT_PADDING_BYTES(0x24);
+ std::array<u8, 0x24> name;
};
static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size");
@@ -25,26 +25,34 @@ struct CalendarTime {
};
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
-// TODO(Rozelette) RE this structure
struct CalendarAdditionalInfo {
- INSERT_PADDING_BYTES(0x18);
+ u32_le day_of_week;
+ u32_le day_of_year;
+ std::array<u8, 8> name;
+ INSERT_PADDING_BYTES(1);
+ s32_le utc_offset;
};
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
"CalendarAdditionalInfo structure has incorrect size");
-// TODO(bunnei) RE this structure
-struct SystemClockContext {
- INSERT_PADDING_BYTES(0x20);
+// TODO(mailwl) RE this structure
+struct TimeZoneRule {
+ INSERT_PADDING_BYTES(0x4000);
};
-static_assert(sizeof(SystemClockContext) == 0x20,
- "SystemClockContext structure has incorrect size");
struct SteadyClockTimePoint {
- u64 value;
+ u64_le value;
INSERT_PADDING_WORDS(4);
};
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
+struct SystemClockContext {
+ u64_le offset;
+ SteadyClockTimePoint time_point;
+};
+static_assert(sizeof(SystemClockContext) == 0x20,
+ "SystemClockContext structure has incorrect size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {