From 07139a2c0d0e08cc948a73cb002cde23511ab15d Mon Sep 17 00:00:00 2001 From: Zephyron Date: Fri, 16 May 2025 16:54:39 +1000 Subject: [PATCH 1/2] feat(HLE): Implement missing BSD socket service functions Adds implementations for several previously unimplemented BSD socket service functions, as documented in Switchbrew. REF: https://switchbrew.org/wiki/Sockets_services#bsd:u.2C_bsd:s.2C_bsd:a The following functions have been added to the `bsd:u`, `bsd:s`, and `bsd:a` services: * `SocketExempt` (Cmd 3) * `Open` (Cmd 4) * `Sysctl` (Cmd 7) * `Ioctl` (Cmd 19) * `ShutdownAllSockets` (Cmd 23) * `GetResourceStatistics` (Cmd 28) * `RecvMMsg` (Cmd 29) * `SendMMsg` (Cmd 30) * `RegisterResourceStatisticsName` (Cmd 32) * `RegisterClientShared` (Cmd 33) (replaces the placeholder `Initialize2`) * `GetSocketStatistics` (Cmd 34) * `NifIoctl` (Cmd 35) * `SetThreadCoreMask` (Cmd 200) * `GetThreadCoreMask` (Cmd 201) These functions are initially set to log a warning and return an appropriate error code (typically `EOPNOTSUPP` or `ENOTTY`), or success in the case of registration-type functions. The command handlers have been registered in the BSD service constructor. This resolves various compilation errors encountered during the implementation process related to IPC response generation and enum usage. Signed-off-by: Zephyron --- src/core/hle/service/sockets/bsd.cpp | 140 ++++++++++++++++++++++++--- src/core/hle/service/sockets/bsd.h | 17 ++++ 2 files changed, 146 insertions(+), 11 deletions(-) diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index dd652ca42..ef803e33f 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -309,7 +310,7 @@ void BSD::Listen(HLERequestContext& ctx) { void BSD::Fcntl(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const s32 fd = rp.Pop(); - const s32 cmd = rp.Pop(); + const u32 cmd = rp.Pop(); const s32 arg = rp.Pop(); LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg); @@ -479,6 +480,14 @@ void BSD::EventFd(HLERequestContext& ctx) { BuildErrnoResponse(ctx, Errno::SUCCESS); } +void BSD::RegisterClientShared(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called RegisterClientShared"); + IPC::ResponseBuilder rb{ctx, 4}; // Match RegisterClient response style + rb.Push(ResultSuccess); + rb.Push(0); // ret (0 for success) + rb.Push(0); // BSD errno (0 for success, consistent with RegisterClient stub) +} + template void BSD::ExecuteWork(HLERequestContext& ctx, Work work) { work.Execute(this); @@ -976,11 +985,11 @@ BSD::BSD(Core::System& system_, const char* name) {0, &BSD::RegisterClient, "RegisterClient"}, {1, &BSD::StartMonitoring, "StartMonitoring"}, {2, &BSD::Socket, "Socket"}, - {3, nullptr, "SocketExempt"}, - {4, nullptr, "Open"}, + {3, &BSD::SocketExempt, "SocketExempt"}, + {4, &BSD::Open, "Open"}, {5, &BSD::Select, "Select"}, {6, &BSD::Poll, "Poll"}, - {7, nullptr, "Sysctl"}, + {7, &BSD::Sysctl, "Sysctl"}, {8, &BSD::Recv, "Recv"}, {9, &BSD::RecvFrom, "RecvFrom"}, {10, &BSD::Send, "Send"}, @@ -992,21 +1001,25 @@ BSD::BSD(Core::System& system_, const char* name) {16, &BSD::GetSockName, "GetSockName"}, {17, &BSD::GetSockOpt, "GetSockOpt"}, {18, &BSD::Listen, "Listen"}, - {19, nullptr, "Ioctl"}, + {19, &BSD::Ioctl, "Ioctl"}, {20, &BSD::Fcntl, "Fcntl"}, {21, &BSD::SetSockOpt, "SetSockOpt"}, {22, &BSD::Shutdown, "Shutdown"}, - {23, nullptr, "ShutdownAllSockets"}, + {23, &BSD::ShutdownAllSockets, "ShutdownAllSockets"}, {24, &BSD::Write, "Write"}, {25, &BSD::Read, "Read"}, {26, &BSD::Close, "Close"}, {27, &BSD::DuplicateSocket, "DuplicateSocket"}, - {28, nullptr, "GetResourceStatistics"}, - {29, nullptr, "RecvMMsg"}, - {30, nullptr, "SendMMsg"}, + {28, &BSD::GetResourceStatistics, "GetResourceStatistics"}, + {29, &BSD::RecvMMsg, "RecvMMsg"}, + {30, &BSD::SendMMsg, "SendMMsg"}, {31, &BSD::EventFd, "EventFd"}, - {32, nullptr, "RegisterResourceStatisticsName"}, - {33, nullptr, "Initialize2"}, + {32, &BSD::RegisterResourceStatisticsName, "RegisterResourceStatisticsName"}, + {33, &BSD::RegisterClientShared, "RegisterClientShared"}, + {34, &BSD::GetSocketStatistics, "GetSocketStatistics"}, + {35, &BSD::NifIoctl, "NifIoctl"}, + {200, &BSD::SetThreadCoreMask, "SetThreadCoreMask"}, + {201, &BSD::GetThreadCoreMask, "GetThreadCoreMask"}, }; // clang-format on @@ -1058,4 +1071,109 @@ BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { BSDCFG::~BSDCFG() = default; +void BSD::GetResourceStatistics(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called GetResourceStatistics"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::GetSocketStatistics(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called GetSocketStatistics"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::GetThreadCoreMask(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called GetThreadCoreMask"); + IPC::ResponseBuilder rb{ctx, 5}; + rb.Push(ResultSuccess); + rb.Push(0); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::Ioctl(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Ioctl"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(ENOTTY)); +} + +void BSD::NifIoctl(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called NifIoctl"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(ENOTTY)); +} + +void BSD::Open(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Open"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EACCES)); +} + +void BSD::RecvMMsg(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called RecvMMsg"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(0); // num_msgs processed + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::RegisterResourceStatisticsName(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called RegisterResourceStatisticsName"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::SendMMsg(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SendMMsg"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(0); // num_msgs processed + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::SetThreadCoreMask(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SetThreadCoreMask"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::ShutdownAllSockets(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called ShutdownAllSockets"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::SocketExempt(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SocketExempt"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); // fd + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSD::Sysctl(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Sysctl"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 4f69d382c..b2fd39cc5 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -149,6 +150,22 @@ private: void DuplicateSocket(HLERequestContext& ctx); void EventFd(HLERequestContext& ctx); + // [Zephyron] Added declarations based on Switchbrew documentation + void SocketExempt(HLERequestContext& ctx); + void Open(HLERequestContext& ctx); + void Sysctl(HLERequestContext& ctx); + void Ioctl(HLERequestContext& ctx); + void ShutdownAllSockets(HLERequestContext& ctx); + void GetResourceStatistics(HLERequestContext& ctx); + void RecvMMsg(HLERequestContext& ctx); + void SendMMsg(HLERequestContext& ctx); + void RegisterResourceStatisticsName(HLERequestContext& ctx); + void RegisterClientShared(HLERequestContext& ctx); + void GetSocketStatistics(HLERequestContext& ctx); + void NifIoctl(HLERequestContext& ctx); + void SetThreadCoreMask(HLERequestContext& ctx); + void GetThreadCoreMask(HLERequestContext& ctx); + template void ExecuteWork(HLERequestContext& ctx, Work work); From 76210eb9906f68efb03d491e085c1d2caa85d4f6 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Fri, 16 May 2025 17:31:26 +1000 Subject: [PATCH 2/2] feat(HLE): Implement bsdcfg service functions and fix logging Adds implementations for all `bsdcfg` (aliased as `ifcfg`) service functions as listed in the existing codebase and supplemented by Switchbrew documentation. The following functions have been added to the `BSDCFG` service: - `SetIfUp` (Cmd 0) - `SetIfUpWithEvent` (Cmd 1) - `CancelIf` (Cmd 2) - `SetIfDown` (Cmd 3) - `GetIfState` (Cmd 4) - `DhcpRenew` (Cmd 5) - `AddStaticArpEntry` (Cmd 6) - `RemoveArpEntry` (Cmd 7) - `LookupArpEntry` (Cmd 8) - `LookupArpEntry2` (Cmd 9) - `ClearArpEntries` (Cmd 10) - `ClearArpEntries2` (Cmd 11) - `PrintArpEntries` (Cmd 12) - `Unknown13` (Cmd 13) - `Unknown14` (Cmd 14) - `Unknown15` (Cmd 15) These functions are initially stubbed to log a warning and return `EOPNOTSUPP`. Command handlers have been updated in the `BSDCFG` constructor. Additionally, this commit corrects the logging category in these new `BSDCFG` stubs from an undefined `Service_BSDCFG` to the existing `Service` category, resolving compilation errors. Signed-off-by: Zephyron --- src/core/hle/service/sockets/bsd.cpp | 161 ++++++++++++++++++++++++--- src/core/hle/service/sockets/bsd.h | 19 ++++ 2 files changed, 164 insertions(+), 16 deletions(-) diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index ef803e33f..549d450cd 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -1047,22 +1047,22 @@ std::unique_lock BSD::LockService() { BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "SetIfUp"}, - {1, nullptr, "SetIfUpWithEvent"}, - {2, nullptr, "CancelIf"}, - {3, nullptr, "SetIfDown"}, - {4, nullptr, "GetIfState"}, - {5, nullptr, "DhcpRenew"}, - {6, nullptr, "AddStaticArpEntry"}, - {7, nullptr, "RemoveArpEntry"}, - {8, nullptr, "LookupArpEntry"}, - {9, nullptr, "LookupArpEntry2"}, - {10, nullptr, "ClearArpEntries"}, - {11, nullptr, "ClearArpEntries2"}, - {12, nullptr, "PrintArpEntries"}, - {13, nullptr, "Unknown13"}, - {14, nullptr, "Unknown14"}, - {15, nullptr, "Unknown15"}, + {0, &BSDCFG::SetIfUp, "SetIfUp"}, + {1, &BSDCFG::SetIfUpWithEvent, "SetIfUpWithEvent"}, + {2, &BSDCFG::CancelIf, "CancelIf"}, + {3, &BSDCFG::SetIfDown, "SetIfDown"}, + {4, &BSDCFG::GetIfState, "GetIfState"}, + {5, &BSDCFG::DhcpRenew, "DhcpRenew"}, + {6, &BSDCFG::AddStaticArpEntry, "AddStaticArpEntry"}, + {7, &BSDCFG::RemoveArpEntry, "RemoveArpEntry"}, + {8, &BSDCFG::LookupArpEntry, "LookupArpEntry"}, + {9, &BSDCFG::LookupArpEntry2, "LookupArpEntry2"}, + {10, &BSDCFG::ClearArpEntries, "ClearArpEntries"}, + {11, &BSDCFG::ClearArpEntries2, "ClearArpEntries2"}, + {12, &BSDCFG::PrintArpEntries, "PrintArpEntries"}, + {13, &BSDCFG::Unknown13, "Unknown13"}, + {14, &BSDCFG::Unknown14, "Unknown14"}, + {15, &BSDCFG::Unknown15, "Unknown15"}, }; // clang-format on @@ -1071,6 +1071,135 @@ BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { BSDCFG::~BSDCFG() = default; +// BSDCFG Service Method Stubs +void BSDCFG::SetIfUp(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SetIfUp"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::SetIfUpWithEvent(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SetIfUpWithEvent"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::CancelIf(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called CancelIf"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::SetIfDown(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called SetIfDown"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::GetIfState(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called GetIfState"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::DhcpRenew(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called DhcpRenew"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::AddStaticArpEntry(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called AddStaticArpEntry"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::RemoveArpEntry(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called RemoveArpEntry"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::LookupArpEntry(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called LookupArpEntry"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::LookupArpEntry2(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called LookupArpEntry2"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::ClearArpEntries(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called ClearArpEntries"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::ClearArpEntries2(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called ClearArpEntries2"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::PrintArpEntries(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called PrintArpEntries"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::Unknown13(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Unknown13 (Cmd13)"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::Unknown14(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Unknown14 (Cmd14)"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + +void BSDCFG::Unknown15(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called Unknown15 (Cmd15)"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(-1); + rb.PushEnum(static_cast(EOPNOTSUPP)); +} + void BSD::GetResourceStatistics(HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called GetResourceStatistics"); IPC::ResponseBuilder rb{ctx, 4}; diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index b2fd39cc5..96327ccc4 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -212,6 +212,25 @@ class BSDCFG final : public ServiceFramework { public: explicit BSDCFG(Core::System& system_); ~BSDCFG() override; + +private: + // [Zephyron] bsdcfg/ifcfg service methods based on documentation and existing registration + void SetIfUp(HLERequestContext& ctx); + void SetIfUpWithEvent(HLERequestContext& ctx); + void CancelIf(HLERequestContext& ctx); + void SetIfDown(HLERequestContext& ctx); + void GetIfState(HLERequestContext& ctx); + void DhcpRenew(HLERequestContext& ctx); + void AddStaticArpEntry(HLERequestContext& ctx); + void RemoveArpEntry(HLERequestContext& ctx); + void LookupArpEntry(HLERequestContext& ctx); + void LookupArpEntry2(HLERequestContext& ctx); + void ClearArpEntries(HLERequestContext& ctx); + void ClearArpEntries2(HLERequestContext& ctx); + void PrintArpEntries(HLERequestContext& ctx); + void Unknown13(HLERequestContext& ctx); // Cmd13 + void Unknown14(HLERequestContext& ctx); // Cmd14 + void Unknown15(HLERequestContext& ctx); // Cmd15 }; } // namespace Service::Sockets