diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hid/emulated_controller.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 74 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.h | 37 |
3 files changed, 76 insertions, 44 deletions
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 7785e6110..aa52f9572 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -299,16 +299,21 @@ public: | |||
| 299 | 299 | ||
| 300 | /** | 300 | /** |
| 301 | * Sends a specific vibration to the output device | 301 | * Sends a specific vibration to the output device |
| 302 | * @return returns true if vibration had no errors | 302 | * @return true if vibration had no errors |
| 303 | */ | 303 | */ |
| 304 | bool SetVibration(std::size_t device_index, VibrationValue vibration); | 304 | bool SetVibration(std::size_t device_index, VibrationValue vibration); |
| 305 | 305 | ||
| 306 | /** | 306 | /** |
| 307 | * Sends a small vibration to the output device | 307 | * Sends a small vibration to the output device |
| 308 | * @return returns true if SetVibration was successfull | 308 | * @return true if SetVibration was successfull |
| 309 | */ | 309 | */ |
| 310 | bool TestVibration(std::size_t device_index); | 310 | bool TestVibration(std::size_t device_index); |
| 311 | 311 | ||
| 312 | /** | ||
| 313 | * Sets the desired data to be polled from a controller | ||
| 314 | * @param polling_mode type of input desired buttons, gyro, nfc, ir, etc. | ||
| 315 | * @return true if SetPollingMode was successfull | ||
| 316 | */ | ||
| 312 | bool SetPollingMode(Common::Input::PollingMode polling_mode); | 317 | bool SetPollingMode(Common::Input::PollingMode polling_mode); |
| 313 | 318 | ||
| 314 | /// Returns the led pattern corresponding to this emulated controller | 319 | /// Returns the led pattern corresponding to this emulated controller |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 459fa798f..63e257975 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -479,7 +479,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | |||
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | 481 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { |
| 482 | if (buffer.size() < sizeof(AmiiboFile)) { | 482 | if (buffer.size() < sizeof(NTAG215File)) { |
| 483 | LOG_ERROR(Service_NFP, "Wrong file size"); | 483 | LOG_ERROR(Service_NFP, "Wrong file size"); |
| 484 | return false; | 484 | return false; |
| 485 | } | 485 | } |
| @@ -490,12 +490,15 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | LOG_INFO(Service_NFP, "Amiibo detected"); | 492 | LOG_INFO(Service_NFP, "Amiibo detected"); |
| 493 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 493 | std::memcpy(&tag_data, buffer.data(), sizeof(tag_data)); |
| 494 | 494 | ||
| 495 | if (!IsAmiiboValid()) { | 495 | if (!IsAmiiboValid()) { |
| 496 | return false; | 496 | return false; |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | // This value can't be dumped from a tag. Generate it | ||
| 500 | tag_data.PWD = GetTagPassword(tag_data.uuid); | ||
| 501 | |||
| 499 | device_state = DeviceState::TagFound; | 502 | device_state = DeviceState::TagFound; |
| 500 | activate_event->GetWritableEvent().Signal(); | 503 | activate_event->GetWritableEvent().Signal(); |
| 501 | return true; | 504 | return true; |
| @@ -511,42 +514,43 @@ void Module::Interface::CloseAmiibo() { | |||
| 511 | } | 514 | } |
| 512 | 515 | ||
| 513 | bool Module::Interface::IsAmiiboValid() const { | 516 | bool Module::Interface::IsAmiiboValid() const { |
| 514 | LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock); | 517 | const auto& amiibo_data = tag_data.user_memory; |
| 515 | LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container); | 518 | LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", tag_data.lock_bytes); |
| 516 | LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init); | 519 | LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", tag_data.compability_container); |
| 517 | LOG_DEBUG(Service_NFP, "write_count={}", amiibo.write_count); | 520 | LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo_data.crypto_init); |
| 518 | 521 | LOG_DEBUG(Service_NFP, "write_count={}", amiibo_data.write_count); | |
| 519 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id); | 522 | |
| 520 | LOG_DEBUG(Service_NFP, "character_variant={}", amiibo.model_info.character_variant); | 523 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); |
| 521 | LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type); | 524 | LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant); |
| 522 | LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number); | 525 | LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type); |
| 523 | LOG_DEBUG(Service_NFP, "series={}", amiibo.model_info.series); | 526 | LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo_data.model_info.model_number); |
| 524 | LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed); | 527 | LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series); |
| 525 | 528 | LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.fixed); | |
| 526 | LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock); | 529 | |
| 527 | LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0); | 530 | LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", tag_data.dynamic_lock); |
| 528 | LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1); | 531 | LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", tag_data.CFG0); |
| 532 | LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", tag_data.CFG1); | ||
| 529 | 533 | ||
| 530 | // Check against all know constants on an amiibo binary | 534 | // Check against all know constants on an amiibo binary |
| 531 | if (amiibo.uuid_lock != 0xE00F) { | 535 | if (tag_data.lock_bytes != 0xE00F) { |
| 532 | return false; | 536 | return false; |
| 533 | } | 537 | } |
| 534 | if (amiibo.compability_container != 0xEEFF10F1UL) { | 538 | if (tag_data.compability_container != 0xEEFF10F1U) { |
| 535 | return false; | 539 | return false; |
| 536 | } | 540 | } |
| 537 | if ((amiibo.crypto_init & 0xFF) != 0xA5) { | 541 | if ((amiibo_data.crypto_init & 0xFF) != 0xA5) { |
| 538 | return false; | 542 | return false; |
| 539 | } | 543 | } |
| 540 | if (amiibo.model_info.fixed != 0x02) { | 544 | if (amiibo_data.model_info.fixed != 0x02) { |
| 541 | return false; | 545 | return false; |
| 542 | } | 546 | } |
| 543 | if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) { | 547 | if ((tag_data.dynamic_lock & 0xFFFFFF) != 0x0F0001) { |
| 544 | return false; | 548 | return false; |
| 545 | } | 549 | } |
| 546 | if (amiibo.tag_CFG0 != 0x04000000UL) { | 550 | if (tag_data.CFG0 != 0x04000000U) { |
| 547 | return false; | 551 | return false; |
| 548 | } | 552 | } |
| 549 | if (amiibo.tag_CFG1 != 0x5F) { | 553 | if (tag_data.CFG1 != 0x5F) { |
| 550 | return false; | 554 | return false; |
| 551 | } | 555 | } |
| 552 | return true; | 556 | return true; |
| @@ -629,12 +633,11 @@ ResultCode Module::Interface::Unmount() { | |||
| 629 | 633 | ||
| 630 | ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { | 634 | ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { |
| 631 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { | 635 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { |
| 632 | // Read this data from the amiibo save file | ||
| 633 | tag_info = { | 636 | tag_info = { |
| 634 | .uuid = amiibo.uuid, | 637 | .uuid = tag_data.uuid, |
| 635 | .uuid_length = static_cast<u8>(amiibo.uuid.size()), | 638 | .uuid_length = static_cast<u8>(tag_data.uuid.size()), |
| 636 | .protocol = protocol, | 639 | .protocol = protocol, |
| 637 | .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type), | 640 | .tag_type = static_cast<u32>(tag_data.user_memory.model_info.amiibo_type), |
| 638 | }; | 641 | }; |
| 639 | return ResultSuccess; | 642 | return ResultSuccess; |
| 640 | } | 643 | } |
| @@ -654,7 +657,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { | |||
| 654 | .last_write_year = 2022, | 657 | .last_write_year = 2022, |
| 655 | .last_write_month = 2, | 658 | .last_write_month = 2, |
| 656 | .last_write_day = 7, | 659 | .last_write_day = 7, |
| 657 | .write_counter = amiibo.write_count, | 660 | .write_counter = tag_data.user_memory.write_count, |
| 658 | .version = 1, | 661 | .version = 1, |
| 659 | .application_area_size = ApplicationAreaSize, | 662 | .application_area_size = ApplicationAreaSize, |
| 660 | }; | 663 | }; |
| @@ -667,7 +670,7 @@ ResultCode Module::Interface::GetModelInfo(ModelInfo& model_info) const { | |||
| 667 | return ErrCodes::WrongDeviceState; | 670 | return ErrCodes::WrongDeviceState; |
| 668 | } | 671 | } |
| 669 | 672 | ||
| 670 | model_info = amiibo.model_info; | 673 | model_info = tag_data.user_memory.model_info; |
| 671 | return ResultSuccess; | 674 | return ResultSuccess; |
| 672 | } | 675 | } |
| 673 | 676 | ||
| @@ -757,7 +760,7 @@ bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { | |||
| 757 | return false; | 760 | return false; |
| 758 | } | 761 | } |
| 759 | 762 | ||
| 760 | const std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { | 763 | std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { |
| 761 | // TODO(german77): Read file | 764 | // TODO(german77): Read file |
| 762 | std::vector<u8> data(ApplicationAreaSize); | 765 | std::vector<u8> data(ApplicationAreaSize); |
| 763 | return data; | 766 | return data; |
| @@ -781,6 +784,15 @@ Core::HID::NpadIdType Module::Interface::GetNpadId() const { | |||
| 781 | return npad_id; | 784 | return npad_id; |
| 782 | } | 785 | } |
| 783 | 786 | ||
| 787 | u32 Module::Interface::GetTagPassword(const TagUuid& uuid) const { | ||
| 788 | // Verifiy that the generated password is correct | ||
| 789 | u32 password = 0xAA ^ (uuid[1] ^ uuid[3]); | ||
| 790 | password &= (0x55 ^ (uuid[2] ^ uuid[4])) << 8; | ||
| 791 | password &= (0xAA ^ (uuid[3] ^ uuid[5])) << 16; | ||
| 792 | password &= (0x55 ^ (uuid[4] ^ uuid[6])) << 24; | ||
| 793 | return password; | ||
| 794 | } | ||
| 795 | |||
| 784 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 796 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 785 | auto module = std::make_shared<Module>(); | 797 | auto module = std::make_shared<Module>(); |
| 786 | std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager); | 798 | std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 633539dcc..bc3b1967f 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/common_funcs.h" | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | 11 | #include "core/hle/service/kernel_helpers.h" |
| 11 | #include "core/hle/service/mii/mii_manager.h" | 12 | #include "core/hle/service/mii/mii_manager.h" |
| 12 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| @@ -85,8 +86,10 @@ enum class AmiiboSeries : u8 { | |||
| 85 | Diablo | 86 | Diablo |
| 86 | }; | 87 | }; |
| 87 | 88 | ||
| 89 | using TagUuid = std::array<u8, 10>; | ||
| 90 | |||
| 88 | struct TagInfo { | 91 | struct TagInfo { |
| 89 | std::array<u8, 10> uuid; | 92 | TagUuid uuid; |
| 90 | u8 uuid_length; | 93 | u8 uuid_length; |
| 91 | INSERT_PADDING_BYTES(0x15); | 94 | INSERT_PADDING_BYTES(0x15); |
| 92 | s32 protocol; | 95 | s32 protocol; |
| @@ -138,10 +141,7 @@ public: | |||
| 138 | const char* name); | 141 | const char* name); |
| 139 | ~Interface() override; | 142 | ~Interface() override; |
| 140 | 143 | ||
| 141 | struct AmiiboFile { | 144 | struct EncryptedAmiiboFile { |
| 142 | std::array<u8, 10> uuid; | ||
| 143 | u16 uuid_lock; // Must be 0F E0 | ||
| 144 | u32 compability_container; // Must be F1 10 FF EE | ||
| 145 | u16 crypto_init; // Must be A5 XX | 145 | u16 crypto_init; // Must be A5 XX |
| 146 | u16 write_count; // Number of times the amiibo has been written? | 146 | u16 write_count; // Number of times the amiibo has been written? |
| 147 | INSERT_PADDING_BYTES(0x20); // System crypts | 147 | INSERT_PADDING_BYTES(0x20); // System crypts |
| @@ -150,11 +150,22 @@ public: | |||
| 150 | INSERT_PADDING_BYTES(0xC); // SHA256-HMAC | 150 | INSERT_PADDING_BYTES(0xC); // SHA256-HMAC |
| 151 | INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer | 151 | INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer |
| 152 | INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer | 152 | INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer |
| 153 | u32 tag_dynamic_lock; // Must be 01 00 0F XX | ||
| 154 | u32 tag_CFG0; // Must be 00 00 00 04 | ||
| 155 | u32 tag_CFG1; // Must be 50 00 00 00 | ||
| 156 | }; | 153 | }; |
| 157 | static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size"); | 154 | static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); |
| 155 | |||
| 156 | struct NTAG215File { | ||
| 157 | TagUuid uuid; // Unique serial number | ||
| 158 | u16 lock_bytes; // Set defined pages as read only | ||
| 159 | u32 compability_container; // Defines available memory | ||
| 160 | EncryptedAmiiboFile user_memory; // Writable data | ||
| 161 | u32 dynamic_lock; // Dynamic lock | ||
| 162 | u32 CFG0; // Defines memory protected by password | ||
| 163 | u32 CFG1; // Defines number of verification attempts | ||
| 164 | u32 PWD; // Password to allow write access | ||
| 165 | u16 PACK; // Password acknowledge reply | ||
| 166 | u16 RFUI; // Reserved for future use | ||
| 167 | }; | ||
| 168 | static_assert(sizeof(NTAG215File) == 0x21C, "NTAG215File is an invalid size"); | ||
| 158 | 169 | ||
| 159 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | 170 | void CreateUserInterface(Kernel::HLERequestContext& ctx); |
| 160 | bool LoadAmiibo(const std::vector<u8>& buffer); | 171 | bool LoadAmiibo(const std::vector<u8>& buffer); |
| @@ -191,17 +202,21 @@ public: | |||
| 191 | private: | 202 | private: |
| 192 | /// Validates that the amiibo file is not corrupted | 203 | /// Validates that the amiibo file is not corrupted |
| 193 | bool IsAmiiboValid() const; | 204 | bool IsAmiiboValid() const; |
| 205 | |||
| 194 | bool AmiiboApplicationDataExist(u32 access_id) const; | 206 | bool AmiiboApplicationDataExist(u32 access_id) const; |
| 195 | const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; | 207 | std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; |
| 196 | void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; | 208 | void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; |
| 197 | 209 | ||
| 210 | /// return password needed to allow write access to protected memory | ||
| 211 | u32 GetTagPassword(const TagUuid& uuid) const; | ||
| 212 | |||
| 198 | const Core::HID::NpadIdType npad_id; | 213 | const Core::HID::NpadIdType npad_id; |
| 199 | 214 | ||
| 200 | DeviceState device_state{DeviceState::Unaviable}; | 215 | DeviceState device_state{DeviceState::Unaviable}; |
| 201 | KernelHelpers::ServiceContext service_context; | 216 | KernelHelpers::ServiceContext service_context; |
| 202 | Kernel::KEvent* activate_event; | 217 | Kernel::KEvent* activate_event; |
| 203 | Kernel::KEvent* deactivate_event; | 218 | Kernel::KEvent* deactivate_event; |
| 204 | AmiiboFile amiibo{}; | 219 | NTAG215File tag_data{}; |
| 205 | s32 protocol; | 220 | s32 protocol; |
| 206 | bool is_application_area_initialized{}; | 221 | bool is_application_area_initialized{}; |
| 207 | u32 application_area_id; | 222 | u32 application_area_id; |