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) {