hle: Stub some service calls used by the home menu. (#6675)

This commit is contained in:
Steveice10 2023-07-07 22:05:38 -07:00 committed by GitHub
parent 26e3f96983
commit 662bb9ba77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 187 additions and 22 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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:

View file

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

View file

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

View file

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

View file

@ -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:

View file

@ -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"},

View file

@ -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"},

View file

@ -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"},

View file

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

View file

@ -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:

View file

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

View file

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

View file

@ -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"},

View file

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

View file

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

View file

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

View file

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