summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-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/service/am/am.cpp13
-rw-r--r--src/core/hle/service/am/am.h1
-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_gpu.cpp22
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h31
10 files changed, 371 insertions, 36 deletions
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/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 12954556d..b8d6b8d4d 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -561,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"},
@@ -684,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 301a6c798..1da79fd01 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -138,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/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_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