ams_mitm: Implement emummc Nintendo folder redirection

This commit is contained in:
Michael Scire
2019-12-05 23:41:33 -08:00
committed by SciresM
parent 733f2b3cdd
commit 746dbfe018
78 changed files with 2190 additions and 187 deletions

View File

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

View File

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

View File

@@ -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. */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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