mirror of
https://github.com/citra-emu/citra-canary.git
synced 2024-12-23 08:45:38 +00:00
hle: Stub some service calls used by the home menu. (#6675)
This commit is contained in:
parent
26e3f96983
commit
662bb9ba77
|
@ -88,6 +88,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Service, FRD) \
|
||||
SUB(Service, FS) \
|
||||
SUB(Service, ERR) \
|
||||
SUB(Service, ACT) \
|
||||
SUB(Service, APT) \
|
||||
SUB(Service, BOSS) \
|
||||
SUB(Service, GSP) \
|
||||
|
|
|
@ -55,6 +55,7 @@ enum class Class : u8 {
|
|||
Service_FRD, ///< The FRD (Friends) service
|
||||
Service_FS, ///< The FS (Filesystem) service implementation
|
||||
Service_ERR, ///< The ERR (Error) port implementation
|
||||
Service_ACT, ///< The ACT (Account) service
|
||||
Service_APT, ///< The APT (Applets) service
|
||||
Service_BOSS, ///< The BOSS (SpotPass) service
|
||||
Service_GSP, ///< The GSP (GPU control) service
|
||||
|
|
|
@ -87,8 +87,7 @@ Handler::Handler(Core::Timing& timing) : timing(timing) {
|
|||
shared_page.sliderstate_3d = static_cast<float_le>(slidestate);
|
||||
}
|
||||
|
||||
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
||||
u64 Handler::GetSystemTime() const {
|
||||
u64 Handler::GetSystemTimeSince2000() const {
|
||||
std::chrono::milliseconds now =
|
||||
init_time + std::chrono::duration_cast<std::chrono::milliseconds>(timing.GetGlobalTimeUs());
|
||||
|
||||
|
@ -104,23 +103,25 @@ u64 Handler::GetSystemTime() const {
|
|||
epoch_tm.tm_isdst = 0;
|
||||
s64 epoch = std::mktime(&epoch_tm) * 1000;
|
||||
|
||||
// 3DS console time uses Jan 1 1900 as internal epoch,
|
||||
// so we use the milliseconds between 1900 and 2000 as base console time
|
||||
u64 console_time = 3155673600000ULL;
|
||||
|
||||
// Only when system time is after 2000, we set it as 3DS system time
|
||||
if (now.count() > epoch) {
|
||||
console_time += (now.count() - epoch);
|
||||
return now.count() - epoch;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return console_time;
|
||||
u64 Handler::GetSystemTimeSince1900() const {
|
||||
// 3DS console time uses Jan 1 1900 as internal epoch,
|
||||
// so we use the milliseconds between 1900 and 2000 as base console time
|
||||
return 3155673600000ULL + GetSystemTimeSince2000();
|
||||
}
|
||||
|
||||
void Handler::UpdateTimeCallback(std::uintptr_t user_data, int cycles_late) {
|
||||
DateTime& date_time =
|
||||
shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1;
|
||||
|
||||
date_time.date_time = GetSystemTime();
|
||||
date_time.date_time = GetSystemTimeSince1900();
|
||||
date_time.update_tick = timing.GetTicks();
|
||||
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11;
|
||||
date_time.tick_offset = 0;
|
||||
|
|
|
@ -110,8 +110,13 @@ public:
|
|||
return sizeof(shared_page);
|
||||
}
|
||||
|
||||
/// Gets the system time in milliseconds since the year 2000.
|
||||
u64 GetSystemTimeSince2000() const;
|
||||
|
||||
/// Gets the system time in milliseconds since the year 1900.
|
||||
u64 GetSystemTimeSince1900() const;
|
||||
|
||||
private:
|
||||
u64 GetSystemTime() const;
|
||||
void UpdateTimeCallback(std::uintptr_t user_data, int cycles_late);
|
||||
Core::Timing& timing;
|
||||
Core::TimingEventType* update_time_event;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/act/act.h"
|
||||
#include "core/hle/service/act/act_a.h"
|
||||
#include "core/hle/service/act/act_u.h"
|
||||
|
@ -14,6 +15,35 @@ Module::Interface::Interface(std::shared_ptr<Module> act, const char* name)
|
|||
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
void Module::Interface::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x1, 2, 4); // 0x10084
|
||||
const auto sdk_version = rp.Pop<u32>();
|
||||
const auto shared_memory_size = rp.Pop<u32>();
|
||||
const auto caller_pid = rp.PopPID();
|
||||
[[maybe_unused]] const auto shared_memory = rp.PopObject<Kernel::SharedMemory>();
|
||||
|
||||
LOG_DEBUG(Service_ACT,
|
||||
"(STUBBED) called sdk_version={:08X}, shared_memory_size={:08X}, caller_pid={}",
|
||||
sdk_version, shared_memory_size, caller_pid);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::Interface::GetAccountDataBlock(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x6, 3, 2); // 0x600C2
|
||||
const auto unknown = rp.Pop<u8>();
|
||||
const auto size = rp.Pop<u32>();
|
||||
const auto block_id = rp.Pop<u32>();
|
||||
[[maybe_unused]] auto output_buffer = rp.PopMappedBuffer();
|
||||
|
||||
LOG_DEBUG(Service_ACT, "(STUBBED) called unknown={:02X}, size={:08X}, block_id={:08X}", unknown,
|
||||
size, block_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto act = std::make_shared<Module>();
|
||||
|
|
|
@ -22,6 +22,33 @@ public:
|
|||
|
||||
protected:
|
||||
std::shared_ptr<Module> act;
|
||||
|
||||
/**
|
||||
* ACT::Initialize service function.
|
||||
* Inputs:
|
||||
* 1 : SDK version
|
||||
* 2 : Shared Memory Size
|
||||
* 3 : PID Translation Header (0x20)
|
||||
* 4 : Caller PID
|
||||
* 5 : Handle Translation Header (0x0)
|
||||
* 6 : Shared Memory Handle
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* ACT::GetAccountDataBlock service function.
|
||||
* Inputs:
|
||||
* 1 : u8 Unknown
|
||||
* 2 : Size
|
||||
* 3 : Block ID
|
||||
* 4 : Output Buffer Mapping Translation Header ((Size << 4) | 0xC)
|
||||
* 5 : Output Buffer Pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void GetAccountDataBlock(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -11,9 +11,9 @@ ACT_A::ACT_A(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "a
|
|||
const FunctionInfo functions[] = {
|
||||
// act:u shared commands
|
||||
// clang-format off
|
||||
{IPC::MakeHeader(0x0001, 2, 4), nullptr, "Initialize"},
|
||||
{IPC::MakeHeader(0x0001, 2, 4), &ACT_A::Initialize, "Initialize"},
|
||||
{IPC::MakeHeader(0x0002, 1, 0), nullptr, "GetErrorCode"},
|
||||
{IPC::MakeHeader(0x0006, 3, 2), nullptr, "GetAccountDataBlock"},
|
||||
{IPC::MakeHeader(0x0006, 3, 2), &ACT_A::GetAccountDataBlock, "GetAccountDataBlock"},
|
||||
{IPC::MakeHeader(0x000B, 1, 2), nullptr, "AcquireEulaList"},
|
||||
{IPC::MakeHeader(0x000D, 1, 0), nullptr, "GenerateUuid"},
|
||||
// act:a
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace Service::ACT {
|
|||
ACT_U::ACT_U(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "act:u") {
|
||||
static const FunctionInfo functions[] = {
|
||||
// clang-format off
|
||||
{IPC::MakeHeader(0x0001, 2, 4), nullptr, "Initialize"},
|
||||
{IPC::MakeHeader(0x0001, 2, 4), &ACT_U::Initialize, "Initialize"},
|
||||
{IPC::MakeHeader(0x0002, 1, 0), nullptr, "GetErrorCode"},
|
||||
{IPC::MakeHeader(0x0006, 3, 2), nullptr, "GetAccountDataBlock"},
|
||||
{IPC::MakeHeader(0x0006, 3, 2), &ACT_U::GetAccountDataBlock, "GetAccountDataBlock"},
|
||||
{IPC::MakeHeader(0x000B, 1, 2), nullptr, "AcquireEulaList"},
|
||||
{IPC::MakeHeader(0x000D, 1, 0), nullptr, "GenerateUuid"},
|
||||
// clang-format on
|
||||
|
|
|
@ -1121,6 +1121,17 @@ void Module::Interface::GetTicketList(Kernel::HLERequestContext& ctx) {
|
|||
ticket_list_count, ticket_index);
|
||||
}
|
||||
|
||||
void Module::Interface::NeedsCleanup(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x0013, 1, 0); // 0x00130040
|
||||
const auto media_type = rp.Pop<u8>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) media_type=0x{:02x}", media_type);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<bool>(false);
|
||||
}
|
||||
|
||||
void Module::Interface::QueryAvailableTitleDatabase(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x0019, 1, 0); // 0x190040
|
||||
u8 media_type = rp.Pop<u8>();
|
||||
|
|
|
@ -357,6 +357,16 @@ public:
|
|||
*/
|
||||
void GetTicketList(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* AM::NeedsCleanup service function
|
||||
* Inputs:
|
||||
* 1 : Media Type
|
||||
* Outputs:
|
||||
* 1 : Result, 0 on success, otherwise error code
|
||||
* 2 : bool, Needs Cleanup
|
||||
*/
|
||||
void NeedsCleanup(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* AM::QueryAvailableTitleDatabase service function
|
||||
* Inputs:
|
||||
|
|
|
@ -28,7 +28,7 @@ AM_NET::AM_NET(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
|
|||
{IPC::MakeHeader(0x0010, 4, 2), nullptr, "GetImportContentContextList"},
|
||||
{IPC::MakeHeader(0x0011, 4, 4), nullptr, "GetImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0012, 4, 2), nullptr, "DeleteImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), nullptr, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), &AM_NET::NeedsCleanup, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0014, 1, 0), nullptr, "DoCleanup"},
|
||||
{IPC::MakeHeader(0x0015, 1, 0), nullptr, "DeleteAllImportContexts"},
|
||||
{IPC::MakeHeader(0x0016, 0, 0), nullptr, "DeleteAllTemporaryPrograms"},
|
||||
|
|
|
@ -28,7 +28,7 @@ AM_SYS::AM_SYS(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
|
|||
{IPC::MakeHeader(0x0010, 4, 2), nullptr, "GetImportContentContextList"},
|
||||
{IPC::MakeHeader(0x0011, 4, 4), nullptr, "GetImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0012, 4, 2), nullptr, "DeleteImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), nullptr, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), &AM_SYS::NeedsCleanup, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0014, 1, 0), nullptr, "DoCleanup"},
|
||||
{IPC::MakeHeader(0x0015, 1, 0), nullptr, "DeleteAllImportContexts"},
|
||||
{IPC::MakeHeader(0x0016, 0, 0), nullptr, "DeleteAllTemporaryPrograms"},
|
||||
|
|
|
@ -28,7 +28,7 @@ AM_U::AM_U(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:u"
|
|||
{IPC::MakeHeader(0x0010, 4, 2), nullptr, "GetImportContentContextList"},
|
||||
{IPC::MakeHeader(0x0011, 4, 4), nullptr, "GetImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0012, 4, 2), nullptr, "DeleteImportContentContexts"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), nullptr, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0013, 1, 0), &AM_U::NeedsCleanup, "NeedsCleanup"},
|
||||
{IPC::MakeHeader(0x0014, 1, 0), nullptr, "DoCleanup"},
|
||||
{IPC::MakeHeader(0x0015, 1, 0), nullptr, "DeleteAllImportContexts"},
|
||||
{IPC::MakeHeader(0x0016, 0, 0), nullptr, "DeleteAllTemporaryPrograms"},
|
||||
|
|
|
@ -271,6 +271,17 @@ void Module::Interface::SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16
|
|||
rb.Push<u8>(static_cast<u8>(cfg->GetRegionValue()));
|
||||
}
|
||||
|
||||
void Module::Interface::SecureInfoGetByte101(Kernel::HLERequestContext& ctx, u16 id) {
|
||||
IPC::RequestParser rp(ctx, id, 0, 0);
|
||||
|
||||
LOG_DEBUG(Service_CFG, "(STUBBED) called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
// According to 3dbrew this is normally 0.
|
||||
rb.Push<u8>(0);
|
||||
}
|
||||
|
||||
void Module::Interface::GenHashConsoleUnique(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x03, 1, 0);
|
||||
const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF;
|
||||
|
|
|
@ -165,6 +165,17 @@ public:
|
|||
*/
|
||||
void SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16 id);
|
||||
|
||||
/**
|
||||
* CFG::SecureInfoGetByte101 service function
|
||||
* Inputs:
|
||||
* 1 : None
|
||||
* Outputs:
|
||||
* 0 : Result Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Value loaded from SecureInfo offset 0x101
|
||||
*/
|
||||
void SecureInfoGetByte101(Kernel::HLERequestContext& ctx, u16 id);
|
||||
|
||||
/**
|
||||
* CFG::GenHashConsoleUnique service function
|
||||
* Inputs:
|
||||
|
|
|
@ -31,7 +31,7 @@ CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "c
|
|||
{IPC::MakeHeader(0x0404, 1, 2), nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{IPC::MakeHeader(0x0405, 0, 0), nullptr, "GetLocalFriendCodeSeed"},
|
||||
{IPC::MakeHeader(0x0406, 0, 0), &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
|
||||
{IPC::MakeHeader(0x0407, 0, 0), nullptr, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0407, 0, 0), &CFG_I::D<&CFG_I::SecureInfoGetByte101, 0x0407>, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0408, 1, 2), nullptr, "SecureInfoGetSerialNo"},
|
||||
{IPC::MakeHeader(0x0409, 0, 0), nullptr, "UpdateConfigBlk00040003"},
|
||||
{IPC::MakeHeader(0x0801, 2, 2), &CFG_I::D<&CFG_I::GetConfigInfoBlk8, 0x0801>, "GetConfigInfoBlk8"},
|
||||
|
@ -55,7 +55,7 @@ CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "c
|
|||
{IPC::MakeHeader(0x0814, 1, 2), nullptr, "SecureInfoGetData"},
|
||||
{IPC::MakeHeader(0x0815, 1, 2), nullptr, "SecureInfoGetSignature"},
|
||||
{IPC::MakeHeader(0x0816, 0, 0), &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0816>, "SecureInfoGetRegion"},
|
||||
{IPC::MakeHeader(0x0817, 0, 0), nullptr, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0817, 0, 0), &CFG_I::D<&CFG_I::SecureInfoGetByte101, 0x0817>, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0818, 1, 2), nullptr, "SecureInfoGetSerialNo"},
|
||||
// clang-format on
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ CFG_S::CFG_S(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "c
|
|||
{IPC::MakeHeader(0x0404, 1, 2), nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{IPC::MakeHeader(0x0405, 0, 0), nullptr, "GetLocalFriendCodeSeed"},
|
||||
{IPC::MakeHeader(0x0406, 0, 0), &CFG_S::D<&CFG_S::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
|
||||
{IPC::MakeHeader(0x0407, 0, 0), nullptr, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0407, 0, 0), &CFG_S::D<&CFG_S::SecureInfoGetByte101, 0x0407>, "SecureInfoGetByte101"},
|
||||
{IPC::MakeHeader(0x0408, 1, 2), nullptr, "SecureInfoGetSerialNo"},
|
||||
{IPC::MakeHeader(0x0409, 0, 0), nullptr, "UpdateConfigBlk00040003"},
|
||||
// clang-format on
|
||||
|
|
|
@ -10,6 +10,13 @@ SERIALIZE_EXPORT_IMPL(Service::NEWS::NEWS_S)
|
|||
|
||||
namespace Service::NEWS {
|
||||
|
||||
struct NewsDbHeader {
|
||||
u8 unknown_one;
|
||||
u8 flags;
|
||||
INSERT_PADDING_BYTES(0xE);
|
||||
};
|
||||
static_assert(sizeof(NewsDbHeader) == 0x10, "News DB Header structure size is wrong");
|
||||
|
||||
void NEWS_S::GetTotalNotifications(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x5, 0, 0);
|
||||
|
||||
|
@ -21,6 +28,22 @@ void NEWS_S::GetTotalNotifications(Kernel::HLERequestContext& ctx) {
|
|||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void NEWS_S::GetNewsDBHeader(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0xA, 1, 2);
|
||||
const auto size = rp.Pop<u32>();
|
||||
auto output_buffer = rp.PopMappedBuffer();
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called size={}", size);
|
||||
|
||||
NewsDbHeader dummy = {.unknown_one = 1, .flags = 0};
|
||||
output_buffer.Write(&dummy, 0, std::min(sizeof(NewsDbHeader), static_cast<std::size_t>(size)));
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(size);
|
||||
}
|
||||
|
||||
NEWS_S::NEWS_S() : ServiceFramework("news:s", 2) {
|
||||
const FunctionInfo functions[] = {
|
||||
// clang-format off
|
||||
|
@ -30,7 +53,7 @@ NEWS_S::NEWS_S() : ServiceFramework("news:s", 2) {
|
|||
{IPC::MakeHeader(0x0007, 2, 2), nullptr, "SetNotificationHeader"},
|
||||
{IPC::MakeHeader(0x0008, 2, 2), nullptr, "SetNotificationMessage"},
|
||||
{IPC::MakeHeader(0x0009, 2, 2), nullptr, "SetNotificationImage"},
|
||||
{IPC::MakeHeader(0x000A, 1, 2), nullptr, "GetNewsDBHeader"},
|
||||
{IPC::MakeHeader(0x000A, 1, 2), &NEWS_S::GetNewsDBHeader, "GetNewsDBHeader"},
|
||||
{IPC::MakeHeader(0x000B, 2, 2), nullptr, "GetNotificationHeader"},
|
||||
{IPC::MakeHeader(0x000C, 2, 2), nullptr, "GetNotificationMessage"},
|
||||
{IPC::MakeHeader(0x000D, 2, 2), nullptr, "GetNotificationImage"},
|
||||
|
|
|
@ -25,6 +25,20 @@ private:
|
|||
*/
|
||||
void GetTotalNotifications(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* GetNewsDBHeader service function.
|
||||
* Inputs:
|
||||
* 0 : 0x000A0042
|
||||
* 1 : Size
|
||||
* 2 : Output Buffer Mapping Translation Header ((Size << 4) | 0xC)
|
||||
* 3 : Output Buffer Pointer
|
||||
* Outputs:
|
||||
* 0 : 0x000A0080
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Actual Size
|
||||
*/
|
||||
void GetNewsDBHeader(Kernel::HLERequestContext& ctx);
|
||||
|
||||
SERVICE_SERIALIZATION_SIMPLE
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "core/file_sys/archive_extsavedata.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/file_backend.h"
|
||||
#include "core/hle/kernel/shared_page.h"
|
||||
#include "core/hle/service/ptm/ptm.h"
|
||||
#include "core/hle/service/ptm/ptm_gets.h"
|
||||
#include "core/hle/service/ptm/ptm_play.h"
|
||||
|
@ -132,6 +133,17 @@ void Module::Interface::CheckNew3DS(Kernel::HLERequestContext& ctx) {
|
|||
Service::PTM::CheckNew3DS(rb);
|
||||
}
|
||||
|
||||
void Module::Interface::GetSystemTime(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x401, 0, 0);
|
||||
|
||||
auto& share_page = Core::System::GetInstance().Kernel().GetSharedPageHandler();
|
||||
const u64 console_time = share_page.GetSystemTimeSince2000();
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(console_time);
|
||||
}
|
||||
|
||||
static void WriteGameCoinData(GameCoin gamecoin_data) {
|
||||
const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
|
||||
FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true);
|
||||
|
|
|
@ -137,6 +137,14 @@ public:
|
|||
*/
|
||||
void CheckNew3DS(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* PTM::GetSystemTime service function
|
||||
* Outputs:
|
||||
* 1: Result code, 0 on success, otherwise error code
|
||||
* 2-3: Time since 01/01/2020.
|
||||
*/
|
||||
void GetSystemTime(Kernel::HLERequestContext& ctx);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> ptm;
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ PTM_Gets::PTM_Gets(std::shared_ptr<Module> ptm)
|
|||
{IPC::MakeHeader(0x000E, 0, 0), nullptr, "GetPedometerRecordingMode"},
|
||||
{IPC::MakeHeader(0x000F, 2, 4), nullptr, "GetStepHistoryAll"},
|
||||
// ptm:gets
|
||||
{IPC::MakeHeader(0x0401, 0, 0), nullptr, "GetSystemTime"},
|
||||
{IPC::MakeHeader(0x0401, 0, 0), &PTM_Gets::GetSystemTime, "GetSystemTime"},
|
||||
// clang-format on
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
|
Loading…
Reference in a new issue