diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/romfs.cpp | 102 | ||||
| -rw-r--r-- | src/core/hle/romfs.h | 22 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 154 | ||||
| -rw-r--r-- | src/core/hle/service/apt/bcfnt/bcfnt.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/frd/frd.cpp | 43 | ||||
| -rw-r--r-- | src/core/hle/service/frd/frd.h | 13 | ||||
| -rw-r--r-- | src/core/hle/service/frd/frd_u.cpp | 2 |
8 files changed, 321 insertions, 23 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b80efe192..360f407f3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -60,6 +60,7 @@ set(SRCS | |||
| 60 | hle/kernel/timer.cpp | 60 | hle/kernel/timer.cpp |
| 61 | hle/kernel/vm_manager.cpp | 61 | hle/kernel/vm_manager.cpp |
| 62 | hle/kernel/wait_object.cpp | 62 | hle/kernel/wait_object.cpp |
| 63 | hle/romfs.cpp | ||
| 63 | hle/service/ac/ac.cpp | 64 | hle/service/ac/ac.cpp |
| 64 | hle/service/ac/ac_i.cpp | 65 | hle/service/ac/ac_i.cpp |
| 65 | hle/service/ac/ac_u.cpp | 66 | hle/service/ac/ac_u.cpp |
| @@ -258,6 +259,7 @@ set(HEADERS | |||
| 258 | hle/kernel/vm_manager.h | 259 | hle/kernel/vm_manager.h |
| 259 | hle/kernel/wait_object.h | 260 | hle/kernel/wait_object.h |
| 260 | hle/result.h | 261 | hle/result.h |
| 262 | hle/romfs.h | ||
| 261 | hle/service/ac/ac.h | 263 | hle/service/ac/ac.h |
| 262 | hle/service/ac/ac_i.h | 264 | hle/service/ac/ac_i.h |
| 263 | hle/service/ac/ac_u.h | 265 | hle/service/ac/ac_u.h |
diff --git a/src/core/hle/romfs.cpp b/src/core/hle/romfs.cpp new file mode 100644 index 000000000..3157df71d --- /dev/null +++ b/src/core/hle/romfs.cpp | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/swap.h" | ||
| 7 | #include "core/hle/romfs.h" | ||
| 8 | |||
| 9 | namespace RomFS { | ||
| 10 | |||
| 11 | struct Header { | ||
| 12 | u32_le header_length; | ||
| 13 | u32_le dir_hash_table_offset; | ||
| 14 | u32_le dir_hash_table_length; | ||
| 15 | u32_le dir_table_offset; | ||
| 16 | u32_le dir_table_length; | ||
| 17 | u32_le file_hash_table_offset; | ||
| 18 | u32_le file_hash_table_length; | ||
| 19 | u32_le file_table_offset; | ||
| 20 | u32_le file_table_length; | ||
| 21 | u32_le data_offset; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static_assert(sizeof(Header) == 0x28, "Header has incorrect size"); | ||
| 25 | |||
| 26 | struct DirectoryMetadata { | ||
| 27 | u32_le parent_dir_offset; | ||
| 28 | u32_le next_dir_offset; | ||
| 29 | u32_le first_child_dir_offset; | ||
| 30 | u32_le first_file_offset; | ||
| 31 | u32_le same_hash_next_dir_offset; | ||
| 32 | u32_le name_length; // in bytes | ||
| 33 | // followed by directory name | ||
| 34 | }; | ||
| 35 | |||
| 36 | static_assert(sizeof(DirectoryMetadata) == 0x18, "DirectoryMetadata has incorrect size"); | ||
| 37 | |||
| 38 | struct FileMetadata { | ||
| 39 | u32_le parent_dir_offset; | ||
| 40 | u32_le next_file_offset; | ||
| 41 | u64_le data_offset; | ||
| 42 | u64_le data_length; | ||
| 43 | u32_le same_hash_next_file_offset; | ||
| 44 | u32_le name_length; // in bytes | ||
| 45 | // followed by file name | ||
| 46 | }; | ||
| 47 | |||
| 48 | static_assert(sizeof(FileMetadata) == 0x20, "FileMetadata has incorrect size"); | ||
| 49 | |||
| 50 | static bool MatchName(const u8* buffer, u32 name_length, const std::u16string& name) { | ||
| 51 | std::vector<char16_t> name_buffer(name_length / sizeof(char16_t)); | ||
| 52 | std::memcpy(name_buffer.data(), buffer, name_length); | ||
| 53 | return name == std::u16string(name_buffer.begin(), name_buffer.end()); | ||
| 54 | } | ||
| 55 | |||
| 56 | const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path) { | ||
| 57 | constexpr u32 INVALID_FIELD = 0xFFFFFFFF; | ||
| 58 | |||
| 59 | // Split path into directory names and file name | ||
| 60 | std::vector<std::u16string> dir_names = path; | ||
| 61 | dir_names.pop_back(); | ||
| 62 | const std::u16string& file_name = path.back(); | ||
| 63 | |||
| 64 | Header header; | ||
| 65 | std::memcpy(&header, romfs, sizeof(header)); | ||
| 66 | |||
| 67 | // Find directories of each level | ||
| 68 | DirectoryMetadata dir; | ||
| 69 | const u8* current_dir = romfs + header.dir_table_offset; | ||
| 70 | std::memcpy(&dir, current_dir, sizeof(dir)); | ||
| 71 | for (const std::u16string& dir_name : dir_names) { | ||
| 72 | u32 child_dir_offset; | ||
| 73 | child_dir_offset = dir.first_child_dir_offset; | ||
| 74 | while (true) { | ||
| 75 | if (child_dir_offset == INVALID_FIELD) { | ||
| 76 | return nullptr; | ||
| 77 | } | ||
| 78 | const u8* current_child_dir = romfs + header.dir_table_offset + child_dir_offset; | ||
| 79 | std::memcpy(&dir, current_child_dir, sizeof(dir)); | ||
| 80 | if (MatchName(current_child_dir + sizeof(dir), dir.name_length, dir_name)) { | ||
| 81 | current_dir = current_child_dir; | ||
| 82 | break; | ||
| 83 | } | ||
| 84 | child_dir_offset = dir.next_dir_offset; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | // Find the file | ||
| 89 | FileMetadata file; | ||
| 90 | u32 file_offset = dir.first_file_offset; | ||
| 91 | while (file_offset != INVALID_FIELD) { | ||
| 92 | const u8* current_file = romfs + header.file_table_offset + file_offset; | ||
| 93 | std::memcpy(&file, current_file, sizeof(file)); | ||
| 94 | if (MatchName(current_file + sizeof(file), file.name_length, file_name)) { | ||
| 95 | return romfs + header.data_offset + file.data_offset; | ||
| 96 | } | ||
| 97 | file_offset = file.next_file_offset; | ||
| 98 | } | ||
| 99 | return nullptr; | ||
| 100 | } | ||
| 101 | |||
| 102 | } // namespace RomFS | ||
diff --git a/src/core/hle/romfs.h b/src/core/hle/romfs.h new file mode 100644 index 000000000..ee9f29760 --- /dev/null +++ b/src/core/hle/romfs.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace RomFS { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Gets the pointer to a file in a RomFS image. | ||
| 15 | * @param romfs The pointer to the RomFS image | ||
| 16 | * @param path A vector containing the directory names and file name of the path to the file | ||
| 17 | * @return the pointer to the file | ||
| 18 | * @todo reimplement this with a full RomFS manager | ||
| 19 | */ | ||
| 20 | const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path); | ||
| 21 | |||
| 22 | } // namespace RomFS | ||
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 25e7b777d..df4b5cc3f 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -6,11 +6,13 @@ | |||
| 6 | #include "common/file_util.h" | 6 | #include "common/file_util.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/file_sys/file_backend.h" | ||
| 9 | #include "core/hle/applets/applet.h" | 10 | #include "core/hle/applets/applet.h" |
| 10 | #include "core/hle/kernel/event.h" | 11 | #include "core/hle/kernel/event.h" |
| 11 | #include "core/hle/kernel/mutex.h" | 12 | #include "core/hle/kernel/mutex.h" |
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/shared_memory.h" | 14 | #include "core/hle/kernel/shared_memory.h" |
| 15 | #include "core/hle/romfs.h" | ||
| 14 | #include "core/hle/service/apt/apt.h" | 16 | #include "core/hle/service/apt/apt.h" |
| 15 | #include "core/hle/service/apt/apt_a.h" | 17 | #include "core/hle/service/apt/apt_a.h" |
| 16 | #include "core/hle/service/apt/apt_s.h" | 18 | #include "core/hle/service/apt/apt_s.h" |
| @@ -27,6 +29,7 @@ namespace APT { | |||
| 27 | 29 | ||
| 28 | /// Handle to shared memory region designated to for shared system font | 30 | /// Handle to shared memory region designated to for shared system font |
| 29 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | 31 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; |
| 32 | static bool shared_font_loaded = false; | ||
| 30 | static bool shared_font_relocated = false; | 33 | static bool shared_font_relocated = false; |
| 31 | 34 | ||
| 32 | static Kernel::SharedPtr<Kernel::Mutex> lock; | 35 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| @@ -71,7 +74,7 @@ void Initialize(Service::Interface* self) { | |||
| 71 | void GetSharedFont(Service::Interface* self) { | 74 | void GetSharedFont(Service::Interface* self) { |
| 72 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 | 75 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 |
| 73 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | 76 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); |
| 74 | if (!shared_font_mem) { | 77 | if (!shared_font_loaded) { |
| 75 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | 78 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); |
| 76 | rb.Push<u32>(-1); // TODO: Find the right error code | 79 | rb.Push<u32>(-1); // TODO: Find the right error code |
| 77 | rb.Skip(1 + 2, true); | 80 | rb.Skip(1 + 2, true); |
| @@ -644,36 +647,146 @@ void CheckNew3DS(Service::Interface* self) { | |||
| 644 | LOG_WARNING(Service_APT, "(STUBBED) called"); | 647 | LOG_WARNING(Service_APT, "(STUBBED) called"); |
| 645 | } | 648 | } |
| 646 | 649 | ||
| 647 | void Init() { | 650 | static u32 DecompressLZ11(const u8* in, u8* out) { |
| 648 | AddService(new APT_A_Interface); | 651 | u32_le decompressed_size; |
| 649 | AddService(new APT_S_Interface); | 652 | memcpy(&decompressed_size, in, sizeof(u32)); |
| 650 | AddService(new APT_U_Interface); | 653 | in += 4; |
| 651 | 654 | ||
| 652 | HLE::Applets::Init(); | 655 | u8 type = decompressed_size & 0xFF; |
| 653 | 656 | ASSERT(type == 0x11); | |
| 654 | // Load the shared system font (if available). | 657 | decompressed_size >>= 8; |
| 658 | |||
| 659 | u32 current_out_size = 0; | ||
| 660 | u8 flags = 0, mask = 1; | ||
| 661 | while (current_out_size < decompressed_size) { | ||
| 662 | if (mask == 1) { | ||
| 663 | flags = *(in++); | ||
| 664 | mask = 0x80; | ||
| 665 | } else { | ||
| 666 | mask >>= 1; | ||
| 667 | } | ||
| 668 | |||
| 669 | if (flags & mask) { | ||
| 670 | u8 byte1 = *(in++); | ||
| 671 | u32 length = byte1 >> 4; | ||
| 672 | u32 offset; | ||
| 673 | if (length == 0) { | ||
| 674 | u8 byte2 = *(in++); | ||
| 675 | u8 byte3 = *(in++); | ||
| 676 | length = (((byte1 & 0x0F) << 4) | (byte2 >> 4)) + 0x11; | ||
| 677 | offset = (((byte2 & 0x0F) << 8) | byte3) + 0x1; | ||
| 678 | } else if (length == 1) { | ||
| 679 | u8 byte2 = *(in++); | ||
| 680 | u8 byte3 = *(in++); | ||
| 681 | u8 byte4 = *(in++); | ||
| 682 | length = (((byte1 & 0x0F) << 12) | (byte2 << 4) | (byte3 >> 4)) + 0x111; | ||
| 683 | offset = (((byte3 & 0x0F) << 8) | byte4) + 0x1; | ||
| 684 | } else { | ||
| 685 | u8 byte2 = *(in++); | ||
| 686 | length = (byte1 >> 4) + 0x1; | ||
| 687 | offset = (((byte1 & 0x0F) << 8) | byte2) + 0x1; | ||
| 688 | } | ||
| 689 | |||
| 690 | for (u32 i = 0; i < length; i++) { | ||
| 691 | *out = *(out - offset); | ||
| 692 | ++out; | ||
| 693 | } | ||
| 694 | |||
| 695 | current_out_size += length; | ||
| 696 | } else { | ||
| 697 | *(out++) = *(in++); | ||
| 698 | current_out_size++; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | return decompressed_size; | ||
| 702 | } | ||
| 703 | |||
| 704 | static bool LoadSharedFont() { | ||
| 705 | // TODO (wwylele): load different font archive for region CHN/KOR/TWN | ||
| 706 | const u64_le shared_font_archive_id_low = 0x0004009b00014002; | ||
| 707 | const u64_le shared_font_archive_id_high = 0x00000001ffffff00; | ||
| 708 | std::vector<u8> shared_font_archive_id(16); | ||
| 709 | std::memcpy(&shared_font_archive_id[0], &shared_font_archive_id_low, sizeof(u64)); | ||
| 710 | std::memcpy(&shared_font_archive_id[8], &shared_font_archive_id_high, sizeof(u64)); | ||
| 711 | FileSys::Path archive_path(shared_font_archive_id); | ||
| 712 | auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::NCCH, archive_path); | ||
| 713 | if (archive_result.Failed()) | ||
| 714 | return false; | ||
| 715 | |||
| 716 | std::vector<u8> romfs_path(20, 0); // 20-byte all zero path for opening RomFS | ||
| 717 | FileSys::Path file_path(romfs_path); | ||
| 718 | FileSys::Mode open_mode = {}; | ||
| 719 | open_mode.read_flag.Assign(1); | ||
| 720 | auto file_result = Service::FS::OpenFileFromArchive(*archive_result, file_path, open_mode); | ||
| 721 | if (file_result.Failed()) | ||
| 722 | return false; | ||
| 723 | |||
| 724 | auto romfs = std::move(file_result).Unwrap(); | ||
| 725 | std::vector<u8> romfs_buffer(romfs->backend->GetSize()); | ||
| 726 | romfs->backend->Read(0, romfs_buffer.size(), romfs_buffer.data()); | ||
| 727 | romfs->backend->Close(); | ||
| 728 | |||
| 729 | const u8* font_file = RomFS::GetFilePointer(romfs_buffer.data(), {u"cbf_std.bcfnt.lz"}); | ||
| 730 | if (font_file == nullptr) | ||
| 731 | return false; | ||
| 732 | |||
| 733 | struct { | ||
| 734 | u32_le status; | ||
| 735 | u32_le region; | ||
| 736 | u32_le decompressed_size; | ||
| 737 | INSERT_PADDING_WORDS(0x1D); | ||
| 738 | } shared_font_header{}; | ||
| 739 | static_assert(sizeof(shared_font_header) == 0x80, "shared_font_header has incorrect size"); | ||
| 740 | |||
| 741 | shared_font_header.status = 2; // successfully loaded | ||
| 742 | shared_font_header.region = 1; // region JPN/EUR/USA | ||
| 743 | shared_font_header.decompressed_size = | ||
| 744 | DecompressLZ11(font_file, shared_font_mem->GetPointer(0x80)); | ||
| 745 | std::memcpy(shared_font_mem->GetPointer(), &shared_font_header, sizeof(shared_font_header)); | ||
| 746 | *shared_font_mem->GetPointer(0x83) = 'U'; // Change the magic from "CFNT" to "CFNU" | ||
| 747 | |||
| 748 | return true; | ||
| 749 | } | ||
| 750 | |||
| 751 | static bool LoadLegacySharedFont() { | ||
| 752 | // This is the legacy method to load shared font. | ||
| 655 | // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header | 753 | // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header |
| 656 | // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided | 754 | // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided |
| 657 | // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file | 755 | // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file |
| 658 | // "shared_font.bin" in the Citra "sysdata" directory. | 756 | // "shared_font.bin" in the Citra "sysdata" directory. |
| 659 | |||
| 660 | std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; | 757 | std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; |
| 661 | 758 | ||
| 662 | FileUtil::CreateFullPath(filepath); // Create path if not already created | 759 | FileUtil::CreateFullPath(filepath); // Create path if not already created |
| 663 | FileUtil::IOFile file(filepath, "rb"); | 760 | FileUtil::IOFile file(filepath, "rb"); |
| 664 | |||
| 665 | if (file.IsOpen()) { | 761 | if (file.IsOpen()) { |
| 666 | // Create shared font memory object | ||
| 667 | using Kernel::MemoryPermission; | ||
| 668 | shared_font_mem = | ||
| 669 | Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB | ||
| 670 | MemoryPermission::ReadWrite, MemoryPermission::Read, 0, | ||
| 671 | Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); | ||
| 672 | // Read shared font data | ||
| 673 | file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize()); | 762 | file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize()); |
| 763 | return true; | ||
| 764 | } | ||
| 765 | |||
| 766 | return false; | ||
| 767 | } | ||
| 768 | |||
| 769 | void Init() { | ||
| 770 | AddService(new APT_A_Interface); | ||
| 771 | AddService(new APT_S_Interface); | ||
| 772 | AddService(new APT_U_Interface); | ||
| 773 | |||
| 774 | HLE::Applets::Init(); | ||
| 775 | |||
| 776 | using Kernel::MemoryPermission; | ||
| 777 | shared_font_mem = | ||
| 778 | Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB | ||
| 779 | MemoryPermission::ReadWrite, MemoryPermission::Read, 0, | ||
| 780 | Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); | ||
| 781 | |||
| 782 | if (LoadSharedFont()) { | ||
| 783 | shared_font_loaded = true; | ||
| 784 | } else if (LoadLegacySharedFont()) { | ||
| 785 | LOG_WARNING(Service_APT, "Loaded shared font by legacy method"); | ||
| 786 | shared_font_loaded = true; | ||
| 674 | } else { | 787 | } else { |
| 675 | LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); | 788 | LOG_WARNING(Service_APT, "Unable to load shared font"); |
| 676 | shared_font_mem = nullptr; | 789 | shared_font_loaded = false; |
| 677 | } | 790 | } |
| 678 | 791 | ||
| 679 | lock = Kernel::Mutex::Create(false, "APT_U:Lock"); | 792 | lock = Kernel::Mutex::Create(false, "APT_U:Lock"); |
| @@ -693,6 +806,7 @@ void Init() { | |||
| 693 | 806 | ||
| 694 | void Shutdown() { | 807 | void Shutdown() { |
| 695 | shared_font_mem = nullptr; | 808 | shared_font_mem = nullptr; |
| 809 | shared_font_loaded = false; | ||
| 696 | shared_font_relocated = false; | 810 | shared_font_relocated = false; |
| 697 | lock = nullptr; | 811 | lock = nullptr; |
| 698 | notification_event = nullptr; | 812 | notification_event = nullptr; |
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp index 57eb39d75..6d2474702 100644 --- a/src/core/hle/service/apt/bcfnt/bcfnt.cpp +++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp | |||
| @@ -78,7 +78,8 @@ void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAd | |||
| 78 | memcpy(&cmap, data, sizeof(cmap)); | 78 | memcpy(&cmap, data, sizeof(cmap)); |
| 79 | 79 | ||
| 80 | // Relocate the offsets in the CMAP section | 80 | // Relocate the offsets in the CMAP section |
| 81 | cmap.next_cmap_offset += offset; | 81 | if (cmap.next_cmap_offset != 0) |
| 82 | cmap.next_cmap_offset += offset; | ||
| 82 | 83 | ||
| 83 | memcpy(data, &cmap, sizeof(cmap)); | 84 | memcpy(data, &cmap, sizeof(cmap)); |
| 84 | } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { | 85 | } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { |
| @@ -86,7 +87,8 @@ void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAd | |||
| 86 | memcpy(&cwdh, data, sizeof(cwdh)); | 87 | memcpy(&cwdh, data, sizeof(cwdh)); |
| 87 | 88 | ||
| 88 | // Relocate the offsets in the CWDH section | 89 | // Relocate the offsets in the CWDH section |
| 89 | cwdh.next_cwdh_offset += offset; | 90 | if (cwdh.next_cwdh_offset != 0) |
| 91 | cwdh.next_cwdh_offset += offset; | ||
| 90 | 92 | ||
| 91 | memcpy(data, &cwdh, sizeof(cwdh)); | 93 | memcpy(data, &cwdh, sizeof(cwdh)); |
| 92 | } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { | 94 | } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { |
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 76ecda8b7..7ad7798da 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 8 | #include "core/hle/ipc.h" | 8 | #include "core/hle/ipc.h" |
| 9 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/result.h" | 10 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/frd/frd.h" | 11 | #include "core/hle/service/frd/frd.h" |
| 11 | #include "core/hle/service/frd/frd_a.h" | 12 | #include "core/hle/service/frd/frd_a.h" |
| @@ -105,6 +106,48 @@ void GetMyScreenName(Service::Interface* self) { | |||
| 105 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | 106 | LOG_WARNING(Service_FRD, "(STUBBED) called"); |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 109 | void UnscrambleLocalFriendCode(Service::Interface* self) { | ||
| 110 | const size_t scrambled_friend_code_size = 12; | ||
| 111 | const size_t friend_code_size = 8; | ||
| 112 | |||
| 113 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1C, 1, 2); | ||
| 114 | const u32 friend_code_count = rp.Pop<u32>(); | ||
| 115 | size_t in_buffer_size; | ||
| 116 | const VAddr scrambled_friend_codes = rp.PopStaticBuffer(&in_buffer_size, false); | ||
| 117 | ASSERT_MSG(in_buffer_size == (friend_code_count * scrambled_friend_code_size), | ||
| 118 | "Wrong input buffer size"); | ||
| 119 | |||
| 120 | size_t out_buffer_size; | ||
| 121 | VAddr unscrambled_friend_codes = rp.PeekStaticBuffer(0, &out_buffer_size); | ||
| 122 | ASSERT_MSG(out_buffer_size == (friend_code_count * friend_code_size), | ||
| 123 | "Wrong output buffer size"); | ||
| 124 | |||
| 125 | for (u32 current = 0; current < friend_code_count; ++current) { | ||
| 126 | // TODO(B3N30): Unscramble the codes and compare them against the friend list | ||
| 127 | // Only write 0 if the code isn't in friend list, otherwise write the | ||
| 128 | // unscrambled one | ||
| 129 | // | ||
| 130 | // Code for unscrambling (should be compared to HW): | ||
| 131 | // std::array<u16, 6> scambled_friend_code; | ||
| 132 | // Memory::ReadBlock(scrambled_friend_codes+(current*scrambled_friend_code_size), | ||
| 133 | // scambled_friend_code.data(), scrambled_friend_code_size); std::array<u16, 4> | ||
| 134 | // unscrambled_friend_code; unscrambled_friend_code[0] = scambled_friend_code[0] ^ | ||
| 135 | // scambled_friend_code[5]; unscrambled_friend_code[1] = scambled_friend_code[1] ^ | ||
| 136 | // scambled_friend_code[5]; unscrambled_friend_code[2] = scambled_friend_code[2] ^ | ||
| 137 | // scambled_friend_code[5]; unscrambled_friend_code[3] = scambled_friend_code[3] ^ | ||
| 138 | // scambled_friend_code[5]; | ||
| 139 | |||
| 140 | u64 result = 0ull; | ||
| 141 | Memory::WriteBlock(unscrambled_friend_codes + (current * sizeof(result)), &result, | ||
| 142 | sizeof(result)); | ||
| 143 | } | ||
| 144 | |||
| 145 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | ||
| 146 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 147 | rb.Push(RESULT_SUCCESS); | ||
| 148 | rb.PushStaticBuffer(unscrambled_friend_codes, out_buffer_size, 0); | ||
| 149 | } | ||
| 150 | |||
| 108 | void SetClientSdkVersion(Service::Interface* self) { | 151 | void SetClientSdkVersion(Service::Interface* self) { |
| 109 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 152 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 110 | 153 | ||
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h index e61940ea0..66a87c8cd 100644 --- a/src/core/hle/service/frd/frd.h +++ b/src/core/hle/service/frd/frd.h | |||
| @@ -96,6 +96,19 @@ void GetMyFriendKey(Service::Interface* self); | |||
| 96 | void GetMyScreenName(Service::Interface* self); | 96 | void GetMyScreenName(Service::Interface* self); |
| 97 | 97 | ||
| 98 | /** | 98 | /** |
| 99 | * FRD::UnscrambleLocalFriendCode service function | ||
| 100 | * Inputs: | ||
| 101 | * 1 : Friend code count | ||
| 102 | * 2 : ((count * 12) << 14) | 0x402 | ||
| 103 | * 3 : Pointer to encoded friend codes. Each is 12 bytes large | ||
| 104 | * 64 : ((count * 8) << 14) | 2 | ||
| 105 | * 65 : Pointer to write decoded local friend codes to. Each is 8 bytes large. | ||
| 106 | * Outputs: | ||
| 107 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 108 | */ | ||
| 109 | void UnscrambleLocalFriendCode(Service::Interface* self); | ||
| 110 | |||
| 111 | /** | ||
| 99 | * FRD::SetClientSdkVersion service function | 112 | * FRD::SetClientSdkVersion service function |
| 100 | * Inputs: | 113 | * Inputs: |
| 101 | * 1 : Used SDK Version | 114 | * 1 : Used SDK Version |
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 496f29ca9..6970ff768 100644 --- a/src/core/hle/service/frd/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp | |||
| @@ -36,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 36 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, | 36 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, |
| 37 | {0x001A00C4, nullptr, "GetFriendInfo"}, | 37 | {0x001A00C4, nullptr, "GetFriendInfo"}, |
| 38 | {0x001B0080, nullptr, "IsIncludedInFriendList"}, | 38 | {0x001B0080, nullptr, "IsIncludedInFriendList"}, |
| 39 | {0x001C0042, nullptr, "UnscrambleLocalFriendCode"}, | 39 | {0x001C0042, UnscrambleLocalFriendCode, "UnscrambleLocalFriendCode"}, |
| 40 | {0x001D0002, nullptr, "UpdateGameModeDescription"}, | 40 | {0x001D0002, nullptr, "UpdateGameModeDescription"}, |
| 41 | {0x001E02C2, nullptr, "UpdateGameMode"}, | 41 | {0x001E02C2, nullptr, "UpdateGameMode"}, |
| 42 | {0x001F0042, nullptr, "SendInvitation"}, | 42 | {0x001F0042, nullptr, "SendInvitation"}, |