Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
ServerDomainManager::Domain::~Domain() {
|
||||
while (!m_entries.empty()) {
|
||||
Entry *entry = std::addressof(m_entries.front());
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == this);
|
||||
entry->owner = nullptr;
|
||||
}
|
||||
entry->object.Reset();
|
||||
m_entries.pop_front();
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::DisposeImpl() {
|
||||
ServerDomainManager *manager = m_manager;
|
||||
std::destroy_at(this);
|
||||
manager->FreeDomain(this);
|
||||
}
|
||||
|
||||
Result ServerDomainManager::Domain::ReserveIds(DomainObjectId *out_ids, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Entry *entry = m_manager->m_entry_manager.AllocateEntry();
|
||||
R_UNLESS(entry != nullptr, sf::cmif::ResultOutOfDomainEntries());
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
out_ids[i] = m_manager->m_entry_manager.GetId(entry);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::ReserveSpecificIds(const DomainObjectId *ids, size_t count) {
|
||||
m_manager->m_entry_manager.AllocateSpecificEntries(ids, count);
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::UnreserveIds(const DomainObjectId *ids, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(ids[i]);
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
entry->owner = this;
|
||||
m_entries.push_back(*entry);
|
||||
}
|
||||
entry->object = std::move(obj);
|
||||
}
|
||||
|
||||
ServiceObjectHolder ServerDomainManager::Domain::UnregisterObject(DomainObjectId id) {
|
||||
ServiceObjectHolder obj;
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
if (entry == nullptr) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
if (entry->owner != this) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
entry->owner = nullptr;
|
||||
obj = std::move(entry->object);
|
||||
m_entries.erase(m_entries.iterator_to(*entry));
|
||||
}
|
||||
m_manager->m_entry_manager.FreeEntry(entry);
|
||||
return obj;
|
||||
}
|
||||
|
||||
ServiceObjectHolder ServerDomainManager::Domain::GetObject(DomainObjectId id) {
|
||||
Entry *entry = m_manager->m_entry_manager.GetEntry(id);
|
||||
if (entry == nullptr) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lk(m_manager->m_entry_owner_lock);
|
||||
if (entry->owner != this) {
|
||||
return ServiceObjectHolder();
|
||||
}
|
||||
}
|
||||
return entry->object.Clone();
|
||||
}
|
||||
|
||||
ServerDomainManager::EntryManager::EntryManager(DomainEntryStorage *entry_storage, size_t entry_count) : m_lock() {
|
||||
m_entries = reinterpret_cast<Entry *>(entry_storage);
|
||||
m_num_entries = entry_count;
|
||||
for (size_t i = 0; i < m_num_entries; i++) {
|
||||
m_free_list.push_back(*std::construct_at(m_entries + i));
|
||||
}
|
||||
}
|
||||
|
||||
ServerDomainManager::EntryManager::~EntryManager() {
|
||||
for (size_t i = 0; i < m_num_entries; i++) {
|
||||
std::destroy_at(m_entries + i);
|
||||
}
|
||||
}
|
||||
|
||||
ServerDomainManager::Entry *ServerDomainManager::EntryManager::AllocateEntry() {
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
if (m_free_list.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Entry *e = std::addressof(m_free_list.front());
|
||||
m_free_list.pop_front();
|
||||
return e;
|
||||
}
|
||||
|
||||
void ServerDomainManager::EntryManager::FreeEntry(Entry *entry) {
|
||||
std::scoped_lock lk(m_lock);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
AMS_ABORT_UNLESS(!entry->object);
|
||||
m_free_list.push_front(*entry);
|
||||
}
|
||||
|
||||
void ServerDomainManager::EntryManager::AllocateSpecificEntries(const DomainObjectId *ids, size_t count) {
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
/* Allocate new IDs. */
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto id = ids[i];
|
||||
Entry *entry = this->GetEntry(id);
|
||||
if (id != InvalidDomainObjectId) {
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
AMS_ABORT_UNLESS(entry->owner == nullptr);
|
||||
m_free_list.erase(m_free_list.iterator_to(*entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
R_RETURN(this->ProcessMessageImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data));
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
R_RETURN(this->ProcessMessageForMitmImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data));
|
||||
}
|
||||
#endif
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
R_UNLESS(static_cast<bool>(target_object), sf::cmif::ResultTargetNotFound());
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), sf::cmif::ResultInvalidNumInObjects());
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = std::addressof(domain_processor);
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(std::addressof(domain_processor));
|
||||
}
|
||||
ctx.srv_obj = target_object.GetServiceObjectUnsafe();
|
||||
R_RETURN(target_object.ProcessMessage(ctx, in_message_raw_data));
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
/* TODO: N doesn't error check here. Should we? */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
R_SUCCEED();
|
||||
default:
|
||||
R_THROW(sf::cmif::ResultInvalidInHeader());
|
||||
}
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* Mitm. If we don't have a target object, we should forward to let the server handle. */
|
||||
if (!target_object) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), sf::cmif::ResultInvalidHeaderSize());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), sf::cmif::ResultInvalidNumInObjects());
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = std::addressof(domain_processor);
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(std::addressof(domain_processor));
|
||||
}
|
||||
ctx.srv_obj = target_object.GetServiceObjectUnsafe();
|
||||
R_RETURN(target_object.ProcessMessage(ctx, in_message_raw_data));
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* If the object is not in the domain, tell the server to close it. */
|
||||
if (!target_object) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* If the object is in the domain, close our copy of it. Mitm objects are required to close their associated domain id, so this shouldn't cause desynch. */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
R_SUCCEED();
|
||||
}
|
||||
default:
|
||||
R_THROW(sf::cmif::ResultInvalidInHeader());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Result DomainServiceObjectProcessor::PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const {
|
||||
/* Validate in object count. */
|
||||
R_UNLESS(m_impl_metadata.GetInObjectCount() == this->GetInObjectCount(), sf::cmif::ResultInvalidNumInObjects());
|
||||
|
||||
/* Nintendo reserves domain object IDs here. We do this later, to support mitm semantics. */
|
||||
|
||||
/* Pass onwards. */
|
||||
R_RETURN(m_impl_processor->PrepareForProcess(ctx, runtime_metadata));
|
||||
}
|
||||
|
||||
Result DomainServiceObjectProcessor::GetInObjects(ServiceObjectHolder *in_objects) const {
|
||||
for (size_t i = 0; i < this->GetInObjectCount(); i++) {
|
||||
in_objects[i] = m_domain->GetObject(m_in_object_ids[i]);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
HipcRequest DomainServiceObjectProcessor::PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
HipcRequest request = m_impl_processor->PrepareForReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_data_total_size = this->GetImplOutDataTotalSize();
|
||||
AMS_ABORT_UNLESS(out_header_size + impl_out_data_total_size + sizeof(DomainObjectId) * this->GetOutObjectCount() <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = static_cast<u32>(this->GetOutObjectCount()), };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
m_out_object_ids = reinterpret_cast<DomainObjectId *>(out_raw_data.GetAddress() + impl_out_data_total_size);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
m_impl_processor->PrepareForErrorReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_headers_size = this->GetImplOutHeadersSize();
|
||||
AMS_ABORT_UNLESS(out_header_size + impl_out_headers_size <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = 0, };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
|
||||
/* Nintendo unreserves domain entries here, but we haven't reserved them yet. */
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *selected_ids) {
|
||||
AMS_UNUSED(ctx, response);
|
||||
|
||||
const size_t num_out_objects = this->GetOutObjectCount();
|
||||
|
||||
/* Copy input object IDs from command impl (normally these are Invalid, in mitm they should be set). */
|
||||
DomainObjectId object_ids[8];
|
||||
bool is_reserved[8];
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
object_ids[i] = selected_ids[i];
|
||||
is_reserved[i] = false;
|
||||
}
|
||||
|
||||
/* Reserve object IDs as necessary. */
|
||||
{
|
||||
DomainObjectId reservations[8];
|
||||
{
|
||||
size_t num_unreserved_ids = 0;
|
||||
DomainObjectId specific_ids[8];
|
||||
size_t num_specific_ids = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
/* In the mitm case, we must not reserve IDs in use by other objects, so mitm objects will set this. */
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
num_unreserved_ids++;
|
||||
} else {
|
||||
specific_ids[num_specific_ids++] = object_ids[i];
|
||||
}
|
||||
}
|
||||
/* TODO: Can we make this error non-fatal? It isn't for N, since they can reserve IDs earlier due to not having to worry about mitm. */
|
||||
R_ABORT_UNLESS(m_domain->ReserveIds(reservations, num_unreserved_ids));
|
||||
m_domain->ReserveSpecificIds(specific_ids, num_specific_ids);
|
||||
}
|
||||
|
||||
size_t reservation_index = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
object_ids[i] = reservations[reservation_index++];
|
||||
is_reserved[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Actually set out objects. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (!out_objects[i]) {
|
||||
if (is_reserved[i]) {
|
||||
m_domain->UnreserveIds(object_ids + i, 1);
|
||||
}
|
||||
object_ids[i] = InvalidDomainObjectId;
|
||||
continue;
|
||||
}
|
||||
m_domain->RegisterObject(object_ids[i], std::move(out_objects[i]));
|
||||
}
|
||||
|
||||
/* Set out object IDs in message. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
m_out_object_ids[i] = object_ids[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
namespace cmif {
|
||||
|
||||
namespace {
|
||||
|
||||
#if !defined(ATMOSPHERE_COMPILER_CLANG)
|
||||
ALWAYS_INLINE util::AtomicRef<uintptr_t> GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
|
||||
return util::AtomicRef<uintptr_t>(*p);
|
||||
}
|
||||
#else
|
||||
ALWAYS_INLINE util::Atomic<uintptr_t> &GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
static_assert(sizeof(std::atomic<uintptr_t>) == sizeof(uintptr_t));
|
||||
static_assert(sizeof(util::Atomic<uintptr_t>) == sizeof(std::atomic<uintptr_t>));
|
||||
|
||||
return *reinterpret_cast<util::Atomic<uintptr_t> *>(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void OnSetInlineContext(os::ThreadType *thread) {
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
/* Ensure that libnx receives the priority value. */
|
||||
::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext(thread)));
|
||||
#else
|
||||
AMS_UNUSED(thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InlineContext GetInlineContext() {
|
||||
/* Get the context. */
|
||||
uintptr_t thread_context = GetAtomicSfInlineContext().Load();
|
||||
|
||||
/* Copy it out. */
|
||||
InlineContext ctx;
|
||||
static_assert(sizeof(ctx) <= sizeof(thread_context));
|
||||
std::memcpy(std::addressof(ctx), std::addressof(thread_context), sizeof(ctx));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
InlineContext SetInlineContext(InlineContext ctx) {
|
||||
/* Get current thread. */
|
||||
os::ThreadType * const cur_thread = os::GetCurrentThread();
|
||||
ON_SCOPE_EXIT { OnSetInlineContext(cur_thread); };
|
||||
|
||||
/* Create the new context. */
|
||||
static_assert(sizeof(ctx) <= sizeof(uintptr_t));
|
||||
uintptr_t new_context_value = 0;
|
||||
std::memcpy(std::addressof(new_context_value), std::addressof(ctx), sizeof(ctx));
|
||||
|
||||
/* Get the old context. */
|
||||
uintptr_t old_context_value = GetAtomicSfInlineContext(cur_thread).Exchange(new_context_value);
|
||||
|
||||
/* Convert and copy it out. */
|
||||
InlineContext old_ctx;
|
||||
std::memcpy(std::addressof(old_ctx), std::addressof(old_context_value), sizeof(old_ctx));
|
||||
return old_ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
#if !defined(ATMOSPHERE_COMPILER_CLANG)
|
||||
ALWAYS_INLINE util::AtomicRef<u8> GetAtomicFsInlineContext(os::ThreadType *thread) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
|
||||
return util::AtomicRef<u8>(*reinterpret_cast<u8 *>(p));
|
||||
}
|
||||
#else
|
||||
ALWAYS_INLINE util::Atomic<u8> &GetAtomicFsInlineContext(os::ThreadType *thread) {
|
||||
uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context);
|
||||
static_assert(sizeof(std::atomic<u8>) == sizeof(u8));
|
||||
static_assert(sizeof(util::Atomic<u8>) == sizeof(std::atomic<u8>));
|
||||
|
||||
return *reinterpret_cast<util::Atomic<u8> *>(reinterpret_cast<u8 *>(p));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
u8 GetFsInlineContext(os::ThreadType *thread) {
|
||||
return GetAtomicFsInlineContext(thread).Load();
|
||||
}
|
||||
|
||||
u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx) {
|
||||
ON_SCOPE_EXIT { cmif::OnSetInlineContext(thread); };
|
||||
|
||||
return GetAtomicFsInlineContext(thread).Exchange(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline u32 InHeaderMagic = util::FourCC<'S','F','C','I'>::Code;
|
||||
constexpr inline u32 OutHeaderMagic = util::FourCC<'S','F','C','O'>::Code;
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
static_assert(InHeaderMagic == CMIF_IN_HEADER_MAGIC);
|
||||
static_assert(OutHeaderMagic == CMIF_OUT_HEADER_MAGIC);
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandlerByBinarySearch(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
/* Binary search for the handler. */
|
||||
ssize_t lo = 0;
|
||||
ssize_t hi = entry_count - 1;
|
||||
while (lo <= hi) {
|
||||
const size_t mid = (lo + hi) / 2;
|
||||
if (entries[mid].cmd_id < cmd_id) {
|
||||
lo = mid + 1;
|
||||
} else if (entries[mid].cmd_id > cmd_id) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
/* Find start. */
|
||||
size_t start = mid;
|
||||
while (start > 0 && entries[start - 1].cmd_id == cmd_id) {
|
||||
--start;
|
||||
}
|
||||
|
||||
/* Find end. */
|
||||
size_t end = mid + 1;
|
||||
while (end < entry_count && entries[end].cmd_id == cmd_id) {
|
||||
++end;
|
||||
}
|
||||
|
||||
for (size_t idx = start; idx < end; ++idx) {
|
||||
if (entries[idx].MatchesVersion(hos_version)) {
|
||||
return entries[idx].GetHandler();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandlerByLinearSearch(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
for (size_t i = 0; i < entry_count; ++i) {
|
||||
if (entries[i].Matches(cmd_id, hos_version)) {
|
||||
return entries[i].GetHandler();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandler(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) {
|
||||
if (entry_count >= 8) {
|
||||
return FindCommandHandlerByBinarySearch(entries, entry_count, cmd_id, hos_version);
|
||||
} else {
|
||||
return FindCommandHandlerByLinearSearch(entries, entry_count, cmd_id, hos_version);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result impl::ServiceDispatchTableBase::ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const {
|
||||
/* Get versioning info. */
|
||||
const auto hos_version = hos::GetVersion();
|
||||
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||
|
||||
/* Parse the CMIF in header. */
|
||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
const auto cmd_handler = FindCommandHandler(entries, entry_count, cmd_id, hos_version);
|
||||
R_UNLESS(cmd_handler != nullptr, sf::cmif::ResultUnknownCommandId());
|
||||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* Forward any meta-context change result. */
|
||||
if (sf::impl::ResultRequestContextChanged::Includes(command_result)) {
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Otherwise, ensure that we're able to write the output header. */
|
||||
if (out_header == nullptr) {
|
||||
AMS_ABORT_UNLESS(R_FAILED(command_result));
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Write output header to raw data. */
|
||||
*out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), interface_id_for_debug};
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
#if AMS_SF_MITM_SUPPORTED
|
||||
Result impl::ServiceDispatchTableBase::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const {
|
||||
/* Get versioning info. */
|
||||
const auto hos_version = hos::GetVersion();
|
||||
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||
|
||||
/* Parse the CMIF in header. */
|
||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize());
|
||||
R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader());
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
const auto cmd_handler = FindCommandHandler(entries, entry_count, cmd_id, hos_version);
|
||||
|
||||
/* If we didn't find a handler, forward the request. */
|
||||
if (cmd_handler == nullptr) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* If we should, forward the request to the forward session. */
|
||||
if (sm::mitm::ResultShouldForwardToSession::Includes(command_result)) {
|
||||
R_RETURN(ctx.session->ForwardRequest(ctx));
|
||||
}
|
||||
|
||||
/* Forward any meta-context change result. */
|
||||
if (sf::impl::ResultRequestContextChanged::Includes(command_result)) {
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Otherwise, ensure that we're able to write the output header. */
|
||||
if (out_header == nullptr) {
|
||||
AMS_ABORT_UNLESS(R_FAILED(command_result));
|
||||
R_RETURN(command_result);
|
||||
}
|
||||
|
||||
/* Write output header to raw data. */
|
||||
*out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), interface_id_for_debug};
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
Result ServiceObjectHolder::ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const auto ProcessHandler = m_dispatch_meta->ProcessHandler;
|
||||
const auto *DispatchTable = m_dispatch_meta->DispatchTable;
|
||||
return (DispatchTable->*ProcessHandler)(ctx, in_raw_data);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user