diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp index 460dbe0f3..2ffc28691 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp @@ -222,6 +222,8 @@ namespace ams::kern { KScopedAutoObject(o).Swap(*this); } + constexpr ALWAYS_INLINE T *GetPointerUnsafe() { return this->obj; } + constexpr ALWAYS_INLINE bool IsNull() const { return this->obj == nullptr; } constexpr ALWAYS_INLINE bool IsNotNull() const { return this->obj != nullptr; } }; diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp new file mode 100644 index 000000000..29768d908 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp @@ -0,0 +1,48 @@ +/* + * 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 . + */ +#pragma once +#include +#include + +namespace ams::kern { + + class KPort; + + class KClientPort final : public KSynchronizationObject { + MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); + private: + std::atomic num_sessions; + std::atomic peak_sessions; + s32 max_sessions; + KPort *parent; + public: + constexpr KClientPort() : num_sessions(), peak_sessions(), max_sessions(), parent() { /* ... */ } + virtual ~KClientPort() { /* ... */ } + + void Initialize(KPort *parent, s32 max_sessions); + + constexpr const KPort *GetParent() const { return this->parent; } + + bool IsLight() const; + + /* Overridden virtual functions. */ + virtual void Destroy() override; + virtual bool IsSignaled() const override; + + /* TODO: More of KClientPort. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_client_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_client_session.hpp new file mode 100644 index 000000000..c6eef389d --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_client_session.hpp @@ -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 . + */ +#pragma once +#include +#include + +namespace ams::kern { + + class KSession; + + class KClientSession final : public KAutoObjectWithSlabHeapAndContainer { + MESOSPHERE_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); + private: + KSession *parent; + public: + constexpr KClientSession() : parent() { /* ... */ } + virtual ~KClientSession() { /* ... */ } + + void Initialize(KSession *parent) { + /* Set member variables. */ + this->parent = parent; + } + + static void PostDestroy(uintptr_t arg) { /* ... */ } + + constexpr const KSession *GetParent() const { return this->parent; } + + /* TODO: More of KClientSession. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp index 281e8aa01..d6ba17cdc 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp @@ -130,11 +130,11 @@ namespace ams::kern { MESOSPHERE_ASSERT_THIS(); /* Handle pseudo-handles. */ - if constexpr (std::is_same::value) { + if constexpr (std::is_base_of::value) { if (handle == ams::svc::PseudoHandle::CurrentProcess) { return GetCurrentProcessPointer(); } - } else if constexpr (std::is_same::value) { + } else if constexpr (std::is_base_of::value) { if (handle == ams::svc::PseudoHandle::CurrentThread) { return GetCurrentThreadPointer(); } @@ -156,11 +156,11 @@ namespace ams::kern { static_assert(!std::is_base_of::value); /* Handle pseudo-handles. */ - if constexpr (std::is_same::value) { + if constexpr (std::is_base_of::value) { if (handle == ams::svc::PseudoHandle::CurrentProcess) { return GetCurrentProcessPointer(); } - } else if constexpr (std::is_same::value) { + } else if constexpr (std::is_base_of::value) { if (handle == ams::svc::PseudoHandle::CurrentThread) { return GetCurrentThreadPointer(); } @@ -201,7 +201,7 @@ namespace ams::kern { template ALWAYS_INLINE void Register(ams::svc::Handle handle, T *obj) { static_assert(std::is_base_of::value); - return this->Add(handle, obj, obj->GetTypeObj().GetClassToken()); + return this->Register(handle, obj, obj->GetTypeObj().GetClassToken()); } private: NOINLINE Result Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_light_client_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_light_client_session.hpp new file mode 100644 index 000000000..474ae35e5 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_light_client_session.hpp @@ -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 . + */ +#pragma once +#include +#include + +namespace ams::kern { + + class KLightSession; + + class KLightClientSession final : public KAutoObjectWithSlabHeapAndContainer { + MESOSPHERE_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject); + private: + KLightSession *parent; + public: + constexpr KLightClientSession() : parent() { /* ... */ } + virtual ~KLightClientSession() { /* ... */ } + + void Initialize(KLightSession *parent) { + /* Set member variables. */ + this->parent = parent; + } + + static void PostDestroy(uintptr_t arg) { /* ... */ } + + constexpr const KLightSession *GetParent() const { return this->parent; } + + /* TODO: More of KLightClientSession. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_light_server_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_light_server_session.hpp new file mode 100644 index 000000000..7fcb23a13 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_light_server_session.hpp @@ -0,0 +1,47 @@ +/* + * 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 . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::kern { + + class KLightSession; + + class KLightServerSession final : public KAutoObjectWithSlabHeapAndContainer, public util::IntrusiveListBaseNode { + MESOSPHERE_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject); + private: + KLightSession *parent; + KThreadQueue request_queue; + KThreadQueue server_queue; + KThread *current_request; + KThread *server_thread; + public: + constexpr KLightServerSession() : parent(), request_queue(), server_queue(), current_request(), server_thread() { /* ... */ } + virtual ~KLightServerSession() { /* ... */ } + + void Initialize(KLightSession *parent); + + static void PostDestroy(uintptr_t arg) { /* ... */ } + + constexpr const KLightSession *GetParent() const { return this->parent; } + + /* TODO: More of KLightServerSession. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_light_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_light_session.hpp index 5edd88999..b4257a150 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_light_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_light_session.hpp @@ -16,14 +16,52 @@ #pragma once #include #include +#include +#include #include namespace ams::kern { + class KClientPort; + class KProcess; + class KLightSession final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KLightSession, KAutoObject); + private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + private: + KLightServerSession server; + KLightClientSession client; + State state; + KClientPort *port; + uintptr_t name; + KProcess *process; + bool initialized; public: + constexpr KLightSession() + : server(), client(), state(State::Invalid), port(), name(), process(), initialized() + { + /* ... */ + } + + virtual ~KLightSession() { /* ... */ } + + virtual bool IsInitialized() const override { return this->initialized; } + virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast(this->process); } + + static void PostDestroy(uintptr_t arg); + /* TODO: This is a placeholder definition. */ + + KLightClientSession &GetClientSession() { return this->client; } + KLightServerSession &GetServerSession() { return this->server; } + const KLightClientSession &GetClientSession() const { return this->client; } + const KLightServerSession &GetServerSession() const { return this->server; } }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_object_name.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_object_name.hpp index 87e76c8c1..09ab27324 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_object_name.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_object_name.hpp @@ -23,7 +23,39 @@ namespace ams::kern { class KObjectName : public KSlabAllocated, public util::IntrusiveListBaseNode { public: - /* TODO: This is a placeholder definition. */ + static constexpr size_t NameLengthMax = 12; + + using List = util::IntrusiveListBaseTraits::ListType; + private: + char name[NameLengthMax]; + KAutoObject *object; + public: + constexpr KObjectName() : name(), object() { /* ... */ } + public: + static Result NewFromName(KAutoObject *obj, const char *name); + static Result Delete(KAutoObject *obj, const char *name); + + static KScopedAutoObject Find(const char *name); + + template + static Result Delete(const char *name) { + /* Find the object. */ + KScopedAutoObject obj = Find(name); + R_UNLESS(obj.IsNotNull(), svc::ResultNotFound()); + + /* Cast the object to the desired type. */ + Derived *derived = obj->DynamicCast(); + R_UNLESS(derived != nullptr, svc::ResultNotFound()); + + return Delete(obj.GetPointerUnsafe(), name); + } + private: + static KScopedAutoObject FindImpl(const char *name); + + void Initialize(KAutoObject *obj, const char *name); + + bool MatchesName(const char *name) const; + KAutoObject *GetObject() const { return this->object; } }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_port.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_port.hpp index 40799b14e..65a4609ff 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_port.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_port.hpp @@ -16,14 +16,46 @@ #pragma once #include #include +#include +#include #include namespace ams::kern { class KPort final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KPort, KAutoObject); + private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + private: + KServerPort server; + KClientPort client; + uintptr_t name; + State state; + bool is_light; public: - /* TODO: This is a placeholder definition. */ + constexpr KPort() : server(), client(), name(), state(State::Invalid), is_light() { /* ... */ } + virtual ~KPort() { /* ... */ } + + static void PostDestroy(uintptr_t arg) { /* ... */ } + + void Initialize(s32 max_sessions, bool is_light, uintptr_t name); + void OnClientClosed(); + void OnServerClosed(); + + uintptr_t GetName() const { return this->name; } + bool IsLight() const { return this->is_light; } + + /* TODO: More of KPort */ + + KClientPort &GetClientPort() { return this->client; } + KServerPort &GetServerPort() { return this->server; } + const KClientPort &GetClientPort() const { return this->client; } + const KServerPort &GetServerPort() const { return this->server; } }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_server_port.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_server_port.hpp new file mode 100644 index 000000000..c8a429a5d --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_server_port.hpp @@ -0,0 +1,56 @@ +/* + * 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 . + */ +#pragma once +#include +#include +#include + +namespace ams::kern { + + class KPort; + class KServerSession; + class KLightServerSession; + + class KServerPort final : public KSynchronizationObject { + MESOSPHERE_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); + private: + using SessionList = util::IntrusiveListBaseTraits::ListType; + using LightSessionList = util::IntrusiveListBaseTraits::ListType; + private: + SessionList session_list; + LightSessionList light_session_list; + KPort *parent; + public: + constexpr KServerPort() : session_list(), light_session_list(), parent() { /* ... */ } + virtual ~KServerPort() { /* ... */ } + + void Initialize(KPort *parent); + + constexpr const KPort *GetParent() const { return this->parent; } + + bool IsLight() const; + + /* Overridden virtual functions. */ + virtual void Destroy() override; + virtual bool IsSignaled() const override; + + /* TODO: More of KClientPort. */ + private: + void CleanupSessions(); + /* TODO: This is a placeholder definition. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp new file mode 100644 index 000000000..70d0583e9 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp @@ -0,0 +1,48 @@ +/* + * 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 . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::kern { + + class KSession; + + class KServerSession final : public KSynchronizationObject, public util::IntrusiveListBaseNode { + MESOSPHERE_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); + private: + using RequestList = util::IntrusiveListBaseTraits::ListType; + private: + KSession *parent; + RequestList request_list; + KSessionRequest *current_request; + KLightLock lock; + public: + constexpr KServerSession() : parent(), request_list(), current_request(), lock() { /* ... */ } + virtual ~KServerSession() { /* ... */ } + + void Initialize(KSession *parent); + + constexpr const KSession *GetParent() const { return this->parent; } + + virtual bool IsSignaled() const override { MESOSPHERE_UNIMPLEMENTED(); } + + /* TODO: More of KServerSession. */ + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp index ccd5bc063..0ee803b05 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp @@ -16,14 +16,52 @@ #pragma once #include #include +#include +#include #include namespace ams::kern { + class KClientPort; + class KProcess; + class KSession final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KSession, KAutoObject); + private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + private: + KServerSession server; + KClientSession client; + State state; + KClientPort *port; + uintptr_t name; + KProcess *process; + bool initialized; public: + constexpr KSession() + : server(), client(), state(State::Invalid), port(), name(), process(), initialized() + { + /* ... */ + } + + virtual ~KSession() { /* ... */ } + + virtual bool IsInitialized() const override { return this->initialized; } + virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast(this->process); } + + static void PostDestroy(uintptr_t arg); + /* TODO: This is a placeholder definition. */ + + KClientSession &GetClientSession() { return this->client; } + KServerSession &GetServerSession() { return this->server; } + const KClientSession &GetClientSession() const { return this->client; } + const KServerSession &GetServerSession() const { return this->server; } }; } diff --git a/libraries/libmesosphere/source/kern_k_client_port.cpp b/libraries/libmesosphere/source/kern_k_client_port.cpp new file mode 100644 index 000000000..10eb84764 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_client_port.cpp @@ -0,0 +1,46 @@ +/* + * 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 . + */ +#include + +namespace ams::kern { + + void KClientPort::Initialize(KPort *parent, s32 max_sessions) { + /* Set member variables. */ + this->num_sessions = 0; + this->peak_sessions = 0; + this->parent = parent; + this->max_sessions = max_sessions; + } + + bool KClientPort::IsLight() const { + return this->GetParent()->IsLight(); + } + + void KClientPort::Destroy() { + /* Note with our parent that we're closed. */ + this->parent->OnClientClosed(); + + /* Close our reference to our parent. */ + this->parent->Close(); + } + + bool KClientPort::IsSignaled() const { + /* TODO: Check preconditions later. */ + MESOSPHERE_ASSERT_THIS(); + return this->num_sessions < this->max_sessions; + } + +} diff --git a/libraries/libmesosphere/source/kern_k_object_name.cpp b/libraries/libmesosphere/source/kern_k_object_name.cpp new file mode 100644 index 000000000..763122450 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_object_name.cpp @@ -0,0 +1,107 @@ +/* + * 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 . + */ +#include + +namespace ams::kern { + + namespace { + + /* TODO: C++20 constinit */ + KLightLock g_object_list_lock; + KObjectName::List g_object_list; + + } + + void KObjectName::Initialize(KAutoObject *obj, const char *name) { + /* Set member variables. */ + this->object = obj; + std::strncpy(this->name, name, sizeof(this->name)); + this->name[sizeof(this->name) - 1] = '\x00'; + + /* Open a reference to the object we hold. */ + this->object->Open(); + } + + bool KObjectName::MatchesName(const char *name) const { + return std::strncmp(this->name, name, sizeof(this->name)) == 0; + } + + Result KObjectName::NewFromName(KAutoObject *obj, const char *name) { + /* Create a new object name. */ + KObjectName *new_name = KObjectName::Allocate(); + R_UNLESS(new_name != nullptr, svc::ResultOutOfResource()); + + /* Initialize the new name. */ + new_name->Initialize(obj, name); + + /* Check if there's an existing name. */ + { + /* Ensure we have exclusive access to the global list. */ + KScopedLightLock lk(g_object_list_lock); + + /* If the object doesn't exist, put it into the list. */ + KScopedAutoObject existing_object = FindImpl(name); + if (existing_object.IsNull()) { + g_object_list.push_back(*new_name); + return ResultSuccess(); + } + } + + /* The object already exists, which is an error condition. Perform cleanup. */ + obj->Close(); + KObjectName::Free(new_name); + return svc::ResultInvalidState(); + } + + Result KObjectName::Delete(KAutoObject *obj, const char *compare_name) { + /* Ensure we have exclusive access to the global list. */ + KScopedLightLock lk(g_object_list_lock); + + /* Find a matching entry in the list, and delete it. */ + for (auto &name : g_object_list) { + if (name.MatchesName(compare_name) && obj == name.GetObject()) { + /* We found a match, clean up its resources. */ + obj->Close(); + g_object_list.erase(g_object_list.iterator_to(name)); + KObjectName::Free(std::addressof(name)); + return ResultSuccess(); + } + } + + /* We didn't find the object in the list. */ + return svc::ResultNotFound(); + } + + KScopedAutoObject KObjectName::Find(const char *name) { + /* Ensure we have exclusive access to the global list. */ + KScopedLightLock lk(g_object_list_lock); + + return FindImpl(name); + } + + KScopedAutoObject KObjectName::FindImpl(const char *compare_name) { + /* Try to find a matching object in the global list. */ + for (const auto &name : g_object_list) { + if (name.MatchesName(compare_name)) { + return name.GetObject(); + } + } + + /* There's no matching entry in the list. */ + return nullptr; + } + +} diff --git a/libraries/libmesosphere/source/kern_k_port.cpp b/libraries/libmesosphere/source/kern_k_port.cpp new file mode 100644 index 000000000..9b081ed3c --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_port.cpp @@ -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 . + */ +#include + +namespace ams::kern { + + void KPort::Initialize(s32 max_sessions, bool is_light, uintptr_t name) { + /* Open a new reference count to the initialized port. */ + this->Open(); + + /* Create and initialize our server/client pair. */ + KAutoObject::Create(std::addressof(this->server)); + KAutoObject::Create(std::addressof(this->client)); + this->server.Initialize(this); + this->client.Initialize(this, max_sessions); + + /* Set our member variables. */ + this->is_light = is_light; + this->name = name; + this->state = State::Normal; + } + + void KPort::OnClientClosed() { + MESOSPHERE_UNIMPLEMENTED(); + } + + void KPort::OnServerClosed() { + MESOSPHERE_UNIMPLEMENTED(); + } + +} diff --git a/libraries/libmesosphere/source/kern_k_server_port.cpp b/libraries/libmesosphere/source/kern_k_server_port.cpp new file mode 100644 index 000000000..06096bc86 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_server_port.cpp @@ -0,0 +1,96 @@ +/* + * 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 . + */ +#include + +namespace ams::kern { + + void KServerPort::Initialize(KPort *parent) { + /* Set member variables. */ + this->parent = parent; + } + + bool KServerPort::IsLight() const { + return this->GetParent()->IsLight(); + } + + void KServerPort::CleanupSessions() { + /* Ensure our preconditions are met. */ + MESOSPHERE_ASSERT(this->IsLight() || this->session_list.empty()); + MESOSPHERE_ASSERT(!this->IsLight() || this->light_session_list.empty()); + + /* Cleanup the session list. */ + while (true) { + /* Get the last session in the list */ + KServerSession *session = nullptr; + { + KScopedSchedulerLock sl; + while (!this->session_list.empty()) { + session = std::addressof(this->session_list.front()); + this->session_list.pop_front(); + } + } + + /* Close the session. */ + if (session != nullptr) { + session->Close(); + } else { + break; + } + } + + /* Cleanup the light session list. */ + while (true) { + /* Get the last session in the list */ + KLightServerSession *session = nullptr; + { + KScopedSchedulerLock sl; + while (!this->light_session_list.empty()) { + session = std::addressof(this->light_session_list.front()); + this->light_session_list.pop_front(); + } + } + + /* Close the session. */ + if (session != nullptr) { + session->Close(); + } else { + break; + } + } + } + + void KServerPort::Destroy() { + /* Note with our parent that we're closed. */ + this->parent->OnClientClosed(); + + /* Perform necessary cleanup of our session lists. */ + this->CleanupSessions(); + + /* Close our reference to our parent. */ + this->parent->Close(); + } + + bool KServerPort::IsSignaled() const { + /* TODO: Check preconditions later. */ + MESOSPHERE_ASSERT_THIS(); + if (this->IsLight()) { + return !this->light_session_list.empty(); + } else { + return this->session_list.empty(); + } + } + +} diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64-broken.s similarity index 100% rename from libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64.s rename to libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64-broken.s diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64-broken.s similarity index 100% rename from libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64.s rename to libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64-broken.s diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64-broken.s similarity index 100% rename from libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64.s rename to libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64-broken.s diff --git a/libraries/libmesosphere/source/libc/kern_libc.arch.generic.c b/libraries/libmesosphere/source/libc/kern_libc_generic.c similarity index 66% rename from libraries/libmesosphere/source/libc/kern_libc.arch.generic.c rename to libraries/libmesosphere/source/libc/kern_libc_generic.c index 3a690342b..fb7e4cc79 100644 --- a/libraries/libmesosphere/source/libc/kern_libc.arch.generic.c +++ b/libraries/libmesosphere/source/libc/kern_libc_generic.c @@ -421,6 +421,228 @@ memcmp (const void *m1, #endif /* not PREFER_SIZE_OVER_SPEED */ } +/* +FUNCTION + <>---counted copy string +INDEX + strncpy +SYNOPSIS + #include + char *strncpy(char *restrict <[dst]>, const char *restrict <[src]>, + size_t <[length]>); +DESCRIPTION + <> copies not more than <[length]> characters from the + the string pointed to by <[src]> (including the terminating + null character) to the array pointed to by <[dst]>. If the + string pointed to by <[src]> is shorter than <[length]> + characters, null characters are appended to the destination + array until a total of <[length]> characters have been + written. +RETURNS + This function returns the initial value of <[dst]>. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strncpy ansi pure +*/ + +#include +#include + +/*SUPPRESS 560*/ +/*SUPPRESS 530*/ + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +#if LONG_MAX == 2147483647L +#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) +#else +#if LONG_MAX == 9223372036854775807L +/* Nonzero if X (a long int) contains a NULL byte. */ +#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) +#else +#error long int is not a 32bit or 64bit type. +#endif +#endif + +#ifndef DETECTNULL +#error long int is not a 32bit or 64bit byte +#endif + +#undef TOO_SMALL +#define TOO_SMALL(LEN) ((LEN) < sizeof (long)) + +char * +strncpy (char *__restrict dst0, + const char *__restrict src0, + size_t count) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + char *dscan; + const char *sscan; + + dscan = dst0; + sscan = src0; + while (count > 0) + { + --count; + if ((*dscan++ = *sscan++) == '\0') + break; + } + while (count-- > 0) + *dscan++ = '\0'; + + return dst0; +#else + char *dst = dst0; + const char *src = src0; + long *aligned_dst; + const long *aligned_src; + + /* If SRC and DEST is aligned and count large enough, then copy words. */ + if (!UNALIGNED (src, dst) && !TOO_SMALL (count)) + { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* SRC and DEST are both "long int" aligned, try to do "long int" + sized copies. */ + while (count >= sizeof (long int) && !DETECTNULL(*aligned_src)) + { + count -= sizeof (long int); + *aligned_dst++ = *aligned_src++; + } + + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (count > 0) + { + --count; + if ((*dst++ = *src++) == '\0') + break; + } + + while (count-- > 0) + *dst++ = '\0'; + + return dst0; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---character string compare + +INDEX + strncmp +SYNOPSIS + #include + int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>); +DESCRIPTION + <> compares up to <[length]> characters + from the string at <[a]> to the string at <[b]>. +RETURNS + If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, + <> returns a number greater than zero. If the two + strings are equivalent, <> returns zero. If <<*<[a]>>> + sorts lexicographically before <<*<[b]>>>, <> returns a + number less than zero. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strncmp ansi pure +*/ + +#include +#include + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */ +#if LONG_MAX == 2147483647L +#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) +#else +#if LONG_MAX == 9223372036854775807L +#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) +#else +#error long int is not a 32bit or 64bit type. +#endif +#endif + +#ifndef DETECTNULL +#error long int is not a 32bit or 64bit byte +#endif + +int +strncmp (const char *s1, + const char *s2, + size_t n) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + if (n == 0) + return 0; + + while (n-- != 0 && *s1 == *s2) + { + if (n == 0 || *s1 == '\0') + break; + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#else + unsigned long *a1; + unsigned long *a2; + + if (n == 0) + return 0; + + /* If s1 or s2 are unaligned, then compare bytes. */ + if (!UNALIGNED (s1, s2)) + { + /* If s1 and s2 are word-aligned, compare them a word at a time. */ + a1 = (unsigned long*)s1; + a2 = (unsigned long*)s2; + while (n >= sizeof (long) && *a1 == *a2) + { + n -= sizeof (long); + + /* If we've run out of bytes or hit a null, return zero + since we already know *a1 == *a2. */ + if (n == 0 || DETECTNULL (*a1)) + return 0; + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of s1, so search bytewise */ + s1 = (char*)a1; + s2 = (char*)a2; + } + + while (n-- > 0 && *s1 == *s2) + { + /* If we've run out of bytes or hit a null, return zero + since we already know *s1 == *s2. */ + if (n == 0 || *s1 == '\0') + return 0; + s1++; + s2++; + } + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/libraries/libmesosphere/source/svc/kern_svc_port.cpp b/libraries/libmesosphere/source/svc/kern_svc_port.cpp index e8b1a73a2..2aa297d0e 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_port.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_port.cpp @@ -21,7 +21,61 @@ namespace ams::kern::svc { namespace { + Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer user_name, s32 max_sessions) { + /* Copy the provided name from user memory to kernel memory. */ + char name[KObjectName::NameLengthMax] = {}; + R_TRY(user_name.CopyStringTo(name, sizeof(name))); + /* Validate that sessions and name are valid. */ + R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange()); + R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange()); + + if (max_sessions > 0) { + MESOSPHERE_LOG("Creating Named Port %s (max sessions = %d)\n", name, max_sessions); + /* Get the current handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Create a new port. */ + KPort *port = KPort::Create(); + R_UNLESS(port != nullptr, svc::ResultOutOfResource()); + + /* Reserve a handle for the server port. */ + R_TRY(handle_table.Reserve(out_server_handle)); + auto reserve_guard = SCOPE_GUARD { handle_table.Unreserve(*out_server_handle); }; + + /* Initialize the new port. */ + port->Initialize(max_sessions, false, 0); + + /* Register the port. */ + KPort::Register(port); + + /* Register the handle in the table. */ + handle_table.Register(*out_server_handle, std::addressof(port->GetServerPort())); + reserve_guard.Cancel(); + auto register_guard = SCOPE_GUARD { handle_table.Remove(*out_server_handle); }; + + /* Create a new object name. */ + R_TRY(KObjectName::NewFromName(std::addressof(port->GetClientPort()), name)); + + /* Perform resource cleanup. */ + port->GetServerPort().Close(); + port->GetClientPort().Close(); + register_guard.Cancel(); + } else /* if (max_sessions == 0) */ { + MESOSPHERE_LOG("Deleting Named Port %s\n", name); + + /* Ensure that this else case is correct. */ + MESOSPHERE_AUDIT(max_sessions == 0); + + /* If we're closing, there's no server handle. */ + *out_server_handle = ams::svc::InvalidHandle; + + /* Delete the object. */ + R_TRY(KObjectName::Delete(name)); + } + + return ResultSuccess(); + } } @@ -36,7 +90,7 @@ namespace ams::kern::svc { } Result ManageNamedPort64(ams::svc::Handle *out_server_handle, KUserPointer name, int32_t max_sessions) { - MESOSPHERE_PANIC("Stubbed SvcManageNamedPort64 was called."); + return ManageNamedPort(out_server_handle, name, max_sessions); } Result ConnectToPort64(ams::svc::Handle *out_handle, ams::svc::Handle port) { @@ -54,7 +108,7 @@ namespace ams::kern::svc { } Result ManageNamedPort64From32(ams::svc::Handle *out_server_handle, KUserPointer name, int32_t max_sessions) { - MESOSPHERE_PANIC("Stubbed SvcManageNamedPort64From32 was called."); + return ManageNamedPort(out_server_handle, name, max_sessions); } Result ConnectToPort64From32(ams::svc::Handle *out_handle, ams::svc::Handle port) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 17350db51..4bf47cdda 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -21,6 +21,32 @@ namespace ams::kern::svc { namespace { + Result GetProcessId(u64 *out_process_id, ams::svc::Handle handle) { + /* Get the object from the handle table. */ + KScopedAutoObject obj = GetCurrentProcess().GetHandleTable().GetObject(handle); + R_UNLESS(obj.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the process from the object. */ + KProcess *process = nullptr; + if (obj->IsDerivedFrom(KProcess::GetStaticTypeObj())) { + /* The object is a process, so we can use it directly. */ + process = reinterpret_cast(obj.GetPointerUnsafe()); + } else if (obj->IsDerivedFrom(KThread::GetStaticTypeObj())) { + /* The object is a thread, so we want to use its parent. */ + process = reinterpret_cast(obj.GetPointerUnsafe())->GetOwnerProcess(); + } else if (obj->IsDerivedFrom(KDebug::GetStaticTypeObj())) { + /* The object is a debug, so we want to use the process it's attached to. */ + MESOSPHERE_UNIMPLEMENTED(); + } + + /* Make sure the target process exists. */ + R_UNLESS(process != nullptr, svc::ResultInvalidHandle()); + + /* Get the process id. */ + *out_process_id = process->GetId(); + return ResultSuccess(); + } + } @@ -32,7 +58,7 @@ namespace ams::kern::svc { } Result GetProcessId64(uint64_t *out_process_id, ams::svc::Handle process_handle) { - MESOSPHERE_PANIC("Stubbed SvcGetProcessId64 was called."); + return GetProcessId(out_process_id, process_handle); } Result GetProcessList64(int32_t *out_num_processes, KUserPointer out_process_ids, int32_t max_out_count) { @@ -62,7 +88,7 @@ namespace ams::kern::svc { } Result GetProcessId64From32(uint64_t *out_process_id, ams::svc::Handle process_handle) { - MESOSPHERE_PANIC("Stubbed SvcGetProcessId64From32 was called."); + return GetProcessId(out_process_id, process_handle); } Result GetProcessList64From32(int32_t *out_num_processes, KUserPointer out_process_ids, int32_t max_out_count) {