diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp
index 460dbe0..2ffc286 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 @@
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 0000000..29768d9
--- /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 0000000..c6eef38
--- /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 281e8aa..d6ba17c 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 @@
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 @@
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 @@
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 0000000..474ae35
--- /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 0000000..7fcb23a
--- /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 5edd889..b4257a1 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 87e76c8..09ab273 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 @@
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 40799b1..65a4609 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 0000000..c8a429a
--- /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 0000000..70d0583
--- /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 ccd5bc0..0ee803b 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 0000000..10eb847
--- /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 0000000..7631224
--- /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 0000000..9b081ed
--- /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 0000000..06096bc
--- /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-broken.s b/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64-broken.s
new file mode 100644
index 0000000..609f7e2
--- /dev/null
+++ b/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64-broken.s
@@ -0,0 +1,133 @@
+/* memcmp - compare memory
+ *
+ * Copyright (c) 2013, Arm Limited.
+ * SPDX-License-Identifier: MIT
+ */
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses.
+ */
+
+#include "asmdefs.h"
+
+/* Parameters and result. */
+#define src1 x0
+#define src2 x1
+#define limit x2
+#define result w0
+
+/* Internal variables. */
+#define data1 x3
+#define data1w w3
+#define data1h x4
+#define data2 x5
+#define data2w w5
+#define data2h x6
+#define tmp1 x7
+#define tmp2 x8
+
+ENTRY (memcmp)
+ subs limit, limit, 8
+ b.lo L(less8)
+
+ ldr data1, [src1], 8
+ ldr data2, [src2], 8
+ cmp data1, data2
+ b.ne L(return)
+
+ subs limit, limit, 8
+ b.gt L(more16)
+
+ ldr data1, [src1, limit]
+ ldr data2, [src2, limit]
+ b L(return)
+
+L(more16):
+ ldr data1, [src1], 8
+ ldr data2, [src2], 8
+ cmp data1, data2
+ bne L(return)
+
+ /* Jump directly to comparing the last 16 bytes for 32 byte (or less)
+ strings. */
+ subs limit, limit, 16
+ b.ls L(last_bytes)
+
+ /* We overlap loads between 0-32 bytes at either side of SRC1 when we
+ try to align, so limit it only to strings larger than 128 bytes. */
+ cmp limit, 96
+ b.ls L(loop16)
+
+ /* Align src1 and adjust src2 with bytes not yet done. */
+ and tmp1, src1, 15
+ add limit, limit, tmp1
+ sub src1, src1, tmp1
+ sub src2, src2, tmp1
+
+ /* Loop performing 16 bytes per iteration using aligned src1.
+ Limit is pre-decremented by 16 and must be larger than zero.
+ Exit if <= 16 bytes left to do or if the data is not equal. */
+ .p2align 4
+L(loop16):
+ ldp data1, data1h, [src1], 16
+ ldp data2, data2h, [src2], 16
+ subs limit, limit, 16
+ ccmp data1, data2, 0, hi
+ ccmp data1h, data2h, 0, eq
+ b.eq L(loop16)
+
+ cmp data1, data2
+ bne L(return)
+ mov data1, data1h
+ mov data2, data2h
+ cmp data1, data2
+ bne L(return)
+
+ /* Compare last 1-16 bytes using unaligned access. */
+L(last_bytes):
+ add src1, src1, limit
+ add src2, src2, limit
+ ldp data1, data1h, [src1]
+ ldp data2, data2h, [src2]
+ cmp data1, data2
+ bne L(return)
+ mov data1, data1h
+ mov data2, data2h
+ cmp data1, data2
+
+ /* Compare data bytes and set return value to 0, -1 or 1. */
+L(return):
+#ifndef __AARCH64EB__
+ rev data1, data1
+ rev data2, data2
+#endif
+ cmp data1, data2
+L(ret_eq):
+ cset result, ne
+ cneg result, result, lo
+ ret
+
+ .p2align 4
+ /* Compare up to 8 bytes. Limit is [-8..-1]. */
+L(less8):
+ adds limit, limit, 4
+ b.lo L(less4)
+ ldr data1w, [src1], 4
+ ldr data2w, [src2], 4
+ cmp data1w, data2w
+ b.ne L(return)
+ sub limit, limit, 4
+L(less4):
+ adds limit, limit, 4
+ beq L(ret_eq)
+L(byte_loop):
+ ldrb data1w, [src1], 1
+ ldrb data2w, [src2], 1
+ subs limit, limit, 1
+ ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */
+ b.eq L(byte_loop)
+ sub result, data1w, data2w
+ ret
+
+END (memcmp)
diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64.s
deleted file mode 100644
index 609f7e2..0000000
--- a/libraries/libmesosphere/source/libc/arch/arm64/memcmp.arch.arm64.s
+++ /dev/null
@@ -1,133 +0,0 @@
-/* memcmp - compare memory
- *
- * Copyright (c) 2013, Arm Limited.
- * SPDX-License-Identifier: MIT
- */
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64, unaligned accesses.
- */
-
-#include "asmdefs.h"
-
-/* Parameters and result. */
-#define src1 x0
-#define src2 x1
-#define limit x2
-#define result w0
-
-/* Internal variables. */
-#define data1 x3
-#define data1w w3
-#define data1h x4
-#define data2 x5
-#define data2w w5
-#define data2h x6
-#define tmp1 x7
-#define tmp2 x8
-
-ENTRY (memcmp)
- subs limit, limit, 8
- b.lo L(less8)
-
- ldr data1, [src1], 8
- ldr data2, [src2], 8
- cmp data1, data2
- b.ne L(return)
-
- subs limit, limit, 8
- b.gt L(more16)
-
- ldr data1, [src1, limit]
- ldr data2, [src2, limit]
- b L(return)
-
-L(more16):
- ldr data1, [src1], 8
- ldr data2, [src2], 8
- cmp data1, data2
- bne L(return)
-
- /* Jump directly to comparing the last 16 bytes for 32 byte (or less)
- strings. */
- subs limit, limit, 16
- b.ls L(last_bytes)
-
- /* We overlap loads between 0-32 bytes at either side of SRC1 when we
- try to align, so limit it only to strings larger than 128 bytes. */
- cmp limit, 96
- b.ls L(loop16)
-
- /* Align src1 and adjust src2 with bytes not yet done. */
- and tmp1, src1, 15
- add limit, limit, tmp1
- sub src1, src1, tmp1
- sub src2, src2, tmp1
-
- /* Loop performing 16 bytes per iteration using aligned src1.
- Limit is pre-decremented by 16 and must be larger than zero.
- Exit if <= 16 bytes left to do or if the data is not equal. */
- .p2align 4
-L(loop16):
- ldp data1, data1h, [src1], 16
- ldp data2, data2h, [src2], 16
- subs limit, limit, 16
- ccmp data1, data2, 0, hi
- ccmp data1h, data2h, 0, eq
- b.eq L(loop16)
-
- cmp data1, data2
- bne L(return)
- mov data1, data1h
- mov data2, data2h
- cmp data1, data2
- bne L(return)
-
- /* Compare last 1-16 bytes using unaligned access. */
-L(last_bytes):
- add src1, src1, limit
- add src2, src2, limit
- ldp data1, data1h, [src1]
- ldp data2, data2h, [src2]
- cmp data1, data2
- bne L(return)
- mov data1, data1h
- mov data2, data2h
- cmp data1, data2
-
- /* Compare data bytes and set return value to 0, -1 or 1. */
-L(return):
-#ifndef __AARCH64EB__
- rev data1, data1
- rev data2, data2
-#endif
- cmp data1, data2
-L(ret_eq):
- cset result, ne
- cneg result, result, lo
- ret
-
- .p2align 4
- /* Compare up to 8 bytes. Limit is [-8..-1]. */
-L(less8):
- adds limit, limit, 4
- b.lo L(less4)
- ldr data1w, [src1], 4
- ldr data2w, [src2], 4
- cmp data1w, data2w
- b.ne L(return)
- sub limit, limit, 4
-L(less4):
- adds limit, limit, 4
- beq L(ret_eq)
-L(byte_loop):
- ldrb data1w, [src1], 1
- ldrb data2w, [src2], 1
- subs limit, limit, 1
- ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */
- b.eq L(byte_loop)
- sub result, data1w, data2w
- ret
-
-END (memcmp)
diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64-broken.s b/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64-broken.s
new file mode 100644
index 0000000..02ed1dd
--- /dev/null
+++ b/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64-broken.s
@@ -0,0 +1,239 @@
+/*
+ * memcpy - copy memory area
+ *
+ * Copyright (c) 2012-2020, Arm Limited.
+ * SPDX-License-Identifier: MIT
+ */
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses.
+ *
+ */
+
+#include "asmdefs.h"
+
+#define dstin x0
+#define src x1
+#define count x2
+#define dst x3
+#define srcend x4
+#define dstend x5
+#define A_l x6
+#define A_lw w6
+#define A_h x7
+#define B_l x8
+#define B_lw w8
+#define B_h x9
+#define C_l x10
+#define C_lw w10
+#define C_h x11
+#define D_l x12
+#define D_h x13
+#define E_l x14
+#define E_h x15
+#define F_l x16
+#define F_h x17
+#define G_l count
+#define G_h dst
+#define H_l src
+#define H_h srcend
+#define tmp1 x14
+
+/* This implementation handles overlaps and supports both memcpy and memmove
+ from a single entry point. It uses unaligned accesses and branchless
+ sequences to keep the code small, simple and improve performance.
+
+ Copies are split into 3 main cases: small copies of up to 32 bytes, medium
+ copies of up to 128 bytes, and large copies. The overhead of the overlap
+ check is negligible since it is only required for large copies.
+
+ Large copies use a software pipelined loop processing 64 bytes per iteration.
+ The destination pointer is 16-byte aligned to minimize unaligned accesses.
+ The loop tail is handled by always copying 64 bytes from the end.
+*/
+
+ENTRY (memcpy)
+ENTRY_ALIAS (memmove)
+ add srcend, src, count
+ add dstend, dstin, count
+ cmp count, 128
+ b.hi L(copy_long)
+ cmp count, 32
+ b.hi L(copy32_128)
+
+ /* Small copies: 0..32 bytes. */
+ cmp count, 16
+ b.lo L(copy16)
+ ldp A_l, A_h, [src]
+ ldp D_l, D_h, [srcend, -16]
+ stp A_l, A_h, [dstin]
+ stp D_l, D_h, [dstend, -16]
+ ret
+
+ /* Copy 8-15 bytes. */
+L(copy16):
+ tbz count, 3, L(copy8)
+ ldr A_l, [src]
+ ldr A_h, [srcend, -8]
+ str A_l, [dstin]
+ str A_h, [dstend, -8]
+ ret
+
+ .p2align 3
+ /* Copy 4-7 bytes. */
+L(copy8):
+ tbz count, 2, L(copy4)
+ ldr A_lw, [src]
+ ldr B_lw, [srcend, -4]
+ str A_lw, [dstin]
+ str B_lw, [dstend, -4]
+ ret
+
+ /* Copy 0..3 bytes using a branchless sequence. */
+L(copy4):
+ cbz count, L(copy0)
+ lsr tmp1, count, 1
+ ldrb A_lw, [src]
+ ldrb C_lw, [srcend, -1]
+ ldrb B_lw, [src, tmp1]
+ strb A_lw, [dstin]
+ strb B_lw, [dstin, tmp1]
+ strb C_lw, [dstend, -1]
+L(copy0):
+ ret
+
+ .p2align 4
+ /* Medium copies: 33..128 bytes. */
+L(copy32_128):
+ ldp A_l, A_h, [src]
+ ldp B_l, B_h, [src, 16]
+ ldp C_l, C_h, [srcend, -32]
+ ldp D_l, D_h, [srcend, -16]
+ cmp count, 64
+ b.hi L(copy128)
+ stp A_l, A_h, [dstin]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstend, -32]
+ stp D_l, D_h, [dstend, -16]
+ ret
+
+ .p2align 4
+ /* Copy 65..128 bytes. */
+L(copy128):
+ ldp E_l, E_h, [src, 32]
+ ldp F_l, F_h, [src, 48]
+ cmp count, 96
+ b.ls L(copy96)
+ ldp G_l, G_h, [srcend, -64]
+ ldp H_l, H_h, [srcend, -48]
+ stp G_l, G_h, [dstend, -64]
+ stp H_l, H_h, [dstend, -48]
+L(copy96):
+ stp A_l, A_h, [dstin]
+ stp B_l, B_h, [dstin, 16]
+ stp E_l, E_h, [dstin, 32]
+ stp F_l, F_h, [dstin, 48]
+ stp C_l, C_h, [dstend, -32]
+ stp D_l, D_h, [dstend, -16]
+ ret
+
+ .p2align 4
+ /* Copy more than 128 bytes. */
+L(copy_long):
+ /* Use backwards copy if there is an overlap. */
+ sub tmp1, dstin, src
+ cbz tmp1, L(copy0)
+ cmp tmp1, count
+ b.lo L(copy_long_backwards)
+
+ /* Copy 16 bytes and then align dst to 16-byte alignment. */
+
+ ldp D_l, D_h, [src]
+ and tmp1, dstin, 15
+ bic dst, dstin, 15
+ sub src, src, tmp1
+ add count, count, tmp1 /* Count is now 16 too large. */
+ ldp A_l, A_h, [src, 16]
+ stp D_l, D_h, [dstin]
+ ldp B_l, B_h, [src, 32]
+ ldp C_l, C_h, [src, 48]
+ ldp D_l, D_h, [src, 64]!
+ subs count, count, 128 + 16 /* Test and readjust count. */
+ b.ls L(copy64_from_end)
+
+L(loop64):
+ stp A_l, A_h, [dst, 16]
+ ldp A_l, A_h, [src, 16]
+ stp B_l, B_h, [dst, 32]
+ ldp B_l, B_h, [src, 32]
+ stp C_l, C_h, [dst, 48]
+ ldp C_l, C_h, [src, 48]
+ stp D_l, D_h, [dst, 64]!
+ ldp D_l, D_h, [src, 64]!
+ subs count, count, 64
+ b.hi L(loop64)
+
+ /* Write the last iteration and copy 64 bytes from the end. */
+L(copy64_from_end):
+ ldp E_l, E_h, [srcend, -64]
+ stp A_l, A_h, [dst, 16]
+ ldp A_l, A_h, [srcend, -48]
+ stp B_l, B_h, [dst, 32]
+ ldp B_l, B_h, [srcend, -32]
+ stp C_l, C_h, [dst, 48]
+ ldp C_l, C_h, [srcend, -16]
+ stp D_l, D_h, [dst, 64]
+ stp E_l, E_h, [dstend, -64]
+ stp A_l, A_h, [dstend, -48]
+ stp B_l, B_h, [dstend, -32]
+ stp C_l, C_h, [dstend, -16]
+ ret
+
+ .p2align 4
+
+ /* Large backwards copy for overlapping copies.
+ Copy 16 bytes and then align dst to 16-byte alignment. */
+L(copy_long_backwards):
+ ldp D_l, D_h, [srcend, -16]
+ and tmp1, dstend, 15
+ sub srcend, srcend, tmp1
+ sub count, count, tmp1
+ ldp A_l, A_h, [srcend, -16]
+ stp D_l, D_h, [dstend, -16]
+ ldp B_l, B_h, [srcend, -32]
+ ldp C_l, C_h, [srcend, -48]
+ ldp D_l, D_h, [srcend, -64]!
+ sub dstend, dstend, tmp1
+ subs count, count, 128
+ b.ls L(copy64_from_start)
+
+L(loop64_backwards):
+ stp A_l, A_h, [dstend, -16]
+ ldp A_l, A_h, [srcend, -16]
+ stp B_l, B_h, [dstend, -32]
+ ldp B_l, B_h, [srcend, -32]
+ stp C_l, C_h, [dstend, -48]
+ ldp C_l, C_h, [srcend, -48]
+ stp D_l, D_h, [dstend, -64]!
+ ldp D_l, D_h, [srcend, -64]!
+ subs count, count, 64
+ b.hi L(loop64_backwards)
+
+ /* Write the last iteration and copy 64 bytes from the start. */
+L(copy64_from_start):
+ ldp G_l, G_h, [src, 48]
+ stp A_l, A_h, [dstend, -16]
+ ldp A_l, A_h, [src, 32]
+ stp B_l, B_h, [dstend, -32]
+ ldp B_l, B_h, [src, 16]
+ stp C_l, C_h, [dstend, -48]
+ ldp C_l, C_h, [src]
+ stp D_l, D_h, [dstend, -64]
+ stp G_l, G_h, [dstin, 48]
+ stp A_l, A_h, [dstin, 32]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstin]
+ ret
+
+END (memcpy)
diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64.s
deleted file mode 100644
index 02ed1dd..0000000
--- a/libraries/libmesosphere/source/libc/arch/arm64/memcpy.arch.arm64.s
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * memcpy - copy memory area
- *
- * Copyright (c) 2012-2020, Arm Limited.
- * SPDX-License-Identifier: MIT
- */
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64, unaligned accesses.
- *
- */
-
-#include "asmdefs.h"
-
-#define dstin x0
-#define src x1
-#define count x2
-#define dst x3
-#define srcend x4
-#define dstend x5
-#define A_l x6
-#define A_lw w6
-#define A_h x7
-#define B_l x8
-#define B_lw w8
-#define B_h x9
-#define C_l x10
-#define C_lw w10
-#define C_h x11
-#define D_l x12
-#define D_h x13
-#define E_l x14
-#define E_h x15
-#define F_l x16
-#define F_h x17
-#define G_l count
-#define G_h dst
-#define H_l src
-#define H_h srcend
-#define tmp1 x14
-
-/* This implementation handles overlaps and supports both memcpy and memmove
- from a single entry point. It uses unaligned accesses and branchless
- sequences to keep the code small, simple and improve performance.
-
- Copies are split into 3 main cases: small copies of up to 32 bytes, medium
- copies of up to 128 bytes, and large copies. The overhead of the overlap
- check is negligible since it is only required for large copies.
-
- Large copies use a software pipelined loop processing 64 bytes per iteration.
- The destination pointer is 16-byte aligned to minimize unaligned accesses.
- The loop tail is handled by always copying 64 bytes from the end.
-*/
-
-ENTRY (memcpy)
-ENTRY_ALIAS (memmove)
- add srcend, src, count
- add dstend, dstin, count
- cmp count, 128
- b.hi L(copy_long)
- cmp count, 32
- b.hi L(copy32_128)
-
- /* Small copies: 0..32 bytes. */
- cmp count, 16
- b.lo L(copy16)
- ldp A_l, A_h, [src]
- ldp D_l, D_h, [srcend, -16]
- stp A_l, A_h, [dstin]
- stp D_l, D_h, [dstend, -16]
- ret
-
- /* Copy 8-15 bytes. */
-L(copy16):
- tbz count, 3, L(copy8)
- ldr A_l, [src]
- ldr A_h, [srcend, -8]
- str A_l, [dstin]
- str A_h, [dstend, -8]
- ret
-
- .p2align 3
- /* Copy 4-7 bytes. */
-L(copy8):
- tbz count, 2, L(copy4)
- ldr A_lw, [src]
- ldr B_lw, [srcend, -4]
- str A_lw, [dstin]
- str B_lw, [dstend, -4]
- ret
-
- /* Copy 0..3 bytes using a branchless sequence. */
-L(copy4):
- cbz count, L(copy0)
- lsr tmp1, count, 1
- ldrb A_lw, [src]
- ldrb C_lw, [srcend, -1]
- ldrb B_lw, [src, tmp1]
- strb A_lw, [dstin]
- strb B_lw, [dstin, tmp1]
- strb C_lw, [dstend, -1]
-L(copy0):
- ret
-
- .p2align 4
- /* Medium copies: 33..128 bytes. */
-L(copy32_128):
- ldp A_l, A_h, [src]
- ldp B_l, B_h, [src, 16]
- ldp C_l, C_h, [srcend, -32]
- ldp D_l, D_h, [srcend, -16]
- cmp count, 64
- b.hi L(copy128)
- stp A_l, A_h, [dstin]
- stp B_l, B_h, [dstin, 16]
- stp C_l, C_h, [dstend, -32]
- stp D_l, D_h, [dstend, -16]
- ret
-
- .p2align 4
- /* Copy 65..128 bytes. */
-L(copy128):
- ldp E_l, E_h, [src, 32]
- ldp F_l, F_h, [src, 48]
- cmp count, 96
- b.ls L(copy96)
- ldp G_l, G_h, [srcend, -64]
- ldp H_l, H_h, [srcend, -48]
- stp G_l, G_h, [dstend, -64]
- stp H_l, H_h, [dstend, -48]
-L(copy96):
- stp A_l, A_h, [dstin]
- stp B_l, B_h, [dstin, 16]
- stp E_l, E_h, [dstin, 32]
- stp F_l, F_h, [dstin, 48]
- stp C_l, C_h, [dstend, -32]
- stp D_l, D_h, [dstend, -16]
- ret
-
- .p2align 4
- /* Copy more than 128 bytes. */
-L(copy_long):
- /* Use backwards copy if there is an overlap. */
- sub tmp1, dstin, src
- cbz tmp1, L(copy0)
- cmp tmp1, count
- b.lo L(copy_long_backwards)
-
- /* Copy 16 bytes and then align dst to 16-byte alignment. */
-
- ldp D_l, D_h, [src]
- and tmp1, dstin, 15
- bic dst, dstin, 15
- sub src, src, tmp1
- add count, count, tmp1 /* Count is now 16 too large. */
- ldp A_l, A_h, [src, 16]
- stp D_l, D_h, [dstin]
- ldp B_l, B_h, [src, 32]
- ldp C_l, C_h, [src, 48]
- ldp D_l, D_h, [src, 64]!
- subs count, count, 128 + 16 /* Test and readjust count. */
- b.ls L(copy64_from_end)
-
-L(loop64):
- stp A_l, A_h, [dst, 16]
- ldp A_l, A_h, [src, 16]
- stp B_l, B_h, [dst, 32]
- ldp B_l, B_h, [src, 32]
- stp C_l, C_h, [dst, 48]
- ldp C_l, C_h, [src, 48]
- stp D_l, D_h, [dst, 64]!
- ldp D_l, D_h, [src, 64]!
- subs count, count, 64
- b.hi L(loop64)
-
- /* Write the last iteration and copy 64 bytes from the end. */
-L(copy64_from_end):
- ldp E_l, E_h, [srcend, -64]
- stp A_l, A_h, [dst, 16]
- ldp A_l, A_h, [srcend, -48]
- stp B_l, B_h, [dst, 32]
- ldp B_l, B_h, [srcend, -32]
- stp C_l, C_h, [dst, 48]
- ldp C_l, C_h, [srcend, -16]
- stp D_l, D_h, [dst, 64]
- stp E_l, E_h, [dstend, -64]
- stp A_l, A_h, [dstend, -48]
- stp B_l, B_h, [dstend, -32]
- stp C_l, C_h, [dstend, -16]
- ret
-
- .p2align 4
-
- /* Large backwards copy for overlapping copies.
- Copy 16 bytes and then align dst to 16-byte alignment. */
-L(copy_long_backwards):
- ldp D_l, D_h, [srcend, -16]
- and tmp1, dstend, 15
- sub srcend, srcend, tmp1
- sub count, count, tmp1
- ldp A_l, A_h, [srcend, -16]
- stp D_l, D_h, [dstend, -16]
- ldp B_l, B_h, [srcend, -32]
- ldp C_l, C_h, [srcend, -48]
- ldp D_l, D_h, [srcend, -64]!
- sub dstend, dstend, tmp1
- subs count, count, 128
- b.ls L(copy64_from_start)
-
-L(loop64_backwards):
- stp A_l, A_h, [dstend, -16]
- ldp A_l, A_h, [srcend, -16]
- stp B_l, B_h, [dstend, -32]
- ldp B_l, B_h, [srcend, -32]
- stp C_l, C_h, [dstend, -48]
- ldp C_l, C_h, [srcend, -48]
- stp D_l, D_h, [dstend, -64]!
- ldp D_l, D_h, [srcend, -64]!
- subs count, count, 64
- b.hi L(loop64_backwards)
-
- /* Write the last iteration and copy 64 bytes from the start. */
-L(copy64_from_start):
- ldp G_l, G_h, [src, 48]
- stp A_l, A_h, [dstend, -16]
- ldp A_l, A_h, [src, 32]
- stp B_l, B_h, [dstend, -32]
- ldp B_l, B_h, [src, 16]
- stp C_l, C_h, [dstend, -48]
- ldp C_l, C_h, [src]
- stp D_l, D_h, [dstend, -64]
- stp G_l, G_h, [dstin, 48]
- stp A_l, A_h, [dstin, 32]
- stp B_l, B_h, [dstin, 16]
- stp C_l, C_h, [dstin]
- ret
-
-END (memcpy)
diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64-broken.s b/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64-broken.s
new file mode 100644
index 0000000..d8d2727
--- /dev/null
+++ b/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64-broken.s
@@ -0,0 +1,170 @@
+/*
+ * memset - fill memory with a constant byte
+ *
+ * Copyright (c) 2012-2020, Arm Limited.
+ * SPDX-License-Identifier: MIT
+ */
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
+ *
+ */
+
+#include "asmdefs.h"
+
+#define DC_ZVA_THRESHOLD 512
+
+#define dstin x0
+#define val x1
+#define valw w1
+#define count x2
+#define dst x3
+#define dstend x4
+#define zva_val x5
+
+ENTRY (memset)
+
+ bfi valw, valw, 8, 8
+ bfi valw, valw, 16, 16
+ bfi val, val, 32, 32
+
+ add dstend, dstin, count
+
+ cmp count, 96
+ b.hi L(set_long)
+ cmp count, 16
+ b.hs L(set_medium)
+
+ /* Set 0..15 bytes. */
+ tbz count, 3, 1f
+ str val, [dstin]
+ str val, [dstend, -8]
+ ret
+1: tbz count, 2, 2f
+ str valw, [dstin]
+ str valw, [dstend, -4]
+ ret
+2: cbz count, 3f
+ strb valw, [dstin]
+ tbz count, 1, 3f
+ strh valw, [dstend, -2]
+3: ret
+
+ /* Set 16..96 bytes. */
+ .p2align 4
+L(set_medium):
+ stp val, val, [dstin]
+ tbnz count, 6, L(set96)
+ stp val, val, [dstend, -16]
+ tbz count, 5, 1f
+ stp val, val, [dstin, 16]
+ stp val, val, [dstend, -32]
+1: ret
+
+ .p2align 4
+ /* Set 64..96 bytes. Write 64 bytes from the start and
+ 32 bytes from the end. */
+L(set96):
+ stp val, val, [dstin, 16]
+ stp val, val, [dstin, 32]
+ stp val, val, [dstin, 48]
+ stp val, val, [dstend, -32]
+ stp val, val, [dstend, -16]
+ ret
+
+ .p2align 4
+L(set_long):
+ stp val, val, [dstin]
+ bic dst, dstin, 15
+#if DC_ZVA_THRESHOLD
+ cmp count, DC_ZVA_THRESHOLD
+ ccmp val, 0, 0, cs
+ b.eq L(zva_64)
+#endif
+ /* Small-size or non-zero memset does not use DC ZVA. */
+ sub count, dstend, dst
+
+ /*
+ * Adjust count and bias for loop. By substracting extra 1 from count,
+ * it is easy to use tbz instruction to check whether loop tailing
+ * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
+ */
+ sub count, count, 64+16+1
+
+#if DC_ZVA_THRESHOLD
+ /* Align loop on 16-byte boundary, this might be friendly to i-cache. */
+ nop
+#endif
+
+1: stp val, val, [dst, 16]
+ stp val, val, [dst, 32]
+ stp val, val, [dst, 48]
+ stp val, val, [dst, 64]!
+ subs count, count, 64
+ b.hs 1b
+
+ tbz count, 5, 1f /* Remaining count is less than 33 bytes? */
+ stp val, val, [dst, 16]
+ stp val, val, [dst, 32]
+1: stp val, val, [dstend, -32]
+ stp val, val, [dstend, -16]
+ ret
+
+#if DC_ZVA_THRESHOLD
+ .p2align 4
+L(zva_64):
+ stp val, val, [dst, 16]
+ stp val, val, [dst, 32]
+ stp val, val, [dst, 48]
+ bic dst, dst, 63
+
+ /*
+ * Previous memory writes might cross cache line boundary, and cause
+ * cache line partially dirty. Zeroing this kind of cache line using
+ * DC ZVA will incur extra cost, for it requires loading untouched
+ * part of the line from memory before zeoring.
+ *
+ * So, write the first 64 byte aligned block using stp to force
+ * fully dirty cache line.
+ */
+ stp val, val, [dst, 64]
+ stp val, val, [dst, 80]
+ stp val, val, [dst, 96]
+ stp val, val, [dst, 112]
+
+ sub count, dstend, dst
+ /*
+ * Adjust count and bias for loop. By substracting extra 1 from count,
+ * it is easy to use tbz instruction to check whether loop tailing
+ * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
+ */
+ sub count, count, 128+64+64+1
+ add dst, dst, 128
+ nop
+
+ /* DC ZVA sets 64 bytes each time. */
+1: dc zva, dst
+ add dst, dst, 64
+ subs count, count, 64
+ b.hs 1b
+
+ /*
+ * Write the last 64 byte aligned block using stp to force fully
+ * dirty cache line.
+ */
+ stp val, val, [dst, 0]
+ stp val, val, [dst, 16]
+ stp val, val, [dst, 32]
+ stp val, val, [dst, 48]
+
+ tbz count, 5, 1f /* Remaining count is less than 33 bytes? */
+ stp val, val, [dst, 64]
+ stp val, val, [dst, 80]
+1: stp val, val, [dstend, -32]
+ stp val, val, [dstend, -16]
+ ret
+#endif
+
+
+END (memset)
diff --git a/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64.s b/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64.s
deleted file mode 100644
index d8d2727..0000000
--- a/libraries/libmesosphere/source/libc/arch/arm64/memset.arch.arm64.s
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * memset - fill memory with a constant byte
- *
- * Copyright (c) 2012-2020, Arm Limited.
- * SPDX-License-Identifier: MIT
- */
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
- *
- */
-
-#include "asmdefs.h"
-
-#define DC_ZVA_THRESHOLD 512
-
-#define dstin x0
-#define val x1
-#define valw w1
-#define count x2
-#define dst x3
-#define dstend x4
-#define zva_val x5
-
-ENTRY (memset)
-
- bfi valw, valw, 8, 8
- bfi valw, valw, 16, 16
- bfi val, val, 32, 32
-
- add dstend, dstin, count
-
- cmp count, 96
- b.hi L(set_long)
- cmp count, 16
- b.hs L(set_medium)
-
- /* Set 0..15 bytes. */
- tbz count, 3, 1f
- str val, [dstin]
- str val, [dstend, -8]
- ret
-1: tbz count, 2, 2f
- str valw, [dstin]
- str valw, [dstend, -4]
- ret
-2: cbz count, 3f
- strb valw, [dstin]
- tbz count, 1, 3f
- strh valw, [dstend, -2]
-3: ret
-
- /* Set 16..96 bytes. */
- .p2align 4
-L(set_medium):
- stp val, val, [dstin]
- tbnz count, 6, L(set96)
- stp val, val, [dstend, -16]
- tbz count, 5, 1f
- stp val, val, [dstin, 16]
- stp val, val, [dstend, -32]
-1: ret
-
- .p2align 4
- /* Set 64..96 bytes. Write 64 bytes from the start and
- 32 bytes from the end. */
-L(set96):
- stp val, val, [dstin, 16]
- stp val, val, [dstin, 32]
- stp val, val, [dstin, 48]
- stp val, val, [dstend, -32]
- stp val, val, [dstend, -16]
- ret
-
- .p2align 4
-L(set_long):
- stp val, val, [dstin]
- bic dst, dstin, 15
-#if DC_ZVA_THRESHOLD
- cmp count, DC_ZVA_THRESHOLD
- ccmp val, 0, 0, cs
- b.eq L(zva_64)
-#endif
- /* Small-size or non-zero memset does not use DC ZVA. */
- sub count, dstend, dst
-
- /*
- * Adjust count and bias for loop. By substracting extra 1 from count,
- * it is easy to use tbz instruction to check whether loop tailing
- * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
- */
- sub count, count, 64+16+1
-
-#if DC_ZVA_THRESHOLD
- /* Align loop on 16-byte boundary, this might be friendly to i-cache. */
- nop
-#endif
-
-1: stp val, val, [dst, 16]
- stp val, val, [dst, 32]
- stp val, val, [dst, 48]
- stp val, val, [dst, 64]!
- subs count, count, 64
- b.hs 1b
-
- tbz count, 5, 1f /* Remaining count is less than 33 bytes? */
- stp val, val, [dst, 16]
- stp val, val, [dst, 32]
-1: stp val, val, [dstend, -32]
- stp val, val, [dstend, -16]
- ret
-
-#if DC_ZVA_THRESHOLD
- .p2align 4
-L(zva_64):
- stp val, val, [dst, 16]
- stp val, val, [dst, 32]
- stp val, val, [dst, 48]
- bic dst, dst, 63
-
- /*
- * Previous memory writes might cross cache line boundary, and cause
- * cache line partially dirty. Zeroing this kind of cache line using
- * DC ZVA will incur extra cost, for it requires loading untouched
- * part of the line from memory before zeoring.
- *
- * So, write the first 64 byte aligned block using stp to force
- * fully dirty cache line.
- */
- stp val, val, [dst, 64]
- stp val, val, [dst, 80]
- stp val, val, [dst, 96]
- stp val, val, [dst, 112]
-
- sub count, dstend, dst
- /*
- * Adjust count and bias for loop. By substracting extra 1 from count,
- * it is easy to use tbz instruction to check whether loop tailing
- * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
- */
- sub count, count, 128+64+64+1
- add dst, dst, 128
- nop
-
- /* DC ZVA sets 64 bytes each time. */
-1: dc zva, dst
- add dst, dst, 64
- subs count, count, 64
- b.hs 1b
-
- /*
- * Write the last 64 byte aligned block using stp to force fully
- * dirty cache line.
- */
- stp val, val, [dst, 0]
- stp val, val, [dst, 16]
- stp val, val, [dst, 32]
- stp val, val, [dst, 48]
-
- tbz count, 5, 1f /* Remaining count is less than 33 bytes? */
- stp val, val, [dst, 64]
- stp val, val, [dst, 80]
-1: stp val, val, [dstend, -32]
- stp val, val, [dstend, -16]
- ret
-#endif
-
-
-END (memset)
diff --git a/libraries/libmesosphere/source/libc/kern_libc.arch.generic.c b/libraries/libmesosphere/source/libc/kern_libc.arch.generic.c
deleted file mode 100644
index 3a69034..0000000
--- a/libraries/libmesosphere/source/libc/kern_libc.arch.generic.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * 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
-#include
-#include
-
-/* Note: copied from newlib */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-FUNCTION
- <>---move possibly overlapping memory
-INDEX
- memmove
-SYNOPSIS
- #include
- void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>);
-DESCRIPTION
- This function moves <[length]> characters from the block of
- memory starting at <<*<[src]>>> to the memory starting at
- <<*<[dst]>>>. <> reproduces the characters correctly
- at <<*<[dst]>>> even if the two areas overlap.
-RETURNS
- The function returns <[dst]> as passed.
-PORTABILITY
-<> is ANSI C.
-<> requires no supporting OS subroutines.
-QUICKREF
- memmove ansi pure
-*/
-
-/* 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)))
-
-/* How many bytes are copied each iteration of the 4X unrolled loop. */
-#define BIGBLOCKSIZE (sizeof (long) << 2)
-
-/* How many bytes are copied each iteration of the word copy loop. */
-#define LITTLEBLOCKSIZE (sizeof (long))
-
-/* Threshhold for punting to the byte copier. */
-#undef TOO_SMALL
-#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
-
-/*SUPPRESS 20*/
-void *
-//__inhibit_loop_to_libcall
-__attribute__((weak))
-memmove (void *dst_void,
- const void *src_void,
- size_t length)
-{
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
- char *dst = dst_void;
- const char *src = src_void;
-
- if (src < dst && dst < src + length)
- {
- /* Have to copy backwards */
- src += length;
- dst += length;
- while (length--)
- {
- *--dst = *--src;
- }
- }
- else
- {
- while (length--)
- {
- *dst++ = *src++;
- }
- }
-
- return dst_void;
-#else
- char *dst = dst_void;
- const char *src = src_void;
- long *aligned_dst;
- const long *aligned_src;
-
- if (src < dst && dst < src + length)
- {
- /* Destructive overlap...have to copy backwards */
- src += length;
- dst += length;
- while (length--)
- {
- *--dst = *--src;
- }
- }
- else
- {
- /* Use optimizing algorithm for a non-destructive copy to closely
- match memcpy. If the size is small or either SRC or DST is unaligned,
- then punt into the byte copy loop. This should be rare. */
- if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
- {
- aligned_dst = (long*)dst;
- aligned_src = (long*)src;
-
- /* Copy 4X long words at a time if possible. */
- while (length >= BIGBLOCKSIZE)
- {
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- length -= BIGBLOCKSIZE;
- }
-
- /* Copy one long word at a time if possible. */
- while (length >= LITTLEBLOCKSIZE)
- {
- *aligned_dst++ = *aligned_src++;
- length -= LITTLEBLOCKSIZE;
- }
-
- /* Pick up any residual with a byte copier. */
- dst = (char*)aligned_dst;
- src = (char*)aligned_src;
- }
-
- while (length--)
- {
- *dst++ = *src++;
- }
- }
-
- return dst_void;
-#endif /* not PREFER_SIZE_OVER_SPEED */
-}
-
-/*
-FUNCTION
- <>---copy memory regions
-SYNOPSIS
- #include
- void* memcpy(void *restrict <[out]>, const void *restrict <[in]>,
- size_t <[n]>);
-DESCRIPTION
- This function copies <[n]> bytes from the memory region
- pointed to by <[in]> to the memory region pointed to by
- <[out]>.
- If the regions overlap, the behavior is undefined.
-RETURNS
- <> returns a pointer to the first byte of the <[out]>
- region.
-PORTABILITY
-<> is ANSI C.
-<> requires no supporting OS subroutines.
-QUICKREF
- memcpy ansi pure
- */
-
-void *
-__attribute__((weak))
-memcpy (void * dst0,
- const void * __restrict src0,
- size_t len0)
-{
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
- char *dst = (char *) dst0;
- char *src = (char *) src0;
-
- void *save = dst0;
-
- while (len0--)
- {
- *dst++ = *src++;
- }
-
- return save;
-#else
- char *dst = dst0;
- const char *src = src0;
- long *aligned_dst;
- const long *aligned_src;
-
- /* If the size is small, or either SRC or DST is unaligned,
- then punt into the byte copy loop. This should be rare. */
- if (!TOO_SMALL(len0) && !UNALIGNED (src, dst))
- {
- aligned_dst = (long*)dst;
- aligned_src = (long*)src;
-
- /* Copy 4X long words at a time if possible. */
- while (len0 >= BIGBLOCKSIZE)
- {
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- *aligned_dst++ = *aligned_src++;
- len0 -= BIGBLOCKSIZE;
- }
-
- /* Copy one long word at a time if possible. */
- while (len0 >= LITTLEBLOCKSIZE)
- {
- *aligned_dst++ = *aligned_src++;
- len0 -= LITTLEBLOCKSIZE;
- }
-
- /* Pick up any residual with a byte copier. */
- dst = (char*)aligned_dst;
- src = (char*)aligned_src;
- }
-
- while (len0--)
- *dst++ = *src++;
-
- return dst0;
-#endif /* not PREFER_SIZE_OVER_SPEED */
-}
-
-/*
-FUNCTION
- <>---set an area of memory
-INDEX
- memset
-SYNOPSIS
- #include
- void *memset(void *<[dst]>, int <[c]>, size_t <[length]>);
-DESCRIPTION
- This function converts the argument <[c]> into an unsigned
- char and fills the first <[length]> characters of the array
- pointed to by <[dst]> to the value.
-RETURNS
- <> returns the value of <[dst]>.
-PORTABILITY
-<> is ANSI C.
- <> requires no supporting OS subroutines.
-QUICKREF
- memset ansi pure
-*/
-
-#include
-
-#undef LBLOCKSIZE
-#undef UNALIGNED
-#undef TOO_SMALL
-
-#define LBLOCKSIZE (sizeof(long))
-#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
-#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
-
-void *
-__attribute__((weak))
-memset (void *m,
- int c,
- size_t n)
-{
- char *s = (char *) m;
-
-#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
- unsigned int i;
- unsigned long buffer;
- unsigned long *aligned_addr;
- unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an
- unsigned variable. */
-
- while (UNALIGNED (s))
- {
- if (n--)
- *s++ = (char) c;
- else
- return m;
- }
-
- if (!TOO_SMALL (n))
- {
- /* If we get this far, we know that n is large and s is word-aligned. */
- aligned_addr = (unsigned long *) s;
-
- /* Store D into each char sized location in BUFFER so that
- we can set large blocks quickly. */
- buffer = (d << 8) | d;
- buffer |= (buffer << 16);
- for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
- buffer = (buffer << i) | buffer;
-
- /* Unroll the loop. */
- while (n >= LBLOCKSIZE*4)
- {
- *aligned_addr++ = buffer;
- *aligned_addr++ = buffer;
- *aligned_addr++ = buffer;
- *aligned_addr++ = buffer;
- n -= 4*LBLOCKSIZE;
- }
-
- while (n >= LBLOCKSIZE)
- {
- *aligned_addr++ = buffer;
- n -= LBLOCKSIZE;
- }
- /* Pick up the remainder with a bytewise loop. */
- s = (char*)aligned_addr;
- }
-
-#endif /* not PREFER_SIZE_OVER_SPEED */
-
- while (n--)
- *s++ = (char) c;
-
- return m;
-}
-
-/*
-FUNCTION
- <>---compare two memory areas
-INDEX
- memcmp
-SYNOPSIS
- #include
- int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>);
-DESCRIPTION
- This function compares not more than <[n]> characters of the
- object pointed to by <[s1]> with the object pointed to by <[s2]>.
-RETURNS
- The function returns an integer greater than, equal to or
- less than zero according to whether the object pointed to by
- <[s1]> is greater than, equal to or less than the object
- pointed to by <[s2]>.
-PORTABILITY
-<> is ANSI C.
-<> requires no supporting OS subroutines.
-QUICKREF
- memcmp ansi pure
-*/
-
-#undef LBLOCKSIZE
-#undef UNALIGNED
-#undef TOO_SMALL
-
-/* 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)))
-
-/* How many bytes are copied each iteration of the word copy loop. */
-#define LBLOCKSIZE (sizeof (long))
-
-/* Threshhold for punting to the byte copier. */
-#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
-
-int
-__attribute__((weak))
-memcmp (const void *m1,
- const void *m2,
- size_t n)
-{
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
- unsigned char *s1 = (unsigned char *) m1;
- unsigned char *s2 = (unsigned char *) m2;
-
- while (n--)
- {
- if (*s1 != *s2)
- {
- return *s1 - *s2;
- }
- s1++;
- s2++;
- }
- return 0;
-#else
- unsigned char *s1 = (unsigned char *) m1;
- unsigned char *s2 = (unsigned char *) m2;
- unsigned long *a1;
- unsigned long *a2;
-
- /* If the size is too small, or either pointer is unaligned,
- then we punt to the byte compare loop. Hopefully this will
- not turn up in inner loops. */
- if (!TOO_SMALL(n) && !UNALIGNED(s1,s2))
- {
- /* Otherwise, load and compare the blocks of memory one
- word at a time. */
- a1 = (unsigned long*) s1;
- a2 = (unsigned long*) s2;
- while (n >= LBLOCKSIZE)
- {
- if (*a1 != *a2)
- break;
- a1++;
- a2++;
- n -= LBLOCKSIZE;
- }
-
- /* check m mod LBLOCKSIZE remaining characters */
-
- s1 = (unsigned char*)a1;
- s2 = (unsigned char*)a2;
- }
-
- while (n--)
- {
- if (*s1 != *s2)
- return *s1 - *s2;
- s1++;
- s2++;
- }
-
- return 0;
-#endif /* not PREFER_SIZE_OVER_SPEED */
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
diff --git a/libraries/libmesosphere/source/libc/kern_libc_generic.c b/libraries/libmesosphere/source/libc/kern_libc_generic.c
new file mode 100644
index 0000000..fb7e4cc
--- /dev/null
+++ b/libraries/libmesosphere/source/libc/kern_libc_generic.c
@@ -0,0 +1,648 @@
+/*
+ * 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
+#include
+#include
+
+/* Note: copied from newlib */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+FUNCTION
+ <>---move possibly overlapping memory
+INDEX
+ memmove
+SYNOPSIS
+ #include
+ void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>);
+DESCRIPTION
+ This function moves <[length]> characters from the block of
+ memory starting at <<*<[src]>>> to the memory starting at
+ <<*<[dst]>>>. <> reproduces the characters correctly
+ at <<*<[dst]>>> even if the two areas overlap.
+RETURNS
+ The function returns <[dst]> as passed.
+PORTABILITY
+<> is ANSI C.
+<> requires no supporting OS subroutines.
+QUICKREF
+ memmove ansi pure
+*/
+
+/* 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)))
+
+/* How many bytes are copied each iteration of the 4X unrolled loop. */
+#define BIGBLOCKSIZE (sizeof (long) << 2)
+
+/* How many bytes are copied each iteration of the word copy loop. */
+#define LITTLEBLOCKSIZE (sizeof (long))
+
+/* Threshhold for punting to the byte copier. */
+#undef TOO_SMALL
+#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
+
+/*SUPPRESS 20*/
+void *
+//__inhibit_loop_to_libcall
+__attribute__((weak))
+memmove (void *dst_void,
+ const void *src_void,
+ size_t length)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *dst = dst_void;
+ const char *src = src_void;
+
+ if (src < dst && dst < src + length)
+ {
+ /* Have to copy backwards */
+ src += length;
+ dst += length;
+ while (length--)
+ {
+ *--dst = *--src;
+ }
+ }
+ else
+ {
+ while (length--)
+ {
+ *dst++ = *src++;
+ }
+ }
+
+ return dst_void;
+#else
+ char *dst = dst_void;
+ const char *src = src_void;
+ long *aligned_dst;
+ const long *aligned_src;
+
+ if (src < dst && dst < src + length)
+ {
+ /* Destructive overlap...have to copy backwards */
+ src += length;
+ dst += length;
+ while (length--)
+ {
+ *--dst = *--src;
+ }
+ }
+ else
+ {
+ /* Use optimizing algorithm for a non-destructive copy to closely
+ match memcpy. If the size is small or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
+ {
+ aligned_dst = (long*)dst;
+ aligned_src = (long*)src;
+
+ /* Copy 4X long words at a time if possible. */
+ while (length >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ length -= BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (length >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ length -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst = (char*)aligned_dst;
+ src = (char*)aligned_src;
+ }
+
+ while (length--)
+ {
+ *dst++ = *src++;
+ }
+ }
+
+ return dst_void;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
+
+/*
+FUNCTION
+ <>---copy memory regions
+SYNOPSIS
+ #include
+ void* memcpy(void *restrict <[out]>, const void *restrict <[in]>,
+ size_t <[n]>);
+DESCRIPTION
+ This function copies <[n]> bytes from the memory region
+ pointed to by <[in]> to the memory region pointed to by
+ <[out]>.
+ If the regions overlap, the behavior is undefined.
+RETURNS
+ <> returns a pointer to the first byte of the <[out]>
+ region.
+PORTABILITY
+<> is ANSI C.
+<> requires no supporting OS subroutines.
+QUICKREF
+ memcpy ansi pure
+ */
+
+void *
+__attribute__((weak))
+memcpy (void * dst0,
+ const void * __restrict src0,
+ size_t len0)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *dst = (char *) dst0;
+ char *src = (char *) src0;
+
+ void *save = dst0;
+
+ while (len0--)
+ {
+ *dst++ = *src++;
+ }
+
+ return save;
+#else
+ char *dst = dst0;
+ const char *src = src0;
+ long *aligned_dst;
+ const long *aligned_src;
+
+ /* If the size is small, or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(len0) && !UNALIGNED (src, dst))
+ {
+ aligned_dst = (long*)dst;
+ aligned_src = (long*)src;
+
+ /* Copy 4X long words at a time if possible. */
+ while (len0 >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ len0 -= BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (len0 >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ len0 -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst = (char*)aligned_dst;
+ src = (char*)aligned_src;
+ }
+
+ while (len0--)
+ *dst++ = *src++;
+
+ return dst0;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
+
+/*
+FUNCTION
+ <>---set an area of memory
+INDEX
+ memset
+SYNOPSIS
+ #include
+ void *memset(void *<[dst]>, int <[c]>, size_t <[length]>);
+DESCRIPTION
+ This function converts the argument <[c]> into an unsigned
+ char and fills the first <[length]> characters of the array
+ pointed to by <[dst]> to the value.
+RETURNS
+ <> returns the value of <[dst]>.
+PORTABILITY
+<> is ANSI C.
+ <> requires no supporting OS subroutines.
+QUICKREF
+ memset ansi pure
+*/
+
+#include
+
+#undef LBLOCKSIZE
+#undef UNALIGNED
+#undef TOO_SMALL
+
+#define LBLOCKSIZE (sizeof(long))
+#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+void *
+__attribute__((weak))
+memset (void *m,
+ int c,
+ size_t n)
+{
+ char *s = (char *) m;
+
+#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
+ unsigned int i;
+ unsigned long buffer;
+ unsigned long *aligned_addr;
+ unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an
+ unsigned variable. */
+
+ while (UNALIGNED (s))
+ {
+ if (n--)
+ *s++ = (char) c;
+ else
+ return m;
+ }
+
+ if (!TOO_SMALL (n))
+ {
+ /* If we get this far, we know that n is large and s is word-aligned. */
+ aligned_addr = (unsigned long *) s;
+
+ /* Store D into each char sized location in BUFFER so that
+ we can set large blocks quickly. */
+ buffer = (d << 8) | d;
+ buffer |= (buffer << 16);
+ for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
+ buffer = (buffer << i) | buffer;
+
+ /* Unroll the loop. */
+ while (n >= LBLOCKSIZE*4)
+ {
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ n -= 4*LBLOCKSIZE;
+ }
+
+ while (n >= LBLOCKSIZE)
+ {
+ *aligned_addr++ = buffer;
+ n -= LBLOCKSIZE;
+ }
+ /* Pick up the remainder with a bytewise loop. */
+ s = (char*)aligned_addr;
+ }
+
+#endif /* not PREFER_SIZE_OVER_SPEED */
+
+ while (n--)
+ *s++ = (char) c;
+
+ return m;
+}
+
+/*
+FUNCTION
+ <>---compare two memory areas
+INDEX
+ memcmp
+SYNOPSIS
+ #include
+ int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>);
+DESCRIPTION
+ This function compares not more than <[n]> characters of the
+ object pointed to by <[s1]> with the object pointed to by <[s2]>.
+RETURNS
+ The function returns an integer greater than, equal to or
+ less than zero according to whether the object pointed to by
+ <[s1]> is greater than, equal to or less than the object
+ pointed to by <[s2]>.
+PORTABILITY
+<> is ANSI C.
+<> requires no supporting OS subroutines.
+QUICKREF
+ memcmp ansi pure
+*/
+
+#undef LBLOCKSIZE
+#undef UNALIGNED
+#undef TOO_SMALL
+
+/* 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)))
+
+/* How many bytes are copied each iteration of the word copy loop. */
+#define LBLOCKSIZE (sizeof (long))
+
+/* Threshhold for punting to the byte copier. */
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+int
+__attribute__((weak))
+memcmp (const void *m1,
+ const void *m2,
+ size_t n)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ unsigned char *s1 = (unsigned char *) m1;
+ unsigned char *s2 = (unsigned char *) m2;
+
+ while (n--)
+ {
+ if (*s1 != *s2)
+ {
+ return *s1 - *s2;
+ }
+ s1++;
+ s2++;
+ }
+ return 0;
+#else
+ unsigned char *s1 = (unsigned char *) m1;
+ unsigned char *s2 = (unsigned char *) m2;
+ unsigned long *a1;
+ unsigned long *a2;
+
+ /* If the size is too small, or either pointer is unaligned,
+ then we punt to the byte compare loop. Hopefully this will
+ not turn up in inner loops. */
+ if (!TOO_SMALL(n) && !UNALIGNED(s1,s2))
+ {
+ /* Otherwise, load and compare the blocks of memory one
+ word at a time. */
+ a1 = (unsigned long*) s1;
+ a2 = (unsigned long*) s2;
+ while (n >= LBLOCKSIZE)
+ {
+ if (*a1 != *a2)
+ break;
+ a1++;
+ a2++;
+ n -= LBLOCKSIZE;
+ }
+
+ /* check m mod LBLOCKSIZE remaining characters */
+
+ s1 = (unsigned char*)a1;
+ s2 = (unsigned char*)a2;
+ }
+
+ while (n--)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++;
+ s2++;
+ }
+
+ return 0;
+#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 e8b1a73..2aa297d 100644
--- a/libraries/libmesosphere/source/svc/kern_svc_port.cpp
+++ b/libraries/libmesosphere/source/svc/kern_svc_port.cpp
@@ -21,7 +21,61 @@
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 @@
}
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 @@
}
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 17350db..4bf47cd 100644
--- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp
+++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp
@@ -21,6 +21,32 @@
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 @@
}
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 @@
}
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) {