kern: implement KHandleTable, other cleanup

This commit is contained in:
Michael Scire 2020-01-30 15:29:51 -08:00
parent d5a4c17ee7
commit 484f132651
41 changed files with 710 additions and 89 deletions

View file

@ -19,40 +19,42 @@
#include <vapours.hpp>
/* First, pull in core macros (panic, etc). */
#include "mesosphere/kern_panic.hpp"
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
/* Primitive types. */
#include "mesosphere/kern_k_typed_address.hpp"
#include "mesosphere/kern_initial_process.hpp"
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_initial_process.hpp>
/* Core pre-initialization includes. */
#include "mesosphere/kern_select_cpu.hpp"
#include "mesosphere/kern_select_k_system_control.hpp"
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_select_k_system_control.hpp>
/* Initialization headers. */
#include "mesosphere/init/kern_init_elf.hpp"
#include "mesosphere/init/kern_init_layout.hpp"
#include "mesosphere/init/kern_init_slab_setup.hpp"
#include "mesosphere/init/kern_init_page_table_select.hpp"
#include "mesosphere/init/kern_init_arguments_select.hpp"
#include "mesosphere/kern_k_memory_layout.hpp"
#include <mesosphere/init/kern_init_elf.hpp>
#include <mesosphere/init/kern_init_layout.hpp>
#include <mesosphere/init/kern_init_slab_setup.hpp>
#include <mesosphere/init/kern_init_page_table_select.hpp>
#include <mesosphere/init/kern_init_arguments_select.hpp>
#include <mesosphere/kern_k_memory_layout.hpp>
/* Core functionality. */
#include "mesosphere/kern_select_interrupt_manager.hpp"
#include "mesosphere/kern_k_spin_lock.hpp"
#include "mesosphere/kern_k_page_heap.hpp"
#include "mesosphere/kern_k_memory_manager.hpp"
#include "mesosphere/kern_k_interrupt_task_manager.hpp"
#include "mesosphere/kern_k_core_local_region.hpp"
#include "mesosphere/kern_k_slab_heap.hpp"
#include "mesosphere/kern_k_light_lock.hpp"
#include "mesosphere/kern_kernel.hpp"
#include <mesosphere/kern_select_interrupt_manager.hpp>
#include <mesosphere/kern_k_spin_lock.hpp>
#include <mesosphere/kern_k_page_heap.hpp>
#include <mesosphere/kern_k_memory_manager.hpp>
#include <mesosphere/kern_k_interrupt_task_manager.hpp>
#include <mesosphere/kern_k_core_local_region.hpp>
#include <mesosphere/kern_k_slab_heap.hpp>
#include <mesosphere/kern_k_light_lock.hpp>
#include <mesosphere/kern_kernel.hpp>
/* Auto Objects. */
#include "mesosphere/kern_k_auto_object.hpp"
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_k_handle_table.hpp>
/* Supervisor Calls. */
#include "mesosphere/kern_svc.hpp"
#include <mesosphere/kern_svc.hpp>
/* Main functionality. */
#include "mesosphere/kern_main.hpp"
#include <mesosphere/kern_main.hpp>

View file

@ -15,7 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_select_cpu.hpp>

View file

@ -15,7 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include "kern_cpu_system_registers.hpp"
#include <mesosphere/arch/arm64/kern_cpu_system_registers.hpp>
namespace ams::kern::arm64::cpu {

View file

@ -17,7 +17,7 @@
#include <mesosphere/kern_k_typed_address.hpp>
#ifdef ATMOSPHERE_ARCH_ARM64
#include "../arch/arm64/init/kern_k_init_arguments.hpp"
#include <mesosphere/arch/arm64/init/kern_k_init_arguments.hpp>
#else
#error "Unknown architecture for KInitArguments"
#endif

View file

@ -17,23 +17,21 @@
#include <vapours.hpp>
#ifdef ATMOSPHERE_ARCH_ARM64
#include "kern_init_elf64.hpp"
#include <mesosphere/init/kern_init_elf64.hpp>
namespace ams::kern::init::Elf {
using namespace ams::kern::init::Elf::Elf64;
enum RelocationType {
R_ARCHITECTURE_RELATIVE = 0x403, /* Real name R_AARCH64_RELATIVE */
};
}
#else
#error "Unknown Architecture"
#endif
namespace ams::kern::init::Elf {
#ifdef ATMOSPHERE_ARCH_ARM64
using namespace ams::kern::init::Elf::Elf64;
enum RelocationType {
R_ARCHITECTURE_RELATIVE = 0x403, /* Real name R_AARCH64_RELATIVE */
};
#else
#error "Unknown Architecture"
#endif
/* API to apply relocations or call init array. */
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic);
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end);

