mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-11-03 23:28:48 +00:00 
			
		
		
		
	Auto-detect original shared_font.bin memory base
This allows a file dumped from either an o3DS or a n3DS (and potentially even an original unrebased file) to be used.
This commit is contained in:
		
							parent
							
								
									b879d8c31b
								
							
						
					
					
						commit
						1f7ec4be9b
					
				
					 3 changed files with 68 additions and 30 deletions
				
			
		| 
						 | 
				
			
			@ -81,13 +81,8 @@ void GetSharedFont(Service::Interface* self) {
 | 
			
		|||
 | 
			
		||||
    // The shared font has to be relocated to the new address before being passed to the application.
 | 
			
		||||
    VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
 | 
			
		||||
    // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
 | 
			
		||||
    // so we relocate it from there to our real address.
 | 
			
		||||
    // TODO(Subv): This address is wrong if the shared font is dumped from a n3DS,
 | 
			
		||||
    // we need a way to automatically calculate the original address of the font from the file.
 | 
			
		||||
    static const VAddr SHARED_FONT_VADDR = 0x18000000;
 | 
			
		||||
    if (!shared_font_relocated) {
 | 
			
		||||
        BCFNT::RelocateSharedFont(shared_font_mem, SHARED_FONT_VADDR, target_address);
 | 
			
		||||
        BCFNT::RelocateSharedFont(shared_font_mem, target_address);
 | 
			
		||||
        shared_font_relocated = true;
 | 
			
		||||
    }
 | 
			
		||||
    cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,60 +9,97 @@ namespace Service {
 | 
			
		|||
namespace APT {
 | 
			
		||||
namespace BCFNT {
 | 
			
		||||
 | 
			
		||||
void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address) {
 | 
			
		||||
void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr new_address) {
 | 
			
		||||
    static const u32 SharedFontStartOffset = 0x80;
 | 
			
		||||
    u8* data = shared_font->GetPointer(SharedFontStartOffset);
 | 
			
		||||
    const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset);
 | 
			
		||||
 | 
			
		||||
    CFNT cfnt;
 | 
			
		||||
    memcpy(&cfnt, data, sizeof(cfnt));
 | 
			
		||||
    memcpy(&cfnt, cfnt_ptr, sizeof(cfnt));
 | 
			
		||||
 | 
			
		||||
    // Advance past the header
 | 
			
		||||
    data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size);
 | 
			
		||||
    u32 assumed_cmap_offset = 0;
 | 
			
		||||
    u32 assumed_cwdh_offset = 0;
 | 
			
		||||
    u32 assumed_tglp_offset = 0;
 | 
			
		||||
    u32 first_cmap_offset = 0;
 | 
			
		||||
    u32 first_cwdh_offset = 0;
 | 
			
		||||
    u32 first_tglp_offset = 0;
 | 
			
		||||
 | 
			
		||||
    // First discover the location of sections so that the rebase offset can be auto-detected
 | 
			
		||||
    u32 current_offset = SharedFontStartOffset + cfnt.header_size;
 | 
			
		||||
    for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
 | 
			
		||||
        const u8* data = shared_font->GetPointer(current_offset);
 | 
			
		||||
 | 
			
		||||
        u32 section_size = 0;
 | 
			
		||||
        if (memcmp(data, "FINF", 4) == 0) {
 | 
			
		||||
        SectionHeader section_header;
 | 
			
		||||
        memcpy(§ion_header, data, sizeof(section_header));
 | 
			
		||||
 | 
			
		||||
        if (first_cmap_offset == 0 && memcmp(section_header.magic, "CMAP", 4) == 0) {
 | 
			
		||||
            first_cmap_offset = current_offset;
 | 
			
		||||
        } else if (first_cwdh_offset == 0 && memcmp(section_header.magic, "CWDH", 4) == 0) {
 | 
			
		||||
            first_cwdh_offset = current_offset;
 | 
			
		||||
        } else if (first_tglp_offset == 0 && memcmp(section_header.magic, "TGLP", 4) == 0) {
 | 
			
		||||
            first_tglp_offset = current_offset;
 | 
			
		||||
        } else if (memcmp(section_header.magic, "FINF", 4) == 0) {
 | 
			
		||||
            BCFNT::FINF finf;
 | 
			
		||||
            memcpy(&finf, data, sizeof(finf));
 | 
			
		||||
 | 
			
		||||
            assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader);
 | 
			
		||||
            assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader);
 | 
			
		||||
            assumed_tglp_offset = finf.tglp_offset - sizeof(SectionHeader);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        current_offset += section_header.section_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u32 previous_base = assumed_cmap_offset - first_cmap_offset;
 | 
			
		||||
    ASSERT(previous_base == assumed_cwdh_offset - first_cwdh_offset);
 | 
			
		||||
    ASSERT(previous_base == assumed_tglp_offset - first_tglp_offset);
 | 
			
		||||
 | 
			
		||||
    u32 offset = new_address - previous_base;
 | 
			
		||||
 | 
			
		||||
    // Reset pointer back to start of sections and do the actual rebase
 | 
			
		||||
    current_offset = SharedFontStartOffset + cfnt.header_size;
 | 
			
		||||
    for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
 | 
			
		||||
        u8* data = shared_font->GetPointer(current_offset);
 | 
			
		||||
 | 
			
		||||
        SectionHeader section_header;
 | 
			
		||||
        memcpy(§ion_header, data, sizeof(section_header));
 | 
			
		||||
 | 
			
		||||
        if (memcmp(section_header.magic, "FINF", 4) == 0) {
 | 
			
		||||
            BCFNT::FINF finf;
 | 
			
		||||
            memcpy(&finf, data, sizeof(finf));
 | 
			
		||||
            section_size = finf.section_size;
 | 
			
		||||
 | 
			
		||||
            // Relocate the offsets in the FINF section
 | 
			
		||||
            finf.cmap_offset += new_address - previous_address;
 | 
			
		||||
            finf.cwdh_offset += new_address - previous_address;
 | 
			
		||||
            finf.tglp_offset += new_address - previous_address;
 | 
			
		||||
            finf.cmap_offset += offset;
 | 
			
		||||
            finf.cwdh_offset += offset;
 | 
			
		||||
            finf.tglp_offset += offset;
 | 
			
		||||
 | 
			
		||||
            memcpy(data, &finf, sizeof(finf));
 | 
			
		||||
        } else if (memcmp(data, "CMAP", 4) == 0) {
 | 
			
		||||
        } else if (memcmp(section_header.magic, "CMAP", 4) == 0) {
 | 
			
		||||
            BCFNT::CMAP cmap;
 | 
			
		||||
            memcpy(&cmap, data, sizeof(cmap));
 | 
			
		||||
            section_size = cmap.section_size;
 | 
			
		||||
 | 
			
		||||
            // Relocate the offsets in the CMAP section
 | 
			
		||||
            cmap.next_cmap_offset += new_address - previous_address;
 | 
			
		||||
            cmap.next_cmap_offset += offset;
 | 
			
		||||
 | 
			
		||||
            memcpy(data, &cmap, sizeof(cmap));
 | 
			
		||||
        } else if (memcmp(data, "CWDH", 4) == 0) {
 | 
			
		||||
        } else if (memcmp(section_header.magic, "CWDH", 4) == 0) {
 | 
			
		||||
            BCFNT::CWDH cwdh;
 | 
			
		||||
            memcpy(&cwdh, data, sizeof(cwdh));
 | 
			
		||||
            section_size = cwdh.section_size;
 | 
			
		||||
 | 
			
		||||
            // Relocate the offsets in the CWDH section
 | 
			
		||||
            cwdh.next_cwdh_offset += new_address - previous_address;
 | 
			
		||||
            cwdh.next_cwdh_offset += offset;
 | 
			
		||||
 | 
			
		||||
            memcpy(data, &cwdh, sizeof(cwdh));
 | 
			
		||||
        } else if (memcmp(data, "TGLP", 4) == 0) {
 | 
			
		||||
        } else if (memcmp(section_header.magic, "TGLP", 4) == 0) {
 | 
			
		||||
            BCFNT::TGLP tglp;
 | 
			
		||||
            memcpy(&tglp, data, sizeof(tglp));
 | 
			
		||||
            section_size = tglp.section_size;
 | 
			
		||||
 | 
			
		||||
            // Relocate the offsets in the TGLP section
 | 
			
		||||
            tglp.sheet_data_offset += new_address - previous_address;
 | 
			
		||||
            tglp.sheet_data_offset += offset;
 | 
			
		||||
 | 
			
		||||
            memcpy(data, &tglp, sizeof(tglp));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data += section_size;
 | 
			
		||||
        current_offset += section_header.section_size;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,11 @@ struct CFNT {
 | 
			
		|||
    u32_le num_blocks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SectionHeader {
 | 
			
		||||
    u8 magic[4];
 | 
			
		||||
    u32_le section_size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FINF {
 | 
			
		||||
    u8 magic[4];
 | 
			
		||||
    u32_le section_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -75,12 +80,13 @@ struct CWDH {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Relocates the internal addresses of the BCFNT Shared Font to the new base.
 | 
			
		||||
 * Relocates the internal addresses of the BCFNT Shared Font to the new base. The current base will
 | 
			
		||||
 * be auto-detected based on the file headers.
 | 
			
		||||
 *
 | 
			
		||||
 * @param shared_font SharedMemory object that contains the Shared Font
 | 
			
		||||
 * @param previous_address Previous address at which the offsets in the structure were based.
 | 
			
		||||
 * @param new_address New base for the offsets in the structure.
 | 
			
		||||
 */
 | 
			
		||||
void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address);
 | 
			
		||||
void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr new_address);
 | 
			
		||||
 | 
			
		||||
} // namespace BCFNT
 | 
			
		||||
} // namespace APT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue