mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-17 17:36:44 +00:00
kern: add SvcCreatePort, SvcConnectToPort
This commit is contained in:
parent
9f79710cb7
commit
93be2ffcba
10 changed files with 338 additions and 11 deletions
|
@ -50,6 +50,7 @@ namespace ams::kern {
|
|||
|
||||
/* TODO: More of KClientPort. */
|
||||
Result CreateSession(KClientSession **out);
|
||||
Result CreateLightSession(KLightClientSession **out);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -29,13 +29,12 @@ namespace ams::kern {
|
|||
constexpr KClientSession() : parent() { /* ... */ }
|
||||
virtual ~KClientSession() { /* ... */ }
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
void Initialize(KSession *parent) {
|
||||
/* Set member variables. */
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
virtual void Destroy() override;
|
||||
static void PostDestroy(uintptr_t arg) { /* ... */ }
|
||||
|
||||
constexpr KSession *GetParent() const { return this->parent; }
|
||||
|
|
|
@ -34,11 +34,14 @@ namespace ams::kern {
|
|||
this->parent = parent;
|
||||
}
|
||||
|
||||
virtual void Destroy() override;
|
||||
static void PostDestroy(uintptr_t arg) { /* ... */ }
|
||||
|
||||
constexpr const KLightSession *GetParent() const { return this->parent; }
|
||||
|
||||
/* TODO: More of KLightClientSession. */
|
||||
Result SendSyncRequest(u32 *data);
|
||||
|
||||
void OnServerClosed();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -35,13 +35,22 @@ namespace ams::kern {
|
|||
constexpr KLightServerSession() : parent(), request_queue(), server_queue(), current_request(), server_thread() { /* ... */ }
|
||||
virtual ~KLightServerSession() { /* ... */ }
|
||||
|
||||
void Initialize(KLightSession *parent);
|
||||
void Initialize(KLightSession *parent) {
|
||||
/* Set member variables. */
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
virtual void Destroy() override;
|
||||
static void PostDestroy(uintptr_t arg) { /* ... */ }
|
||||
|
||||
constexpr const KLightSession *GetParent() const { return this->parent; }
|
||||
|
||||
/* TODO: More of KLightServerSession. */
|
||||
Result OnRequest(KThread *request_thread);
|
||||
Result ReplyAndReceive(u32 *data);
|
||||
|
||||
void OnClientClosed();
|
||||
private:
|
||||
void CleanupRequests();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -51,12 +51,21 @@ namespace ams::kern {
|
|||
|
||||
virtual ~KLightSession() { /* ... */ }
|
||||
|
||||
void Initialize(KClientPort *client_port, uintptr_t name);
|
||||
virtual void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override { return this->initialized; }
|
||||
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(this->process); }
|
||||
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
/* TODO: This is a placeholder definition. */
|
||||
void OnServerClosed();
|
||||
void OnClientClosed();
|
||||
|
||||
bool IsServerClosed() const { return this->state != State::Normal; }
|
||||
bool IsClientClosed() const { return this->state != State::Normal; }
|
||||
|
||||
Result OnRequest(KThread *request_thread) { return this->server.OnRequest(request_thread); }
|
||||
|
||||
KLightClientSession &GetClientSession() { return this->client; }
|
||||
KLightServerSession &GetServerSession() { return this->server; }
|
||||
|
|
|
@ -120,7 +120,72 @@ namespace ams::kern {
|
|||
session_guard.Cancel();
|
||||
*out = std::addressof(session->GetClientSession());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KClientPort::CreateLightSession(KLightClientSession **out) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Reserve a new session from the resource limit. */
|
||||
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(), ams::svc::LimitableResource_SessionCountMax);
|
||||
R_UNLESS(session_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Update the session counts. */
|
||||
{
|
||||
/* Atomically increment the number of sessions. */
|
||||
s32 new_sessions;
|
||||
{
|
||||
const auto max = this->max_sessions;
|
||||
auto cur_sessions = this->num_sessions.load(std::memory_order_acquire);
|
||||
do {
|
||||
R_UNLESS(cur_sessions < max, svc::ResultOutOfSessions());
|
||||
new_sessions = cur_sessions + 1;
|
||||
} while (!this->num_sessions.compare_exchange_weak(cur_sessions, new_sessions, std::memory_order_relaxed));
|
||||
|
||||
}
|
||||
|
||||
/* Atomically update the peak session tracking. */
|
||||
{
|
||||
auto peak = this->peak_sessions.load(std::memory_order_acquire);
|
||||
do {
|
||||
if (peak >= new_sessions) {
|
||||
break;
|
||||
}
|
||||
} while (!this->peak_sessions.compare_exchange_weak(peak, new_sessions, std::memory_order_relaxed));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new session. */
|
||||
KLightSession *session = KLightSession::Create();
|
||||
if (session == nullptr) {
|
||||
/* Decrement the session count. */
|
||||
const auto prev = this->num_sessions--;
|
||||
if (prev == this->max_sessions) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
|
||||
return svc::ResultOutOfResource();
|
||||
}
|
||||
|
||||
/* Initialize the session. */
|
||||
session->Initialize(this, this->parent->GetName());
|
||||
|
||||
/* Commit the session reservation. */
|
||||
session_reservation.Commit();
|
||||
|
||||
/* Register the session. */
|
||||
KLightSession::Register(session);
|
||||
auto session_guard = SCOPE_GUARD {
|
||||
session->GetClientSession().Close();
|
||||
session->GetServerSession().Close();
|
||||
};
|
||||
|
||||
/* Enqueue the session with our parent. */
|
||||
R_TRY(this->parent->EnqueueSession(std::addressof(session->GetServerSession())));
|
||||
|
||||
/* We succeeded, so set the output. */
|
||||
session_guard.Cancel();
|
||||
*out = std::addressof(session->GetClientSession());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KLightClientSession::Destroy() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
this->parent->OnClientClosed();
|
||||
}
|
||||
|
||||
void KLightClientSession::OnServerClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
}
|
||||
|
||||
Result KLightClientSession::SendSyncRequest(u32 *data) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KLightServerSession::Destroy() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
this->CleanupRequests();
|
||||
|
||||
this->parent->OnServerClosed();
|
||||
}
|
||||
|
||||
void KLightServerSession::OnClientClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
}
|
||||
|
||||
Result KLightServerSession::OnRequest(KThread *request_thread) {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
Result KLightServerSession::ReplyAndReceive(u32 *data) {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void KLightServerSession::CleanupRequests() {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
}
|
91
libraries/libmesosphere/source/kern_k_light_session.cpp
Normal file
91
libraries/libmesosphere/source/kern_k_light_session.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KLightSession::Initialize(KClientPort *client_port, uintptr_t name) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Increment reference count. */
|
||||
/* Because reference count is one on creation, this will result */
|
||||
/* in a reference count of two. Thus, when both server and client are closed */
|
||||
/* this object will be destroyed. */
|
||||
this->Open();
|
||||
|
||||
/* Create our sub sessions. */
|
||||
KAutoObject::Create(std::addressof(this->server));
|
||||
KAutoObject::Create(std::addressof(this->client));
|
||||
|
||||
/* Initialize our sub sessions. */
|
||||
this->server.Initialize(this);
|
||||
this->client.Initialize(this);
|
||||
|
||||
/* Set state and name. */
|
||||
this->state = State::Normal;
|
||||
this->name = name;
|
||||
|
||||
/* Set our owner process. */
|
||||
this->process = GetCurrentProcessPointer();
|
||||
this->process->Open();
|
||||
|
||||
/* Set our port. */
|
||||
this->port = client_port;
|
||||
if (this->port != nullptr) {
|
||||
this->port->Open();
|
||||
}
|
||||
|
||||
/* Mark initialized. */
|
||||
this->initialized = true;
|
||||
}
|
||||
|
||||
void KLightSession::Finalize() {
|
||||
if (this->port != nullptr) {
|
||||
this->port->OnSessionFinalized();
|
||||
this->port->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void KLightSession::OnServerClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ServerClosed;
|
||||
this->client.OnServerClosed();
|
||||
}
|
||||
|
||||
this->Close();
|
||||
}
|
||||
|
||||
void KLightSession::OnClientClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ClientClosed;
|
||||
this->server.OnClientClosed();
|
||||
}
|
||||
|
||||
this->Close();
|
||||
}
|
||||
|
||||
void KLightSession::PostDestroy(uintptr_t arg) {
|
||||
/* Release the session count resource the owner process holds. */
|
||||
KProcess *owner = reinterpret_cast<KProcess *>(arg);
|
||||
owner->ReleaseResource(ams::svc::LimitableResource_SessionCountMax, 1);
|
||||
owner->Close();
|
||||
}
|
||||
|
||||
}
|
|
@ -47,7 +47,7 @@ namespace ams::kern::svc {
|
|||
port->Initialize(max_sessions, false, 0);
|
||||
|
||||
/* Register the port. */
|
||||
KPort::Register(port);
|
||||
R_TRY(KPort::Register(port));
|
||||
|
||||
/* Register the handle in the table. */
|
||||
handle_table.Register(*out_server_handle, std::addressof(port->GetServerPort()));
|
||||
|
@ -77,6 +77,43 @@ namespace ams::kern::svc {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CreatePort(ams::svc::Handle *out_server, ams::svc::Handle *out_client, int32_t max_sessions, bool is_light, uintptr_t name) {
|
||||
/* Ensure max sessions is valid. */
|
||||
R_UNLESS(max_sessions > 0, svc::ResultOutOfRange());
|
||||
|
||||
/* Get the current handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Create a new port. */
|
||||
KPort *port = KPort::Create();
|
||||
R_UNLESS(port != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Initialize the port. */
|
||||
port->Initialize(max_sessions, is_light, name);
|
||||
|
||||
/* Ensure that we clean up the port (and its only references are handle table) on function end. */
|
||||
ON_SCOPE_EXIT {
|
||||
port->GetServerPort().Close();
|
||||
port->GetClientPort().Close();
|
||||
};
|
||||
|
||||
/* Register the port. */
|
||||
R_TRY(KPort::Register(port));
|
||||
|
||||
/* Add the client to the handle table. */
|
||||
R_TRY(handle_table.Add(out_client, std::addressof(port->GetClientPort())));
|
||||
|
||||
/* Ensure that we maintaing a clean handle state on exit. */
|
||||
auto handle_guard = SCOPE_GUARD { handle_table.Remove(*out_client); };
|
||||
|
||||
/* Add the server to the handle table. */
|
||||
R_TRY(handle_table.Add(out_server, std::addressof(port->GetServerPort())));
|
||||
|
||||
/* We succeeded! */
|
||||
handle_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer<const char *> user_name) {
|
||||
/* Copy the provided name from user memory to kernel memory. */
|
||||
char name[KObjectName::NameLengthMax] = {};
|
||||
|
@ -112,6 +149,39 @@ namespace ams::kern::svc {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ConnectToPort(ams::svc::Handle *out, ams::svc::Handle port) {
|
||||
/* Get the current handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Get the client port. */
|
||||
KScopedAutoObject client_port = handle_table.GetObject<KClientPort>(port);
|
||||
R_UNLESS(client_port.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* 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 and register session. */
|
||||
if (client_port->IsLight()) {
|
||||
KLightClientSession *session;
|
||||
R_TRY(client_port->CreateLightSession(std::addressof(session)));
|
||||
|
||||
handle_table.Register(*out, session);
|
||||
session->Close();
|
||||
} else {
|
||||
KClientSession *session;
|
||||
R_TRY(client_port->CreateSession(std::addressof(session)));
|
||||
|
||||
handle_table.Register(*out, session);
|
||||
session->Close();
|
||||
}
|
||||
|
||||
/* We succeeded. */
|
||||
handle_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
@ -121,7 +191,7 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result CreatePort64(ams::svc::Handle *out_server_handle, ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ams::svc::Address name) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcCreatePort64 was called.");
|
||||
return CreatePort(out_server_handle, out_client_handle, max_sessions, is_light, name);
|
||||
}
|
||||
|
||||
Result ManageNamedPort64(ams::svc::Handle *out_server_handle, KUserPointer<const char *> name, int32_t max_sessions) {
|
||||
|
@ -129,7 +199,7 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result ConnectToPort64(ams::svc::Handle *out_handle, ams::svc::Handle port) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcConnectToPort64 was called.");
|
||||
return ConnectToPort(out_handle, port);
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
@ -139,7 +209,7 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result CreatePort64From32(ams::svc::Handle *out_server_handle, ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ams::svc::Address name) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcCreatePort64From32 was called.");
|
||||
return CreatePort(out_server_handle, out_client_handle, max_sessions, is_light, name);
|
||||
}
|
||||
|
||||
Result ManageNamedPort64From32(ams::svc::Handle *out_server_handle, KUserPointer<const char *> name, int32_t max_sessions) {
|
||||
|
@ -147,7 +217,7 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result ConnectToPort64From32(ams::svc::Handle *out_handle, ams::svc::Handle port) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcConnectToPort64From32 was called.");
|
||||
return ConnectToPort(out_handle, port);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue