mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	hle: Stub some service calls used by the home menu. (#6675)
This commit is contained in:
		
							parent
							
								
									26e3f96983
								
							
						
					
					
						commit
						662bb9ba77
					
				
					 22 changed files with 187 additions and 22 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue