mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Attempt to fix crashes in SSBU and refactor IsValidNRO
This commit is contained in:
		
							parent
							
								
									dfd1badc12
								
							
						
					
					
						commit
						151a3fe7b3
					
				@ -39,22 +39,27 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
 | 
				
			|||||||
constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
 | 
					constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
 | 
				
			||||||
constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
 | 
					constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Certification {
 | 
					constexpr std::size_t TEXT_INDEX{0};
 | 
				
			||||||
 | 
					constexpr std::size_t RO_INDEX{1};
 | 
				
			||||||
 | 
					constexpr std::size_t DATA_INDEX{2};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct NRRCertification {
 | 
				
			||||||
    u64_le application_id_mask;
 | 
					    u64_le application_id_mask;
 | 
				
			||||||
    u64_le application_id_pattern;
 | 
					    u64_le application_id_pattern;
 | 
				
			||||||
    std::array<u8, 0x10> reserved;
 | 
					    std::array<u8, 0x10> reserved;
 | 
				
			||||||
    std::array<u8, 0x100> public_key; // Also known as modulus
 | 
					    std::array<u8, 0x100> public_key; // Also known as modulus
 | 
				
			||||||
    std::array<u8, 0x100> signature;
 | 
					    std::array<u8, 0x100> signature;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
static_assert(sizeof(Certification) == 0x220, "Certification has invalid size!");
 | 
					static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using SHA256Hash = std::array<u8, 0x20>;
 | 
					using SHA256Hash = std::array<u8, 0x20>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(1)
 | 
				
			||||||
struct NRRHeader {
 | 
					struct NRRHeader {
 | 
				
			||||||
    u32_le magic;
 | 
					    u32_le magic;
 | 
				
			||||||
    u32_le certification_signature_key_generation; // 9.0.0+
 | 
					    u32_le certification_signature_key_generation; // 9.0.0+
 | 
				
			||||||
    u64_le reserved;
 | 
					    u64_le reserved;
 | 
				
			||||||
    Certification certification;
 | 
					    NRRCertification certification;
 | 
				
			||||||
    std::array<u8, 0x100> signature;
 | 
					    std::array<u8, 0x100> signature;
 | 
				
			||||||
    u64_le application_id;
 | 
					    u64_le application_id;
 | 
				
			||||||
    u32_le size;
 | 
					    u32_le size;
 | 
				
			||||||
@ -63,21 +68,19 @@ struct NRRHeader {
 | 
				
			|||||||
    u32_le hash_offset;
 | 
					    u32_le hash_offset;
 | 
				
			||||||
    u32_le hash_count;
 | 
					    u32_le hash_count;
 | 
				
			||||||
    u64_le reserved_3;
 | 
					    u64_le reserved_3;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Must be dynamically allocated because, according to
 | 
					 | 
				
			||||||
    // SwitchBrew, its size is (0x20 * hash_count) and
 | 
					 | 
				
			||||||
    // it's impossible to determine the value of hash_count
 | 
					 | 
				
			||||||
    // (SwitchBrew calls it "NumHash") before runtime,
 | 
					 | 
				
			||||||
    // therefore it's not possible to calculate a SHA-256
 | 
					 | 
				
			||||||
    std::vector<SHA256Hash> NroHashList;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#pragma pack()
 | 
				
			||||||
 | 
					static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(1)
 | 
				
			||||||
struct SegmentHeader {
 | 
					struct SegmentHeader {
 | 
				
			||||||
    u32_le memory_offset;
 | 
					    u32_le memory_offset;
 | 
				
			||||||
    u32_le memory_size;
 | 
					    u32_le memory_size;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#pragma pack()
 | 
				
			||||||
static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!");
 | 
					static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(1)
 | 
				
			||||||
struct NROHeader {
 | 
					struct NROHeader {
 | 
				
			||||||
    // Switchbrew calls this "Start" (0x10)
 | 
					    // Switchbrew calls this "Start" (0x10)
 | 
				
			||||||
    u32_le unused;
 | 
					    u32_le unused;
 | 
				
			||||||
@ -99,8 +102,10 @@ struct NROHeader {
 | 
				
			|||||||
    // .apiInfo, .dynstr, .dynsym
 | 
					    // .apiInfo, .dynstr, .dynsym
 | 
				
			||||||
    std::array<SegmentHeader, 3> segment_headers_2;
 | 
					    std::array<SegmentHeader, 3> segment_headers_2;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#pragma pack()
 | 
				
			||||||
static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
 | 
					static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(1)
 | 
				
			||||||
struct NROInfo {
 | 
					struct NROInfo {
 | 
				
			||||||
    SHA256Hash hash{};
 | 
					    SHA256Hash hash{};
 | 
				
			||||||
    VAddr nro_address{};
 | 
					    VAddr nro_address{};
 | 
				
			||||||
@ -112,6 +117,8 @@ struct NROInfo {
 | 
				
			|||||||
    std::size_t data_size{};
 | 
					    std::size_t data_size{};
 | 
				
			||||||
    VAddr src_addr{};
 | 
					    VAddr src_addr{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#pragma pack()
 | 
				
			||||||
 | 
					static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
 | 
					class DebugMonitor final : public ServiceFramework<DebugMonitor> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
@ -369,10 +376,10 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr,
 | 
					    ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr,
 | 
				
			||||||
                       VAddr start) const {
 | 
					                       VAddr start) const {
 | 
				
			||||||
        const VAddr text_start{start + nro_header.segment_headers[0].memory_offset};
 | 
					        const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
 | 
				
			||||||
        const VAddr ro_start{start + nro_header.segment_headers[1].memory_offset};
 | 
					        const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
 | 
				
			||||||
        const VAddr data_start{start + nro_header.segment_headers[2].memory_offset};
 | 
					        const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset};
 | 
				
			||||||
        const VAddr bss_start{data_start + nro_header.segment_headers[2].memory_size};
 | 
					        const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size};
 | 
				
			||||||
        const VAddr bss_end_addr{
 | 
					        const VAddr bss_end_addr{
 | 
				
			||||||
            Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)};
 | 
					            Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -381,12 +388,12 @@ public:
 | 
				
			|||||||
            system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size());
 | 
					            system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size());
 | 
				
			||||||
            system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
 | 
					            system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
 | 
				
			||||||
        }};
 | 
					        }};
 | 
				
			||||||
        CopyCode(nro_addr + nro_header.segment_headers[0].memory_offset, text_start,
 | 
					        CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
 | 
				
			||||||
                 nro_header.segment_headers[0].memory_size);
 | 
					                 nro_header.segment_headers[TEXT_INDEX].memory_size);
 | 
				
			||||||
        CopyCode(nro_addr + nro_header.segment_headers[1].memory_offset, ro_start,
 | 
					        CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
 | 
				
			||||||
                 nro_header.segment_headers[1].memory_size);
 | 
					                 nro_header.segment_headers[RO_INDEX].memory_size);
 | 
				
			||||||
        CopyCode(nro_addr + nro_header.segment_headers[2].memory_offset, data_start,
 | 
					        CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
 | 
				
			||||||
                 nro_header.segment_headers[2].memory_size);
 | 
					                 nro_header.segment_headers[DATA_INDEX].memory_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
 | 
					        CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
 | 
				
			||||||
            text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute));
 | 
					            text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute));
 | 
				
			||||||
