summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/acc/acc.cpp42
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp19
-rw-r--r--src/core/hle/service/acc/profile_manager.h6
-rw-r--r--src/core/hle/service/am/am.cpp16
-rw-r--r--src/core/hle/service/am/am.h36
-rw-r--r--src/core/hle/service/am/applets/applet_mii.cpp101
-rw-r--r--src/core/hle/service/am/applets/applet_mii.h90
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.h2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp17
-rw-r--r--src/core/hle/service/am/applets/applets.h9
-rw-r--r--src/core/hle/service/apm/apm_controller.cpp10
-rw-r--r--src/core/hle/service/apm/apm_controller.h15
-rw-r--r--src/core/hle/service/friend/friend.cpp6
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/kernel_helpers.cpp8
-rw-r--r--src/core/hle/service/ldr/ldr.cpp78
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp12
-rw-r--r--src/core/hle/service/mii/mii_manager.h4
-rw-r--r--src/core/hle/service/mnpp/mnpp_app.cpp45
-rw-r--r--src/core/hle/service/mnpp/mnpp_app.h20
-rw-r--r--src/core/hle/service/nfp/nfp.cpp916
-rw-r--r--src/core/hle/service/nfp/nfp.h242
-rw-r--r--src/core/hle/service/ns/pdm_qry.cpp2
-rw-r--r--src/core/hle/service/pm/pm.cpp45
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sm/sm.cpp2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp4
-rw-r--r--src/core/hle/service/time/clock_types.h2
-rw-r--r--src/core/hle/service/time/steady_clock_core.h2
-rw-r--r--src/core/hle/service/time/time_manager.cpp2
-rw-r--r--src/core/hle/service/vi/display/vi_display.h2
33 files changed, 1420 insertions, 354 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 6e63e057e..e34ef5a78 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -39,9 +39,9 @@ constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
// Thumbnails are hard coded to be at least this size
constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
-static std::filesystem::path GetImagePath(Common::UUID uuid) {
+static std::filesystem::path GetImagePath(const Common::UUID& uuid) {
return Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
- fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormatSwitch());
+ fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
}
static constexpr u32 SanitizeJPEGSize(std::size_t size) {
@@ -290,7 +290,7 @@ public:
protected:
void Get(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
ProfileBase profile_base{};
ProfileData data{};
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
@@ -300,21 +300,21 @@ protected:
rb.PushRaw(profile_base);
} else {
LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}",
- user_id.Format());
+ user_id.RawString());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
}
}
void GetBase(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
ProfileBase profile_base{};
if (profile_manager.GetProfileBase(user_id, profile_base)) {
IPC::ResponseBuilder rb{ctx, 16};
rb.Push(ResultSuccess);
rb.PushRaw(profile_base);
} else {
- LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.Format());
+ LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.RawString());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
}
@@ -373,7 +373,7 @@ protected:
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
- base.timestamp, base.user_uuid.Format());
+ base.timestamp, base.user_uuid.RawString());
if (user_data.size() < sizeof(ProfileData)) {
LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
@@ -406,7 +406,7 @@ protected:
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
- base.timestamp, base.user_uuid.Format());
+ base.timestamp, base.user_uuid.RawString());
if (user_data.size() < sizeof(ProfileData)) {
LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
@@ -435,7 +435,7 @@ protected:
}
ProfileManager& profile_manager;
- Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to.
+ Common::UUID user_id{}; ///< The user id this profile refers to.
};
class IProfile final : public IProfileCommon {
@@ -547,7 +547,7 @@ private:
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.PushRaw<u64>(user_id.GetNintendoID());
+ rb.PushRaw<u64>(user_id.Hash());
}
void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) {
@@ -577,7 +577,7 @@ private:
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.PushRaw<u64>(user_id.GetNintendoID());
+ rb.PushRaw<u64>(user_id.Hash());
}
void StoreOpenContext(Kernel::HLERequestContext& ctx) {
@@ -587,7 +587,7 @@ private:
}
std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{};
- Common::UUID user_id{Common::INVALID_UUID};
+ Common::UUID user_id{};
};
// 6.0.0+
@@ -687,7 +687,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
- LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -718,7 +718,7 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
- LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -833,7 +833,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
- LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.RawString());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -875,7 +875,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
- LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.Format());
+ LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.RawString());
// TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable
// way of confirming things like the TID, we're going to assume a non zero value for the time
@@ -889,7 +889,7 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext&
const auto uuid = rp.PopRaw<Common::UUID>();
const auto tid = rp.Pop<u64_le>();
- LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.Format(), tid);
+ LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.RawString(), tid);
StoreSaveDataThumbnail(ctx, uuid, tid);
}
@@ -903,7 +903,7 @@ void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx,
return;
}
- if (!uuid) {
+ if (uuid.IsInvalid()) {
LOG_ERROR(Service_ACC, "User ID is not valid!");
rb.Push(ERR_INVALID_USER_ID);
return;
@@ -927,20 +927,20 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
IPC::ResponseBuilder rb{ctx, 6};
if (profile_manager->GetUserCount() != 1) {
rb.Push(ResultSuccess);
- rb.PushRaw<u128>(Common::INVALID_UUID);
+ rb.PushRaw(Common::InvalidUUID);
return;
}
const auto user_list = profile_manager->GetAllUsers();
if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) {
rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code
- rb.PushRaw<u128>(Common::INVALID_UUID);
+ rb.PushRaw(Common::InvalidUUID);
return;
}
// Select the first user we have
rb.Push(ResultSuccess);
- rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
+ rb.PushRaw(profile_manager->GetUser(0)->uuid);
}
Module::Interface::Interface(std::shared_ptr<Module> module_,
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 568303ced..fba847142 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -19,8 +19,8 @@ namespace FS = Common::FS;
using Common::UUID;
struct UserRaw {
- UUID uuid{Common::INVALID_UUID};
- UUID uuid2{Common::INVALID_UUID};
+ UUID uuid{};
+ UUID uuid2{};
u64 timestamp{};
ProfileUsername username{};
ProfileData extra_data{};
@@ -45,7 +45,7 @@ ProfileManager::ProfileManager() {
// Create an user if none are present
if (user_count == 0) {
- CreateNewUser(UUID::Generate(), "yuzu");
+ CreateNewUser(UUID::MakeRandom(), "yuzu");
}
auto current =
@@ -101,7 +101,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern
if (user_count == MAX_USERS) {
return ERROR_TOO_MANY_USERS;
}
- if (!uuid) {
+ if (uuid.IsInvalid()) {
return ERROR_ARGUMENT_IS_NULL;
}
if (username[0] == 0x0) {
@@ -145,7 +145,7 @@ std::optional<UUID> ProfileManager::GetUser(std::size_t index) const {
/// Returns a users profile index based on their user id.
std::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const {
- if (!uuid) {
+ if (uuid.IsInvalid()) {
return std::nullopt;
}
@@ -250,9 +250,10 @@ UserIDArray ProfileManager::GetOpenUsers() const {
std::ranges::transform(profiles, output.begin(), [](const ProfileInfo& p) {
if (p.is_open)
return p.user_uuid;
- return UUID{Common::INVALID_UUID};
+ return Common::InvalidUUID;
});
- std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; });
+ std::stable_partition(output.begin(), output.end(),
+ [](const UUID& uuid) { return uuid.IsValid(); });
return output;
}
@@ -299,7 +300,7 @@ bool ProfileManager::RemoveUser(UUID uuid) {
profiles[*index] = ProfileInfo{};
std::stable_partition(profiles.begin(), profiles.end(),
- [](const ProfileInfo& profile) { return profile.user_uuid; });
+ [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); });
return true;
}
@@ -361,7 +362,7 @@ void ProfileManager::ParseUserSaveFile() {
}
std::stable_partition(profiles.begin(), profiles.end(),
- [](const ProfileInfo& profile) { return profile.user_uuid; });
+ [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); });
}
void ProfileManager::WriteUserSaveFile() {
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 71b9d5518..17347f7ef 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -35,7 +35,7 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect
/// This holds general information about a users profile. This is where we store all the information
/// based on a specific user
struct ProfileInfo {
- Common::UUID user_uuid{Common::INVALID_UUID};
+ Common::UUID user_uuid{};
ProfileUsername username{};
u64 creation_time{};
ProfileData data{}; // TODO(ognik): Work out what this is
@@ -49,7 +49,7 @@ struct ProfileBase {
// Zero out all the fields to make the profile slot considered "Empty"
void Invalidate() {
- user_uuid.Invalidate();
+ user_uuid = {};
timestamp = 0;
username.fill(0);
}
@@ -103,7 +103,7 @@ private:
std::array<ProfileInfo, MAX_USERS> profiles{};
std::size_t user_count{};
- Common::UUID last_opened_user{Common::INVALID_UUID};
+ Common::UUID last_opened_user{};
};
}; // namespace Service::Account
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index e60661fe1..420de3c54 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -55,7 +55,7 @@ constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
struct LaunchParameterAccountPreselectedUser {
u32_le magic;
u32_le is_account_selected;
- u128 current_user;
+ Common::UUID current_user;
INSERT_PADDING_BYTES(0x70);
};
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
@@ -618,7 +618,7 @@ void AppletMessageQueue::PushMessage(AppletMessage msg) {
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
if (messages.empty()) {
on_new_message->GetWritableEvent().Clear();
- return AppletMessage::NoMessage;
+ return AppletMessage::None;
}
auto msg = messages.front();
messages.pop();
@@ -633,7 +633,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
}
void AppletMessageQueue::RequestExit() {
- PushMessage(AppletMessage::ExitRequested);
+ PushMessage(AppletMessage::Exit);
}
void AppletMessageQueue::FocusStateChanged() {
@@ -732,7 +732,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
const auto message = msg_queue->PopMessage();
IPC::ResponseBuilder rb{ctx, 3};
- if (message == AppletMessageQueue::AppletMessage::NoMessage) {
+ if (message == AppletMessageQueue::AppletMessage::None) {
LOG_ERROR(Service_AM, "Message queue is empty");
rb.Push(ERR_NO_MESSAGES);
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
@@ -980,7 +980,7 @@ private:
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -1007,7 +1007,7 @@ private:
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock());
ASSERT(applet->IsInitialized());
applet->ExecuteInteractive();
@@ -1453,8 +1453,8 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
Account::ProfileManager profile_manager{};
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
- ASSERT(uuid);
- params.current_user = uuid->uuid;
+ ASSERT(uuid.has_value() && uuid->IsValid());
+ params.current_user = *uuid;
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 2a578aea5..fdd937b82 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -22,6 +22,7 @@ class NVFlinger;
namespace Service::AM {
+// This is nn::settings::Language
enum SystemLanguage {
Japanese = 0,
English = 1, // en-US
@@ -41,16 +42,44 @@ enum SystemLanguage {
// 4.0.0+
SimplifiedChinese = 15,
TraditionalChinese = 16,
+ // 10.1.0+
+ BrazilianPortuguese = 17,
};
class AppletMessageQueue {
public:
+ // This is nn::am::AppletMessage
enum class AppletMessage : u32 {
- NoMessage = 0,
- ExitRequested = 4,
+ None = 0,
+ ChangeIntoForeground = 1,
+ ChangeIntoBackground = 2,
+ Exit = 4,
+ ApplicationExited = 6,
FocusStateChanged = 15,
+ Resume = 16,
+ DetectShortPressingHomeButton = 20,
+ DetectLongPressingHomeButton = 21,
+ DetectShortPressingPowerButton = 22,
+ DetectMiddlePressingPowerButton = 23,
+ DetectLongPressingPowerButton = 24,
+ RequestToPrepareSleep = 25,
+ FinishedSleepSequence = 26,
+ SleepRequiredByHighTemperature = 27,
+ SleepRequiredByLowBattery = 28,
+ AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
+ DetectReceivingCecSystemStandby = 32,
+ SdCardRemoved = 33,
+ LaunchApplicationRequested = 50,
+ RequestToDisplay = 51,
+ ShowApplicationLogo = 55,
+ HideApplicationLogo = 56,
+ ForceHideApplicationLogo = 57,
+ FloatingApplicationDetected = 60,
+ DetectShortPressingCaptureButton = 90,
+ AlbumScreenShotTaken = 92,
+ AlbumRecordingSaved = 93,
};
explicit AppletMessageQueue(Core::System& system);
@@ -179,11 +208,14 @@ public:
~ICommonStateGetter() override;
private:
+ // This is nn::oe::FocusState
enum class FocusState : u8 {
InFocus = 1,
NotInFocus = 2,
+ Background = 3,
};
+ // This is nn::oe::OperationMode
enum class OperationMode : u8 {
Handheld = 0,
Docked = 1,
diff --git a/src/core/hle/service/am/applets/applet_mii.cpp b/src/core/hle/service/am/applets/applet_mii.cpp
new file mode 100644
index 000000000..8c4173737
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_mii.cpp
@@ -0,0 +1,101 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/frontend/applets/mii.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/applet_mii.h"
+#include "core/reporter.h"
+
+namespace Service::AM::Applets {
+
+Mii::Mii(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::MiiApplet& frontend_)
+ : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
+
+Mii::~Mii() = default;
+
+void Mii::Initialize() {
+ is_complete = false;
+
+ const auto storage = broker.PopNormalDataToApplet();
+ ASSERT(storage != nullptr);
+
+ const auto data = storage->GetData();
+ ASSERT(data.size() == sizeof(MiiAppletInput));
+
+ std::memcpy(&input_data, data.data(), sizeof(MiiAppletInput));
+}
+
+bool Mii::TransactionComplete() const {
+ return is_complete;
+}
+
+ResultCode Mii::GetStatus() const {
+ return ResultSuccess;
+}
+
+void Mii::ExecuteInteractive() {
+ UNREACHABLE_MSG("Unexpected interactive applet data!");
+}
+
+void Mii::Execute() {
+ if (is_complete) {
+ return;
+ }
+
+ const auto callback = [this](const Core::Frontend::MiiParameters& parameters) {
+ DisplayCompleted(parameters);
+ };
+
+ switch (input_data.applet_mode) {
+ case MiiAppletMode::ShowMiiEdit: {
+ Service::Mii::MiiManager manager;
+ Core::Frontend::MiiParameters params{
+ .is_editable = false,
+ .mii_data = input_data.mii_char_info.mii_data,
+ };
+ frontend.ShowMii(params, callback);
+ break;
+ }
+ case MiiAppletMode::EditMii: {
+ Service::Mii::MiiManager manager;
+ Core::Frontend::MiiParameters params{
+ .is_editable = true,
+ .mii_data = input_data.mii_char_info.mii_data,
+ };
+ frontend.ShowMii(params, callback);
+ break;
+ }
+ case MiiAppletMode::CreateMii: {
+ Service::Mii::MiiManager manager;
+ Core::Frontend::MiiParameters params{
+ .is_editable = true,
+ .mii_data = manager.BuildDefault(0),
+ };
+ frontend.ShowMii(params, callback);
+ break;
+ }
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented LibAppletMiiEdit mode={:02X}!", input_data.applet_mode);
+ }
+}
+
+void Mii::DisplayCompleted(const Core::Frontend::MiiParameters& parameters) {
+ is_complete = true;
+
+ std::vector<u8> reply(sizeof(AppletOutputForCharInfoEditing));
+ output_data = {
+ .result = ResultSuccess,
+ .mii_data = parameters.mii_data,
+ };
+
+ std::memcpy(reply.data(), &output_data, sizeof(AppletOutputForCharInfoEditing));
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+ broker.SignalStateChanged();
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_mii.h b/src/core/hle/service/am/applets/applet_mii.h
new file mode 100644
index 000000000..42326bfc2
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_mii.h
@@ -0,0 +1,90 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/mii/mii_manager.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::AM::Applets {
+
+// This is nn::mii::AppletMode
+enum class MiiAppletMode : u32 {
+ ShowMiiEdit = 0,
+ AppendMii = 1,
+ AppendMiiImage = 2,
+ UpdateMiiImage = 3,
+ CreateMii = 4,
+ EditMii = 5,
+};
+
+struct MiiCharInfo {
+ Service::Mii::MiiInfo mii_data{};
+ INSERT_PADDING_BYTES(0x28);
+};
+static_assert(sizeof(MiiCharInfo) == 0x80, "MiiCharInfo has incorrect size.");
+
+// This is nn::mii::AppletInput
+struct MiiAppletInput {
+ s32 version{};
+ MiiAppletMode applet_mode{};
+ u32 special_mii_key_code{};
+ union {
+ std::array<Common::UUID, 8> valid_uuid;
+ MiiCharInfo mii_char_info;
+ };
+ Common::UUID used_uuid;
+ INSERT_PADDING_BYTES(0x64);
+};
+static_assert(sizeof(MiiAppletInput) == 0x100, "MiiAppletInput has incorrect size.");
+
+// This is nn::mii::AppletOutput
+struct MiiAppletOutput {
+ ResultCode result{ResultSuccess};
+ s32 index{};
+ INSERT_PADDING_BYTES(0x18);
+};
+static_assert(sizeof(MiiAppletOutput) == 0x20, "MiiAppletOutput has incorrect size.");
+
+// This is nn::mii::AppletOutputForCharInfoEditing
+struct AppletOutputForCharInfoEditing {
+ ResultCode result{ResultSuccess};
+ Service::Mii::MiiInfo mii_data{};
+ INSERT_PADDING_BYTES(0x24);
+};
+static_assert(sizeof(AppletOutputForCharInfoEditing) == 0x80,
+ "AppletOutputForCharInfoEditing has incorrect size.");
+
+class Mii final : public Applet {
+public:
+ explicit Mii(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::MiiApplet& frontend_);
+ ~Mii() override;
+
+ void Initialize() override;
+
+ bool TransactionComplete() const override;
+ ResultCode GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+
+ void DisplayCompleted(const Core::Frontend::MiiParameters& parameters);
+
+private:
+ const Core::Frontend::MiiApplet& frontend;
+ MiiAppletInput input_data{};
+ AppletOutputForCharInfoEditing output_data{};
+
+ bool is_complete = false;
+ Core::System& system;
+};
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp
index a6e891944..82500e121 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.cpp
+++ b/src/core/hle/service/am/applets/applet_profile_select.cpp
@@ -62,11 +62,11 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
if (uuid.has_value() && uuid->IsValid()) {
output.result = 0;
- output.uuid_selected = uuid->uuid;
+ output.uuid_selected = *uuid;
} else {
status = ERR_USER_CANCELLED_SELECTION;
output.result = ERR_USER_CANCELLED_SELECTION.raw;
- output.uuid_selected = Common::INVALID_UUID;
+ output.uuid_selected = Common::InvalidUUID;
}
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h
index 8fb76e6c4..852e1e0c0 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.h
+++ b/src/core/hle/service/am/applets/applet_profile_select.h
@@ -27,7 +27,7 @@ static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has inco
struct UserSelectionOutput {
u64 result;
- u128 uuid_selected;
+ Common::UUID uuid_selected;
};
static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size.");
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 134ac1ee2..79e62679d 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -9,6 +9,7 @@
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
+#include "core/frontend/applets/mii.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
@@ -19,6 +20,7 @@
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
+#include "core/hle/service/am/applets/applet_mii.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/applets/applet_software_keyboard.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
@@ -172,10 +174,11 @@ AppletFrontendSet::AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
ParentalControlsApplet parental_controls_applet,
- PhotoViewer photo_viewer_, ProfileSelect profile_select_,
+ MiiApplet mii_applet, PhotoViewer photo_viewer_,
+ ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
: controller{std::move(controller_applet)}, error{std::move(error_applet)},
- parental_controls{std::move(parental_controls_applet)},
+ parental_controls{std::move(parental_controls_applet)}, mii{std::move(mii_applet)},
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
@@ -206,6 +209,10 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
frontend.parental_controls = std::move(set.parental_controls);
}
+ if (set.mii != nullptr) {
+ frontend.mii = std::move(set.mii);
+ }
+
if (set.photo_viewer != nullptr) {
frontend.photo_viewer = std::move(set.photo_viewer);
}
@@ -243,6 +250,10 @@ void AppletManager::SetDefaultAppletsIfMissing() {
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
}
+ if (frontend.mii == nullptr) {
+ frontend.mii = std::make_unique<Core::Frontend::DefaultMiiApplet>();
+ }
+
if (frontend.photo_viewer == nullptr) {
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
}
@@ -277,6 +288,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
+ case AppletId::MiiEdit:
+ return std::make_shared<Mii>(system, mode, *frontend.mii);
case AppletId::Web:
case AppletId::Shop:
case AppletId::OfflineWeb:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 15eeb4ee1..0c44aec79 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -21,6 +21,7 @@ class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
class ParentalControlsApplet;
+class MiiApplet;
class PhotoViewerApplet;
class ProfileSelectApplet;
class SoftwareKeyboardApplet;
@@ -179,6 +180,7 @@ struct AppletFrontendSet {
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
+ using MiiApplet = std::unique_ptr<Core::Frontend::MiiApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
@@ -186,9 +188,9 @@ struct AppletFrontendSet {
AppletFrontendSet();
AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
- ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
- ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
- WebBrowser web_browser_);
+ ParentalControlsApplet parental_controls_applet, MiiApplet mii_applet,
+ PhotoViewer photo_viewer_, ProfileSelect profile_select_,
+ SoftwareKeyboard software_keyboard_, WebBrowser web_browser_);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -200,6 +202,7 @@ struct AppletFrontendSet {
ControllerApplet controller;
ErrorApplet error;
ParentalControlsApplet parental_controls;
+ MiiApplet mii;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp
index 98839fe97..187fef2ad 100644
--- a/src/core/hle/service/apm/apm_controller.cpp
+++ b/src/core/hle/service/apm/apm_controller.cpp
@@ -17,8 +17,8 @@ constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Con
Controller::Controller(Core::Timing::CoreTiming& core_timing_)
: core_timing{core_timing_}, configs{
- {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
- {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
+ {PerformanceMode::Normal, DEFAULT_PERFORMANCE_CONFIGURATION},
+ {PerformanceMode::Boost, DEFAULT_PERFORMANCE_CONFIGURATION},
} {}
Controller::~Controller() = default;
@@ -63,13 +63,13 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
PerformanceConfiguration::Config15,
}};
- SetPerformanceConfiguration(PerformanceMode::Docked,
+ SetPerformanceConfiguration(PerformanceMode::Boost,
BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode)));
}
PerformanceMode Controller::GetCurrentPerformanceMode() const {
- return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked
- : PerformanceMode::Handheld;
+ return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Boost
+ : PerformanceMode::Normal;
}
PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
diff --git a/src/core/hle/service/apm/apm_controller.h b/src/core/hle/service/apm/apm_controller.h
index 8d48e0104..d6fbd2c0c 100644
--- a/src/core/hle/service/apm/apm_controller.h
+++ b/src/core/hle/service/apm/apm_controller.h
@@ -32,15 +32,18 @@ enum class PerformanceConfiguration : u32 {
Config16 = 0x9222000C,
};
+// This is nn::oe::CpuBoostMode
enum class CpuBoostMode : u32 {
- Disabled = 0,
- Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16
- Partial = 2, // GPU Only -> Config 15 or 16
+ Normal = 0, // Boost mode disabled
+ FastLoad = 1, // CPU + GPU -> Config 13, 14, 15, or 16
+ Partial = 2, // GPU Only -> Config 15 or 16
};
-enum class PerformanceMode : u8 {
- Handheld = 0,
- Docked = 1,
+// This is nn::oe::PerformanceMode
+enum class PerformanceMode : s32 {
+ Invalid = -1,
+ Normal = 0,
+ Boost = 1,
};
// Class to manage the state and change of the emulated system performance.
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 9f9cea1e0..79cd3acbb 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -173,7 +173,7 @@ private:
const auto uuid = rp.PopRaw<Common::UUID>();
LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play,
- uuid.Format());
+ uuid.RawString());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -186,7 +186,7 @@ private:
[[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
const auto pid = rp.Pop<u64>();
LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
- uuid.Format(), pid);
+ uuid.RawString(), pid);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -312,7 +312,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
IPC::RequestParser rp{ctx};
auto uuid = rp.PopRaw<Common::UUID>();
- LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.Format());
+ LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.RawString());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a2bf7defb..d9202ea6c 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -320,7 +320,7 @@ Hid::Hid(Core::System& system_)
{308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
{309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
{310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
- {400, nullptr, "IsUsbFullKeyControllerEnabled"},
+ {400, &Hid::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
{401, nullptr, "EnableUsbFullKeyController"},
{402, nullptr, "IsUsbFullKeyControllerConnected"},
{403, nullptr, "HasBattery"},
@@ -1673,6 +1673,16 @@ void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
+void Hid::IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(false);
+}
+
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index d290df161..c281081a7 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -159,6 +159,7 @@ private:
void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx);
+ void IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx);
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index 62f4cdfb2..ff0bbb788 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#include "core/core.h"
+#include "core/core_timing.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_resource_limit.h"
@@ -15,9 +17,11 @@ namespace Service::KernelHelpers {
ServiceContext::ServiceContext(Core::System& system_, std::string name_)
: kernel(system_.Kernel()) {
+ // Create the process.
process = Kernel::KProcess::Create(kernel);
ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_),
- Kernel::KProcess::ProcessType::Userland)
+ Kernel::KProcess::ProcessType::KernelInternal,
+ kernel.GetSystemResourceLimit())
.IsSuccess());
}
@@ -43,7 +47,7 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
}
// Initialize the event.
- event->Initialize(std::move(name));
+ event->Initialize(std::move(name), process);
// Commit the thread reservation.
event_reservation.Commit();
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 9fc7bb1b1..099276420 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -288,7 +288,7 @@ public:
}
bool ValidateRegionForMap(Kernel::KPageTable& page_table, VAddr start, std::size_t size) const {
- constexpr std::size_t padding_size{4 * Kernel::PageSize};
+ const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize};
const auto start_info{page_table.QueryInfo(start - 1)};
if (start_info.state != Kernel::KMemoryState::Free) {
@@ -308,31 +308,69 @@ public:
return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize());
}
- VAddr GetRandomMapRegion(const Kernel::KPageTable& page_table, std::size_t size) const {
- VAddr addr{};
- const std::size_t end_pages{(page_table.GetAliasCodeRegionSize() - size) >>
- Kernel::PageBits};
- do {
- addr = page_table.GetAliasCodeRegionStart() +
- (Kernel::KSystemControl::GenerateRandomRange(0, end_pages) << Kernel::PageBits);
- } while (!page_table.IsInsideAddressSpace(addr, size) ||
- page_table.IsInsideHeapRegion(addr, size) ||
- page_table.IsInsideAliasRegion(addr, size));
- return addr;
+ ResultCode GetAvailableMapRegion(Kernel::KPageTable& page_table, u64 size, VAddr& out_addr) {
+ size = Common::AlignUp(size, Kernel::PageSize);
+ size += page_table.GetNumGuardPages() * Kernel::PageSize * 4;
+
+ const auto is_region_available = [&](VAddr addr) {
+ const auto end_addr = addr + size;
+ while (addr < end_addr) {
+ if (system.Memory().IsValidVirtualAddress(addr)) {
+ return false;
+ }
+
+ if (!page_table.IsInsideAddressSpace(out_addr, size)) {
+ return false;
+ }
+
+ if (page_table.IsInsideHeapRegion(out_addr, size)) {
+ return false;
+ }
+
+ if (page_table.IsInsideAliasRegion(out_addr, size)) {
+ return false;
+ }
+
+ addr += Kernel::PageSize;
+ }
+ return true;
+ };
+
+ bool succeeded = false;
+ const auto map_region_end =
+ page_table.GetAliasCodeRegionStart() + page_table.GetAliasCodeRegionSize();
+ while (current_map_addr < map_region_end) {
+ if (is_region_available(current_map_addr)) {
+ succeeded = true;
+ break;
+ }
+ current_map_addr += 0x100000;
+ }
+
+ if (!succeeded) {
+ UNREACHABLE_MSG("Out of address space!");
+ return Kernel::ResultOutOfMemory;
+ }
+
+ out_addr = current_map_addr;
+ current_map_addr += size;
+
+ return ResultSuccess;
}
- ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr baseAddress,
- u64 size) const {
+ ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
+ auto& page_table{process->PageTable()};
+ VAddr addr{};
+
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
- auto& page_table{process->PageTable()};
- const VAddr addr{GetRandomMapRegion(page_table, size)};
- const ResultCode result{page_table.MapCodeMemory(addr, baseAddress, size)};
+ R_TRY(GetAvailableMapRegion(page_table, size, addr));
+ const ResultCode result{page_table.MapCodeMemory(addr, base_addr, size)};
if (result == Kernel::ResultInvalidCurrentMemory) {
continue;
}
- CASCADE_CODE(result);
+ R_TRY(result);
if (ValidateRegionForMap(page_table, addr, size)) {
return addr;
@@ -343,7 +381,7 @@ public:
}
ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
- VAddr bss_addr, std::size_t bss_size, std::size_t size) const {
+ VAddr bss_addr, std::size_t bss_size, std::size_t size) {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->PageTable()};
VAddr addr{};
@@ -597,6 +635,7 @@ public:
LOG_WARNING(Service_LDR, "(STUBBED) called");
initialized = true;
+ current_map_addr = system.CurrentProcess()->PageTable().GetAliasCodeRegionStart();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -607,6 +646,7 @@ private:
std::map<VAddr, NROInfo> nro;
std::map<VAddr, std::vector<SHA256Hash>> nrr;
+ VAddr current_map_addr{};
bool IsValidNROHash(const SHA256Hash& hash) const {
return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) {
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index ca4ed35bb..0a57c3cde 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -118,16 +118,6 @@ u16 GenerateCrc16(const void* data, std::size_t size) {
return Common::swap16(static_cast<u16>(crc));
}
-Common::UUID GenerateValidUUID() {
- auto uuid{Common::UUID::Generate()};
-
- // Bit 7 must be set, and bit 6 unset for the UUID to be valid
- uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL;
- uuid.uuid[1] |= 0x0000000000000080ULL;
-
- return uuid;
-}
-
template <typename T>
T GetRandomValue(T min, T max) {
std::random_device device;
@@ -383,7 +373,7 @@ MiiStoreData::MiiStoreData() = default;
MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields,
const Common::UUID& user_id) {
data.name = name;
- data.uuid = GenerateValidUUID();
+ data.uuid = Common::UUID::MakeRandomRFC4122V4();
std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields));
data_crc = GenerateCrc16(data.data.data(), sizeof(data));
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index 8e048fc56..6999d15b1 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -202,7 +202,7 @@ struct MiiStoreData {
static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size.");
Name name{};
- Common::UUID uuid{Common::INVALID_UUID};
+ Common::UUID uuid{};
} data;
u16 data_crc{};
@@ -326,7 +326,7 @@ public:
ResultCode GetIndex(const MiiInfo& info, u32& index);
private:
- const Common::UUID user_id{Common::INVALID_UUID};
+ const Common::UUID user_id{};
u64 update_counter{};
};
diff --git a/src/core/hle/service/mnpp/mnpp_app.cpp b/src/core/hle/service/mnpp/mnpp_app.cpp
new file mode 100644
index 000000000..53497612f
--- /dev/null
+++ b/src/core/hle/service/mnpp/mnpp_app.cpp
@@ -0,0 +1,45 @@
+// Copyright 2022 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/mnpp/mnpp_app.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::MNPP {
+
+class MNPP_APP final : public ServiceFramework<MNPP_APP> {
+public:
+ explicit MNPP_APP(Core::System& system_) : ServiceFramework{system_, "mnpp:app"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &MNPP_APP::Unknown0, "unknown0"},
+ {1, &MNPP_APP::Unknown1, "unknown1"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void Unknown0(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_MNPP, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void Unknown1(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_MNPP, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<MNPP_APP>(system)->InstallAsService(service_manager);
+}
+
+} // namespace Service::MNPP
diff --git a/src/core/hle/service/mnpp/mnpp_app.h b/src/core/hle/service/mnpp/mnpp_app.h
new file mode 100644
index 000000000..6bf20b494
--- /dev/null
+++ b/src/core/hle/service/mnpp/mnpp_app.h
@@ -0,0 +1,20 @@
+// Copyright 2022 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Core {
+class System;
+}
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::MNPP {
+
+/// Registers all MNPP services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+
+} // namespace Service::MNPP
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 761d0d3c6..513107715 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,6 +7,9 @@
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
+#include "core/hid/hid_types.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/nfp/nfp.h"
@@ -14,343 +17,790 @@
namespace Service::NFP {
namespace ErrCodes {
-constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
+constexpr ResultCode DeviceNotFound(ErrorModule::NFP, 64);
+constexpr ResultCode WrongDeviceState(ErrorModule::NFP, 73);
+constexpr ResultCode ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr ResultCode ApplicationAreaExist(ErrorModule::NFP, 168);
} // namespace ErrCodes
-Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
- const char* name)
- : ServiceFramework{system_, name}, module{std::move(module_)}, service_context{system_,
- "NFP::IUser"} {
- nfc_tag_load = service_context.CreateEvent("NFP::IUser:NFCTagDetected");
-}
-
-Module::Interface::~Interface() {
- service_context.CloseEvent(nfc_tag_load);
-}
-
-class IUser final : public ServiceFramework<IUser> {
-public:
- explicit IUser(Module::Interface& nfp_interface_, Core::System& system_,
- KernelHelpers::ServiceContext& service_context_)
- : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_},
- service_context{service_context_} {
- static const FunctionInfo functions[] = {
- {0, &IUser::Initialize, "Initialize"},
- {1, &IUser::Finalize, "Finalize"},
- {2, &IUser::ListDevices, "ListDevices"},
- {3, &IUser::StartDetection, "StartDetection"},
- {4, &IUser::StopDetection, "StopDetection"},
- {5, &IUser::Mount, "Mount"},
- {6, &IUser::Unmount, "Unmount"},
- {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
- {8, &IUser::GetApplicationArea, "GetApplicationArea"},
- {9, nullptr, "SetApplicationArea"},
- {10, nullptr, "Flush"},
- {11, nullptr, "Restore"},
- {12, nullptr, "CreateApplicationArea"},
- {13, &IUser::GetTagInfo, "GetTagInfo"},
- {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
- {15, &IUser::GetCommonInfo, "GetCommonInfo"},
- {16, &IUser::GetModelInfo, "GetModelInfo"},
- {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
- {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
- {19, &IUser::GetState, "GetState"},
- {20, &IUser::GetDeviceState, "GetDeviceState"},
- {21, &IUser::GetNpadId, "GetNpadId"},
- {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
- {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
- {24, nullptr, "RecreateApplicationArea"},
- };
- RegisterHandlers(functions);
+constexpr u32 ApplicationAreaSize = 0xD8;
+
+IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_)
+ : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name},
+ nfp_interface{nfp_interface_} {
+ static const FunctionInfo functions[] = {
+ {0, &IUser::Initialize, "Initialize"},
+ {1, &IUser::Finalize, "Finalize"},
+ {2, &IUser::ListDevices, "ListDevices"},
+ {3, &IUser::StartDetection, "StartDetection"},
+ {4, &IUser::StopDetection, "StopDetection"},
+ {5, &IUser::Mount, "Mount"},
+ {6, &IUser::Unmount, "Unmount"},
+ {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
+ {8, &IUser::GetApplicationArea, "GetApplicationArea"},
+ {9, &IUser::SetApplicationArea, "SetApplicationArea"},
+ {10, nullptr, "Flush"},
+ {11, nullptr, "Restore"},
+ {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
+ {13, &IUser::GetTagInfo, "GetTagInfo"},
+ {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
+ {15, &IUser::GetCommonInfo, "GetCommonInfo"},
+ {16, &IUser::GetModelInfo, "GetModelInfo"},
+ {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
+ {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {19, &IUser::GetState, "GetState"},
+ {20, &IUser::GetDeviceState, "GetDeviceState"},
+ {21, &IUser::GetNpadId, "GetNpadId"},
+ {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
+ {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {24, nullptr, "RecreateApplicationArea"},
+ };
+ RegisterHandlers(functions);
- deactivate_event = service_context.CreateEvent("NFP::IUser:DeactivateEvent");
- availability_change_event =
- service_context.CreateEvent("NFP::IUser:AvailabilityChangeEvent");
- }
+ availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
+}
- ~IUser() override {
- service_context.CloseEvent(deactivate_event);
- service_context.CloseEvent(availability_change_event);
- }
+void IUser::Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
-private:
- struct TagInfo {
- std::array<u8, 10> uuid;
- u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
- // mean something else
- std::array<u8, 0x15> padding_1;
- u32_le protocol;
- u32_le tag_type;
- std::array<u8, 0x2c> padding_2;
- };
- static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
+ state = State::Initialized;
- enum class State : u32 {
- NonInitialized = 0,
- Initialized = 1,
- };
+ // TODO(german77): Loop through all interfaces
+ nfp_interface.Initialize();
- enum class DeviceState : u32 {
- Initialized = 0,
- SearchingForTag = 1,
- TagFound = 2,
- TagRemoved = 3,
- TagNearby = 4,
- Unknown5 = 5,
- Finalized = 6
- };
+ IPC::ResponseBuilder rb{ctx, 2, 0};
+ rb.Push(ResultSuccess);
+}
- struct CommonInfo {
- u16_be last_write_year;
- u8 last_write_month;
- u8 last_write_day;
- u16_be write_counter;
- u16_be version;
- u32_be application_area_size;
- INSERT_PADDING_BYTES(0x34);
- };
- static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
+void IUser::Finalize(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFP, "called");
- void Initialize(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
+ state = State::NonInitialized;
- IPC::ResponseBuilder rb{ctx, 2, 0};
- rb.Push(ResultSuccess);
+ // TODO(german77): Loop through all interfaces
+ nfp_interface.Finalize();
- state = State::Initialized;
- }
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
- void GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
+void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFP, "called");
- IPC::ResponseBuilder rb{ctx, 3, 0};
- rb.Push(ResultSuccess);
- rb.PushRaw<u32>(static_cast<u32>(state));
+ std::vector<u64> devices;
+
+ // TODO(german77): Loop through all interfaces
+ devices.push_back(nfp_interface.GetHandle());
+
+ ctx.WriteBuffer(devices);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<s32>(devices.size()));
+}
+
+void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto nfp_protocol{rp.Pop<s32>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.StartDetection(nfp_protocol);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
}
- void ListDevices(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u32 array_size = rp.Pop<u32>();
- LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- ctx.WriteBuffer(device_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(1);
+void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.StopDetection();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
}
- void GetNpadId(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 dev_handle = rp.Pop<u64>();
- LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(npad_id);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::Mount(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto model_type{rp.PopEnum<ModelType>()};
+ const auto mount_target{rp.PopEnum<MountTarget>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
+ model_type, mount_target);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.Mount();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
}
- void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 dev_handle = rp.Pop<u64>();
- LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(nfp_interface.GetNFCEvent());
- has_attached_handle = true;
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::Unmount(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.Unmount();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
}
- void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 dev_handle = rp.Pop<u64>();
- LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(deactivate_event->GetReadableEvent());
- }
-
- void StopDetection(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
-
- switch (device_state) {
- case DeviceState::TagFound:
- case DeviceState::TagNearby:
- deactivate_event->GetWritableEvent().Signal();
- device_state = DeviceState::Initialized;
- break;
- case DeviceState::SearchingForTag:
- case DeviceState::TagRemoved:
- device_state = DeviceState::Initialized;
- break;
- default:
- break;
- }
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto access_id{rp.Pop<u32>()};
+ LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, access_id={}", device_handle,
+ access_id);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.OpenApplicationArea(access_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void GetDeviceState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ std::vector<u8> data{};
+ const auto result = nfp_interface.GetApplicationArea(data);
+ ctx.WriteBuffer(data);
IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(device_state));
+ rb.Push(result);
+ rb.Push(static_cast<u32>(data.size()));
+ return;
}
- void StartDetection(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
- device_state = DeviceState::SearchingForTag;
- }
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto data{ctx.ReadBuffer()};
+ LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}", device_handle,
+ data.size());
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.SetApplicationArea(data);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void GetTagInfo(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto access_id{rp.Pop<u32>()};
+ const auto data{ctx.ReadBuffer()};
+ LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}, access_id={}",
+ device_handle, access_id, data.size());
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ const auto result = nfp_interface.CreateApplicationArea(access_id, data);
IPC::ResponseBuilder rb{ctx, 2};
- const auto& amiibo = nfp_interface.GetAmiiboBuffer();
- const TagInfo tag_info{
- .uuid = amiibo.uuid,
- .uuid_length = static_cast<u8>(amiibo.uuid.size()),
- .padding_1 = {},
- .protocol = 1, // TODO(ogniK): Figure out actual values
- .tag_type = 2,
- .padding_2 = {},
- };
- ctx.WriteBuffer(tag_info);
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void Mount(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
- device_state = DeviceState::TagNearby;
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ TagInfo tag_info{};
+ const auto result = nfp_interface.GetTagInfo(tag_info);
+ ctx.WriteBuffer(tag_info);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void GetModelInfo(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ RegisterInfo register_info{};
+ const auto result = nfp_interface.GetRegisterInfo(register_info);
+ ctx.WriteBuffer(register_info);
IPC::ResponseBuilder rb{ctx, 2};
- const auto& amiibo = nfp_interface.GetAmiiboBuffer();
- ctx.WriteBuffer(amiibo.model_info);
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void Unmount(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- device_state = DeviceState::TagFound;
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ CommonInfo common_info{};
+ const auto result = nfp_interface.GetCommonInfo(common_info);
+ ctx.WriteBuffer(common_info);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void Finalize(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
- device_state = DeviceState::Finalized;
+void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ ModelInfo model_info{};
+ const auto result = nfp_interface.GetModelInfo(model_info);
+ ctx.WriteBuffer(model_info);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
+ return;
}
- void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
- rb.PushCopyObjects(availability_change_event->GetReadableEvent());
+ rb.PushCopyObjects(nfp_interface.GetActivateEvent());
+ return;
}
- void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- // TODO(ogniK): Pull Mii and owner data from amiibo
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
- IPC::ResponseBuilder rb{ctx, 2};
+void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
+ rb.PushCopyObjects(nfp_interface.GetDeactivateEvent());
+ return;
}
- void GetCommonInfo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- // TODO(ogniK): Pull common information from amiibo
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
- CommonInfo common_info{};
- common_info.application_area_size = 0;
- ctx.WriteBuffer(common_info);
+void IUser::GetState(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
- IPC::ResponseBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 3, 0};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(state);
+}
+
+void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
+ rb.PushEnum(nfp_interface.GetCurrentState());
+ return;
}
- void OpenApplicationArea(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA);
- }
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
- void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
- // We don't need to worry about this since we can just open the file
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
+ rb.PushEnum(nfp_interface.GetNpadId());
+ return;
}
- void GetApplicationArea(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFP, "(STUBBED) called");
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
- // TODO(ogniK): Pull application area from amiibo
+void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+ // TODO(german77): Loop through all interfaces
+ if (device_handle == nfp_interface.GetHandle()) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
+ rb.Push(ApplicationAreaSize);
+ return;
}
- Module::Interface& nfp_interface;
- KernelHelpers::ServiceContext& service_context;
+ LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ErrCodes::DeviceNotFound);
+}
+
+void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFP, "(STUBBED) called");
- bool has_attached_handle{};
- const u64 device_handle{0}; // Npad device 1
- const u32 npad_id{0}; // Player 1 controller
- State state{State::NonInitialized};
- DeviceState device_state{DeviceState::Initialized};
- Kernel::KEvent* deactivate_event;
- Kernel::KEvent* availability_change_event;
-};
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(availability_change_event->GetReadableEvent());
+}
+
+Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
+ const char* name)
+ : ServiceFramework{system_, name}, module{std::move(module_)},
+ npad_id{Core::HID::NpadIdType::Player1}, service_context{system_, service_name} {
+ activate_event = service_context.CreateEvent("IUser:NFPActivateEvent");
+ deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent");
+}
+
+Module::Interface::~Interface() = default;
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<IUser>(*this, system, service_context);
+ rb.PushIpcInterface<IUser>(*this, system);
}
bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
- if (buffer.size() < sizeof(AmiiboFile)) {
+ if (device_state != DeviceState::SearchingForTag) {
+ LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state);
+ return false;
+ }
+
+ constexpr auto tag_size = sizeof(NTAG215File);
+ constexpr auto tag_size_without_password = sizeof(NTAG215File) - sizeof(NTAG215Password);
+
+ std::vector<u8> amiibo_buffer = buffer;
+
+ if (amiibo_buffer.size() < tag_size_without_password) {
+ LOG_ERROR(Service_NFP, "Wrong file size {}", buffer.size());
+ return false;
+ }
+
+ // Ensure it has the correct size
+ if (amiibo_buffer.size() != tag_size) {
+ amiibo_buffer.resize(tag_size, 0);
+ }
+
+ LOG_INFO(Service_NFP, "Amiibo detected");
+ std::memcpy(&tag_data, buffer.data(), tag_size);
+
+ if (!IsAmiiboValid()) {
return false;
}
- std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
- nfc_tag_load->GetWritableEvent().Signal();
+ // This value can't be dumped from a tag. Generate it
+ tag_data.password.PWD = GetTagPassword(tag_data.uuid);
+
+ device_state = DeviceState::TagFound;
+ activate_event->GetWritableEvent().Signal();
return true;
}
-Kernel::KReadableEvent& Module::Interface::GetNFCEvent() {
- return nfc_tag_load->GetReadableEvent();
+void Module::Interface::CloseAmiibo() {
+ LOG_INFO(Service_NFP, "Remove amiibo");
+ device_state = DeviceState::TagRemoved;
+ is_application_area_initialized = false;
+ application_area_id = 0;
+ application_area_data.clear();
+ deactivate_event->GetWritableEvent().Signal();
+}
+
+bool Module::Interface::IsAmiiboValid() const {
+ const auto& amiibo_data = tag_data.user_memory;
+ LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", tag_data.lock_bytes);
+ LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", tag_data.compability_container);
+ LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo_data.crypto_init);
+ LOG_DEBUG(Service_NFP, "write_count={}", amiibo_data.write_count);
+
+ LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
+ LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant);
+ LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type);
+ LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo_data.model_info.model_number);
+ LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series);
+ LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.fixed);
+
+ LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", tag_data.dynamic_lock);
+ LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", tag_data.CFG0);
+ LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", tag_data.CFG1);
+
+ // Check against all know constants on an amiibo binary
+ if (tag_data.lock_bytes != 0xE00F) {
+ return false;
+ }
+ if (tag_data.compability_container != 0xEEFF10F1U) {
+ return false;
+ }
+ if ((amiibo_data.crypto_init & 0xFF) != 0xA5) {
+ return false;
+ }
+ if (amiibo_data.model_info.fixed != 0x02) {
+ return false;
+ }
+ if ((tag_data.dynamic_lock & 0xFFFFFF) != 0x0F0001) {
+ return false;
+ }
+ if (tag_data.CFG0 != 0x04000000U) {
+ return false;
+ }
+ if (tag_data.CFG1 != 0x5F) {
+ return false;
+ }
+ return true;
+}
+
+Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const {
+ return activate_event->GetReadableEvent();
+}
+
+Kernel::KReadableEvent& Module::Interface::GetDeactivateEvent() const {
+ return deactivate_event->GetReadableEvent();
+}
+
+void Module::Interface::Initialize() {
+ device_state = DeviceState::Initialized;
+}
+
+void Module::Interface::Finalize() {
+ device_state = DeviceState::Unaviable;
+ is_application_area_initialized = false;
+ application_area_id = 0;
+ application_area_data.clear();
+}
+
+ResultCode Module::Interface::StartDetection(s32 protocol_) {
+ auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
+
+ // TODO(german77): Add callback for when nfc data is available
+
+ if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
+ npad_device->SetPollingMode(Common::Input::PollingMode::NFC);
+ device_state = DeviceState::SearchingForTag;
+ protocol = protocol_;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+}
+
+ResultCode Module::Interface::StopDetection() {
+ auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
+ npad_device->SetPollingMode(Common::Input::PollingMode::Active);
+
+ if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
+ CloseAmiibo();
+ return ResultSuccess;
+ }
+ if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
+ device_state = DeviceState::Initialized;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+}
+
+ResultCode Module::Interface::Mount() {
+ if (device_state == DeviceState::TagFound) {
+ device_state = DeviceState::TagMounted;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+}
+
+ResultCode Module::Interface::Unmount() {
+ if (device_state == DeviceState::TagMounted) {
+ is_application_area_initialized = false;
+ application_area_id = 0;
+ application_area_data.clear();
+ device_state = DeviceState::TagFound;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+}
+
+ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const {
+ if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
+ tag_info = {
+ .uuid = tag_data.uuid,
+ .uuid_length = static_cast<u8>(tag_data.uuid.size()),
+ .protocol = protocol,
+ .tag_type = static_cast<u32>(tag_data.user_memory.model_info.amiibo_type),
+ };
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+}
+
+ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+
+ // Read this data from the amiibo save file
+ common_info = {
+ .last_write_year = 2022,
+ .last_write_month = 2,
+ .last_write_day = 7,
+ .write_counter = tag_data.user_memory.write_count,
+ .version = 1,
+ .application_area_size = ApplicationAreaSize,
+ };
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::GetModelInfo(ModelInfo& model_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+
+ model_info = tag_data.user_memory.model_info;
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+
+ Service::Mii::MiiManager manager;
+
+ // Read this data from the amiibo save file
+ register_info = {
+ .mii_char_info = manager.BuildDefault(0),
+ .first_write_year = 2022,
+ .first_write_month = 2,
+ .first_write_day = 7,
+ .amiibo_name = {'Y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o', 0},
+ .unknown = {},
+ };
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::OpenApplicationArea(u32 access_id) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+ if (AmiiboApplicationDataExist(access_id)) {
+ application_area_data = LoadAmiiboApplicationData(access_id);
+ application_area_id = access_id;
+ is_application_area_initialized = true;
+ }
+ if (!is_application_area_initialized) {
+ LOG_WARNING(Service_NFP, "Application area is not initialized");
+ return ErrCodes::ApplicationAreaIsNotInitialized;
+ }
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::GetApplicationArea(std::vector<u8>& data) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+ if (!is_application_area_initialized) {
+ LOG_ERROR(Service_NFP, "Application area is not initialized");
+ return ErrCodes::ApplicationAreaIsNotInitialized;
+ }
+
+ data = application_area_data;
+
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+ if (!is_application_area_initialized) {
+ LOG_ERROR(Service_NFP, "Application area is not initialized");
+ return ErrCodes::ApplicationAreaIsNotInitialized;
+ }
+ application_area_data = data;
+ SaveAmiiboApplicationData(application_area_id, application_area_data);
+ return ResultSuccess;
+}
+
+ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::vector<u8>& data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ErrCodes::WrongDeviceState;
+ }
+ if (AmiiboApplicationDataExist(access_id)) {
+ LOG_ERROR(Service_NFP, "Application area already exist");
+ return ErrCodes::ApplicationAreaExist;
+ }
+ application_area_data = data;
+ application_area_id = access_id;
+ SaveAmiiboApplicationData(application_area_id, application_area_data);
+ return ResultSuccess;
+}
+
+bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const {
+ // TODO(german77): Check if file exist
+ return false;
+}
+
+std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const {
+ // TODO(german77): Read file
+ std::vector<u8> data(ApplicationAreaSize);
+ return data;
+}
+
+void Module::Interface::SaveAmiiboApplicationData(u32 access_id,
+ const std::vector<u8>& data) const {
+ // TODO(german77): Save file
+}
+
+u64 Module::Interface::GetHandle() const {
+ // Generate a handle based of the npad id
+ return static_cast<u64>(npad_id);
+}
+
+DeviceState Module::Interface::GetCurrentState() const {
+ return device_state;
+}
+
+Core::HID::NpadIdType Module::Interface::GetNpadId() const {
+ return npad_id;
}
-const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
- return amiibo;
+u32 Module::Interface::GetTagPassword(const TagUuid& uuid) const {
+ // Verifiy that the generated password is correct
+ u32 password = 0xAA ^ (uuid[1] ^ uuid[3]);
+ password &= (0x55 ^ (uuid[2] ^ uuid[4])) << 8;
+ password &= (0xAA ^ (uuid[3] ^ uuid[5])) << 16;
+ password &= (0x55 ^ (uuid[4] ^ uuid[6])) << 24;
+ return password;
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 95c127efb..022f13b29 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -7,15 +7,132 @@
#include <array>
#include <vector>
+#include "common/common_funcs.h"
#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KEvent;
-}
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core::HID {
+enum class NpadIdType : u32;
+} // namespace Core::HID
namespace Service::NFP {
+enum class ServiceType : u32 {
+ User,
+ Debug,
+ System,
+};
+
+enum class State : u32 {
+ NonInitialized,
+ Initialized,
+};
+
+enum class DeviceState : u32 {
+ Initialized,
+ SearchingForTag,
+ TagFound,
+ TagRemoved,
+ TagMounted,
+ Unaviable,
+ Finalized,
+};
+
+enum class ModelType : u32 {
+ Amiibo,
+};
+
+enum class MountTarget : u32 {
+ Rom,
+ Ram,
+ All,
+};
+
+enum class AmiiboType : u8 {
+ Figure,
+ Card,
+ Yarn,
+};
+
+enum class AmiiboSeries : u8 {
+ SuperSmashBros,
+ SuperMario,
+ ChibiRobo,
+ YoshiWoollyWorld,
+ Splatoon,
+ AnimalCrossing,
+ EightBitMario,
+ Skylanders,
+ Unknown8,
+ TheLegendOfZelda,
+ ShovelKnight,
+ Unknown11,
+ Kiby,
+ Pokemon,
+ MarioSportsSuperstars,
+ MonsterHunter,
+ BoxBoy,
+ Pikmin,
+ FireEmblem,
+ Metroid,
+ Others,
+ MegaMan,
+ Diablo
+};
+
+using TagUuid = std::array<u8, 10>;
+
+struct TagInfo {
+ TagUuid uuid;
+ u8 uuid_length;
+ INSERT_PADDING_BYTES(0x15);
+ s32 protocol;
+ u32 tag_type;
+ INSERT_PADDING_BYTES(0x30);
+};
+static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
+
+struct CommonInfo {
+ u16 last_write_year;
+ u8 last_write_month;
+ u8 last_write_day;
+ u16 write_counter;
+ u16 version;
+ u32 application_area_size;
+ INSERT_PADDING_BYTES(0x34);
+};
+static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
+
+struct ModelInfo {
+ u16 character_id;
+ u8 character_variant;
+ AmiiboType amiibo_type;
+ u16 model_number;
+ AmiiboSeries series;
+ u8 fixed; // Must be 02
+ INSERT_PADDING_BYTES(0x4); // Unknown
+ INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash
+ INSERT_PADDING_BYTES(0x14); // SHA256-HMAC
+};
+static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
+
+struct RegisterInfo {
+ Service::Mii::MiiInfo mii_char_info;
+ u16 first_write_year;
+ u8 first_write_month;
+ u8 first_write_day;
+ std::array<u8, 11> amiibo_name;
+ u8 unknown;
+ INSERT_PADDING_BYTES(0x98);
+};
+static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
@@ -24,34 +141,131 @@ public:
const char* name);
~Interface() override;
- struct ModelInfo {
- std::array<u8, 0x8> amiibo_identification_block;
- INSERT_PADDING_BYTES(0x38);
+ struct EncryptedAmiiboFile {
+ u16 crypto_init; // Must be A5 XX
+ u16 write_count; // Number of times the amiibo has been written?
+ INSERT_PADDING_BYTES(0x20); // System crypts
+ INSERT_PADDING_BYTES(0x20); // SHA256-(HMAC?) hash
+ ModelInfo model_info; // This struct is bigger than documentation
+ INSERT_PADDING_BYTES(0xC); // SHA256-HMAC
+ INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer
+ INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer
+ };
+ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
+
+ struct NTAG215Password {
+ u32 PWD; // Password to allow write access
+ u16 PACK; // Password acknowledge reply
+ u16 RFUI; // Reserved for future use
};
- static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
+ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid size");
- struct AmiiboFile {
- std::array<u8, 10> uuid;
- INSERT_PADDING_BYTES(0x4a);
- ModelInfo model_info;
+ struct NTAG215File {
+ TagUuid uuid; // Unique serial number
+ u16 lock_bytes; // Set defined pages as read only
+ u32 compability_container; // Defines available memory
+ EncryptedAmiiboFile user_memory; // Writable data
+ u32 dynamic_lock; // Dynamic lock
+ u32 CFG0; // Defines memory protected by password
+ u32 CFG1; // Defines number of verification attempts
+ NTAG215Password password; // Password data
};
- static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size");
+ static_assert(sizeof(NTAG215File) == 0x21C, "NTAG215File is an invalid size");
void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer);
- Kernel::KReadableEvent& GetNFCEvent();
- const AmiiboFile& GetAmiiboBuffer() const;
+ void CloseAmiibo();
+
+ void Initialize();
+ void Finalize();
+
+ ResultCode StartDetection(s32 protocol_);
+ ResultCode StopDetection();
+ ResultCode Mount();
+ ResultCode Unmount();
+
+ ResultCode GetTagInfo(TagInfo& tag_info) const;
+ ResultCode GetCommonInfo(CommonInfo& common_info) const;
+ ResultCode GetModelInfo(ModelInfo& model_info) const;
+ ResultCode GetRegisterInfo(RegisterInfo& register_info) const;
+
+ ResultCode OpenApplicationArea(u32 access_id);
+ ResultCode GetApplicationArea(std::vector<u8>& data) const;
+ ResultCode SetApplicationArea(const std::vector<u8>& data);
+ ResultCode CreateApplicationArea(u32 access_id, const std::vector<u8>& data);
+
+ u64 GetHandle() const;
+ DeviceState GetCurrentState() const;
+ Core::HID::NpadIdType GetNpadId() const;
+
+ Kernel::KReadableEvent& GetActivateEvent() const;
+ Kernel::KReadableEvent& GetDeactivateEvent() const;
protected:
std::shared_ptr<Module> module;
private:
+ /// Validates that the amiibo file is not corrupted
+ bool IsAmiiboValid() const;
+
+ bool AmiiboApplicationDataExist(u32 access_id) const;
+ std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const;
+ void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const;
+
+ /// return password needed to allow write access to protected memory
+ u32 GetTagPassword(const TagUuid& uuid) const;
+
+ const Core::HID::NpadIdType npad_id;
+
+ DeviceState device_state{DeviceState::Unaviable};
KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* nfc_tag_load;
- AmiiboFile amiibo{};
+ Kernel::KEvent* activate_event;
+ Kernel::KEvent* deactivate_event;
+ NTAG215File tag_data{};
+ s32 protocol;
+ bool is_application_area_initialized{};
+ u32 application_area_id;
+ std::vector<u8> application_area_data;
};
};
+class IUser final : public ServiceFramework<IUser> {
+public:
+ explicit IUser(Module::Interface& nfp_interface_, Core::System& system_);
+
+private:
+ void Initialize(Kernel::HLERequestContext& ctx);
+ void Finalize(Kernel::HLERequestContext& ctx);
+ void ListDevices(Kernel::HLERequestContext& ctx);
+ void StartDetection(Kernel::HLERequestContext& ctx);
+ void StopDetection(Kernel::HLERequestContext& ctx);
+ void Mount(Kernel::HLERequestContext& ctx);
+ void Unmount(Kernel::HLERequestContext& ctx);
+ void OpenApplicationArea(Kernel::HLERequestContext& ctx);
+ void GetApplicationArea(Kernel::HLERequestContext& ctx);
+ void SetApplicationArea(Kernel::HLERequestContext& ctx);
+ void CreateApplicationArea(Kernel::HLERequestContext& ctx);
+ void GetTagInfo(Kernel::HLERequestContext& ctx);
+ void GetRegisterInfo(Kernel::HLERequestContext& ctx);
+ void GetCommonInfo(Kernel::HLERequestContext& ctx);
+ void GetModelInfo(Kernel::HLERequestContext& ctx);
+ void AttachActivateEvent(Kernel::HLERequestContext& ctx);
+ void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
+ void GetState(Kernel::HLERequestContext& ctx);
+ void GetDeviceState(Kernel::HLERequestContext& ctx);
+ void GetNpadId(Kernel::HLERequestContext& ctx);
+ void GetApplicationAreaSize(Kernel::HLERequestContext& ctx);
+ void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
+
+ KernelHelpers::ServiceContext service_context;
+
+ // TODO(german77): We should have a vector of interfaces
+ Module::Interface& nfp_interface;
+
+ State state{State::NonInitialized};
+ Kernel::KEvent* availability_change_event;
+};
+
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::NFP
diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp
index e2fab5c3f..36ce46353 100644
--- a/src/core/hle/service/ns/pdm_qry.cpp
+++ b/src/core/hle/service/ns/pdm_qry.cpp
@@ -59,7 +59,7 @@ void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequ
LOG_WARNING(Service_NS,
"(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}",
- unknown, application_id, user_account_uid.Format());
+ unknown, application_id, user_account_uid.RawString());
IPC::ResponseBuilder rb{ctx, 12};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 277abc17a..057666021 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -91,6 +91,8 @@ public:
{4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
{5, nullptr, "HookToCreateApplicationProgress"},
{6, nullptr, "ClearHook"},
+ {65000, &DebugMonitor::AtmosphereGetProcessInfo, "AtmosphereGetProcessInfo"},
+ {65001, nullptr, "AtmosphereGetCurrentLimitInfo"},
};
// clang-format on
@@ -125,6 +127,49 @@ private:
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
+ void AtmosphereGetProcessInfo(Kernel::HLERequestContext& ctx) {
+ // https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/pm/source/impl/pm_process_manager.cpp#L614
+ // This implementation is incomplete; only a handle to the process is returned.
+ IPC::RequestParser rp{ctx};
+ const auto pid = rp.PopRaw<u64>();
+
+ LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
+
+ const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) {
+ return proc->GetProcessID() == pid;
+ });
+
+ if (!process.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultProcessNotFound);
+ return;
+ }
+
+ struct ProgramLocation {
+ u64 program_id;
+ u8 storage_id;
+ };
+ static_assert(sizeof(ProgramLocation) == 0x10, "ProgramLocation has an invalid size");
+
+ struct OverrideStatus {
+ u64 keys_held;
+ u64 flags;
+ };
+ static_assert(sizeof(OverrideStatus) == 0x10, "OverrideStatus has an invalid size");
+
+ OverrideStatus override_status{};
+ ProgramLocation program_location{
+ .program_id = (*process)->GetProgramID(),
+ .storage_id = 0,
+ };
+
+ IPC::ResponseBuilder rb{ctx, 10, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(*process);
+ rb.PushRaw(program_location);
+ rb.PushRaw(override_status);
+ }
+
const Kernel::KernelCore& kernel;
};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index f54e6fe56..eb1138313 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -39,6 +39,7 @@
#include "core/hle/service/mig/mig.h"
#include "core/hle/service/mii/mii.h"
#include "core/hle/service/mm/mm_u.h"
+#include "core/hle/service/mnpp/mnpp_app.h"
#include "core/hle/service/ncm/ncm.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfp/nfp.h"
@@ -265,6 +266,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
Migration::InstallInterfaces(*sm, system);
Mii::InstallInterfaces(*sm, system);
MM::InstallInterfaces(*sm, system);
+ MNPP::InstallInterfaces(*sm, system);
NCM::InstallInterfaces(*sm, system);
NFC::InstallInterfaces(*sm, system);
NFP::InstallInterfaces(*sm, system);
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index eaa172595..695a1faa6 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -81,6 +81,8 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
}
auto* port = Kernel::KPort::Create(kernel);
+ SCOPE_EXIT({ port->Close(); });
+
port->Initialize(ServerSessionCountMax, false, name);
auto handler = it->second;
port->GetServerPort().SetSessionHandler(std::move(handler));
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index f83272633..3dbac5a23 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -569,9 +569,9 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
new_descriptor.socket = std::move(result.socket);
new_descriptor.is_connection_based = descriptor.is_connection_based;
- ASSERT(write_buffer.size() == sizeof(SockAddrIn));
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
- std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in));
+ const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size());
+ std::memcpy(write_buffer.data(), &guest_addr_in, length);
return {new_fd, Errno::SUCCESS};
}
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
index 392e16863..d0cacb80c 100644
--- a/src/core/hle/service/time/clock_types.h
+++ b/src/core/hle/service/time/clock_types.h
@@ -36,7 +36,7 @@ struct SteadyClockTimePoint {
}
static SteadyClockTimePoint GetRandom() {
- return {0, Common::UUID::Generate()};
+ return {0, Common::UUID::MakeRandom()};
}
};
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h
index d80a2385f..5ee2c0e0a 100644
--- a/src/core/hle/service/time/steady_clock_core.h
+++ b/src/core/hle/service/time/steady_clock_core.h
@@ -49,7 +49,7 @@ public:
}
private:
- Common::UUID clock_source_id{Common::UUID::Generate()};
+ Common::UUID clock_source_id{Common::UUID::MakeRandom()};
bool is_initialized{};
};
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index c1e4e6cce..00f1ae8cf 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -45,7 +45,7 @@ struct TimeManager::Impl final {
time_zone_content_manager{system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
- SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
+ SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
Clock::SystemClockContext clock_context{};
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 0979fc421..329f4ba86 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -28,10 +28,10 @@ class Layer;
/// Represents a single display type
class Display {
+public:
YUZU_NON_COPYABLE(Display);
YUZU_NON_MOVEABLE(Display);
-public:
/// Constructs a display with a given unique ID and name.
///
/// @param id The unique ID for this display.