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