summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/svc/svc_port.cpp
blob: 2b7cebde532cc908ad1042506b5088544dac5d28 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// 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();
    auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();

    // 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;
}

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));
}

Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) {
    R_RETURN(ConnectToPort(system, out_handle, port));
}

} // namespace Kernel::Svc