Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
ServerDomainManager::Domain::~Domain() {
|
||||
while (!m_entries.empty()) {
|
||||
Entry *entry = std::addressof(m_entries.front());
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == this);
|
||||
entry->owner = nullptr;
|
||||
}
|
||||
entry->object.Reset();
|
||||
m_entries.pop_front();
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::DisposeImpl() {
|
||||
ServerDomainManager *manager = m_manager;
|
||||
std::destroy_at(this);
|
||||
manager->FreeDomain(this);
|
||||
}
|
||||
|
||||
Result ServerDomainManager::Domain::ReserveIds(DomainObjectId *out_ids, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Entry *entry = m_manager->m_entry_manager.AllocateEntry();
|
||||
R_UNLESS(entry != nullptr, sf::cmif::ResultOutOfDomainEntries());
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
out_ids[i] = m_manager->m_entry_manager.GetId(entry);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::ReserveSpecificIds(const DomainObjectId *ids, size_t count) {
|
||||
m_manager->m_entry_manager.AllocateSpecificEntries(ids, count);
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::UnreserveIds(const DomainObjectId *ids, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(ids[i]);
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
entry->owner = this;
|
||||
m_entries.push_back(*entry);
|
||||
}
|
||||
entry->object = std::move(obj);
|
||||
}
|
||||
|
||||
ServiceObjectHolder ServerDomainManager::Domain::UnregisterObject(DomainObjectId id) {
|
||||
ServiceObjectHolder obj;
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
if (entry == nullptr) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
if (entry->owner != this) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
entry->owner = nullptr;
|
||||
obj = std::move(entry->object);
|
||||
m_entries.erase(m_entries.iterator_to(*entry));
|
||||
}
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
return obj;
|
||||
}
|
||||
|
||||
ServiceObjectHolder ServerDomainManager::Domain::GetObject(DomainObjectId id) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
if (entry == nullptr) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
if (entry->owner != this) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
}
|
||||
return entry->object.Clone();
|
||||
}
|
||||
|
||||
ServerDomainManager::EntryManager::EntryManager(DomainEntryStorage *entry_storage, size_t entry_count) : m_lock() {
|
||||
m_entries = reinterpret_cast<Entry *>(entry_storage);
|
||||
m_num_entries = entry_count;
|
||||
for (size_t i = 0; i < m_num_entries; i++) {
|
||||
m_free_list.push_back(*std::construct_at(m_entries + i));
|
||||
}
|
||||
}
|
||||
|
||||
ServerDomainManager::EntryManager::~EntryManager() {
|
||||
for (size_t i = 0; i < m_num_entries; i++) {
|
||||
std::destroy_at(m_entries + i);
|
||||
}
|
||||
}
|
||||
|
||||
ServerDomainManager::Entry *ServerDomainManager::EntryManager::AllocateEntry() {
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
if (m_free_list.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Entry *e = std::addressof(m_free_list.front());
|
||||
m_free_list.pop_front();
|
||||
return e;
|
||||
}
|
||||
|
||||
void ServerDomainManager::EntryManager::FreeEntry(Entry *entry) {
|
||||
std::scoped_lock lk(m_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
AMS_ABORT_UNLESS(!entry->object);
|
||||
m_free_list.push_front(*entry);
|
||||
}
|
||||
|
||||
void ServerDomainManager::EntryManager::AllocateSpecificEntries(const DomainObjectId *ids, size_t count) {
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
/* Allocate new IDs. */
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto id = ids[i];
|
||||
Entry *entry = this->GetEntry(id);
|
||||
if (id != InvalidDomainObjectId) {
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
m_free_list.erase(m_free_list.iterator_to(*entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
R_RETURN(this->ProcessMessageImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data));
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
R_RETURN(this->ProcessMessageForMitmImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data));
|
||||
}
|
||||
#endif
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
R_UNLESS(static_cast<bool>(target_object), sf::cmif::ResultTargetNotFound());
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), sf::cmif::ResultInvalidNumInObjects());
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = std::addressof(domain_processor);
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(std::addressof(domain_processor));
|
||||
}
|
||||
ctx.srv_obj = target_object.GetServiceObjectUnsafe();
|
||||
R_RETURN(target_object.ProcessMessage(ctx, in_message_raw_data));
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
/* TODO: N doesn't error check here. Should we? */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
R_SUCCEED();
|
||||
default:
|
||||
R_THROW(sf::cmif::ResultInvalidInHeader());
|
||||
}
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* Mitm. If we don't have a target object, we should forward to let the server handle. */
|
||||
if (!target_object) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), sf::cmif::ResultInvalidNumInObjects());
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = std::addressof(domain_processor);
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(std::addressof(domain_processor));
|
||||
}
|
||||
ctx.srv_obj = target_object.GetServiceObjectUnsafe();
|
||||
R_RETURN(target_object.ProcessMessage(ctx, in_message_raw_data));
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* If the object is not in the domain, tell the server to close it. */
|
||||
if (!target_object) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* If the object is in the domain, close our copy of it. Mitm objects are required to close their associated domain id, so this shouldn't cause desynch. */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
R_SUCCEED();
|
||||
}
|
||||
default:
|
||||
R_THROW(sf::cmif::ResultInvalidInHeader());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Result DomainServiceObjectProcessor::PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const {
|
||||
/* Validate in object count. */
|
||||
R_UNLESS(m_impl_metadata.GetInObjectCount() == this->GetInObjectCount(), sf::cmif::ResultInvalidNumInObjects());
|
||||
|
||||
/* Nintendo reserves domain object IDs here. We do this later, to support mitm semantics. */
|
||||
|
||||
/* Pass onwards. */
|
||||
R_RETURN(m_impl_processor->PrepareForProcess(ctx, runtime_metadata));
|
||||
}
|
||||
|
||||
Result DomainServiceObjectProcessor::GetInObjects(ServiceObjectHolder *in_objects) const {
|
||||
for (size_t i = 0; i < this->GetInObjectCount(); i++) {
|
||||
in_objects[i] = m_domain->GetObject(m_in_object_ids[i]);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
HipcRequest DomainServiceObjectProcessor::PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
HipcRequest request = m_impl_processor->PrepareForReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_data_total_size = this->GetImplOutDataTotalSize();
|
||||
AMS_ABORT_UNLESS(out_header_size + impl_out_data_total_size + sizeof(DomainObjectId) * this->GetOutObjectCount() <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = static_cast<u32>(this->GetOutObjectCount()), };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
m_out_object_ids = reinterpret_cast<DomainObjectId *>(out_raw_data.GetAddress() + impl_out_data_total_size);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
m_impl_processor->PrepareForErrorReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_headers_size = this->GetImplOutHeadersSize();
|
||||
AMS_ABORT_UNLESS(out_header_size + impl_out_headers_size <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = 0, };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
|
||||
/* Nintendo unreserves domain entries here, but we haven't reserved them yet. */
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *selected_ids) {
|
||||
AMS_UNUSED(ctx, response);
|
||||
|
||||
const size_t num_out_objects = this->GetOutObjectCount();
|
||||
|
||||
/* Copy input object IDs from command impl (normally these are Invalid, in mitm they should be set). */
|
||||
DomainObjectId object_ids[8];
|
||||
bool is_reserved[8];
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
object_ids[i] = selected_ids[i];
|
||||
is_reserved[i] = false;
|
||||
}
|
||||
|
||||
/* Reserve object IDs as necessary. */
|
||||
{
|
||||
DomainObjectId reservations[8];
|
||||
{
|
||||
size_t num_unreserved_ids = 0;
|
||||
DomainObjectId specific_ids[8];
|
||||
size_t num_specific_ids = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
/* In the mitm case, we must not reserve IDs in use by other objects, so mitm objects will set this. */
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
num_unreserved_ids++;
|
||||
} else {
|
||||
specific_ids[num_specific_ids++] = object_ids[i];
|
||||
}
|
||||
}
|
||||
/* TODO: Can we make this error non-fatal? It isn't for N, since they can reserve IDs earlier due to not having to worry about mitm. */
|
||||
R_ABORT_UNLESS(m_domain->ReserveIds(reservations, num_unreserved_ids));
|
||||
m_domain->ReserveSpecificIds(specific_ids, num_specific_ids);
|
||||
}
|
||||
|
||||
size_t reservation_index = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
object_ids[i] = reservations[reservation_index++];
|
||||
is_reserved[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Actually set out objects. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (!out_objects[i]) {
|
||||
if (is_reserved[i]) {
|
||||
m_domain->UnreserveIds(object_ids + i, 1);
|
||||
}
|
||||
object_ids[i] = InvalidDomainObjectId;
|
||||
continue;
|
||||
}
|
||||
m_domain->RegisterObject(object_ids[i], std::move(out_objects[i]));
|
||||
}
|
||||
|
||||
/* Set out object IDs in message. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
m_out_object_ids[i] = object_ids[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
namespace cmif {
|
||||
|
||||
namespace {
|
||||
|
||||
#if !defined(ATMOSPHERE_COMPILER_CLANG)
|
||||
ALWAYS_INLINE util::AtomicRef<uintptr_t> GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
|
||||
return util::AtomicRef<uintptr_t>(*p);
|
||||
}
|
||||
#else
|
||||
ALWAYS_INLINE util::Atomic<uintptr_t> &GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
static_assert(sizeof(std::atomic<uintptr_t>) == sizeof(uintptr_t));
|
||||
static_assert(sizeof(util::Atomic<uintptr_t>) == sizeof(std::atomic<uintptr_t>));
|
||||
|
||||
return *reinterpret_cast<util::Atomic<uintptr_t> *>(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void OnSetInlineContext(os::ThreadType *thread) {
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
/* Ensure that libnx receives the priority value. */
|
||||
::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext(thread)));
|
||||
#else
|
||||
AMS_UNUSED(thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InlineContext GetInlineContext() {
|
||||
/* Get the context. */
|
||||
uintptr_t thread_context = GetAtomicSfInlineContext().Load();
|
||||
|
||||
/* Copy it out. */
|
||||
InlineContext ctx;
|
||||
static_assert(sizeof(ctx) <= sizeof(thread_context));
|
||||
std::memcpy(std::addressof(ctx), std::addressof(thread_context), sizeof(ctx));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
InlineContext SetInlineContext(InlineContext ctx) {
|
||||
/* Get current thread. */
|
||||
os::ThreadType * const cur_thread = os::GetCurrentThread();
|
||||
ON_SCOPE_EXIT { OnSetInlineContext(cur_thread); };
|
||||
|
||||
/* Create the new context. */
|
||||
static_assert(sizeof(ctx) <= sizeof(uintptr_t));
|
||||
uintptr_t new_context_value = 0;
|
||||
std::memcpy(std::addressof(new_context_value), std::addressof(ctx), sizeof(ctx));
|
||||
|
||||
/* Get the old context. */
|
||||
uintptr_t old_context_value = GetAtomicSfInlineContext(cur_thread).Exchange(new_context_value);
|
||||
|
||||
/* Convert and copy it out. */
|
||||
InlineContext old_ctx;
|
||||
std::memcpy(std::addressof(old_ctx), std::addressof(old_context_value), sizeof(old_ctx));
|
||||
return old_ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
#if !defined(ATMOSPHERE_COMPILER_CLANG)
|
||||
ALWAYS_INLINE util::AtomicRef<u8> GetAtomicFsInlineContext(os::ThreadType *thread) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
|
||||
return util::AtomicRef<u8>(*reinterpret_cast<u8 *>(p));
|
||||
}
|
||||
#else
|
||||
ALWAYS_INLINE util::Atomic<u8> &GetAtomicFsInlineContext(os::ThreadType *thread) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
static_assert(sizeof(std::atomic<u8>) == sizeof(u8));
|
||||
static_assert(sizeof(util::Atomic<u8>) == sizeof(std::atomic<u8>));
|
||||
|
||||
return *reinterpret_cast<util::Atomic<u8> *>(reinterpret_cast<u8 *>(p));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
u8 GetFsInlineContext(os::ThreadType *thread) {
|
||||
return GetAtomicFsInlineContext(thread).Load();
|
||||
}
|
||||
|
||||
u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx) {
|
||||
ON_SCOPE_EXIT { cmif::OnSetInlineContext(thread); };
|
||||
|
||||
return GetAtomicFsInlineContext(thread).Exchange(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline u32 InHeaderMagic = util::FourCC<'S','F','C','I'>::Code;
|
||||
constexpr inline u32 OutHeaderMagic = util::FourCC<'S','F','C','O'>::Code;
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
static_assert(InHeaderMagic == CMIF_IN_HEADER_MAGIC);
|
||||
static_assert(OutHeaderMagic == CMIF_OUT_HEADER_MAGIC);
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandlerByBinarySearch(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
/* Binary search for the handler. */
|
||||
ssize_t lo = 0;
|
||||
ssize_t hi = entry_count - 1;
|
||||
while (lo <= hi) {
|
||||
const size_t mid = (lo + hi) / 2;
|
||||
if (entries[mid].cmd_id < cmd_id) {
|
||||
lo = mid + 1;
|
||||
} else if (entries[mid].cmd_id > cmd_id) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
/* Find start. */
|
||||
size_t start = mid;
|
||||
while (start > 0 && entries[start - 1].cmd_id == cmd_id) {
|
||||
--start;
|
||||
}
|
||||
|
||||
/* Find end. */
|
||||
size_t end = mid + 1;
|
||||
while (end < entry_count && entries[end].cmd_id == cmd_id) {
|
||||
++end;
|
||||
}
|
||||
|
||||
for (size_t idx = start; idx < end; ++idx) {
|
||||
if (entries[idx].MatchesVersion(hos_version)) {
|
||||
return entries[idx].GetHandler();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandlerByLinearSearch(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
for (size_t i = 0; i < entry_count; ++i) {
|
||||
if (entries[i].Matches(cmd_id, hos_version)) {
|
||||
return entries[i].GetHandler();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandler(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
if (entry_count >= 8) {
|
||||
return FindCommandHandlerByBinarySearch(entries, entry_count, cmd_id, hos_version);
|
||||
} else {
|
||||
return FindCommandHandlerByLinearSearch(entries, entry_count, cmd_id, hos_version);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result impl::ServiceDispatchTableBase::ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const {
|
||||
/* Get versioning info. */
|
||||
const auto hos_version = hos::GetVersion();
|
||||
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||
|
||||
/* Parse the CMIF in header. */
|
||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
const auto cmd_handler = FindCommandHandler(entries, entry_count, cmd_id, hos_version);
|
||||
R_UNLESS(cmd_handler != nullptr, sf::cmif::ResultUnknownCommandId());
|
||||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* Forward any meta-context change result. */
|
||||
if (sf::impl::ResultRequestContextChanged::Includes(command_result)) {
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Otherwise, ensure that we're able to write the output header. */
|
||||
if (out_header == nullptr) {
|
||||
AMS_ABORT_UNLESS(R_FAILED(command_result));
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Write output header to raw data. */
|
||||
*out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), interface_id_for_debug};
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result impl::ServiceDispatchTableBase::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const {
|
||||
/* Get versioning info. */
|
||||
const auto hos_version = hos::GetVersion();
|
||||
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||
|
||||
/* Parse the CMIF in header. */
|
||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
const auto cmd_handler = FindCommandHandler(entries, entry_count, cmd_id, hos_version);
|
||||
|
||||
/* If we didn't find a handler, forward the request. */
|
||||
if (cmd_handler == nullptr) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* If we should, forward the request to the forward session. */
|
||||
if (sm::mitm::ResultShouldForwardToSession::Includes(command_result)) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* Forward any meta-context change result. */
|
||||
if (sf::impl::ResultRequestContextChanged::Includes(command_result)) {
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Otherwise, ensure that we're able to write the output header. */
|
||||
if (out_header == nullptr) {
|
||||
AMS_ABORT_UNLESS(R_FAILED(command_result));
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Write output header to raw data. */
|
||||
*out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), interface_id_for_debug};
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
Result ServiceObjectHolder::ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const auto ProcessHandler = m_dispatch_meta->ProcessHandler;
|
||||
const auto *DispatchTable = m_dispatch_meta->DispatchTable;
|
||||
return (DispatchTable->*ProcessHandler)(ctx, in_raw_data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *, os::NativeHandle) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::AttachMultiWaitHolderForAccept");
|
||||
}
|
||||
|
||||
void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *, os::NativeHandle) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::AttachMultiWaitHolderForAccept");
|
||||
}
|
||||
|
||||
Result Receive(ReceiveResult *, os::NativeHandle, const cmif::PointerAndSize &) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::Receive(ReceiveResult *, os::NativeHandle, const cmif::PointerAndSize &)");
|
||||
}
|
||||
|
||||
Result Receive(bool *, os::NativeHandle, const cmif::PointerAndSize &) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::Receive(bool *, os::NativeHandle, const cmif::PointerAndSize &)");
|
||||
}
|
||||
|
||||
Result Reply(os::NativeHandle, const cmif::PointerAndSize &) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::Reply");
|
||||
}
|
||||
|
||||
Result CreateSession(os::NativeHandle *, os::NativeHandle *) {
|
||||
AMS_ABORT("TODO: Generic ams::sf::hipc::CreateSession");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE Result ReceiveImpl(os::NativeHandle session_handle, void *message_buf, size_t message_buf_size) {
|
||||
s32 unused_index;
|
||||
if (message_buf == hipc::GetMessageBufferOnTls()) {
|
||||
/* Consider: AMS_ABORT_UNLESS(message_buf_size == TlsMessageBufferSize); */
|
||||
R_RETURN(svc::ReplyAndReceive(&unused_index, &session_handle, 1, svc::InvalidHandle, std::numeric_limits<u64>::max()));
|
||||
} else {
|
||||
R_RETURN(svc::ReplyAndReceiveWithUserBuffer(&unused_index, reinterpret_cast<uintptr_t>(message_buf), message_buf_size, &session_handle, 1, svc::InvalidHandle, std::numeric_limits<u64>::max()));
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReplyImpl(os::NativeHandle session_handle, void *message_buf, size_t message_buf_size) {
|
||||
s32 unused_index;
|
||||
if (message_buf == hipc::GetMessageBufferOnTls()) {
|
||||
/* Consider: AMS_ABORT_UNLESS(message_buf_size == TlsMessageBufferSize); */
|
||||
R_RETURN(svc::ReplyAndReceive(&unused_index, &session_handle, 0, session_handle, 0));
|
||||
} else {
|
||||
R_RETURN(svc::ReplyAndReceiveWithUserBuffer(&unused_index, reinterpret_cast<uintptr_t>(message_buf), message_buf_size, &session_handle, 0, session_handle, 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *holder, os::NativeHandle port) {
|
||||
return os::InitializeMultiWaitHolder(holder, port);
|
||||
}
|
||||
|
||||
void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *holder, os::NativeHandle request) {
|
||||
return os::InitializeMultiWaitHolder(holder, request);
|
||||
}
|
||||
|
||||
Result Receive(ReceiveResult *out_recv_result, os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer) {
|
||||
R_TRY_CATCH(ReceiveImpl(session_handle, message_buffer.GetPointer(), message_buffer.GetSize())) {
|
||||
R_CATCH(svc::ResultSessionClosed) {
|
||||
*out_recv_result = ReceiveResult::Closed;
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_CATCH(svc::ResultReceiveListBroken) {
|
||||
*out_recv_result = ReceiveResult::NeedsRetry;
|
||||
R_SUCCEED();
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
*out_recv_result = ReceiveResult::Success;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Receive(bool *out_closed, os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer) {
|
||||
R_TRY_CATCH(ReceiveImpl(session_handle, message_buffer.GetPointer(), message_buffer.GetSize())) {
|
||||
R_CATCH(svc::ResultSessionClosed) {
|
||||
*out_closed = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
*out_closed = false;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Reply(os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer) {
|
||||
R_TRY_CATCH(ReplyImpl(session_handle, message_buffer.GetPointer(), message_buffer.GetSize())) {
|
||||
R_CONVERT(svc::ResultTimedOut, ResultSuccess())
|
||||
R_CONVERT(svc::ResultSessionClosed, ResultSuccess())
|
||||
} R_END_TRY_CATCH;
|
||||
/* ReplyImpl should *always* return an error. */
|
||||
AMS_ABORT_UNLESS(false);
|
||||
}
|
||||
|
||||
Result CreateSession(os::NativeHandle *out_server_handle, os::NativeHandle *out_client_handle) {
|
||||
R_TRY_CATCH(svc::CreateSession(out_server_handle, out_client_handle, 0, 0)) {
|
||||
R_CONVERT(svc::ResultOutOfResource, sf::hipc::ResultOutOfSessions());
|
||||
} R_END_TRY_CATCH;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#include "sf_hipc_mitm_query_api.hpp"
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
|
||||
#define AMS_SF_HIPC_IMPL_I_MITM_QUERY_SERVICE_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 65000, void, ShouldMitm, (sf::Out<bool> out, const sm::MitmProcessInfo &client_info), (out, client_info))
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sf::hipc::impl, IMitmQueryService, AMS_SF_HIPC_IMPL_I_MITM_QUERY_SERVICE_INTERFACE_INFO, 0xEC6BE3FF)
|
||||
|
||||
namespace ams::sf::hipc::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
class MitmQueryService {
|
||||
private:
|
||||
const ServerManagerBase::MitmQueryFunction m_query_function;
|
||||
public:
|
||||
MitmQueryService(ServerManagerBase::MitmQueryFunction qf) : m_query_function(qf) { /* ... */ }
|
||||
|
||||
void ShouldMitm(sf::Out<bool> out, const sm::MitmProcessInfo &client_info) {
|
||||
*out = m_query_function(client_info);
|
||||
}
|
||||
};
|
||||
static_assert(IsIMitmQueryService<MitmQueryService>);
|
||||
|
||||
/* Globals. */
|
||||
constinit os::SdkMutex g_query_server_lock;
|
||||
constinit bool g_constructed_server = false;
|
||||
constinit bool g_registered_any = false;
|
||||
|
||||
void QueryServerProcessThreadMain(void *query_server) {
|
||||
reinterpret_cast<ServerManagerBase *>(query_server)->LoopProcess();
|
||||
}
|
||||
|
||||
alignas(os::ThreadStackAlignment) constinit u8 g_server_process_thread_stack[16_KB];
|
||||
constinit os::ThreadType g_query_server_process_thread;
|
||||
|
||||
constexpr size_t MaxServers = 0;
|
||||
util::TypedStorage<sf::hipc::ServerManager<MaxServers>> g_query_server_storage;
|
||||
|
||||
}
|
||||
|
||||
void RegisterMitmQueryHandle(os::NativeHandle query_handle, ServerManagerBase::MitmQueryFunction query_func) {
|
||||
std::scoped_lock lk(g_query_server_lock);
|
||||
|
||||
if (AMS_UNLIKELY(!g_constructed_server)) {
|
||||
util::ConstructAt(g_query_server_storage);
|
||||
g_constructed_server = true;
|
||||
}
|
||||
|
||||
/* TODO: Better object factory? */
|
||||
R_ABORT_UNLESS(GetReference(g_query_server_storage).RegisterSession(query_handle, cmif::ServiceObjectHolder(sf::CreateSharedObjectEmplaced<IMitmQueryService, MitmQueryService>(query_func))));
|
||||
|
||||
if (AMS_UNLIKELY(!g_registered_any)) {
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_query_server_process_thread), &QueryServerProcessThreadMain, GetPointer(g_query_server_storage), g_server_process_thread_stack, sizeof(g_server_process_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(mitm_sf, QueryServerProcessThread)));
|
||||
os::SetThreadNamePointer(std::addressof(g_query_server_process_thread), AMS_GET_SYSTEM_THREAD_NAME(mitm_sf, QueryServerProcessThread));
|
||||
os::StartThread(std::addressof(g_query_server_process_thread));
|
||||
g_registered_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::hipc::impl {
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
void RegisterMitmQueryHandle(os::NativeHandle query_handle, ServerManagerBase::MitmQueryFunction query_func);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#include "sf_i_hipc_manager.hpp"
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class HipcManagerImpl {
|
||||
private:
|
||||
ServerDomainSessionManager *m_manager;
|
||||
ServerSession *m_session;
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
const bool m_is_mitm_session;
|
||||
#endif
|
||||
private:
|
||||
Result CloneCurrentObjectImpl(sf::OutMoveHandle &out_client_handle, ServerSessionManager *tagged_manager) {
|
||||
/* Clone the object. */
|
||||
cmif::ServiceObjectHolder &&clone = m_session->m_srv_obj_holder.Clone();
|
||||
R_UNLESS(clone, sf::hipc::ResultDomainObjectNotFound());
|
||||
|
||||
/* Create new session handles. */
|
||||
os::NativeHandle server_handle, client_handle;
|
||||
R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle)));
|
||||
|
||||
/* Register with manager. */
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
if (!m_is_mitm_session) {
|
||||
#endif
|
||||
R_ABORT_UNLESS(tagged_manager->RegisterSession(server_handle, std::move(clone)));
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
} else {
|
||||
/* Check that we can create a mitm session. */
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
/* Clone the forward service. */
|
||||
std::shared_ptr<::Service> new_forward_service = ServerSession::CreateForwardService();
|
||||
R_ABORT_UNLESS(serviceClone(util::GetReference(m_session->m_forward_service).get(), new_forward_service.get()));
|
||||
R_ABORT_UNLESS(tagged_manager->RegisterMitmSession(server_handle, std::move(clone), std::move(new_forward_service)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set output client handle. */
|
||||
out_client_handle.SetValue(client_handle, false);
|
||||
R_SUCCEED();
|
||||
}
|
||||
public:
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s), m_is_mitm_session(s->IsMitmSession()) { /* ... */ }
|
||||
#else
|
||||
explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s) { /* ... */ }
|
||||
#endif
|
||||
|
||||
Result ConvertCurrentObjectToDomain(sf::Out<cmif::DomainObjectId> out) {
|
||||
/* Allocate a domain. */
|
||||
auto domain = m_manager->AllocateDomainServiceObject();
|
||||
R_UNLESS(domain, sf::hipc::ResultOutOfDomains());
|
||||
|
||||
/* Set up the new domain object. */
|
||||
cmif::DomainObjectId object_id = cmif::InvalidDomainObjectId;
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
if (m_is_mitm_session) {
|
||||
/* Check that we can create a mitm session. */
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
/* Make a new shared pointer to manage the allocated domain. */
|
||||
SharedPointer<cmif::MitmDomainServiceObject> cmif_domain(static_cast<cmif::MitmDomainServiceObject *>(domain), false);
|
||||
|
||||
/* Convert the remote session to domain. */
|
||||
AMS_ABORT_UNLESS(util::GetReference(m_session->m_forward_service)->own_handle);
|
||||
R_TRY(serviceConvertToDomain(util::GetReference(m_session->m_forward_service).get()));
|
||||
|
||||
/* The object ID reservation cannot fail here, as that would cause desynchronization from target domain. */
|
||||
object_id = cmif::DomainObjectId{util::GetReference(m_session->m_forward_service)->object_id};
|
||||
domain->ReserveSpecificIds(std::addressof(object_id), 1);
|
||||
|
||||
/* Register the object. */
|
||||
domain->RegisterObject(object_id, std::move(m_session->m_srv_obj_holder));
|
||||
|
||||
/* Set the new object holder. */
|
||||
m_session->m_srv_obj_holder = cmif::ServiceObjectHolder(std::move(cmif_domain));
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
/* Make a new shared pointer to manage the allocated domain. */
|
||||
SharedPointer<cmif::DomainServiceObject> cmif_domain(domain, false);
|
||||
|
||||
/* Reserve a new object in the domain. */
|
||||
R_TRY(domain->ReserveIds(std::addressof(object_id), 1));
|
||||
|
||||
/* Register the object. */
|
||||
domain->RegisterObject(object_id, std::move(m_session->m_srv_obj_holder));
|
||||
|
||||
/* Set the new object holder. */
|
||||
m_session->m_srv_obj_holder = cmif::ServiceObjectHolder(std::move(cmif_domain));
|
||||
}
|
||||
|
||||
/* Return the allocated id. */
|
||||
AMS_ABORT_UNLESS(object_id != cmif::InvalidDomainObjectId);
|
||||
*out = object_id;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CopyFromCurrentDomain(sf::OutMoveHandle out, cmif::DomainObjectId object_id) {
|
||||
/* Get domain. */
|
||||
auto domain = m_session->m_srv_obj_holder.GetServiceObject<cmif::DomainServiceObject>();
|
||||
R_UNLESS(domain != nullptr, sf::hipc::ResultTargetNotDomain());
|
||||
|
||||
/* Get domain object. */
|
||||
auto &&object = domain->GetObject(object_id);
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
if (!object) {
|
||||
R_UNLESS(m_is_mitm_session, sf::hipc::ResultDomainObjectNotFound());
|
||||
|
||||
/* Check that we can create a mitm session. */
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
os::NativeHandle handle;
|
||||
R_TRY(cmifCopyFromCurrentDomain(util::GetReference(m_session->m_forward_service)->session, object_id.value, std::addressof(handle)));
|
||||
|
||||
out.SetValue(handle, false);
|
||||
R_SUCCEED();
|
||||
}
|
||||
#else
|
||||
R_UNLESS(!!(object), sf::hipc::ResultDomainObjectNotFound());
|
||||
#endif
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
if (!m_is_mitm_session || (ServerManagerBase::CanAnyManageMitmServers() && object_id.value != serviceGetObjectId(util::GetReference(m_session->m_forward_service).get()))) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
/* Create new session handles. */
|
||||
os::NativeHandle server_handle, client_handle;
|
||||
R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle)));
|
||||
|
||||
/* Register. */
|
||||
R_ABORT_UNLESS(m_manager->RegisterSession(server_handle, std::move(object)));
|
||||
|
||||
/* Set output client handle. */
|
||||
out.SetValue(client_handle, false);
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
} else {
|
||||
/* Check that we can create a mitm session. */
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
/* Copy from the target domain. */
|
||||
os::NativeHandle new_forward_target;
|
||||
R_TRY(cmifCopyFromCurrentDomain(util::GetReference(m_session->m_forward_service)->session, object_id.value, std::addressof(new_forward_target)));
|
||||
|
||||
/* Create new session handles. */
|
||||
os::NativeHandle server_handle, client_handle;
|
||||
R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle)));
|
||||
|
||||
/* Register. */
|
||||
std::shared_ptr<::Service> new_forward_service = ServerSession::CreateForwardService();
|
||||
serviceCreate(new_forward_service.get(), new_forward_target);
|
||||
R_ABORT_UNLESS(m_manager->RegisterMitmSession(server_handle, std::move(object), std::move(new_forward_service)));
|
||||
|
||||
/* Set output client handle. */
|
||||
out.SetValue(client_handle, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CloneCurrentObject(sf::OutMoveHandle out) {
|
||||
R_RETURN(this->CloneCurrentObjectImpl(out, m_manager));
|
||||
}
|
||||
|
||||
void QueryPointerBufferSize(sf::Out<u16> out) {
|
||||
out.SetValue(m_session->m_pointer_buffer.GetSize());
|
||||
}
|
||||
|
||||
Result CloneCurrentObjectEx(sf::OutMoveHandle out, u32 tag) {
|
||||
R_RETURN(this->CloneCurrentObjectImpl(out, m_manager->GetSessionManagerByTag(tag)));
|
||||
}
|
||||
};
|
||||
static_assert(IsIHipcManager<HipcManagerImpl>);
|
||||
|
||||
}
|
||||
|
||||
Result ServerDomainSessionManager::DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) {
|
||||
/* Make a stack object, and pass a shared pointer to it to DispatchRequest. */
|
||||
/* Note: This is safe, as no additional references to the hipc manager can ever be stored. */
|
||||
/* The shared pointer to stack object is definitely gross, though. */
|
||||
UnmanagedServiceObject<impl::IHipcManager, impl::HipcManagerImpl> hipc_manager(this, session);
|
||||
R_RETURN(this->DispatchRequest(cmif::ServiceObjectHolder(hipc_manager.GetShared()), session, in_message, out_message));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#include "sf_hipc_mitm_query_api.hpp"
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result ServerManagerBase::InstallMitmServerImpl(os::NativeHandle *out_port_handle, sm::ServiceName service_name, ServerManagerBase::MitmQueryFunction query_func) {
|
||||
/* Install the Mitm. */
|
||||
os::NativeHandle query_handle = os::InvalidNativeHandle;
|
||||
R_TRY(sm::mitm::InstallMitm(out_port_handle, std::addressof(query_handle), service_name));
|
||||
|
||||
/* Register the query handle. */
|
||||
impl::RegisterMitmQueryHandle(query_handle, query_func);
|
||||
|
||||
/* Clear future declarations if any, now that our query handler is present. */
|
||||
R_ABORT_UNLESS(sm::mitm::ClearFutureMitm(service_name));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ServerManagerBase::RegisterServerSessionToWait(ServerSession *session) {
|
||||
session->m_has_received = false;
|
||||
|
||||
/* Set user data tag. */
|
||||
os::SetMultiWaitHolderUserData(session, static_cast<uintptr_t>(UserDataTag::Session));
|
||||
|
||||
this->LinkToDeferredList(session);
|
||||
}
|
||||
|
||||
void ServerManagerBase::LinkToDeferredList(os::MultiWaitHolderType *holder) {
|
||||
std::scoped_lock lk(m_deferred_list_mutex);
|
||||
os::LinkMultiWaitHolder(std::addressof(m_deferred_list), holder);
|
||||
m_notify_event.Signal();
|
||||
}
|
||||
|
||||
void ServerManagerBase::LinkDeferred() {
|
||||
std::scoped_lock lk(m_deferred_list_mutex);
|
||||
os::MoveAllMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_deferred_list));
|
||||
}
|
||||
|
||||
os::MultiWaitHolderType *ServerManagerBase::WaitSignaled() {
|
||||
std::scoped_lock lk(m_selection_mutex);
|
||||
while (true) {
|
||||
this->LinkDeferred();
|
||||
auto selected = os::WaitAny(std::addressof(m_multi_wait));
|
||||
if (selected == std::addressof(m_request_stop_event_holder)) {
|
||||
return nullptr;
|
||||
} else if (selected == std::addressof(m_notify_event_holder)) {
|
||||
m_notify_event.Clear();
|
||||
} else {
|
||||
os::UnlinkMultiWaitHolder(selected);
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManagerBase::ResumeProcessing() {
|
||||
m_request_stop_event.Clear();
|
||||
}
|
||||
|
||||
void ServerManagerBase::RequestStopProcessing() {
|
||||
m_request_stop_event.Signal();
|
||||
}
|
||||
|
||||
void ServerManagerBase::AddUserMultiWaitHolder(os::MultiWaitHolderType *holder) {
|
||||
const auto user_data_tag = static_cast<UserDataTag>(os::GetMultiWaitHolderUserData(holder));
|
||||
AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Server);
|
||||
AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Session);
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
AMS_ABORT_UNLESS(user_data_tag != UserDataTag::MitmServer);
|
||||
#endif
|
||||
this->LinkToDeferredList(holder);
|
||||
}
|
||||
|
||||
Result ServerManagerBase::ProcessForServer(os::MultiWaitHolderType *holder) {
|
||||
AMS_ABORT_UNLESS(static_cast<UserDataTag>(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::Server);
|
||||
|
||||
Server *server = static_cast<Server *>(holder);
|
||||
ON_SCOPE_EXIT { this->LinkToDeferredList(server); };
|
||||
|
||||
/* Create new session. */
|
||||
if (server->m_static_object) {
|
||||
R_RETURN(this->AcceptSession(server->m_port_handle, server->m_static_object.Clone()));
|
||||
} else {
|
||||
R_RETURN(this->OnNeedsToAccept(server->m_index, server));
|
||||
}
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result ServerManagerBase::ProcessForMitmServer(os::MultiWaitHolderType *holder) {
|
||||
AMS_ABORT_UNLESS(static_cast<UserDataTag>(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::MitmServer);
|
||||
|
||||
Server *server = static_cast<Server *>(holder);
|
||||
ON_SCOPE_EXIT { this->LinkToDeferredList(server); };
|
||||
|
||||
/* Create resources for new session. */
|
||||
R_RETURN(this->OnNeedsToAccept(server->m_index, server));
|
||||
}
|
||||
#endif
|
||||
|
||||
Result ServerManagerBase::ProcessForSession(os::MultiWaitHolderType *holder) {
|
||||
AMS_ABORT_UNLESS(static_cast<UserDataTag>(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::Session);
|
||||
|
||||
ServerSession *session = static_cast<ServerSession *>(holder);
|
||||
|
||||
cmif::PointerAndSize tls_message(hipc::GetMessageBufferOnTls(), hipc::TlsMessageBufferSize);
|
||||
if (this->CanDeferInvokeRequest()) {
|
||||
const cmif::PointerAndSize &saved_message = session->m_saved_message;
|
||||
AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize());
|
||||
|
||||
if (!session->m_has_received) {
|
||||
R_TRY(this->ReceiveRequest(session, tls_message));
|
||||
session->m_has_received = true;
|
||||
std::memcpy(saved_message.GetPointer(), tls_message.GetPointer(), tls_message.GetSize());
|
||||
} else {
|
||||
/* We were deferred and are re-receiving, so just memcpy. */
|
||||
std::memcpy(tls_message.GetPointer(), saved_message.GetPointer(), tls_message.GetSize());
|
||||
}
|
||||
|
||||
/* Treat a meta "Context Invalidated" message as a success. */
|
||||
R_TRY_CATCH(this->ProcessRequest(session, tls_message)) {
|
||||
R_CONVERT(sf::impl::ResultRequestInvalidated, ResultSuccess());
|
||||
} R_END_TRY_CATCH;
|
||||
} else {
|
||||
if (!session->m_has_received) {
|
||||
R_TRY(this->ReceiveRequest(session, tls_message));
|
||||
session->m_has_received = true;
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
if (this->CanManageMitmServers()) {
|
||||
const cmif::PointerAndSize &saved_message = session->m_saved_message;
|
||||
AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize());
|
||||
|
||||
std::memcpy(saved_message.GetPointer(), tls_message.GetPointer(), tls_message.GetSize());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
R_TRY_CATCH(this->ProcessRequest(session, tls_message)) {
|
||||
R_CATCH(sf::ResultRequestDeferred) { AMS_ABORT("Request Deferred on server which does not support deferral"); }
|
||||
R_CATCH(sf::impl::ResultRequestInvalidated) { AMS_ABORT("Request Invalidated on server which does not support deferral"); }
|
||||
} R_END_TRY_CATCH;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerManagerBase::Process(os::MultiWaitHolderType *holder) {
|
||||
switch (static_cast<UserDataTag>(os::GetMultiWaitHolderUserData(holder))) {
|
||||
case UserDataTag::Server:
|
||||
R_RETURN(this->ProcessForServer(holder));
|
||||
case UserDataTag::Session:
|
||||
R_RETURN(this->ProcessForSession(holder));
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
case UserDataTag::MitmServer:
|
||||
AMS_ABORT_UNLESS(this->CanManageMitmServers());
|
||||
R_RETURN(this->ProcessForMitmServer(holder));
|
||||
#endif
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerManagerBase::WaitAndProcessImpl() {
|
||||
if (auto *signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) {
|
||||
R_ABORT_UNLESS(this->Process(signaled_holder));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManagerBase::WaitAndProcess() {
|
||||
this->WaitAndProcessImpl();
|
||||
}
|
||||
|
||||
void ServerManagerBase::LoopProcess() {
|
||||
while (this->WaitAndProcessImpl()) {
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
namespace {
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
constexpr inline void PreProcessCommandBufferForMitm(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &pointer_buffer, uintptr_t cmd_buffer) {
|
||||
/* TODO: Less gross method of editing command buffer? */
|
||||
if (ctx.request.meta.send_pid) {
|
||||
constexpr u64 MitmProcessIdTag = 0xFFFE000000000000ul;
|
||||
constexpr u64 OldProcessIdMask = 0x0000FFFFFFFFFFFFul;
|
||||
u64 *process_id = reinterpret_cast<u64 *>(cmd_buffer + sizeof(HipcHeader) + sizeof(HipcSpecialHeader));
|
||||
*process_id = (MitmProcessIdTag) | (*process_id & OldProcessIdMask);
|
||||
}
|
||||
|
||||
if (ctx.request.meta.num_recv_statics) {
|
||||
/* TODO: Can we do this without gross bit-hackery? */
|
||||
reinterpret_cast<HipcHeader *>(cmd_buffer)->recv_static_mode = 2;
|
||||
const uintptr_t old_recv_list_entry = reinterpret_cast<uintptr_t>(ctx.request.data.recv_list);
|
||||
const size_t old_recv_list_offset = old_recv_list_entry - util::AlignDown(old_recv_list_entry, TlsMessageBufferSize);
|
||||
*reinterpret_cast<HipcRecvListEntry *>(cmd_buffer + old_recv_list_offset) = hipcMakeRecvStatic(pointer_buffer.GetPointer(), pointer_buffer.GetSize());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result ServerSession::ForwardRequest(const cmif::ServiceDispatchContext &ctx) const {
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
AMS_ABORT_UNLESS(this->IsMitmSession());
|
||||
|
||||
/* TODO: Support non-TLS messages? */
|
||||
AMS_ABORT_UNLESS(m_saved_message.GetPointer() != nullptr);
|
||||
AMS_ABORT_UNLESS(m_saved_message.GetSize() == TlsMessageBufferSize);
|
||||
|
||||
/* Get TLS message buffer. */
|
||||
u32 * const message_buffer = static_cast<u32 *>(hipc::GetMessageBufferOnTls());
|
||||
|
||||
/* Copy saved TLS in. */
|
||||
std::memcpy(message_buffer, m_saved_message.GetPointer(), m_saved_message.GetSize());
|
||||
|
||||
/* Prepare buffer. */
|
||||
PreProcessCommandBufferForMitm(ctx, m_pointer_buffer, reinterpret_cast<uintptr_t>(message_buffer));
|
||||
|
||||
/* Dispatch forwards. */
|
||||
R_TRY(svc::SendSyncRequest(util::GetReference(m_forward_service)->session));
|
||||
|
||||
/* Parse, to ensure we catch any copy handles and close them. */
|
||||
{
|
||||
const auto response = hipcParseResponse(message_buffer);
|
||||
if (response.num_copy_handles) {
|
||||
ctx.handles_to_close->num_handles = response.num_copy_handles;
|
||||
for (size_t i = 0; i < response.num_copy_handles; i++) {
|
||||
ctx.handles_to_close->handles[i] = response.copy_handles[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ServerSessionManager::DestroySession(ServerSession *session) {
|
||||
/* Destroy object. */
|
||||
std::destroy_at(session);
|
||||
|
||||
/* Free object memory. */
|
||||
this->FreeSession(session);
|
||||
}
|
||||
|
||||
void ServerSessionManager::CloseSessionImpl(ServerSession *session) {
|
||||
const auto session_handle = session->m_session_handle;
|
||||
os::FinalizeMultiWaitHolder(session);
|
||||
this->DestroySession(session);
|
||||
os::CloseNativeHandle(session_handle);
|
||||
}
|
||||
|
||||
Result ServerSessionManager::RegisterSessionImpl(ServerSession *session_memory, os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
/* Create session object. */
|
||||
std::construct_at(session_memory, session_handle, std::forward<cmif::ServiceObjectHolder>(obj));
|
||||
|
||||
/* Assign session resources. */
|
||||
session_memory->m_pointer_buffer = this->GetSessionPointerBuffer(session_memory);
|
||||
session_memory->m_saved_message = this->GetSessionSavedMessageBuffer(session_memory);
|
||||
|
||||
/* Register to wait list. */
|
||||
this->RegisterServerSessionToWait(session_memory);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerSessionManager::AcceptSessionImpl(ServerSession *session_memory, os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
/* Create session handle. */
|
||||
os::NativeHandle session_handle;
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
R_TRY(svc::AcceptSession(std::addressof(session_handle), port_handle));
|
||||
#else
|
||||
AMS_UNUSED(port_handle);
|
||||
AMS_ABORT("TODO");
|
||||
#endif
|
||||
|
||||
auto session_guard = SCOPE_GUARD { os::CloseNativeHandle(session_handle); };
|
||||
|
||||
/* Register session. */
|
||||
R_TRY(this->RegisterSessionImpl(session_memory, session_handle, std::forward<cmif::ServiceObjectHolder>(obj)));
|
||||
|
||||
session_guard.Cancel();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result ServerSessionManager::RegisterMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
/* Create session object. */
|
||||
std::construct_at(session_memory, mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv));
|
||||
|
||||
/* Assign session resources. */
|
||||
session_memory->m_pointer_buffer = this->GetSessionPointerBuffer(session_memory);
|
||||
session_memory->m_saved_message = this->GetSessionSavedMessageBuffer(session_memory);
|
||||
|
||||
/* Validate session pointer buffer. */
|
||||
AMS_ABORT_UNLESS(session_memory->m_pointer_buffer.GetSize() >= util::GetReference(session_memory->m_forward_service)->pointer_buffer_size);
|
||||
session_memory->m_pointer_buffer = cmif::PointerAndSize(session_memory->m_pointer_buffer.GetAddress(), util::GetReference(session_memory->m_forward_service)->pointer_buffer_size);
|
||||
|
||||
/* Register to wait list. */
|
||||
this->RegisterServerSessionToWait(session_memory);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerSessionManager::AcceptMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
|
||||
|
||||
/* Create session handle. */
|
||||
os::NativeHandle mitm_session_handle;
|
||||
R_TRY(svc::AcceptSession(std::addressof(mitm_session_handle), mitm_port_handle));
|
||||
|
||||
auto session_guard = SCOPE_GUARD { os::CloseNativeHandle(mitm_session_handle); };
|
||||
|
||||
/* Register session. */
|
||||
R_TRY(this->RegisterMitmSessionImpl(session_memory, mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv)));
|
||||
|
||||
session_guard.Cancel();
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
Result ServerSessionManager::RegisterSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
/* We don't actually care about what happens to the session. It'll get linked. */
|
||||
ServerSession *session_ptr = nullptr;
|
||||
R_RETURN(this->RegisterSession(std::addressof(session_ptr), session_handle, std::forward<cmif::ServiceObjectHolder>(obj)));
|
||||
}
|
||||
|
||||
Result ServerSessionManager::AcceptSession(os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
/* We don't actually care about what happens to the session. It'll get linked. */
|
||||
ServerSession *session_ptr = nullptr;
|
||||
R_RETURN(this->AcceptSession(std::addressof(session_ptr), port_handle, std::forward<cmif::ServiceObjectHolder>(obj)));
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result ServerSessionManager::RegisterMitmSession(os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
/* We don't actually care about what happens to the session. It'll get linked. */
|
||||
ServerSession *session_ptr = nullptr;
|
||||
R_RETURN(this->RegisterMitmSession(std::addressof(session_ptr), mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv)));
|
||||
}
|
||||
|
||||
Result ServerSessionManager::AcceptMitmSession(os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
/* We don't actually care about what happens to the session. It'll get linked. */
|
||||
ServerSession *session_ptr = nullptr;
|
||||
R_RETURN(this->AcceptMitmSession(std::addressof(session_ptr), mitm_port_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv)));
|
||||
}
|
||||
#endif
|
||||
|
||||
Result ServerSessionManager::ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message) {
|
||||
const cmif::PointerAndSize &pointer_buffer = session->m_pointer_buffer;
|
||||
|
||||
/* If the receive list is odd, we may need to receive repeatedly. */
|
||||
while (true) {
|
||||
if (pointer_buffer.GetPointer()) {
|
||||
hipcMakeRequestInline(message.GetPointer(),
|
||||
.type = CmifCommandType_Invalid,
|
||||
.num_recv_statics = HIPC_AUTO_RECV_STATIC,
|
||||
).recv_list[0] = hipcMakeRecvStatic(pointer_buffer.GetPointer(), pointer_buffer.GetSize());
|
||||
} else {
|
||||
hipcMakeRequestInline(message.GetPointer(),
|
||||
.type = CmifCommandType_Invalid,
|
||||
);
|
||||
}
|
||||
hipc::ReceiveResult recv_result;
|
||||
R_TRY(hipc::Receive(std::addressof(recv_result), session->m_session_handle, message));
|
||||
switch (recv_result) {
|
||||
case hipc::ReceiveResult::Success:
|
||||
session->m_is_closed = false;
|
||||
R_SUCCEED();
|
||||
case hipc::ReceiveResult::Closed:
|
||||
session->m_is_closed = true;
|
||||
R_SUCCEED();
|
||||
case hipc::ReceiveResult::NeedsRetry:
|
||||
continue;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE u32 GetCmifCommandType(const cmif::PointerAndSize &message) {
|
||||
HipcHeader hdr = {};
|
||||
__builtin_memcpy(std::addressof(hdr), message.GetPointer(), sizeof(hdr));
|
||||
return hdr.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result ServerSessionManager::ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message) {
|
||||
if (session->m_is_closed) {
|
||||
this->CloseSessionImpl(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
switch (GetCmifCommandType(message)) {
|
||||
case CmifCommandType_Close:
|
||||
{
|
||||
this->CloseSessionImpl(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
default:
|
||||
{
|
||||
R_TRY_CATCH(this->ProcessRequestImpl(session, message, message)) {
|
||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged) /* A meta message changing the request context has been sent. */
|
||||
R_CATCH_ALL() {
|
||||
/* All other results indicate something went very wrong. */
|
||||
this->CloseSessionImpl(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* We succeeded, so we can process future messages on this session. */
|
||||
this->RegisterServerSessionToWait(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerSessionManager::ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) {
|
||||
/* TODO: Inline context support, retrieve from raw data + 0xC. */
|
||||
const auto cmif_command_type = GetCmifCommandType(in_message);
|
||||
|
||||
const auto GetInlineContext = [&]() -> cmif::InlineContext {
|
||||
cmif::InlineContext ret = {};
|
||||
switch (cmif_command_type) {
|
||||
case CmifCommandType_RequestWithContext:
|
||||
case CmifCommandType_ControlWithContext:
|
||||
if (in_message.GetSize() >= 0x10) {
|
||||
static_assert(sizeof(cmif::InlineContext) == 4);
|
||||
std::memcpy(std::addressof(ret), static_cast<u8 *>(in_message.GetPointer()) + 0xC, sizeof(ret));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
cmif::ScopedInlineContextChanger sicc(GetInlineContext());
|
||||
switch (cmif_command_type) {
|
||||
case CmifCommandType_Request:
|
||||
case CmifCommandType_RequestWithContext:
|
||||
R_RETURN(this->DispatchRequest(session->m_srv_obj_holder.Clone(), session, in_message, out_message));
|
||||
case CmifCommandType_Control:
|
||||
case CmifCommandType_ControlWithContext:
|
||||
R_RETURN(this->DispatchManagerRequest(session, in_message, out_message));
|
||||
default:
|
||||
R_THROW(sf::hipc::ResultUnknownCommandType());
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerSessionManager::DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) {
|
||||
/* This will get overridden by ... WithDomain class. */
|
||||
AMS_UNUSED(session, in_message, out_message);
|
||||
R_THROW(sf::ResultNotSupported());
|
||||
}
|
||||
|
||||
Result ServerSessionManager::DispatchRequest(cmif::ServiceObjectHolder &&obj_holder, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) {
|
||||
/* Create request context. */
|
||||
cmif::HandlesToClose handles_to_close = {};
|
||||
cmif::ServiceDispatchContext dispatch_ctx = {
|
||||
.srv_obj = obj_holder.GetServiceObjectUnsafe(),
|
||||
.manager = this,
|
||||
.session = session,
|
||||
.processor = nullptr, /* Filled in by template implementations. */
|
||||
.handles_to_close = std::addressof(handles_to_close),
|
||||
.pointer_buffer = session->m_pointer_buffer,
|
||||
.in_message_buffer = in_message,
|
||||
.out_message_buffer = out_message,
|
||||
.request = hipcParseRequest(in_message.GetPointer()),
|
||||
};
|
||||
|
||||
/* Validate message sizes. */
|
||||
const uintptr_t in_message_buffer_end = in_message.GetAddress() + in_message.GetSize();
|
||||
const uintptr_t in_raw_addr = reinterpret_cast<uintptr_t>(dispatch_ctx.request.data.data_words);
|
||||
const size_t in_raw_size = dispatch_ctx.request.meta.num_data_words * sizeof(u32);
|
||||
/* Note: Nintendo does not validate this size before subtracting 0x10 from it. This is not exploitable. */
|
||||
R_UNLESS(in_raw_size >= 0x10, sf::hipc::ResultInvalidRequestSize());
|
||||
R_UNLESS(in_raw_addr + in_raw_size <= in_message_buffer_end, sf::hipc::ResultInvalidRequestSize());
|
||||
const size_t recv_list_size = dispatch_ctx.request.meta.num_recv_statics == HIPC_AUTO_RECV_STATIC ? 1 : dispatch_ctx.request.meta.num_recv_statics;
|
||||
const uintptr_t recv_list_end = reinterpret_cast<uintptr_t>(dispatch_ctx.request.data.recv_list + recv_list_size);
|
||||
R_UNLESS(recv_list_end <= in_message_buffer_end, sf::hipc::ResultInvalidRequestSize());
|
||||
|
||||
/* CMIF has 0x10 of padding in raw data, and requires 0x10 alignment. */
|
||||
const cmif::PointerAndSize in_raw_data(util::AlignUp(in_raw_addr, 0x10), in_raw_size - 0x10);
|
||||
|
||||
/* Invoke command handler. */
|
||||
R_TRY(obj_holder.ProcessMessage(dispatch_ctx, in_raw_data));
|
||||
|
||||
/* Reply. */
|
||||
{
|
||||
ON_SCOPE_EXIT {
|
||||
for (size_t i = 0; i < handles_to_close.num_handles; i++) {
|
||||
os::CloseNativeHandle(handles_to_close.handles[i]);
|
||||
}
|
||||
};
|
||||
R_TRY(hipc::Reply(session->m_session_handle, out_message));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#pragma once
|
||||
|
||||
#define AMS_SF_HIPC_IMPL_I_HIPC_MANAGER_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ConvertCurrentObjectToDomain, (ams::sf::Out<ams::sf::cmif::DomainObjectId> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, CopyFromCurrentDomain, (ams::sf::OutMoveHandle out, ams::sf::cmif::DomainObjectId object_id), (out, object_id)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, CloneCurrentObject, (ams::sf::OutMoveHandle out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, void, QueryPointerBufferSize, (ams::sf::Out<u16> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, CloneCurrentObjectEx, (ams::sf::OutMoveHandle out, u32 tag), (out, tag))
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sf::hipc::impl, IHipcManager, AMS_SF_HIPC_IMPL_I_HIPC_MANAGER_INTERFACE_INFO, 0xEC6BE3FF)
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
namespace {
|
||||
|
||||
struct DefaultAllocatorImpl {
|
||||
os::SdkMutexType tls_lock;
|
||||
std::atomic_bool tls_allocated;
|
||||
os::TlsSlot current_mr_tls_slot;
|
||||
MemoryResource *default_mr;
|
||||
|
||||
void EnsureCurrentMemoryResourceTlsSlotInitialized() {
|
||||
if (!tls_allocated.load(std::memory_order_acquire)) {
|
||||
os::LockSdkMutex(std::addressof(tls_lock));
|
||||
if (!tls_allocated.load(std::memory_order_relaxed)) {
|
||||
R_ABORT_UNLESS(os::SdkAllocateTlsSlot(std::addressof(current_mr_tls_slot), nullptr));
|
||||
tls_allocated.store(true, std::memory_order_release);
|
||||
}
|
||||
os::UnlockSdkMutex(std::addressof(tls_lock));
|
||||
}
|
||||
}
|
||||
|
||||
MemoryResource *GetDefaultMemoryResource() {
|
||||
return default_mr;
|
||||
}
|
||||
|
||||
MemoryResource *SetDefaultMemoryResource(MemoryResource *mr) {
|
||||
return util::Exchange(std::addressof(default_mr), mr);
|
||||
}
|
||||
|
||||
MemoryResource *GetCurrentMemoryResource() {
|
||||
EnsureCurrentMemoryResourceTlsSlotInitialized();
|
||||
return reinterpret_cast<MemoryResource *>(os::GetTlsValue(current_mr_tls_slot));
|
||||
}
|
||||
|
||||
MemoryResource *SetCurrentMemoryResource(MemoryResource *mr) {
|
||||
EnsureCurrentMemoryResourceTlsSlotInitialized();
|
||||
auto ret = reinterpret_cast<MemoryResource *>(os::GetTlsValue(current_mr_tls_slot));
|
||||
os::SetTlsValue(current_mr_tls_slot, reinterpret_cast<uintptr_t>(mr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemoryResource *GetCurrentEffectiveMemoryResourceImpl() {
|
||||
if (auto mr = GetCurrentMemoryResource(); mr != nullptr) {
|
||||
return mr;
|
||||
}
|
||||
if (auto mr = GetGlobalDefaultMemoryResource(); mr != nullptr) {
|
||||
return mr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
constinit DefaultAllocatorImpl g_default_allocator_impl = {};
|
||||
|
||||
inline void *DefaultAllocate(size_t size, size_t align) {
|
||||
AMS_UNUSED(align);
|
||||
return ::operator new(size, std::nothrow);
|
||||
}
|
||||
|
||||
inline void DefaultDeallocate(void *ptr, size_t size, size_t align) {
|
||||
AMS_UNUSED(size, align);
|
||||
return ::operator delete(ptr, std::nothrow);
|
||||
}
|
||||
|
||||
class NewDeleteMemoryResource final : public MemoryResource {
|
||||
private:
|
||||
virtual void *AllocateImpl(size_t size, size_t alignment) override {
|
||||
return DefaultAllocate(size, alignment);
|
||||
}
|
||||
|
||||
virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override {
|
||||
return DefaultDeallocate(buffer, size, alignment);
|
||||
}
|
||||
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const override {
|
||||
return this == std::addressof(resource);
|
||||
}
|
||||
};
|
||||
|
||||
constinit NewDeleteMemoryResource g_new_delete_memory_resource;
|
||||
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
void *DefaultAllocateImpl(size_t size, size_t align, size_t offset) {
|
||||
auto mr = g_default_allocator_impl.GetCurrentEffectiveMemoryResourceImpl();
|
||||
auto h = mr != nullptr ? mr->allocate(size, align) : DefaultAllocate(size, align);
|
||||
if (h == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*static_cast<MemoryResource **>(h) = mr;
|
||||
return static_cast<u8 *>(h) + offset;
|
||||
}
|
||||
|
||||
void DefaultDeallocateImpl(void *ptr, size_t size, size_t align, size_t offset) {
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto h = static_cast<u8 *>(ptr) - offset;
|
||||
if (auto mr = *reinterpret_cast<MemoryResource **>(h); mr != nullptr) {
|
||||
return mr->deallocate(h, size, align);
|
||||
} else {
|
||||
return DefaultDeallocate(h, size, align);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MemoryResource *GetGlobalDefaultMemoryResource() {
|
||||
return g_default_allocator_impl.GetDefaultMemoryResource();
|
||||
}
|
||||
|
||||
MemoryResource *GetCurrentEffectiveMemoryResource() {
|
||||
if (auto mr = g_default_allocator_impl.GetCurrentEffectiveMemoryResourceImpl(); mr != nullptr) {
|
||||
return mr;
|
||||
}
|
||||
return GetNewDeleteMemoryResource();
|
||||
}
|
||||
|
||||
MemoryResource *GetCurrentMemoryResource() {
|
||||
return g_default_allocator_impl.GetCurrentMemoryResource();
|
||||
}
|
||||
|
||||
MemoryResource *GetNewDeleteMemoryResource() {
|
||||
return std::addressof(g_new_delete_memory_resource);
|
||||
}
|
||||
|
||||
MemoryResource *SetGlobalDefaultMemoryResource(MemoryResource *mr) {
|
||||
return g_default_allocator_impl.SetDefaultMemoryResource(mr);
|
||||
}
|
||||
|
||||
MemoryResource *SetCurrentMemoryResource(MemoryResource *mr) {
|
||||
return g_default_allocator_impl.SetCurrentMemoryResource(mr);
|
||||
}
|
||||
|
||||
ScopedCurrentMemoryResourceSetter::ScopedCurrentMemoryResourceSetter(MemoryResource *mr) : m_prev(g_default_allocator_impl.GetCurrentMemoryResource()) {
|
||||
os::SetTlsValue(g_default_allocator_impl.current_mr_tls_slot, reinterpret_cast<uintptr_t>(mr));
|
||||
}
|
||||
|
||||
ScopedCurrentMemoryResourceSetter::~ScopedCurrentMemoryResourceSetter() {
|
||||
os::SetTlsValue(g_default_allocator_impl.current_mr_tls_slot, reinterpret_cast<uintptr_t>(m_prev));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#include "../capsrv/server/decodersrv/decodersrv_decoder_control_service.hpp"
|
||||
#include "../lm/sf/lm_i_log_getter.hpp"
|
||||
#include "../lm/sf/lm_i_log_service.hpp"
|
||||
#include "../sf/hipc/sf_i_hipc_manager.hpp"
|
||||
#include "../sprofile/srv/sprofile_srv_i_service_getter.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 GenerateInterfaceIdFromName(const char *s) {
|
||||
/* Get the interface length. */
|
||||
const auto len = ams::util::Strlen(s);
|
||||
|
||||
/* Calculate the sha256. */
|
||||
u8 hash[ams::crypto::Sha256Generator::HashSize] = {};
|
||||
ams::crypto::GenerateSha256(hash, sizeof(hash), s, len);
|
||||
|
||||
/* Read it out as little endian. */
|
||||
u32 id = 0;
|
||||
for (size_t i = 0; i < sizeof(id); ++i) {
|
||||
id |= static_cast<u32>(hash[i]) << (BITSIZEOF(u8) * i);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static_assert(GenerateInterfaceIdFromName("nn::sf::hipc::detail::IHipcManager") == 0xEC6BE3FF);
|
||||
|
||||
constexpr void ConvertAtmosphereNameToNintendoName(char *dst, const char *src) {
|
||||
/* Determine src len. */
|
||||
const auto len = ams::util::Strlen(src);
|
||||
const auto *s = src;
|
||||
|
||||
/* Atmosphere names begin with ams::, Nintendo names begin with nn::. */
|
||||
AMS_ASSUME(src[0] == 'a');
|
||||
AMS_ASSUME(src[1] == 'm');
|
||||
AMS_ASSERT(src[2] == 's');
|
||||
dst[0] = 'n';
|
||||
dst[1] = 'n';
|
||||
src += 3;
|
||||
dst += 2;
|
||||
|
||||
/* Copy over. */
|
||||
while ((src - s) < len) {
|
||||
/* Atmosphere uses ::impl:: instead of ::detail::, ::IDeprecated* for deprecated services. */
|
||||
if (src[0] == ':' && src[1] == ':' && src[2] == 'i' && src[3] == 'm' && src[4] == 'p' && src[5] == 'l' && src[6] == ':' && src[7] == ':') {
|
||||
dst[0] = ':';
|
||||
dst[1] = ':';
|
||||
dst[2] = 'd';
|
||||
dst[3] = 'e';
|
||||
dst[4] = 't';
|
||||
dst[5] = 'a';
|
||||
dst[6] = 'i';
|
||||
dst[7] = 'l';
|
||||
|
||||
src += 6; /* ::impl */
|
||||
dst += 8; /* ::detail */
|
||||
} else if (src[0] == ':' && src[1] == ':' && src[2] == 'I' && src[3] == 'D' && src[4] == 'e' && src[5] == 'p' && src[6] == 'r' && src[7] == 'e' && src[8] == 'c' && src[9] == 'a' && src[10] == 't' && src[11] == 'e' && src[12] == 'd') {
|
||||
dst[0] = ':';
|
||||
dst[1] = ':';
|
||||
dst[2] = 'I';
|
||||
|
||||
src += 13; /* ::IDeprecated */
|
||||
dst += 3; /* ::I */
|
||||
} else {
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
constexpr u32 GenerateInterfaceIdFromAtmosphereName(const char *ams) {
|
||||
char nn[0x100] = {};
|
||||
ConvertAtmosphereNameToNintendoName(nn, ams);
|
||||
|
||||
return GenerateInterfaceIdFromName(nn);
|
||||
}
|
||||
|
||||
static_assert(GenerateInterfaceIdFromAtmosphereName("ams::sf::hipc::impl::IHipcManager") == GenerateInterfaceIdFromName("nn::sf::hipc::detail::IHipcManager"));
|
||||
|
||||
}
|
||||
|
||||
#define AMS_IMPL_CHECK_INTERFACE_ID(AMS_INTF) \
|
||||
static_assert(AMS_INTF::InterfaceIdForDebug == GenerateInterfaceIdFromAtmosphereName( #AMS_INTF ), #AMS_INTF)
|
||||
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::capsrv::sf::IDecoderControlService);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::erpt::sf::IAttachment);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::erpt::sf::IContext);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::erpt::sf::IManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::erpt::sf::IReport);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::erpt::sf::ISession);
|
||||
|
||||
static_assert(::ams::fatal::impl::IPrivateService::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::fatalsrv::IPrivateService")); // TODO: FIX-TO-MATCH
|
||||
static_assert(::ams::fatal::impl::IService::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::fatalsrv::IService")); // TODO: FIX-TO-MATCH
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IDirectory);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IFile);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IFileSystem);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IStorage);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IDeviceOperator);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IEventNotifier);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IFileSystemProxy);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IFileSystemProxyForLoader);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::fssrv::sf::IProgramRegistry);
|
||||
|
||||
static_assert(::ams::gpio::sf::IManager::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::gpio::IManager")); // TODO: FIX-TO-MATCH
|
||||
static_assert(::ams::gpio::sf::IPadSession::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::gpio::IPadSession")); // TODO: FIX-TO-MATCH
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::htc::tenv::IService);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::htc::tenv::IServiceManager);
|
||||
|
||||
static_assert(::ams::i2c::sf::IManager::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::i2c::IManager")); // TODO: FIX-TO-MATCH
|
||||
static_assert(::ams::i2c::sf::ISession::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::i2c::ISession")); // TODO: FIX-TO-MATCH
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ldr::impl::IDebugMonitorInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ldr::impl::IProcessManagerInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ldr::impl::IShellInterface);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lr::IAddOnContentLocationResolver);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lr::ILocationResolver);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lr::ILocationResolverManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lr::IRegisteredLocationResolver);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lm::ILogGetter);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lm::ILogger);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::lm::ILogService);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ncm::IContentManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ncm::IContentMetaDatabase);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ncm::IContentStorage);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ns::impl::IAsyncResult);
|
||||
|
||||
//AMS_IMPL_CHECK_INTERFACE_ID(ams::pgl::sf::IEventObserver);
|
||||
//AMS_IMPL_CHECK_INTERFACE_ID(ams::pgl::sf::IShellInterface);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IBootModeInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IDebugMonitorInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IDeprecatedDebugMonitorInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IInformationInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IShellInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::pm::impl::IDeprecatedShellInterface);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::psc::sf::IPmModule);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::psc::sf::IPmService);
|
||||
|
||||
static_assert(::ams::pwm::sf::IChannelSession::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::pwm::IChannelSession")); // TODO: FIX-TO-MATCH
|
||||
static_assert(::ams::pwm::sf::IManager::InterfaceIdForDebug == GenerateInterfaceIdFromName("nn::pwm::IManager")); // TODO: FIX-TO-MATCH
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ro::impl::IDebugMonitorInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::ro::impl::IRoInterface);
|
||||
|
||||
//AMS_IMPL_CHECK_INTERFACE_ID(ams::sf::hipc::impl::IMitmQueryService);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sf::hipc::impl::IHipcManager);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::ICryptoInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IDeprecatedGeneralInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IDeviceUniqueDataInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IEsInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IFsInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IGeneralInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IManuInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::IRandomInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::spl::impl::ISslInterface);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::IProfileControllerForDebug);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::IProfileImporter);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::IProfileReader);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::IProfileUpdateObserver);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::ISprofileServiceForBgAgent);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::ISprofileServiceForSystemProcess);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::sprofile::srv::IServiceGetter);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IDirectoryAccessor);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IFileAccessor);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IFileManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IDeprecatedFileManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IHtcsManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::IHtcManager);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::tma::ISocket);
|
||||
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::usb::ds::IDsEndpoint);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::usb::ds::IDsInterface);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::usb::ds::IDsService);
|
||||
AMS_IMPL_CHECK_INTERFACE_ID(ams::usb::ds::IDsRootSession);
|
||||
Reference in New Issue
Block a user