From db2fdd0352d023787fcac032101e1e36fb8aa03f Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Fri, 28 Jun 2019 21:02:34 -0400
Subject: [PATCH] fsp-srv: Implement OutputAccessLogToSdCard Allows games to
 log data to the SD.

---
 src/core/core.cpp                             |  2 +-
 .../hle/service/filesystem/filesystem.cpp     | 10 ++---
 src/core/hle/service/filesystem/filesystem.h  |  2 +-
 src/core/hle/service/filesystem/fsp_srv.cpp   | 43 +++++++++++++------
 src/core/hle/service/filesystem/fsp_srv.h     | 24 ++++++++++-
 src/core/hle/service/service.cpp              |  5 +--
 src/core/hle/service/service.h                |  3 +-
 7 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index df26eb109b..678fa8cea1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -142,7 +142,7 @@ struct System::Impl {
         telemetry_session = std::make_unique<Core::TelemetrySession>();
         service_manager = std::make_shared<Service::SM::ServiceManager>();
 
-        Service::Init(service_manager, system, *virtual_filesystem);
+        Service::Init(service_manager, system);
         GDBStub::Init();
 
         renderer = VideoCore::CreateRenderer(emu_window, system);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 1ebfeb4bf4..8ce110dd11 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -472,12 +472,12 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
     }
 }
 
-void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
+void InstallInterfaces(Core::System& system) {
     romfs_factory = nullptr;
-    CreateFactories(vfs, false);
-    std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
-    std::make_shared<FSP_PR>()->InstallAsService(service_manager);
-    std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
+    CreateFactories(*system.GetFilesystem(), false);
+    std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
+    std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
+    std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
 }
 
 } // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6481f237c4..3849dd89eb 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -65,7 +65,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
 // above is called.
 void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
 
-void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs);
+void InstallInterfaces(Core::System& system);
 
 // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
 // pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e7df8fd98b..bfe0c32b78 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -26,6 +26,7 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/hle/service/filesystem/fsp_srv.h"
+#include "core/reporter.h"
 
 namespace Service::FileSystem {
 
@@ -613,7 +614,7 @@ private:
     u64 next_entry_index = 0;
 };
 
-FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
     // clang-format off
     static const FunctionInfo functions[] = {
         {0, nullptr, "OpenFileSystem"},
@@ -710,9 +711,9 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
         {1001, nullptr, "SetSaveDataSize"},
         {1002, nullptr, "SetSaveDataRootPath"},
         {1003, nullptr, "DisableAutoSaveDataCreation"},
-        {1004, nullptr, "SetGlobalAccessLogMode"},
+        {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
         {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
-        {1006, nullptr, "OutputAccessLogToSdCard"},
+        {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
         {1007, nullptr, "RegisterUpdatePartition"},
         {1008, nullptr, "OpenRegisteredUpdatePartition"},
         {1009, nullptr, "GetAndClearMemoryReportInfo"},
@@ -814,21 +815,22 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
     rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
 }
 
+void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    log_mode = rp.PopEnum<LogMode>();
+
+    LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
 void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
-    LOG_WARNING(Service_FS, "(STUBBED) called");
+    LOG_WARNING(Service_FS, "called");
 
-    enum class LogMode : u32 {
-        Off,
-        Log,
-        RedirectToSdCard,
-        LogToSdCard = Log | RedirectToSdCard,
-    };
-
-    // Given we always want to receive logging information,
-    // we always specify logging as enabled.
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.PushEnum(LogMode::Log);
+    rb.PushEnum(log_mode);
 }
 
 void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
@@ -902,4 +904,17 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
     rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
 }
 
+void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
+    const auto raw = ctx.ReadBuffer();
+    auto log = Common::StringFromFixedZeroTerminatedBuffer(
+        reinterpret_cast<const char*>(raw.data()), raw.size());
+
+    LOG_DEBUG(Service_FS, "called, log='{}'", log);
+
+    reporter.SaveFilesystemAccessReport(log_mode, std::move(log));
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
 } // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index d7572ba7a5..bfaeaad5dd 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -7,15 +7,32 @@
 #include <memory>
 #include "core/hle/service/service.h"
 
+namespace Core {
+class Reporter;
+}
+
 namespace FileSys {
 class FileSystemBackend;
 }
 
 namespace Service::FileSystem {
 
+enum class AccessLogVersion : u32 {
+    V7_0_0 = 2,
+
+    Latest = V7_0_0,
+};
+
+enum class LogMode : u32 {
+    Off,
+    Log,
+    RedirectToSdCard,
+    LogToSdCard = Log | RedirectToSdCard,
+};
+
 class FSP_SRV final : public ServiceFramework<FSP_SRV> {
 public:
-    explicit FSP_SRV();
+    explicit FSP_SRV(const Core::Reporter& reporter);
     ~FSP_SRV() override;
 
 private:
@@ -26,13 +43,18 @@ private:
     void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
     void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
     void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
+    void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
     void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
     void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
     void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
     void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
+    void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
 
     FileSys::VirtualFile romfs;
     u64 current_process_id = 0;
+    LogMode log_mode;
+
+    const Core::Reporter& reporter;
 };
 
 } // namespace Service::FileSystem
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ec9d755b73..60155f2d06 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -195,8 +195,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
 // Module interface
 
 /// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
-          FileSys::VfsFilesystem& vfs) {
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
     // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
     // here and pass it into the respective InstallInterfaces functions.
     auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
@@ -218,7 +217,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
     EUPLD::InstallInterfaces(*sm);
     Fatal::InstallInterfaces(*sm);
     FGM::InstallInterfaces(*sm);
-    FileSystem::InstallInterfaces(*sm, vfs);
+    FileSystem::InstallInterfaces(system);
     Friend::InstallInterfaces(*sm);
     Glue::InstallInterfaces(system);
     GRC::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index abbfe5524e..c6c4bdae5a 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -182,8 +182,7 @@ private:
 };
 
 /// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
-          FileSys::VfsFilesystem& vfs);
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
 
 /// Shutdown ServiceManager
 void Shutdown();