Add missing FS:USER functions (#7051)

This commit is contained in:
PabloMK7 2023-10-31 22:01:25 +01:00 committed by GitHub
parent b231a22ea5
commit 597a2e8ead
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 232 additions and 21 deletions

View File

@ -221,6 +221,13 @@ public:
return session; return session;
} }
/**
* Returns the client thread that made the service request.
*/
std::shared_ptr<Thread> ClientThread() const {
return thread;
}
class WakeupCallback { class WakeupCallback {
public: public:
virtual ~WakeupCallback() = default; virtual ~WakeupCallback() = default;

View File

@ -670,6 +670,26 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) {
rb.Push<bool>(format_info->duplicate_data != 0); rb.Push<bool>(format_info->duplicate_data != 0);
} }
void FS_USER::GetProductInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u32 process_id = rp.Pop<u32>();
LOG_DEBUG(Service_FS, "called, process_id={}", process_id);
IPC::RequestBuilder rb = rp.MakeBuilder(6, 0);
const auto product_info = GetProductInfo(process_id);
if (!product_info.has_value()) {
rb.Push(ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS,
ErrorSummary::NotFound, ErrorLevel::Status));
return;
}
rb.Push(RESULT_SUCCESS);
rb.PushRaw<ProductInfo>(product_info.value());
}
void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto process_id = rp.Pop<u32>(); const auto process_id = rp.Pop<u32>();
@ -687,8 +707,20 @@ void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) {
return; return;
} }
ProgramInfo program_info = program_info_result.Unwrap();
// Always report the launched program mediatype is SD if the friends module is requesting this
// information and the media type is game card. Otherwise, friends will append a "romid" field
// to the NASC request with a cartridge unique identifier. Using a dump of a game card and the
// game card itself at the same time online is known to have caused issues in the past.
auto process = ctx.ClientThread()->owner_process.lock();
if (process && process->codeset->name == "friends" &&
program_info.media_type == MediaType::GameCard) {
program_info.media_type = MediaType::SDMC;
}
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushRaw(program_info_result.Unwrap()); rb.PushRaw<ProgramInfo>(program_info);
} }
void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) {
@ -775,12 +807,12 @@ void FS_USER::AddSeed(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void FS_USER::SetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { void FS_USER::ObsoletedSetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
u64 value = rp.Pop<u64>(); const u64 value = rp.Pop<u64>();
u32 secure_value_slot = rp.Pop<u32>(); const u32 secure_value_slot = rp.Pop<u32>();
u32 unique_id = rp.Pop<u32>(); const u32 unique_id = rp.Pop<u32>();
u8 title_variation = rp.Pop<u8>(); const u8 title_variation = rp.Pop<u8>();
// TODO: Generate and Save the Secure Value // TODO: Generate and Save the Secure Value
@ -794,12 +826,11 @@ void FS_USER::SetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { void FS_USER::ObsoletedGetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const u32 secure_value_slot = rp.Pop<u32>();
u32 secure_value_slot = rp.Pop<u32>(); const u32 unique_id = rp.Pop<u32>();
u32 unique_id = rp.Pop<u32>(); const u8 title_variation = rp.Pop<u8>();
u8 title_variation = rp.Pop<u8>();
LOG_WARNING( LOG_WARNING(
Service_FS, Service_FS,
@ -816,7 +847,77 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(0); // the secure value rb.Push<u64>(0); // the secure value
} }
void FS_USER::Register(u32 process_id, u64 program_id, const std::string& filepath) { void FS_USER::SetThisSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const u32 secure_value_slot = rp.Pop<u32>();
const u64 value = rp.Pop<u64>();
// TODO: Generate and Save the Secure Value
LOG_WARNING(Service_FS, "(STUBBED) called, value=0x{:016x} secure_value_slot=0x{:08X}", value,
secure_value_slot);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
void FS_USER::GetThisSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const u32 secure_value_slot = rp.Pop<u32>();
LOG_WARNING(Service_FS, "(STUBBED) called secure_value_slot=0x{:08X}", secure_value_slot);
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
rb.Push(RESULT_SUCCESS);
// TODO: Implement Secure Value Lookup & Generation
rb.Push<bool>(false); // indicates that the secure value doesn't exist
rb.Push<bool>(false); // looks like a boolean value, purpose unknown
rb.Push<u64>(0); // the secure value
}
void FS_USER::SetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto archive_handle = rp.PopRaw<ArchiveHandle>();
const u32 secure_value_slot = rp.Pop<u32>();
const u64 value = rp.Pop<u64>();
const bool flush = rp.Pop<bool>();
// TODO: Generate and Save the Secure Value
LOG_WARNING(Service_FS,
"(STUBBED) called, value=0x{:016x} secure_value_slot=0x{:04X} "
"archive_handle=0x{:08X} flush={}",
value, secure_value_slot, archive_handle, flush);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto archive_handle = rp.PopRaw<ArchiveHandle>();
const u32 secure_value_slot = rp.Pop<u32>();
LOG_WARNING(Service_FS, "(STUBBED) called secure_value_slot=0x{:08X} archive_handle=0x{:08X}",
secure_value_slot, archive_handle);
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
rb.Push(RESULT_SUCCESS);
// TODO: Implement Secure Value Lookup & Generation
rb.Push<bool>(false); // indicates that the secure value doesn't exist
rb.Push<bool>(false); // looks like a boolean value, purpose unknown
rb.Push<u64>(0); // the secure value
}
void FS_USER::RegisterProgramInfo(u32 process_id, u64 program_id, const std::string& filepath) {
const MediaType media_type = GetMediaTypeFromPath(filepath); const MediaType media_type = GetMediaTypeFromPath(filepath);
program_info_map.insert_or_assign(process_id, ProgramInfo{program_id, media_type}); program_info_map.insert_or_assign(process_id, ProgramInfo{program_id, media_type});
if (media_type == MediaType::GameCard) { if (media_type == MediaType::GameCard) {
@ -828,6 +929,19 @@ std::string FS_USER::GetCurrentGamecardPath() const {
return current_gamecard_path; return current_gamecard_path;
} }
void FS_USER::RegisterProductInfo(u32 process_id, const ProductInfo& product_info) {
product_info_map.insert_or_assign(process_id, product_info);
}
std::optional<FS_USER::ProductInfo> FS_USER::GetProductInfo(u32 process_id) {
auto it = product_info_map.find(process_id);
if (it != product_info_map.end()) {
return it->second;
} else {
return {};
}
}
ResultVal<u16> FS_USER::GetSpecialContentIndexFromGameCard(u64 title_id, SpecialContentType type) { ResultVal<u16> FS_USER::GetSpecialContentIndexFromGameCard(u64 title_id, SpecialContentType type) {
// TODO(B3N30) check if on real 3DS NCSD is checked if partition exists // TODO(B3N30) check if on real 3DS NCSD is checked if partition exists
@ -929,7 +1043,7 @@ FS_USER::FS_USER(Core::System& system)
{0x082B, nullptr, "CardNorDirectRead_4xIO"}, {0x082B, nullptr, "CardNorDirectRead_4xIO"},
{0x082C, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, {0x082C, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
{0x082D, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, {0x082D, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
{0x082E, nullptr, "GetProductInfo"}, {0x082E, &FS_USER::GetProductInfo, "GetProductInfo"},
{0x082F, &FS_USER::GetProgramLaunchInfo, "GetProgramLaunchInfo"}, {0x082F, &FS_USER::GetProgramLaunchInfo, "GetProgramLaunchInfo"},
{0x0830, &FS_USER::ObsoletedCreateExtSaveData, "Obsoleted_3_0_CreateExtSaveData"}, {0x0830, &FS_USER::ObsoletedCreateExtSaveData, "Obsoleted_3_0_CreateExtSaveData"},
{0x0831, nullptr, "CreateSharedExtSaveData"}, {0x0831, nullptr, "CreateSharedExtSaveData"},
@ -984,12 +1098,16 @@ FS_USER::FS_USER(Core::System& system)
{0x0862, &FS_USER::SetPriority, "SetPriority"}, {0x0862, &FS_USER::SetPriority, "SetPriority"},
{0x0863, &FS_USER::GetPriority, "GetPriority"}, {0x0863, &FS_USER::GetPriority, "GetPriority"},
{0x0864, nullptr, "GetNandInfo"}, {0x0864, nullptr, "GetNandInfo"},
{0x0865, &FS_USER::SetSaveDataSecureValue, "SetSaveDataSecureValue"}, {0x0865, &FS_USER::ObsoletedSetSaveDataSecureValue, "SetSaveDataSecureValue"},
{0x0866, &FS_USER::GetSaveDataSecureValue, "GetSaveDataSecureValue"}, {0x0866, &FS_USER::ObsoletedGetSaveDataSecureValue, "GetSaveDataSecureValue"},
{0x0867, nullptr, "ControlSecureSave"}, {0x0867, nullptr, "ControlSecureSave"},
{0x0868, nullptr, "GetMediaType"}, {0x0868, nullptr, "GetMediaType"},
{0x0869, nullptr, "GetNandEraseCount"}, {0x0869, nullptr, "GetNandEraseCount"},
{0x086A, nullptr, "ReadNandReport"}, {0x086A, nullptr, "ReadNandReport"},
{0x086E, &FS_USER::SetThisSaveDataSecureValue, "SetThisSaveDataSecureValue" },
{0x086F, &FS_USER::GetThisSaveDataSecureValue, "GetThisSaveDataSecureValue" },
{0x0875, &FS_USER::SetSaveDataSecureValue, "SetSaveDataSecureValue" },
{0x0876, &FS_USER::GetSaveDataSecureValue, "GetSaveDataSecureValue" },
{0x087A, &FS_USER::AddSeed, "AddSeed"}, {0x087A, &FS_USER::AddSeed, "AddSeed"},
{0x087D, &FS_USER::GetNumSeeds, "GetNumSeeds"}, {0x087D, &FS_USER::GetNumSeeds, "GetNumSeeds"},
{0x0886, nullptr, "CheckUpdatedDat"}, {0x0886, nullptr, "CheckUpdatedDat"},

View File

@ -4,10 +4,12 @@
#pragma once #pragma once
#include <optional>
#include <unordered_map> #include <unordered_map>
#include <boost/serialization/base_object.hpp> #include <boost/serialization/base_object.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Core { namespace Core {
@ -47,12 +49,23 @@ class FS_USER final : public ServiceFramework<FS_USER, ClientSlot> {
public: public:
explicit FS_USER(Core::System& system); explicit FS_USER(Core::System& system);
// On real HW this is part of FS:Reg. But since that module is only used by loader and pm, which // On real HW this is part of FSReg (FSReg:Register). But since that module is only used by
// we HLEed, we can just directly use it here // loader and pm, which we HLEed, we can just directly use it here
void Register(u32 process_id, u64 program_id, const std::string& filepath); void RegisterProgramInfo(u32 process_id, u64 program_id, const std::string& filepath);
std::string GetCurrentGamecardPath() const; std::string GetCurrentGamecardPath() const;
struct ProductInfo {
std::array<u8, 0x10> product_code;
u16_le maker_code;
u16_le remaster_version;
};
static_assert(sizeof(ProductInfo) == 0x14);
void RegisterProductInfo(u32 process_id, const ProductInfo& product_info);
std::optional<ProductInfo> GetProductInfo(u32 process_id);
/// Gets the registered program info of a process. /// Gets the registered program info of a process.
ResultVal<ProgramInfo> GetProgramLaunchInfo(u32 process_id) const { ResultVal<ProgramInfo> GetProgramLaunchInfo(u32 process_id) const {
auto info = program_info_map.find(process_id); auto info = program_info_map.find(process_id);
@ -509,6 +522,17 @@ private:
*/ */
void GetFormatInfo(Kernel::HLERequestContext& ctx); void GetFormatInfo(Kernel::HLERequestContext& ctx);
/**
* FS_User::GetProductInfo service function.
* Inputs:
* 0 : 0x082E0040
* 1 : Process ID
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2-6 : Product info
*/
void GetProductInfo(Kernel::HLERequestContext& ctx);
/** /**
* FS_User::GetProgramLaunchInfo service function. * FS_User::GetProgramLaunchInfo service function.
* Inputs: * Inputs:
@ -600,7 +624,7 @@ private:
* 0 : 0x08650140 * 0 : 0x08650140
* 1 : Result of function, 0 on success, otherwise error code * 1 : Result of function, 0 on success, otherwise error code
*/ */
void SetSaveDataSecureValue(Kernel::HLERequestContext& ctx); void ObsoletedSetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/** /**
* FS_User::GetSaveDataSecureValue service function. * FS_User::GetSaveDataSecureValue service function.
@ -615,6 +639,57 @@ private:
* 2 : If Secure Value doesn't exist, 0, if it exists, 1 * 2 : If Secure Value doesn't exist, 0, if it exists, 1
* 3-4 : Secure Value * 3-4 : Secure Value
*/ */
void ObsoletedGetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/**
* FS_User::SetThisSaveDataSecureValue service function.
* Inputs:
* 1 : Secure Value Slot
* 2-3 : Secure Value
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void SetThisSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/**
* FS_User::GetSaveDataSecureValue service function.
* Inputs:
* 1 : Secure Value Slot
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : If Secure Value doesn't exist, 0, if it exists, 1
* 3 : Unknown
* 4-5 : Secure Value
*/
void GetThisSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/**
* FS_User::SetSaveDataSecureValue service function.
* Inputs:
* 0 : 0x08750180
* 1-2 : Archive
* 3 : Secure Value Slot
* 4 : value
* 5 : flush
* Outputs:
* 0 : header
* 1 : Result of function, 0 on success, otherwise error code
*/
void SetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/**
* FS_User::GetSaveDataSecureValue service function.
* Inputs:
* 0 : 0x087600C0
* 1-2 : Archive
* 2 : Secure Value slot
* Outputs:
* 0 : Header
* 1 : Result of function, 0 on success, otherwise error code
* 2 : If Secure Value doesn't exist, 0, if it exists, 1
* 3 : unknown
* 4-5 : Secure Value
*/
void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx); void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
static ResultVal<u16> GetSpecialContentIndexFromGameCard(u64 title_id, SpecialContentType type); static ResultVal<u16> GetSpecialContentIndexFromGameCard(u64 title_id, SpecialContentType type);
@ -624,6 +699,8 @@ private:
std::unordered_map<u32, ProgramInfo> program_info_map; std::unordered_map<u32, ProgramInfo> program_info_map;
std::string current_gamecard_path; std::string current_gamecard_path;
std::unordered_map<u32, ProductInfo> product_info_map;
u32 priority = -1; ///< For SetPriority and GetPriority service functions u32 priority = -1; ///< For SetPriority and GetPriority service functions
Core::System& system; Core::System& system;

View File

@ -282,7 +282,7 @@ ResultStatus AppLoader_THREEDSX::Load(std::shared_ptr<Kernel::Process>& process)
// On real HW this is done with FS:Reg, but we can be lazy // On real HW this is done with FS:Reg, but we can be lazy
auto fs_user = auto fs_user =
Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>("fs:USER"); Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>("fs:USER");
fs_user->Register(process->GetObjectId(), process->codeset->program_id, filepath); fs_user->RegisterProgramInfo(process->GetObjectId(), process->codeset->program_id, filepath);
process->Run(48, Kernel::DEFAULT_STACK_SIZE); process->Run(48, Kernel::DEFAULT_STACK_SIZE);

View File

@ -174,7 +174,16 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
auto fs_user = auto fs_user =
Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>( Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>(
"fs:USER"); "fs:USER");
fs_user->Register(process->process_id, process->codeset->program_id, filepath); fs_user->RegisterProgramInfo(process->process_id, process->codeset->program_id, filepath);
Service::FS::FS_USER::ProductInfo product_info{};
std::memcpy(product_info.product_code.data(), overlay_ncch->ncch_header.product_code,
product_info.product_code.size());
std::memcpy(&product_info.remaster_version,
overlay_ncch->exheader_header.codeset_info.flags.remaster_version,
sizeof(product_info.remaster_version));
product_info.maker_code = overlay_ncch->ncch_header.maker_code;
fs_user->RegisterProductInfo(process->process_id, product_info);
process->Run(priority, stack_size); process->Run(priority, stack_size);
return ResultStatus::Success; return ResultStatus::Success;