2022-10-05 02:15:40 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#include "common/scope_exit.h"
|
|
|
|
#include "core/core.h"
|
|
|
|
#include "core/hle/kernel/k_client_port.h"
|
|
|
|
#include "core/hle/kernel/k_client_session.h"
|
|
|
|
#include "core/hle/kernel/k_port.h"
|
|
|
|
#include "core/hle/kernel/k_process.h"
|
|
|
|
#include "core/hle/kernel/svc.h"
|
|
|
|
|
|
|
|
namespace Kernel::Svc {
|
|
|
|
|
|
|
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
|
|
|
Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
|
|
|
|
auto& memory = system.Memory();
|
|
|
|
if (!memory.IsValidVirtualAddress(port_name_address)) {
|
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
|
|
|
|
port_name_address);
|
|
|
|
return ResultNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr std::size_t PortNameMaxLength = 11;
|
|
|
|
// Read 1 char beyond the max allowed port name to detect names that are too long.
|
|
|
|
const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
|
|
|
|
if (port_name.size() > PortNameMaxLength) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
|
|
|
|
port_name.size());
|
|
|
|
return ResultOutOfRange;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
|
|
|
|
|
|
|
|
// Get the current handle table.
|
|
|
|
auto& kernel = system.Kernel();
|
2023-02-13 16:44:41 +01:00
|
|
|
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
|
2022-10-05 02:15:40 +02:00
|
|
|
|
|
|
|
// Find the client port.
|
|
|
|
auto port = kernel.CreateNamedServicePort(port_name);
|
|
|
|
if (!port) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
|
|
|
|
return ResultNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reserve a handle for the port.
|
|
|
|
// NOTE: Nintendo really does write directly to the output handle here.
|
|
|
|
R_TRY(handle_table.Reserve(out));
|
|
|
|
auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); });
|
|
|
|
|
|
|
|
// Create a session.
|
|
|
|
KClientSession* session{};
|
|
|
|
R_TRY(port->CreateSession(std::addressof(session)));
|
|
|
|
|
|
|
|
kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
|
|
|
|
|
|
|
|
// Register the session in the table, close the extra reference.
|
|
|
|
handle_table.Register(*out, session);
|
|
|
|
session->Close();
|
|
|
|
|
|
|
|
// We succeeded.
|
|
|
|
handle_guard.Cancel();
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
2023-02-05 20:22:02 +01:00
|
|
|
Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
|
|
|
|
int32_t max_sessions, bool is_light, uintptr_t name) {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
R_THROW(ResultNotImplemented);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
R_THROW(ResultNotImplemented);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name,
|
|
|
|
int32_t max_sessions) {
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
R_THROW(ResultNotImplemented);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
|
|
|
|
R_RETURN(ConnectToNamedPort(system, out_handle, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle,
|
|
|
|
int32_t max_sessions, bool is_light, uint64_t name) {
|
|
|
|
R_RETURN(
|
|
|
|
CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name,
|
|
|
|
int32_t max_sessions) {
|
|
|
|
R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port) {
|
|
|
|
R_RETURN(ConnectToPort(system, out_handle, port));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name) {
|
|
|
|
R_RETURN(ConnectToNamedPort(system, out_handle, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result CreatePort64From32(Core::System& system, Handle* out_server_handle,
|
|
|
|
Handle* out_client_handle, int32_t max_sessions, bool is_light,
|
|
|
|
uint32_t name) {
|
|
|
|
R_RETURN(
|
|
|
|
CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name,
|
|
|
|
int32_t max_sessions) {
|
|
|
|
R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
|
|
|
|
}
|
2022-10-05 02:15:40 +02:00
|
|
|
|
2023-02-05 20:22:02 +01:00
|
|
|
Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) {
|
|
|
|
R_RETURN(ConnectToPort(system, out_handle, port));
|
2022-10-05 02:15:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Kernel::Svc
|