View file

@ -16,7 +16,7 @@
#pragma once
#ifdef ATMOSPHERE_ARCH_ARM64
#include "../arch/arm64/init/kern_k_init_page_table.hpp"
#include <mesosphere/arch/arm64/init/kern_k_init_page_table.hpp>
#else
#error "Unknown architecture for KInitialPageTable"
#endif

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "kern_panic.hpp"
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_k_class_token.hpp>
@ -74,14 +73,14 @@ namespace ams::kern {
public:
static KAutoObject *Create(KAutoObject *ptr);
public:
constexpr ALWAYS_INLINE explicit KAutoObject() : ref_count(0) { /* ... */ }
virtual ~KAutoObject() { /* ... */ }
constexpr ALWAYS_INLINE explicit KAutoObject() : ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
virtual ~KAutoObject() { MESOSPHERE_ASSERT_THIS(); }
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
virtual void Destroy() { /* ... */ }
virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); }
/* Finalize is responsible for cleaning up resource, but does not destroy the object. */
virtual void Finalize() { /* ... */ }
virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); }
virtual KProcess *GetOwner() const { return nullptr; }
@ -122,6 +121,8 @@ namespace ams::kern {
}
ALWAYS_INLINE bool Open() {
MESOSPHERE_ASSERT_THIS();
/* Atomically increment the reference count, only if it's positive. */
u32 cur_ref_count = this->ref_count.load(std::memory_order_acquire);
do {
@ -135,6 +136,8 @@ namespace ams::kern {
}
ALWAYS_INLINE void Close() {
MESOSPHERE_ASSERT_THIS();
/* Atomically decrement the reference count, not allowing it to become negative. */
u32 cur_ref_count = this->ref_count.load(std::memory_order_acquire);
do {
@ -189,7 +192,11 @@ namespace ams::kern {
}
public:
constexpr ALWAYS_INLINE KScopedAutoObject() : obj(nullptr) { /* ... */ }
constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : obj(o) { /* ... */ }
constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : obj(o) {
if (this->obj != nullptr) {
this->obj->Open();
}
}
ALWAYS_INLINE ~KScopedAutoObject() {
if (this->obj != nullptr) {
this->obj->Close();

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_k_light_lock.hpp>
@ -51,10 +51,10 @@ namespace ams::kern {
KLightLock lock;
ListType object_list;
public:
constexpr KAutoObjectWithListContainer() : lock(), object_list() { /* ... */ }
constexpr KAutoObjectWithListContainer() : lock(), object_list() { MESOSPHERE_ASSERT_THIS(); }
void Initialize() { /* Nothing to do. */ }
void Finalize() { /* Nothing to do. */ }
void Initialize() { MESOSPHERE_ASSERT_THIS(); }
void Finalize() { MESOSPHERE_ASSERT_THIS(); }
Result Register(KAutoObjectWithList *obj);
Result Unregister(KAutoObjectWithList *obj);

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_current_context.hpp>
#include <mesosphere/kern_k_scheduler.hpp>

View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_k_spin_lock.hpp>
#include <mesosphere/kern_k_thread.hpp>
namespace ams::kern {
constexpr ALWAYS_INLINE util::BitPack32 GetHandleBitPack(ams::svc::Handle handle) {
return util::BitPack32{handle};
}
class KHandleTable {
NON_COPYABLE(KHandleTable);
NON_MOVEABLE(KHandleTable);
public:
static constexpr size_t MaxTableSize = 1024;
private:
using HandleRawValue = util::BitPack32::Field<0, BITSIZEOF(u32), u32>;
using HandleEncoded = util::BitPack32::Field<0, BITSIZEOF(ams::svc::Handle), ams::svc::Handle>;
using HandleIndex = util::BitPack32::Field<0, 15, u16>;
using HandleLinearId = util::BitPack32::Field<HandleIndex::Next, 15, u16>;
using HandleReserved = util::BitPack32::Field<HandleLinearId::Next, 2, u32>;
static constexpr u16 MinLinearId = 1;
static constexpr u16 MaxLinearId = util::BitPack32{std::numeric_limits<u32>::max()}.Get<HandleLinearId>();
static constexpr ALWAYS_INLINE ams::svc::Handle EncodeHandle(u16 index, u16 linear_id) {
util::BitPack32 pack = {0};
pack.Set<HandleIndex>(index);
pack.Set<HandleLinearId>(linear_id);
pack.Set<HandleReserved>(0);
return pack.Get<HandleEncoded>();
}
class Entry {
private:
union {
struct {
u16 linear_id;
u16 type;
} info;
Entry *next_free_entry;
} meta;
KAutoObject *object;
public:
constexpr Entry() : meta(), object(nullptr) { /* ... */ }
constexpr ALWAYS_INLINE void SetFree(Entry *next) {
this->object = nullptr;
this->meta.next_free_entry = next;
}
constexpr ALWAYS_INLINE void SetUsed(KAutoObject *obj, u16 linear_id, u16 type) {
this->object = obj;
this->meta.info = { linear_id, type };
}
constexpr ALWAYS_INLINE KAutoObject *GetObject() const { return this->object; }
constexpr ALWAYS_INLINE Entry *GetNextFreeEntry() const { return this->meta.next_free_entry; }
constexpr ALWAYS_INLINE u16 GetLinearId() const { return this->meta.info.linear_id; }
constexpr ALWAYS_INLINE u16 GetType() const { return this->meta.info.type; }
};
private:
mutable KSpinLock lock;
Entry *table;
Entry *free_head;
Entry entries[MaxTableSize];
u16 table_size;
u16 max_count;
u16 next_linear_id;
u16 count;
public:
constexpr KHandleTable() :
lock(), table(nullptr), free_head(nullptr), entries(), table_size(0), max_count(0), next_linear_id(MinLinearId), count(0)
{ MESOSPHERE_ASSERT_THIS(); }
constexpr NOINLINE Result Initialize(s32 size) {
MESOSPHERE_ASSERT_THIS();
R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory());
/* Initialize all fields. */
this->table = this->entries;
this->table_size = (size <= 0) ? MaxTableSize : table_size;
this->next_linear_id = MinLinearId;
this->count = 0;
this->max_count = 0;
/* Free all entries. */
for (size_t i = 0; i < static_cast<size_t>(this->table_size - 1); i++) {
this->entries[i].SetFree(std::addressof(this->entries[i + 1]));
}
this->entries[this->table_size - 1].SetFree(nullptr);
this->free_head = std::addressof(this->entries[0]);
return ResultSuccess();
}
constexpr ALWAYS_INLINE size_t GetTableSize() const { return this->table_size; }
constexpr ALWAYS_INLINE size_t GetCount() const { return this->count; }
constexpr ALWAYS_INLINE size_t GetMaxCount() const { return this->max_count; }
NOINLINE Result Finalize();
NOINLINE bool Remove(ams::svc::Handle handle);
template<typename T = KAutoObject>
ALWAYS_INLINE KScopedAutoObject<T> GetObject(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
if constexpr (std::is_same<T, KAutoObject>::value) {
return this->GetObjectImpl(handle);
} else {
return this->GetObjectImpl(handle)->DynamicCast<T*>();
}
}
template<typename T = KAutoObject>
ALWAYS_INLINE KScopedAutoObject<T> GetObjectForIpc(ams::svc::Handle handle) const {
/* TODO: static_assert(!std::is_base_of<KInterruptEvent, T>::value); */
KAutoObject *obj = this->GetObjectImpl(handle);
if (false /* TODO: obj->DynamicCast<KInterruptEvent *>() != nullptr */) {
return nullptr;
}
if constexpr (std::is_same<T, KAutoObject>::value) {
return obj;
} else {
return obj->DynamicCast<T*>();
}
}
ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectByIndex(ams::svc::Handle *out_handle, size_t index) const {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
return this->GetObjectByIndexImpl(out_handle, index);
}
NOINLINE Result Reserve(ams::svc::Handle *out_handle);
NOINLINE void Unreserve(ams::svc::Handle handle);
template<typename T>
ALWAYS_INLINE Result Add(ams::svc::Handle *out_handle, T *obj) {
static_assert(std::is_base_of<KAutoObject, T>::value);
return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken());
}
template<typename T>
ALWAYS_INLINE void Register(ams::svc::Handle handle, T *obj) {
static_assert(std::is_base_of<KAutoObject, T>::value);
return this->Add(handle, obj, obj->GetTypeObj().GetClassToken());
}
private:
NOINLINE Result Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type);
NOINLINE void Register(ams::svc::Handle handle, KAutoObject *obj, u16 type);
constexpr ALWAYS_INLINE Entry *AllocateEntry() {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->count < this->table_size);
Entry *entry = this->free_head;
this->free_head = entry->GetNextFreeEntry();
this->count++;
this->max_count = std::max(this->max_count, this->count);
return entry;
}
constexpr ALWAYS_INLINE void FreeEntry(Entry *entry) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->count > 0);
entry->SetFree(this->free_head);
this->free_head = entry;
this->count--;
}
constexpr ALWAYS_INLINE u16 AllocateLinearId() {
const u16 id = this->next_linear_id++;
if (this->next_linear_id > MaxLinearId) {
this->next_linear_id = MinLinearId;
}
return id;
}
constexpr ALWAYS_INLINE size_t GetEntryIndex(Entry *entry) {
const size_t index = entry - this->table;
MESOSPHERE_ASSERT(index < this->table_size);
return index;
}
constexpr ALWAYS_INLINE Entry *FindEntry(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
/* Unpack the handle. */
const auto handle_pack = GetHandleBitPack(handle);
const auto raw_value = handle_pack.Get<HandleRawValue>();
const auto index = handle_pack.Get<HandleIndex>();
const auto linear_id = handle_pack.Get<HandleLinearId>();
const auto reserved = handle_pack.Get<HandleReserved>();
MESOSPHERE_ASSERT(reserved == 0);
/* Validate our indexing information. */
if (raw_value == 0) {
return nullptr;
}
if (linear_id == 0) {
return nullptr;
}
if (index >= this->table_size) {
return nullptr;
}
/* Get the entry, and ensure our serial id is correct. */
Entry *entry = std::addressof(this->table[index]);
if (entry->GetObject() == nullptr) {
return nullptr;
}
if (entry->GetLinearId() != linear_id) {
return nullptr;
}
return entry;
}
constexpr NOINLINE KAutoObject *GetObjectImpl(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
/* Handles must not have reserved bits set. */
if (GetHandleBitPack(handle).Get<HandleReserved>() != 0) {
return nullptr;
}
if (Entry *entry = this->FindEntry(handle); entry != nullptr) {
return entry->GetObject();
} else {
return nullptr;
}
}
constexpr NOINLINE KAutoObject *GetObjectByIndexImpl(ams::svc::Handle *out_handle, size_t index) const {
MESOSPHERE_ASSERT_THIS();
/* Index must be in bounds. */
if (index >= this->table_size || this->table == nullptr) {
return nullptr;
}
/* Ensure entry has an object. */
Entry *entry = std::addressof(this->table[index]);
if (entry->GetObject() == nullptr) {
return nullptr;
}
*out_handle = EncodeHandle(index, entry->GetLinearId());
return entry->GetObject();
}
};
}

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_current_context.hpp>
@ -27,6 +27,8 @@ namespace ams::kern {
constexpr KLightLock() : tag(0) { /* ... */ }
void Lock() {
MESOSPHERE_ASSERT_THIS();
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer());
while (true) {
@ -45,6 +47,8 @@ namespace ams::kern {
}
void Unlock() {
MESOSPHERE_ASSERT_THIS();
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer());
uintptr_t expected = cur_thread;
if (!this->tag.compare_exchange_weak(expected, 0, std::memory_order_release)) {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
@ -24,9 +24,10 @@ namespace ams::kern {
private:
void *item;
public:
constexpr KLinkedListNode() : util::IntrusiveListBaseNode<KLinkedListNode>(), item(nullptr) { /* ... */ }
constexpr KLinkedListNode() : util::IntrusiveListBaseNode<KLinkedListNode>(), item(nullptr) { MESOSPHERE_ASSERT_THIS(); }
constexpr void Initialize(void *it) {
MESOSPHERE_ASSERT_THIS();
this->item = it;
}

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/init/kern_init_page_table_select.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
namespace ams::kern {
@ -33,7 +32,7 @@ namespace ams::kern {
std::atomic<Node *> head;
size_t obj_size;
public:
constexpr KSlabHeapImpl() : head(nullptr), obj_size(0) { /* ... */ }
constexpr KSlabHeapImpl() : head(nullptr), obj_size(0) { MESOSPHERE_ASSERT_THIS(); }
void Initialize(size_t size) {
MESOSPHERE_INIT_ABORT_UNLESS(this->head == nullptr);
@ -49,6 +48,8 @@ namespace ams::kern {
}
void *Allocate() {
MESOSPHERE_ASSERT_THIS();
Node *ret = this->head.load();
do {
@ -61,6 +62,8 @@ namespace ams::kern {
}
void Free(void *obj) {
MESOSPHERE_ASSERT_THIS();
Node *node = reinterpret_cast<Node *>(obj);
Node *cur_head = this->head.load();
@ -90,13 +93,15 @@ namespace ams::kern {
return std::addressof(this->impl);
}
public:
constexpr KSlabHeapBase() : impl(), peak(0), start(0), end(0) { /* ... */ }
constexpr KSlabHeapBase() : impl(), peak(0), start(0), end(0) { MESOSPHERE_ASSERT_THIS(); }
ALWAYS_INLINE bool Contains(uintptr_t address) const {
return this->start <= address && address < this->end;
}
void InitializeImpl(size_t obj_size, void *memory, size_t memory_size) {
MESOSPHERE_ASSERT_THIS();
/* Ensure we don't initialize a slab using null memory. */
MESOSPHERE_ABORT_UNLESS(memory != nullptr);
@ -127,6 +132,8 @@ namespace ams::kern {
}
void *AllocateImpl() {
MESOSPHERE_ASSERT_THIS();
void *obj = this->GetImpl()->Allocate();
/* TODO: under some debug define, track the peak for statistics, as N does? */
@ -135,6 +142,8 @@ namespace ams::kern {
}
void FreeImpl(void *obj) {
MESOSPHERE_ASSERT_THIS();
/* Don't allow freeing an object that wasn't allocated from this heap. */
MESOSPHERE_ABORT_UNLESS(this->Contains(reinterpret_cast<uintptr_t>(obj)));

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "kern_panic.hpp"
#include <mesosphere/kern_common.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64)

View file

@ -30,10 +30,10 @@ namespace ams::kern {
private:
ThreadList thread_list;
protected:
constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list() { /* ... */ }
virtual ~KSynchronizationObject() { /* ... */ }
constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list() { MESOSPHERE_ASSERT_THIS(); }
virtual ~KSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); }
virtual void OnFinalizeSynchronizationObject() { /* ... */ }
virtual void OnFinalizeSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); }
void NotifyAvailable();
void NotifyAbort(Result abort_reason);

View file

@ -36,4 +36,26 @@ namespace ams::kern {
/* TODO: This is a placeholder definition. */
};
class KScopedDisableDispatch {
public:
explicit ALWAYS_INLINE KScopedDisableDispatch() {
/* TODO */
}
ALWAYS_INLINE ~KScopedDisableDispatch() {
/* TODO */
}
};
class KScopedEnableDispatch {
public:
explicit ALWAYS_INLINE KScopedEnableDispatch() {
/* TODO */
}
ALWAYS_INLINE ~KScopedEnableDispatch() {
/* TODO */
}
};
}

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_common.hpp>
namespace ams::kern {
@ -37,12 +37,18 @@ namespace ams::kern {
} \
})
#else
#define MESOSPHERE_ASSERT_IMPL(expr, ...) do { } while (0)
#define MESOSPHERE_ASSERT_IMPL(expr, ...) do { static_cast<void>(expr); } while (0)
#endif
#define MESOSPHERE_ASSERT(expr) MESOSPHERE_ASSERT_IMPL(expr, "Assertion failed: %s", #expr)
#define MESOSPHERE_R_ASSERT(expr) MESOSPHERE_ASSERT_IMPL(R_SUCCEEDED(expr), "Result assertion failed: %s", #expr)
#ifdef MESOSPHERE_ENABLE_THIS_ASSERT
#define MESOSPHERE_ASSERT_THIS() MESOSPHERE_ASSERT(this != nullptr)
#else
#define MESOSPHERE_ASSERT_THIS()
#endif
#define MESOSPHERE_ABORT() MESOSPHERE_PANIC("Abort()");
#define MESOSPHERE_INIT_ABORT() do { /* ... */ } while (true)

View file

@ -16,7 +16,7 @@
#pragma once
#ifdef ATMOSPHERE_ARCH_ARM64
#include "arch/arm64/kern_cpu.hpp"
#include <mesosphere/arch/arm64/kern_cpu.hpp>
namespace ams::kern::cpu {

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "kern_panic.hpp"
#include <mesosphere/kern_common.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64)

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "kern_panic.hpp"
#include <mesosphere/kern_common.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64)

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "kern_panic.hpp"
#include <mesosphere/kern_common.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64)

View file

@ -16,7 +16,7 @@
#pragma once
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
#include "board/nintendo/switch/kern_k_system_control.hpp"
#include <mesosphere/board/nintendo/switch/kern_k_system_control.hpp>
#else
#error "Unknown board for KSystemControl"
#endif

View file

@ -14,8 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_k_slab_heap.hpp>
#include <mesosphere/kern_k_auto_object_container.hpp>

View file

@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "svc/kern_svc_k_user_pointer.hpp"
#include "svc/kern_svc_prototypes.hpp"
#include "svc/kern_svc_tables.hpp"
#include <mesosphere/svc/kern_svc_results.hpp>
#include <mesosphere/svc/kern_svc_k_user_pointer.hpp>
#include <mesosphere/svc/kern_svc_prototypes.hpp>
#include <mesosphere/svc/kern_svc_tables.hpp>

View file

@ -15,6 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
namespace ams::kern::svc {

View file

@ -15,7 +15,8 @@
*/
#pragma once
#include <vapours.hpp>
#include "kern_svc_k_user_pointer.hpp"
#include <mesosphere/svc/kern_svc_k_user_pointer.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
namespace ams::kern::svc {

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::kern::svc {
/* 7 */ using ::ams::svc::ResultOutOfSessions;
/* 14 */ using ::ams::svc::ResultInvalidArgument;
/* 33 */ using ::ams::svc::ResultNotImplemented;
/* 59 */ using ::ams::svc::ResultThreadTerminating;
/* 70 */ using ::ams::svc::ResultNoEvent;
/* 101 */ using ::ams::svc::ResultInvalidSize;
/* 102 */ using ::ams::svc::ResultInvalidAddress;
/* 103 */ using ::ams::svc::ResultOutOfResource;
/* 104 */ using ::ams::svc::ResultOutOfMemory;
/* 105 */ using ::ams::svc::ResultOutOfHandles;
/* 106 */ using ::ams::svc::ResultInvalidCurrentMemoryState;
/* 108 */ using ::ams::svc::ResultInvalidNewMemoryPermissions;
/* 110 */ using ::ams::svc::ResultInvalidMemoryRegion;
/* 112 */ using ::ams::svc::ResultInvalidPriority;
/* 113 */ using ::ams::svc::ResultInvalidCoreId;
/* 114 */ using ::ams::svc::ResultInvalidHandle;
/* 115 */ using ::ams::svc::ResultInvalidPointer;
/* 116 */ using ::ams::svc::ResultInvalidCombination;
/* 117 */ using ::ams::svc::ResultTimedOut;
/* 118 */ using ::ams::svc::ResultCancelled;
/* 119 */ using ::ams::svc::ResultOutOfRange;
/* 120 */ using ::ams::svc::ResultInvalidEnumValue;
/* 121 */ using ::ams::svc::ResultNotFound;
/* 122 */ using ::ams::svc::ResultBusy;
/* 123 */ using ::ams::svc::ResultSessionClosed;
/* 124 */ using ::ams::svc::ResultNotHandled;
/* 125 */ using ::ams::svc::ResultInvalidState;
/* 126 */ using ::ams::svc::ResultReservedValue;
/* 127 */ using ::ams::svc::ResultNotSupported;
/* 128 */ using ::ams::svc::ResultDebug;
/* 129 */ using ::ams::svc::ResultThreadNotOwned;
/* 131 */ using ::ams::svc::ResultPortClosed;
/* 132 */ using ::ams::svc::ResultLimitReached;
/* 258 */ using ::ams::svc::ResultReceiveListBroken;
/* 259 */ using ::ams::svc::ResultOutOfAddressSpace;
/* 260 */ using ::ams::svc::ResultMessageTooLarge;
/* 520 */ using ::ams::svc::ResultProcessTerminated;
}

View file

@ -15,6 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
namespace ams::kern::svc {

View file

@ -19,6 +19,8 @@ namespace ams::kern {
Result KAutoObjectWithListContainer::Register(KAutoObjectWithList *obj) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(this->lock);
this->object_list.insert(*obj);
@ -27,6 +29,8 @@ namespace ams::kern {
}
Result KAutoObjectWithListContainer::Unregister(KAutoObjectWithList *obj) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(this->lock);
this->object_list.erase(this->object_list.iterator_to(*obj));
@ -35,6 +39,8 @@ namespace ams::kern {
}
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess *owner) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(this->lock);
size_t count = 0;

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
namespace ams::kern {
Result KHandleTable::Finalize() {
MESOSPHERE_ASSERT_THIS();
/* Get the table and clear our record of it. */
Entry *saved_table = nullptr;
u16 saved_table_size = 0;
{
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
std::swap(this->table, saved_table);
std::swap(this->table_size, saved_table_size);
}
/* Close and free all entries. */
for (size_t i = 0; i < saved_table_size; i++) {
Entry *entry = std::addressof(saved_table[i]);
if (KAutoObject *obj = entry->GetObject(); obj != nullptr) {
obj->Close();
this->FreeEntry(entry);
}
}
return ResultSuccess();
}
bool KHandleTable::Remove(ams::svc::Handle handle) {
MESOSPHERE_ASSERT_THIS();
/* Don't allow removal of a pseudo-handle. */
if (ams::svc::IsPseudoHandle(handle)) {
return false;
}
/* Handles must not have reserved bits set. */
if (GetHandleBitPack(handle).Get<HandleReserved>() != 0) {
return false;
}
/* Find the object and free the entry. */
KAutoObject *obj = nullptr;
{
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
if (Entry *entry = this->FindEntry(handle); entry != nullptr) {
obj = entry->GetObject();
this->FreeEntry(entry);
} else {
return false;
}
}
/* Close the object. */
obj->Close();
return true;
}
Result KHandleTable::Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type) {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
/* Never exceed our capacity. */
R_UNLESS(this->count < this->table_size, svc::ResultOutOfHandles());
/* Allocate entry, set output handle. */
{
const auto linear_id = this->AllocateLinearId();
Entry *entry = this->AllocateEntry();
entry->SetUsed(obj, linear_id, type);
obj->Open();
*out_handle = EncodeHandle(this->GetEntryIndex(entry), linear_id);
}
return ResultSuccess();
}
Result KHandleTable::Reserve(ams::svc::Handle *out_handle) {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
/* Never exceed our capacity. */
R_UNLESS(this->count < this->table_size, svc::ResultOutOfHandles());
*out_handle = EncodeHandle(this->GetEntryIndex(this->AllocateEntry()), this->AllocateLinearId());
return ResultSuccess();
}
void KHandleTable::Unreserve(ams::svc::Handle handle) {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
/* Unpack the handle. */
const auto handle_pack = GetHandleBitPack(handle);
const auto index = handle_pack.Get<HandleIndex>();
const auto linear_id = handle_pack.Get<HandleLinearId>();
const auto reserved = handle_pack.Get<HandleReserved>();
MESOSPHERE_ASSERT(reserved == 0);
MESOSPHERE_ASSERT(linear_id != 0);
MESOSPHERE_ASSERT(index < this->table_size);
/* Free the entry. */
/* NOTE: This code does not check the linear id. */
Entry *entry = std::addressof(this->table[index]);
MESOSPHERE_ASSERT(entry->GetObject() == nullptr);
this->FreeEntry(entry);
}
void KHandleTable::Register(ams::svc::Handle handle, KAutoObject *obj, u16 type) {
MESOSPHERE_ASSERT_THIS();
KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock);
/* Unpack the handle. */
const auto handle_pack = GetHandleBitPack(handle);
const auto index = handle_pack.Get<HandleIndex>();
const auto linear_id = handle_pack.Get<HandleLinearId>();
const auto reserved = handle_pack.Get<HandleReserved>();
MESOSPHERE_ASSERT(reserved == 0);
MESOSPHERE_ASSERT(linear_id != 0);
MESOSPHERE_ASSERT(index < this->table_size);
/* Set the entry. */
Entry *entry = std::addressof(this->table[index]);
MESOSPHERE_ASSERT(entry->GetObject() == nullptr);
entry->SetUsed(obj, linear_id, type);
obj->Open();
}
}

View file

@ -18,36 +18,53 @@
namespace ams::kern {
void NotifyAvailable() {
MESOSPHERE_ASSERT_THIS();
/* TODO: Implement this. */
MESOSPHERE_ABORT();
}
void NotifyAbort(Result abort_reason) {
MESOSPHERE_ASSERT_THIS();
/* TODO: Implement this. */
MESOSPHERE_ABORT();
}
void KSynchronizationObject::Finalize() {
MESOSPHERE_ASSERT_THIS();
this->OnFinalizeSynchronizationObject();
KAutoObject::Finalize();
}
void KSynchronizationObject::DebugWaiters() {
MESOSPHERE_ASSERT_THIS();
/* TODO: Do useful debug operation here. */
}
KSynchronizationObject::iterator KSynchronizationObject::AddWaiterThread(KThread *thread) {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.insert(this->thread_list.end(), *thread);
}
KSynchronizationObject::iterator KSynchronizationObject::RemoveWaiterThread(KSynchronizationObject::iterator it) {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.erase(it);
}
KSynchronizationObject::iterator KSynchronizationObject::begin() {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.begin();
}
KSynchronizationObject::iterator KSynchronizationObject::end() {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.end();
}

View file

@ -15,7 +15,7 @@
*/
#pragma once
#include "../results.hpp"
#include <vapours/results.hpp>
namespace ams::svc {
@ -28,6 +28,31 @@ namespace ams::svc {
#error "Unknown target for svc::Handle"
#endif
enum class PseudoHandle : Handle {
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
constexpr ALWAYS_INLINE bool operator==(const Handle &lhs, const PseudoHandle &rhs) {
return static_cast<Handle>(lhs) == static_cast<Handle>(rhs);
}
constexpr ALWAYS_INLINE bool operator==(const PseudoHandle &lhs, const Handle &rhs) {
return static_cast<Handle>(lhs) == static_cast<Handle>(rhs);
}
constexpr ALWAYS_INLINE bool operator!=(const Handle &lhs, const PseudoHandle &rhs) {
return !(lhs == rhs);
}
constexpr ALWAYS_INLINE bool operator!=(const PseudoHandle &lhs, const Handle &rhs) {
return !(lhs == rhs);
}
constexpr ALWAYS_INLINE bool IsPseudoHandle(const Handle &handle) {
return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread;
}
#ifdef ATMOSPHERE_ARCH_ARM64