@ -510,9 +517,9 @@ public:
 | 
				
			|||||||
        // Track the loaded NRO
 | 
					        // Track the loaded NRO
 | 
				
			||||||
        nro.insert_or_assign(*map_result,
 | 
					        nro.insert_or_assign(*map_result,
 | 
				
			||||||
                             NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
 | 
					                             NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
 | 
				
			||||||
                                     header.segment_headers[0].memory_size,
 | 
					                                     header.segment_headers[TEXT_INDEX].memory_size,
 | 
				
			||||||
                                     header.segment_headers[1].memory_size,
 | 
					                                     header.segment_headers[RO_INDEX].memory_size,
 | 
				
			||||||
                                     header.segment_headers[2].memory_size, nro_address});
 | 
					                                     header.segment_headers[DATA_INDEX].memory_size, nro_address});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Invalidate JIT caches for the newly mapped process code
 | 
					        // Invalidate JIT caches for the newly mapped process code
 | 
				
			||||||
        system.InvalidateCpuInstructionCaches();
 | 
					        system.InvalidateCpuInstructionCaches();
 | 
				
			||||||
@ -608,19 +615,35 @@ private:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
 | 
					    static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
 | 
				
			||||||
        return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
 | 
					
 | 
				
			||||||
               header.nro_size == nro_size && header.bss_size == bss_size &&
 | 
					        const bool valid_magic = header.magic == Common::MakeMagic('N', 'R', 'O', '0');
 | 
				
			||||||
               header.segment_headers[1].memory_offset ==
 | 
					
 | 
				
			||||||
                   header.segment_headers[0].memory_offset +
 | 
					        const bool valid_nro_size = header.nro_size == nro_size;
 | 
				
			||||||
                       header.segment_headers[0].memory_size &&
 | 
					
 | 
				
			||||||
               header.segment_headers[2].memory_offset ==
 | 
					        const bool valid_bss_size = header.bss_size == bss_size;
 | 
				
			||||||
                   header.segment_headers[1].memory_offset +
 | 
					
 | 
				
			||||||
                       header.segment_headers[1].memory_size &&
 | 
					        const bool valid_ro_offset = header.segment_headers[RO_INDEX].memory_offset ==
 | 
				
			||||||
               nro_size == header.segment_headers[2].memory_offset +
 | 
					                                     header.segment_headers[TEXT_INDEX].memory_offset +
 | 
				
			||||||
                               header.segment_headers[2].memory_size &&
 | 
					                                         header.segment_headers[TEXT_INDEX].memory_size;
 | 
				
			||||||
               Common::Is4KBAligned(header.segment_headers[0].memory_size) &&
 | 
					
 | 
				
			||||||
               Common::Is4KBAligned(header.segment_headers[1].memory_size) &&
 | 
					        const bool valid_rw_offset = header.segment_headers[DATA_INDEX].memory_offset ==
 | 
				
			||||||
               Common::Is4KBAligned(header.segment_headers[2].memory_size);
 | 
					                                     header.segment_headers[RO_INDEX].memory_offset +
 | 
				
			||||||
 | 
					                                         header.segment_headers[RO_INDEX].memory_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const bool valid_nro_calculated_size =
 | 
				
			||||||
 | 
					            nro_size == header.segment_headers[DATA_INDEX].memory_offset +
 | 
				
			||||||
 | 
					                            header.segment_headers[DATA_INDEX].memory_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const bool text_aligned =
 | 
				
			||||||
 | 
					            Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const bool ro_aligned = Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const bool rw_aligned =
 | 
				
			||||||
 | 
					            Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset &&
 | 
				
			||||||
 | 
					               valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && rw_aligned;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user