Narr the Reg 4 лет назад
Родитель
Сommit
29f9a454eb
2 измененных файлов с 145 добавлено и 41 удалено
  1. 84 31
      src/core/hle/service/nfp/nfp.cpp
  2. 61 10
      src/core/hle/service/nfp/nfp.h

+ 84 - 31
src/core/hle/service/nfp/nfp.cpp

@@ -108,7 +108,7 @@ void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
 
     // TODO(german77): Loop through all interfaces
     if (device_handle == nfp_interface.GetHandle()) {
-        const auto result = nfp_interface.StartDetection();
+        const auto result = nfp_interface.StartDetection(nfp_protocol);
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(result);
         return;
@@ -209,7 +209,6 @@ void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {
     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(result);
@@ -232,7 +231,6 @@ void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {
     // 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(result);
         return;
@@ -255,7 +253,6 @@ void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
     // 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};
         rb.Push(result);
         return;
@@ -390,7 +387,7 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
 }
 
 void IUser::GetState(Kernel::HLERequestContext& ctx) {
-    LOG_INFO(Service_NFC, "called");
+    LOG_DEBUG(Service_NFC, "called");
 
     IPC::ResponseBuilder rb{ctx, 3, 0};
     rb.Push(ResultSuccess);
@@ -400,7 +397,7 @@ void IUser::GetState(Kernel::HLERequestContext& ctx) {
 void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
 
     // TODO(german77): Loop through all interfaces
     if (device_handle == nfp_interface.GetHandle()) {
@@ -419,7 +416,7 @@ void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
 void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
 
     // TODO(german77): Loop through all interfaces
     if (device_handle == nfp_interface.GetHandle()) {
@@ -438,7 +435,7 @@ void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
 void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
 
     // TODO(german77): Loop through all interfaces
     if (device_handle == nfp_interface.GetHandle()) {
@@ -493,6 +490,11 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
 
     LOG_INFO(Service_NFP, "New Amiibo detected");
     std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
+
+    if (!IsAmiiboValid()) {
+        return false;
+    }
+
     device_state = DeviceState::TagFound;
     activate_event->GetWritableEvent().Signal();
     return true;
@@ -501,13 +503,54 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
 void Module::Interface::CloseAmiibo() {
     LOG_INFO(Service_NFP, "Remove amiibo");
     device_state = DeviceState::TagRemoved;
-    write_counter = 0;
     is_application_area_initialized = false;
     application_area_id = 0;
     application_area_data.clear();
     deactivate_event->GetWritableEvent().Signal();
 }
 
+bool Module::Interface::IsAmiiboValid() const {
+    LOG_INFO(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock);
+    LOG_INFO(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container);
+    LOG_INFO(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init);
+    LOG_INFO(Service_NFP, "write_count={}", amiibo.write_count);
+
+    LOG_INFO(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id);
+    LOG_INFO(Service_NFP, "character_variant={}", amiibo.model_info.character_variant);
+    LOG_INFO(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type);
+    LOG_INFO(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number);
+    LOG_INFO(Service_NFP, "series={}", amiibo.model_info.series);
+    LOG_INFO(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed);
+
+    LOG_INFO(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock);
+    LOG_INFO(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0);
+    LOG_INFO(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1);
+
+    // Check against all know constants on an amiibo binary
+    if (amiibo.uuid_lock != 0xE00F) {
+        return false;
+    }
+    if (amiibo.compability_container != 0xEEFF10F1UL) {
+        return false;
+    }
+    if ((amiibo.crypto_init & 0xFF) != 0xA5) {
+        return false;
+    }
+    if (amiibo.model_info.fixed != 0x02) {
+        return false;
+    }
+    if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) {
+        return false;
+    }
+    if (amiibo.tag_CFG0 != 0x04000000UL) {
+        return false;
+    }
+    if (amiibo.tag_CFG1 != 0x5F) {
+        return false;
+    }
+    return true;
+}
+
 Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const {
     return activate_event->GetReadableEvent();
 }
@@ -522,13 +565,12 @@ void Module::Interface::Initialize() {
 
 void Module::Interface::Finalize() {
     device_state = DeviceState::Unaviable;
-    write_counter = 0;
     is_application_area_initialized = false;
     application_area_id = 0;
     application_area_data.clear();
 }
 
-ResultCode Module::Interface::StartDetection() {
+ResultCode Module::Interface::StartDetection(s32 protocol_) {
     auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
 
     // TODO(german77): Add callback for when nfc data is available
@@ -536,6 +578,7 @@ ResultCode Module::Interface::StartDetection() {
     if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
         npad_device->SetPollingMode(Common::Input::PollingMode::NFC);
         device_state = DeviceState::SearchingForTag;
+        protocol = protocol_;
         return ResultSuccess;
     }
 
@@ -589,8 +632,8 @@ ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const {
         tag_info = {
             .uuid = amiibo.uuid,
             .uuid_length = static_cast<u8>(amiibo.uuid.size()),
-            .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values
-            .tag_type = 0xFFFFFFFF,
+            .protocol = protocol,
+            .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type),
         };
         return ResultSuccess;
     }
@@ -610,7 +653,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const {
         .last_write_year = 2022,
         .last_write_month = 2,
         .last_write_day = 7,
-        .write_counter = write_counter,
+        .write_counter = amiibo.write_count,
         .version = 1,
         .application_area_size = ApplicationAreaSize,
     };
@@ -652,11 +695,11 @@ ResultCode Module::Interface::OpenApplicationArea(u32 access_id) {
         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 (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_ERROR(Service_NFP, "Application area is not initialized");
         return ErrCodes::ApplicationAreaIsNotInitialized;
@@ -689,8 +732,7 @@ ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) {
         return ErrCodes::ApplicationAreaIsNotInitialized;
     }
     application_area_data = data;
-    write_counter++;
-    // SaveAmiiboApplicationData(application_area_id,application_area_data);
+    SaveAmiiboApplicationData(application_area_id, application_area_data);
     return ResultSuccess;
 }
 
@@ -699,21 +741,32 @@ ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::ve
         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;
-    // }
-    // if (LoadAmiiboApplicationData(access_id,data)) {
-    //    is_application_area_initialized = true;
-    //    application_area_id = access_id;
-    // }
+    if (AmiiboApplicationDataExist(access_id)) {
+        LOG_ERROR(Service_NFP, "Application area already exist");
+        return ErrCodes::ApplicationAreaExist;
+    }
     application_area_data = data;
     application_area_id = access_id;
-    write_counter = 0;
-    // SaveAmiiboApplicationData(application_area_id,application_area_data);
+    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;
+}
+
+const 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);

+ 61 - 10
src/core/hle/service/nfp/nfp.h

@@ -53,11 +53,43 @@ enum class MountTarget : u32 {
     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
+};
+
 struct TagInfo {
     std::array<u8, 10> uuid;
     u8 uuid_length;
     INSERT_PADDING_BYTES(0x15);
-    u32 protocol;
+    s32 protocol;
     u32 tag_type;
     INSERT_PADDING_BYTES(0x30);
 };
@@ -77,10 +109,13 @@ static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
 struct ModelInfo {
     u16 character_id;
     u8 character_variant;
-    u8 figure_type;
+    AmiiboType amiibo_type;
     u16 model_number;
-    u8 series;
-    INSERT_PADDING_BYTES(0x39);
+    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");
 
@@ -105,11 +140,21 @@ public:
 
         struct AmiiboFile {
             std::array<u8, 10> uuid;
-            INSERT_PADDING_BYTES(0x4); // Compability container
-            INSERT_PADDING_BYTES(0x46);
-            ModelInfo model_info;
+            u16 uuid_lock;               // Must be 0F E0
+            u32 compability_container;   // Must be F1 10 FF EE
+            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
+            u32 tag_dynamic_lock;        // Must be 01 00 0F XX
+            u32 tag_CFG0;                // Must be 00 00 00 04
+            u32 tag_CFG1;                // Must be 50 00 00 00
         };
-        static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size");
+        static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size");
 
         void CreateUserInterface(Kernel::HLERequestContext& ctx);
         bool LoadAmiibo(const std::vector<u8>& buffer);
@@ -118,7 +163,7 @@ public:
         void Initialize();
         void Finalize();
 
-        ResultCode StartDetection();
+        ResultCode StartDetection(s32 protocol_);
         ResultCode StopDetection();
         ResultCode Mount();
         ResultCode Unmount();
@@ -144,6 +189,12 @@ public:
         std::shared_ptr<Module> module;
 
     private:
+        /// Validates that the amiibo file is not corrupted
+        bool IsAmiiboValid() const;
+        bool AmiiboApplicationDataExist(u32 access_id) const;
+        const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const;
+        void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const;
+
         const Core::HID::NpadIdType npad_id;
 
         DeviceState device_state{DeviceState::Unaviable};
@@ -151,7 +202,7 @@ public:
         Kernel::KEvent* activate_event;
         Kernel::KEvent* deactivate_event;
         AmiiboFile amiibo{};
-        u16 write_counter{};
+        s32 protocol;
         bool is_application_area_initialized{};
         u32 application_area_id;
         std::vector<u8> application_area_data;