mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 00:12:03 +00:00
kern: SvcConnectToNamedPort
This commit is contained in:
parent
a2eb93fde8
commit
7400a8ff68
15 changed files with 376 additions and 15 deletions
|
@ -177,10 +177,12 @@ namespace ams::kern {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename T> requires std::derived_from<T, KAutoObject>
|
||||
class KScopedAutoObject {
|
||||
static_assert(std::is_base_of<KAutoObject, T>::value);
|
||||
NON_COPYABLE(KScopedAutoObject);
|
||||
private:
|
||||
template<typename U>
|
||||
friend class KScopedAutoObject;
|
||||
private:
|
||||
T *obj;
|
||||
private:
|
||||
|
@ -202,12 +204,32 @@ namespace ams::kern {
|
|||
this->obj = nullptr;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE KScopedAutoObject(KScopedAutoObject &&rhs) {
|
||||
template<typename U>
|
||||
constexpr ALWAYS_INLINE KScopedAutoObject(KScopedAutoObject<U> &&rhs) {
|
||||
if constexpr (std::same_as<T, U>) {
|
||||
this->obj = rhs.obj;
|
||||
rhs.obj = nullptr;
|
||||
} else {
|
||||
T *derived = rhs.obj->template DynamicCast<T *>();
|
||||
if (derived == nullptr) {
|
||||
rhs.obj->Close();
|
||||
}
|
||||
|
||||
this->obj = derived;
|
||||
rhs.obj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
constexpr ALWAYS_INLINE KScopedAutoObject &operator=(KScopedAutoObject<U> &&rhs) {
|
||||
if constexpr (!std::same_as<T, U>) {
|
||||
T *derived = rhs.obj->template DynamicCast<T *>();
|
||||
if (derived == nullptr) {
|
||||
rhs.obj->Close();
|
||||
}
|
||||
rhs.obj = nullptr;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE KScopedAutoObject &operator=(KScopedAutoObject &&rhs) {
|
||||
rhs.Swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
namespace ams::kern {
|
||||
|
||||
class KPort;
|
||||
class KSession;
|
||||
class KClientSession;
|
||||
class KLightSession;
|
||||
class KLightClientSession;
|
||||
|
||||
class KClientPort final : public KSynchronizationObject {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
|
||||
|
@ -33,6 +37,8 @@ namespace ams::kern {
|
|||
virtual ~KClientPort() { /* ... */ }
|
||||
|
||||
void Initialize(KPort *parent, s32 max_sessions);
|
||||
void OnSessionFinalized();
|
||||
void OnServerClosed();
|
||||
|
||||
constexpr const KPort *GetParent() const { return this->parent; }
|
||||
|
||||
|
@ -43,6 +49,7 @@ namespace ams::kern {
|
|||
virtual bool IsSignaled() const override;
|
||||
|
||||
/* TODO: More of KClientPort. */
|
||||
Result CreateSession(KClientSession **out);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace ams::kern {
|
|||
constexpr const KSession *GetParent() const { return this->parent; }
|
||||
|
||||
/* TODO: More of KClientSession. */
|
||||
void OnServerClosed();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,11 @@ namespace ams::kern {
|
|||
|
||||
return Delete(obj.GetPointerUnsafe(), name);
|
||||
}
|
||||
|
||||
template<typename Derived> requires std::derived_from<Derived, KAutoObject>
|
||||
static KScopedAutoObject<Derived> Find(const char *name) {
|
||||
return Find(name);
|
||||
}
|
||||
private:
|
||||
static KScopedAutoObject<KAutoObject> FindImpl(const char *name);
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
|
||||
namespace ams::kern {
|
||||
|
||||
class KServerSession;
|
||||
class KLightServerSession;
|
||||
|
||||
class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KPort, KAutoObject);
|
||||
private:
|
||||
|
@ -50,7 +53,8 @@ namespace ams::kern {
|
|||
uintptr_t GetName() const { return this->name; }
|
||||
bool IsLight() const { return this->is_light; }
|
||||
|
||||
/* TODO: More of KPort */
|
||||
Result EnqueueSession(KServerSession *session);
|
||||
Result EnqueueSession(KLightServerSession *session);
|
||||
|
||||
KClientPort &GetClientPort() { return this->client; }
|
||||
KServerPort &GetServerPort() { return this->server; }
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace ams::kern {
|
|||
virtual ~KServerPort() { /* ... */ }
|
||||
|
||||
void Initialize(KPort *parent);
|
||||
void EnqueueSession(KServerSession *session);
|
||||
void EnqueueSession(KLightServerSession *session);
|
||||
|
||||
constexpr const KPort *GetParent() const { return this->parent; }
|
||||
|
||||
|
@ -47,7 +49,7 @@ namespace ams::kern {
|
|||
virtual void Destroy() override;
|
||||
virtual bool IsSignaled() const override;
|
||||
|
||||
/* TODO: More of KClientPort. */
|
||||
/* TODO: More of KServerPort. */
|
||||
private:
|
||||
void CleanupSessions();
|
||||
/* TODO: This is a placeholder definition. */
|
||||
|
|
|
@ -36,13 +36,16 @@ namespace ams::kern {
|
|||
constexpr KServerSession() : parent(), request_list(), current_request(), lock() { /* ... */ }
|
||||
virtual ~KServerSession() { /* ... */ }
|
||||
|
||||
void Initialize(KSession *parent);
|
||||
void Initialize(KSession *p) { this->parent = p; }
|
||||
|
||||
constexpr const KSession *GetParent() const { return this->parent; }
|
||||
|
||||
virtual bool IsSignaled() const override { MESOSPHERE_UNIMPLEMENTED(); }
|
||||
|
||||
/* TODO: More of KServerSession. */
|
||||
Result OnRequest(KSessionRequest *request);
|
||||
|
||||
void OnClientClosed();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -51,12 +51,21 @@ namespace ams::kern {
|
|||
|
||||
virtual ~KSession() { /* ... */ }
|
||||
|
||||
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(KSessionRequest *request) { return this->server.OnRequest(request); }
|
||||
|
||||
KClientSession &GetClientSession() { return this->client; }
|
||||
KServerSession &GetServerSession() { return this->server; }
|
||||
|
|
|
@ -25,6 +25,19 @@ namespace ams::kern {
|
|||
this->max_sessions = max_sessions;
|
||||
}
|
||||
|
||||
void KClientPort::OnSessionFinalized() {
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
const auto prev = this->num_sessions--;
|
||||
if (prev == this->max_sessions) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
void KClientPort::OnServerClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
}
|
||||
|
||||
bool KClientPort::IsLight() const {
|
||||
return this->GetParent()->IsLight();
|
||||
}
|
||||
|
@ -43,4 +56,71 @@ namespace ams::kern {
|
|||
return this->num_sessions < this->max_sessions;
|
||||
}
|
||||
|
||||
Result KClientPort::CreateSession(KClientSession **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. */
|
||||
KSession *session = KSession::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. */
|
||||
KSession::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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
24
libraries/libmesosphere/source/kern_k_client_session.cpp
Normal file
24
libraries/libmesosphere/source/kern_k_client_session.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 KClientSession::OnServerClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
}
|
||||
|
||||
}
|
|
@ -34,11 +34,41 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
void KPort::OnClientClosed() {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ClientClosed;
|
||||
}
|
||||
}
|
||||
|
||||
void KPort::OnServerClosed() {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ServerClosed;
|
||||
}
|
||||
}
|
||||
|
||||
Result KPort::EnqueueSession(KServerSession *session) {
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
R_UNLESS(this->state == State::Normal, svc::ResultPortClosed());
|
||||
|
||||
this->server.EnqueueSession(session);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPort::EnqueueSession(KLightServerSession *session) {
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
R_UNLESS(this->state == State::Normal, svc::ResultPortClosed());
|
||||
|
||||
this->server.EnqueueSession(session);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,7 +89,33 @@ namespace ams::kern {
|
|||
if (this->IsLight()) {
|
||||
return !this->light_session_list.empty();
|
||||
} else {
|
||||
return this->session_list.empty();
|
||||
return !this->session_list.empty();
|
||||
}
|
||||
}
|
||||
|
||||
void KServerPort::EnqueueSession(KServerSession *session) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
MESOSPHERE_ASSERT(!this->IsLight());
|
||||
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Add the session to our queue. */
|
||||
this->session_list.push_back(*session);
|
||||
if (this->session_list.size() == 1) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
void KServerPort::EnqueueSession(KLightServerSession *session) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
MESOSPHERE_ASSERT(this->IsLight());
|
||||
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Add the session to our queue. */
|
||||
this->light_session_list.push_back(*session);
|
||||
if (this->light_session_list.size() == 1) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
29
libraries/libmesosphere/source/kern_k_server_session.cpp
Normal file
29
libraries/libmesosphere/source/kern_k_server_session.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 {
|
||||
|
||||
Result KServerSession::OnRequest(KSessionRequest *request) {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void KServerSession::OnClientClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
}
|
84
libraries/libmesosphere/source/kern_k_session.cpp
Normal file
84
libraries/libmesosphere/source/kern_k_session.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 KSession::Initialize(KClientPort *client_port, uintptr_t name) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Increment reference count. */
|
||||
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 = port;
|
||||
if (this->port != nullptr) {
|
||||
this->port->Open();
|
||||
}
|
||||
|
||||
/* Mark initialized. */
|
||||
this->initialized = true;
|
||||
}
|
||||
|
||||
void KSession::Finalize() {
|
||||
if (this->port != nullptr) {
|
||||
this->port->OnSessionFinalized();
|
||||
this->port->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void KSession::OnServerClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ServerClosed;
|
||||
this->client.OnServerClosed();
|
||||
}
|
||||
}
|
||||
|
||||
void KSession::OnClientClosed() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
if (this->state == State::Normal) {
|
||||
this->state = State::ClientClosed;
|
||||
this->server.OnClientClosed();
|
||||
}
|
||||
}
|
||||
|
||||
void KSession::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();
|
||||
}
|
||||
|
||||
}
|
|
@ -77,12 +77,47 @@ namespace ams::kern::svc {
|
|||
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] = {};
|
||||
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
|
||||
|
||||
/* Validate that name is valid. */
|
||||
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
|
||||
|
||||
MESOSPHERE_LOG("%s: ConnectToNamedPort(%s) was called\n", GetCurrentProcess().GetName(), name);
|
||||
|
||||
/* Get the current handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Find the client port. */
|
||||
auto port = KObjectName::Find<KClientPort>(name);
|
||||
R_UNLESS(port.IsNotNull(), svc::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)));
|
||||
|
||||
/* Register the session in the table, close the extra reference. */
|
||||
handle_table.Register(*out, session);
|
||||
session->Close();
|
||||
|
||||
/* We succeeded. */
|
||||
handle_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result ConnectToNamedPort64(ams::svc::Handle *out_handle, KUserPointer<const char *> name) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcConnectToNamedPort64 was called.");
|
||||
return ConnectToNamedPort(out_handle, name);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -100,7 +135,7 @@ namespace ams::kern::svc {
|
|||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result ConnectToNamedPort64From32(ams::svc::Handle *out_handle, KUserPointer<const char *> name) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcConnectToNamedPort64From32 was called.");
|
||||
return ConnectToNamedPort(out_handle, name);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue