Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"

This reverts commit 15b7df8ef1.
This commit is contained in:
souldbminersmwc
2025-11-09 16:14:52 -05:00
parent 22ec140738
commit 21a3f953d7
3804 changed files with 435 additions and 570162 deletions

View File

@@ -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));
}
}
}
}

View File

@@ -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];
}
}
}

View File

@@ -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);
}
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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));
}
}

View File

@@ -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()) {
/* ... */
}
}
}

View File

@@ -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();
}
}

View File

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

View File

@@ -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));
}
}

View File

@@ -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);