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 <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-05-16 16:54:39 +10:00
parent c5e56bc72a
commit 07139a2c0d
2 changed files with 146 additions and 11 deletions

View File

@@ -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 <array>
@@ -309,7 +310,7 @@ void BSD::Listen(HLERequestContext& ctx) {
void BSD::Fcntl(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const s32 cmd = rp.Pop<s32>();
const u32 cmd = rp.Pop<u32>();
const s32 arg = rp.Pop<s32>();
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<s32>(0); // ret (0 for success)
rb.Push<s32>(0); // BSD errno (0 for success, consistent with RegisterClient stub)
}
template <typename Work>
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<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::GetSocketStatistics(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called GetSocketStatistics");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::GetThreadCoreMask(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called GetThreadCoreMask");
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.Push<u64>(0);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::Ioctl(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called Ioctl");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(ENOTTY));
}
void BSD::NifIoctl(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called NifIoctl");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(ENOTTY));
}
void BSD::Open(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called Open");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EACCES));
}
void BSD::RecvMMsg(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called RecvMMsg");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(0); // num_msgs processed
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::RegisterResourceStatisticsName(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called RegisterResourceStatisticsName");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::SendMMsg(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called SendMMsg");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(0); // num_msgs processed
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::SetThreadCoreMask(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called SetThreadCoreMask");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::ShutdownAllSockets(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called ShutdownAllSockets");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::SocketExempt(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called SocketExempt");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1); // fd
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
void BSD::Sysctl(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called Sysctl");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(static_cast<Errno>(EOPNOTSUPP));
}
} // namespace Service::Sockets

View File

@@ -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 <typename Work>
void ExecuteWork(HLERequestContext& ctx, Work work);