ams_mitm: Implement emummc Nintendo folder redirection
This commit is contained in:
@@ -33,7 +33,7 @@ extern "C" {
|
||||
void __appExit(void);
|
||||
|
||||
/* Exception handling. */
|
||||
alignas(16) u8 __nx_exception_stack[0x1000];
|
||||
alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize];
|
||||
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace ams::mitm {
|
||||
public: \
|
||||
static constexpr size_t ThreadPriority = prio; \
|
||||
static constexpr size_t StackSize = ss; \
|
||||
alignas(0x1000) static inline u8 Stack[StackSize]; \
|
||||
alignas(os::MemoryPageSize) static inline u8 Stack[StackSize]; \
|
||||
public: \
|
||||
static void ThreadFunction(void *); \
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace ams::mitm::bpc {
|
||||
};
|
||||
|
||||
/* Globals. */
|
||||
alignas(0x1000) u8 g_work_page[0x1000];
|
||||
alignas(0x1000) u8 g_reboot_payload[IramPayloadMaxSize];
|
||||
alignas(os::MemoryPageSize) u8 g_work_page[os::MemoryPageSize];
|
||||
alignas(os::MemoryPageSize) u8 g_reboot_payload[IramPayloadMaxSize];
|
||||
RebootType g_reboot_type = RebootType::ToRcm;
|
||||
|
||||
/* Helpers. */
|
||||
@@ -54,9 +54,9 @@ namespace ams::mitm::bpc {
|
||||
ClearIram();
|
||||
|
||||
/* Copy in payload. */
|
||||
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
||||
std::memcpy(g_work_page, &g_reboot_payload[ofs], std::min(sizeof(g_reboot_payload) - ofs, size_t(0x1000)));
|
||||
exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, 0x1000);
|
||||
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += sizeof(g_work_page)) {
|
||||
std::memcpy(g_work_page, &g_reboot_payload[ofs], std::min(sizeof(g_reboot_payload) - ofs, sizeof(g_work_page)));
|
||||
exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, sizeof(g_work_page));
|
||||
}
|
||||
|
||||
/* Copy in fatal error context, if relevant. */
|
||||
|
||||
@@ -62,13 +62,29 @@ namespace ams::mitm::fs {
|
||||
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenSdCardFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> out) {
|
||||
/* We only care about redirecting this for NS/emummc. */
|
||||
R_UNLESS(this->client_info.program_id == ncm::ProgramId::Ns, sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(emummc::IsActive(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Create a new SD card filesystem. */
|
||||
FsFileSystem sd_fs;
|
||||
R_TRY(fsOpenSdCardFileSystemFwd(this->forward_service.get(), &sd_fs));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&sd_fs.s)};
|
||||
|
||||
/* Return output filesystem. */
|
||||
std::shared_ptr<fs::fsa::IFileSystem> redir_fs = std::make_shared<fssystem::DirectoryRedirectionFileSystem>(std::make_shared<RemoteFileSystem>(sd_fs), "/Nintendo", emummc::GetNintendoDirPath());
|
||||
out.SetValue(std::make_shared<IFileSystemInterface>(std::move(redir_fs), false), target_object_id);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenBisStorage(sf::Out<std::shared_ptr<IStorageInterface>> out, u32 _bis_partition_id) {
|
||||
const ::FsBisPartitionId bis_partition_id = static_cast<::FsBisPartitionId>(_bis_partition_id);
|
||||
|
||||
/* Try to open a storage for the partition. */
|
||||
FsStorage bis_storage;
|
||||
R_TRY(fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id));
|
||||
const sf::cmif::DomainObjectId target_object_id{bis_storage.s.object_id};
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&bis_storage.s)};
|
||||
|
||||
const bool is_sysmodule = ncm::IsSystemProgramId(this->client_info.program_id);
|
||||
const bool is_hbl = this->client_info.override_status.IsHbl();
|
||||
@@ -118,7 +134,7 @@ namespace ams::mitm::fs {
|
||||
/* Try to open the process romfs. */
|
||||
FsStorage data_storage;
|
||||
R_TRY(fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage));
|
||||
const sf::cmif::DomainObjectId target_object_id{data_storage.s.object_id};
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&data_storage.s)};
|
||||
|
||||
/* Try to get a storage from the cache. */
|
||||
{
|
||||
@@ -160,7 +176,7 @@ namespace ams::mitm::fs {
|
||||
/* Try to open the process romfs. */
|
||||
FsStorage data_storage;
|
||||
R_TRY(fsOpenDataStorageByDataIdFwd(this->forward_service.get(), &data_storage, static_cast<u64>(data_id), static_cast<NcmStorageId>(storage_id)));
|
||||
const sf::cmif::DomainObjectId target_object_id{data_storage.s.object_id};
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&data_storage.s)};
|
||||
|
||||
/* Try to get a storage from the cache. */
|
||||
{
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "fsmitm_istorage_interface.hpp"
|
||||
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
using IStorageInterface = ams::fssrv::impl::StorageInterfaceAdapter;
|
||||
using IFileSystemInterface = ams::fssrv::impl::FileSystemInterfaceAdapter;
|
||||
|
||||
/* TODO: Consider re-enabling the mitm flag logic. */
|
||||
|
||||
class FsMitmService : public sf::IMitmServiceObject {
|
||||
@@ -59,7 +62,7 @@ namespace ams::mitm::fs {
|
||||
/* Overridden commands. */
|
||||
/* Result OpenFileSystemWithPatch(Out<std::shared_ptr<IFileSystemInterface>> out, u64 program_id, u32 filesystem_type); */
|
||||
/* Result OpenFileSystemWithId(Out<std::shared_ptr<IFileSystemInterface>> out, InPointer<char> path, u64 program_id, u32 filesystem_type); */
|
||||
/* Result OpenSdCardFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out); */
|
||||
Result OpenSdCardFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> out);
|
||||
/* Result OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out, u8 space_id, FsSave save_struct); */
|
||||
Result OpenBisStorage(sf::Out<std::shared_ptr<IStorageInterface>> out, u32 bis_partition_id);
|
||||
Result OpenDataStorageByCurrentProcess(sf::Out<std::shared_ptr<IStorageInterface>> out);
|
||||
@@ -68,7 +71,7 @@ namespace ams::mitm::fs {
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
/* MAKE_SERVICE_COMMAND_META(OpenFileSystemWithPatch, hos::Version_200), */
|
||||
/* MAKE_SERVICE_COMMAND_META(OpenFileSystemWithId, hos::Version_200), */
|
||||
/* MAKE_SERVICE_COMMAND_META(OpenSdCardFileSystem), */
|
||||
MAKE_SERVICE_COMMAND_META(OpenSdCardFileSystem),
|
||||
/* MAKE_SERVICE_COMMAND_META(OpenSaveDataFileSystem), */
|
||||
MAKE_SERVICE_COMMAND_META(OpenBisStorage),
|
||||
MAKE_SERVICE_COMMAND_META(OpenDataStorageByCurrentProcess),
|
||||
|
||||
@@ -16,6 +16,17 @@
|
||||
#include "fs_shim.h"
|
||||
|
||||
/* Missing fsp-srv commands. */
|
||||
static Result _fsOpenSession(Service *s, Service* out, u32 cmd_id) {
|
||||
return serviceDispatch(s, cmd_id,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = out,
|
||||
);
|
||||
}
|
||||
|
||||
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out) {
|
||||
return _fsOpenSession(s, &out->s, 18);
|
||||
}
|
||||
|
||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id) {
|
||||
const u32 tmp = partition_id;
|
||||
return serviceDispatchIn(s, 12, tmp,
|
||||
@@ -25,10 +36,7 @@ Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partitio
|
||||
}
|
||||
|
||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
|
||||
return serviceDispatch(s, 200,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s,
|
||||
);
|
||||
return _fsOpenSession(s, &out->s, 200);
|
||||
}
|
||||
|
||||
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id) {
|
||||
|
||||
@@ -12,6 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Missing fsp-srv commands. */
|
||||
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out);
|
||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id);
|
||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out);
|
||||
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id);
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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 "fsmitm_istorage_interface.hpp"
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
using namespace ams::fs;
|
||||
|
||||
Result IStorageInterface::Read(s64 offset, const sf::OutNonSecureBuffer &buffer, s64 size) {
|
||||
/* TODO: N retries on ResultDataCorrupted, we may want to eventually. */
|
||||
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
|
||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||
return this->base_storage->Read(offset, buffer.GetPointer(), size);
|
||||
}
|
||||
|
||||
Result IStorageInterface::Write(s64 offset, const sf::InNonSecureBuffer &buffer, s64 size) {
|
||||
/* TODO: N increases thread priority temporarily when writing. We may want to eventually. */
|
||||
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
|
||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||
return this->base_storage->Write(offset, buffer.GetPointer(), size);
|
||||
}
|
||||
|
||||
Result IStorageInterface::Flush() {
|
||||
return this->base_storage->Flush();
|
||||
}
|
||||
|
||||
Result IStorageInterface::SetSize(s64 size) {
|
||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||
return this->base_storage->SetSize(size);
|
||||
}
|
||||
|
||||
Result IStorageInterface::GetSize(sf::Out<s64> out) {
|
||||
return this->base_storage->GetSize(out.GetPointer());
|
||||
}
|
||||
|
||||
Result IStorageInterface::OperateRange(sf::Out<StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) {
|
||||
/* N includes this redundant check, so we will too. */
|
||||
R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument());
|
||||
|
||||
out->Clear();
|
||||
if (op_id == static_cast<s32>(fs::OperationId::QueryRange)) {
|
||||
fs::StorageQueryRangeInfo info;
|
||||
R_TRY(this->base_storage->OperateRange(&info, sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0));
|
||||
out->Merge(info);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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::mitm::fs {
|
||||
|
||||
class IStorageInterface : public sf::IServiceObject {
|
||||
private:
|
||||
enum class CommandId {
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
Flush = 2,
|
||||
SetSize = 3,
|
||||
GetSize = 4,
|
||||
OperateRange = 5,
|
||||
};
|
||||
private:
|
||||
std::unique_ptr<ams::fs::IStorage> base_storage;
|
||||
public:
|
||||
IStorageInterface(ams::fs::IStorage *s) : base_storage(s) { /* ... */ }
|
||||
IStorageInterface(std::unique_ptr<ams::fs::IStorage> s) : base_storage(std::move(s)) { /* ... */ }
|
||||
private:
|
||||
/* Command API. */
|
||||
virtual Result Read(s64 offset, const sf::OutNonSecureBuffer &buffer, s64 size) final;
|
||||
virtual Result Write(s64 offset, const sf::InNonSecureBuffer &buffer, s64 size) final;
|
||||
virtual Result Flush() final;
|
||||
virtual Result SetSize(s64 size) final;
|
||||
virtual Result GetSize(sf::Out<s64> out) final;
|
||||
virtual Result OperateRange(sf::Out<ams::fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) final;
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
/* 1.0.0- */
|
||||
MAKE_SERVICE_COMMAND_META(Read),
|
||||
MAKE_SERVICE_COMMAND_META(Write),
|
||||
MAKE_SERVICE_COMMAND_META(Flush),
|
||||
MAKE_SERVICE_COMMAND_META(SetSize),
|
||||
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||
|
||||
/* 4.0.0- */
|
||||
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user