forked from eden-emu/eden
		
	bktr: Implement IVFC offset shifting
Fixes base game read errors
This commit is contained in:
		
							parent
							
								
									e88835cd40
								
							
						
					
					
						commit
						b8f8b0fa47
					
				
					 8 changed files with 36 additions and 8 deletions
				
			
		|  | @ -215,7 +215,7 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) | NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) | ||||||
|     : file(std::move(file_)), |     : file(std::move(file_)), | ||||||
|       bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) { |       bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) { | ||||||
|     status = Loader::ResultStatus::Success; |     status = Loader::ResultStatus::Success; | ||||||
|  | @ -292,6 +292,7 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) | ||||||
|     is_update = std::find_if(sections.begin(), sections.end(), [](const NCASectionHeader& header) { |     is_update = std::find_if(sections.begin(), sections.end(), [](const NCASectionHeader& header) { | ||||||
|                     return header.raw.header.crypto_type == NCASectionCryptoType::BKTR; |                     return header.raw.header.crypto_type == NCASectionCryptoType::BKTR; | ||||||
|                 }) != sections.end(); |                 }) != sections.end(); | ||||||
|  |     ivfc_offset = 0; | ||||||
| 
 | 
 | ||||||
|     for (std::ptrdiff_t i = 0; i < number_sections; ++i) { |     for (std::ptrdiff_t i = 0; i < number_sections; ++i) { | ||||||
|         auto section = sections[i]; |         auto section = sections[i]; | ||||||
|  | @ -299,8 +300,8 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) | ||||||
|         if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { |         if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { | ||||||
|             const size_t base_offset = |             const size_t base_offset = | ||||||
|                 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; |                 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; | ||||||
|             const size_t romfs_offset = |             ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; | ||||||
|                 base_offset + section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; |             const size_t romfs_offset = base_offset + ivfc_offset; | ||||||
|             const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; |             const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; | ||||||
|             auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset); |             auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset); | ||||||
|             auto dec = Decrypt(section, raw, romfs_offset); |             auto dec = Decrypt(section, raw, romfs_offset); | ||||||
|  | @ -414,7 +415,7 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) | ||||||
|                     bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), |                     bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), | ||||||
|                     relocation_block, relocation_buckets, subsection_block, subsection_buckets, |                     relocation_block, relocation_buckets, subsection_block, subsection_buckets, | ||||||
|                     encrypted, encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, |                     encrypted, encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, | ||||||
|                     romfs_offset - base_offset, section.raw.section_ctr); |                     bktr_base_ivfc_offset, section.raw.section_ctr); | ||||||
| 
 | 
 | ||||||
|                 // BKTR applies to entire IVFC, so make an offset version to level 6
 |                 // BKTR applies to entire IVFC, so make an offset version to level 6
 | ||||||
| 
 | 
 | ||||||
|  | @ -511,6 +512,10 @@ VirtualFile NCA::GetBaseFile() const { | ||||||
|     return file; |     return file; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u64 NCA::GetBaseIVFCOffset() const { | ||||||
|  |     return ivfc_offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { | bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -79,7 +79,8 @@ bool IsValidNCA(const NCAHeader& header); | ||||||
| // After construction, use GetStatus to determine if the file is valid and ready to be used.
 | // After construction, use GetStatus to determine if the file is valid and ready to be used.
 | ||||||
| class NCA : public ReadOnlyVfsDirectory { | class NCA : public ReadOnlyVfsDirectory { | ||||||
| public: | public: | ||||||
|     explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr); |     explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, | ||||||
|  |                  u64 bktr_base_ivfc_offset = 0); | ||||||
|     Loader::ResultStatus GetStatus() const; |     Loader::ResultStatus GetStatus() const; | ||||||
| 
 | 
 | ||||||
|     std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; |     std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | ||||||
|  | @ -96,6 +97,9 @@ public: | ||||||
| 
 | 
 | ||||||
|     VirtualFile GetBaseFile() const; |     VirtualFile GetBaseFile() const; | ||||||
| 
 | 
 | ||||||
|  |     // Returns the base ivfc offset used in BKTR patching.
 | ||||||
|  |     u64 GetBaseIVFCOffset() const; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; |     bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; | ||||||
| 
 | 
 | ||||||
|  | @ -112,6 +116,7 @@ private: | ||||||
|     VirtualDir exefs = nullptr; |     VirtualDir exefs = nullptr; | ||||||
|     VirtualFile file; |     VirtualFile file; | ||||||
|     VirtualFile bktr_base_romfs; |     VirtualFile bktr_base_romfs; | ||||||
|  |     u64 ivfc_offset; | ||||||
| 
 | 
 | ||||||
|     NCAHeader header{}; |     NCAHeader header{}; | ||||||
|     bool has_rights_id{}; |     bool has_rights_id{}; | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const { | ||||||
| 
 | 
 | ||||||
|     if (!bktr_read) { |     if (!bktr_read) { | ||||||
|         ASSERT_MSG(section_offset > ivfc_offset, "Offset calculation negative."); |         ASSERT_MSG(section_offset > ivfc_offset, "Offset calculation negative."); | ||||||
|         return base_romfs->Read(data, length, section_offset); |         return base_romfs->Read(data, length, section_offset - ivfc_offset); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!encrypted) { |     if (!encrypted) { | ||||||
|  |  | ||||||
|  | @ -24,14 +24,15 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     updatable = app_loader.IsRomFSUpdatable(); |     updatable = app_loader.IsRomFSUpdatable(); | ||||||
|  |     ivfc_offset = app_loader.ReadRomFSIVFCOffset(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | ||||||
|     if (!updatable) |     if (!updatable) | ||||||
|         return MakeResult<VirtualFile>(file); |         return MakeResult<VirtualFile>(file); | ||||||
| 
 | 
 | ||||||
|     const PatchManager patch_manager(Core::CurrentProcess()->process_id); |     const PatchManager patch_manager(Core::CurrentProcess()->program_id); | ||||||
|     return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file)); |     return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { | ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ public: | ||||||
| private: | private: | ||||||
|     VirtualFile file; |     VirtualFile file; | ||||||
|     bool updatable; |     bool updatable; | ||||||
|  |     u64 ivfc_offset; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -214,6 +214,15 @@ public: | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS) | ||||||
|  |      * data. Needed for bktr patching. | ||||||
|  |      * @return IVFC offset for romfs. | ||||||
|  |      */ | ||||||
|  |     virtual u64 ReadRomFSIVFCOffset() const { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Get the title of the application |      * Get the title of the application | ||||||
|      * @param title Reference to store the application title into |      * @param title Reference to store the application title into | ||||||
|  |  | ||||||
|  | @ -71,6 +71,12 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { | ||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u64 AppLoader_NCA::ReadRomFSIVFCOffset() const { | ||||||
|  |     if (nca == nullptr) | ||||||
|  |         return 0; | ||||||
|  |     return nca->GetBaseIVFCOffset(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | ||||||
|     if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) |     if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) | ||||||
|         return ResultStatus::ErrorNotInitialized; |         return ResultStatus::ErrorNotInitialized; | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ public: | ||||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||||
| 
 | 
 | ||||||
|     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | ||||||
|  |     u64 ReadRomFSIVFCOffset() const override; | ||||||
|     ResultStatus ReadProgramId(u64& out_program_id) override; |     ResultStatus ReadProgramId(u64& out_program_id) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zach Hilman
						Zach Hilman