forked from eden-emu/eden
		
	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.
 |     // 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); |     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) { |     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; |         shared_font_relocated = true; | ||||||
|     } |     } | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); |     cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | ||||||
|  |  | ||||||
|  | @ -9,60 +9,97 @@ namespace Service { | ||||||
| namespace APT { | namespace APT { | ||||||
| namespace BCFNT { | 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; |     static const u32 SharedFontStartOffset = 0x80; | ||||||
|     u8* data = shared_font->GetPointer(SharedFontStartOffset); |     const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset); | ||||||
| 
 | 
 | ||||||
|     CFNT cfnt; |     CFNT cfnt; | ||||||
|     memcpy(&cfnt, data, sizeof(cfnt)); |     memcpy(&cfnt, cfnt_ptr, sizeof(cfnt)); | ||||||
| 
 | 
 | ||||||
|     // Advance past the header
 |     u32 assumed_cmap_offset = 0; | ||||||
|     data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size); |     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) { |     for (unsigned block = 0; block < cfnt.num_blocks; ++block) { | ||||||
|  |         const u8* data = shared_font->GetPointer(current_offset); | ||||||
| 
 | 
 | ||||||
|         u32 section_size = 0; |         SectionHeader section_header; | ||||||
|         if (memcmp(data, "FINF", 4) == 0) { |         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; |             BCFNT::FINF finf; | ||||||
|             memcpy(&finf, data, sizeof(finf)); |             memcpy(&finf, data, sizeof(finf)); | ||||||
|             section_size = finf.section_size; |  | ||||||
| 
 | 
 | ||||||
|             // Relocate the offsets in the FINF section
 |             // Relocate the offsets in the FINF section
 | ||||||
|             finf.cmap_offset += new_address - previous_address; |             finf.cmap_offset += offset; | ||||||
|             finf.cwdh_offset += new_address - previous_address; |             finf.cwdh_offset += offset; | ||||||
|             finf.tglp_offset += new_address - previous_address; |             finf.tglp_offset += offset; | ||||||
| 
 | 
 | ||||||
|             memcpy(data, &finf, sizeof(finf)); |             memcpy(data, &finf, sizeof(finf)); | ||||||
|         } else if (memcmp(data, "CMAP", 4) == 0) { |         } else if (memcmp(section_header.magic, "CMAP", 4) == 0) { | ||||||
|             BCFNT::CMAP cmap; |             BCFNT::CMAP cmap; | ||||||
|             memcpy(&cmap, data, sizeof(cmap)); |             memcpy(&cmap, data, sizeof(cmap)); | ||||||
|             section_size = cmap.section_size; |  | ||||||
| 
 | 
 | ||||||
|             // Relocate the offsets in the CMAP section
 |             // 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)); |             memcpy(data, &cmap, sizeof(cmap)); | ||||||
|         } else if (memcmp(data, "CWDH", 4) == 0) { |         } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { | ||||||
|             BCFNT::CWDH cwdh; |             BCFNT::CWDH cwdh; | ||||||
|             memcpy(&cwdh, data, sizeof(cwdh)); |             memcpy(&cwdh, data, sizeof(cwdh)); | ||||||
|             section_size = cwdh.section_size; |  | ||||||
| 
 | 
 | ||||||
|             // Relocate the offsets in the CWDH section
 |             // 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)); |             memcpy(data, &cwdh, sizeof(cwdh)); | ||||||
|         } else if (memcmp(data, "TGLP", 4) == 0) { |         } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { | ||||||
|             BCFNT::TGLP tglp; |             BCFNT::TGLP tglp; | ||||||
|             memcpy(&tglp, data, sizeof(tglp)); |             memcpy(&tglp, data, sizeof(tglp)); | ||||||
|             section_size = tglp.section_size; |  | ||||||
| 
 | 
 | ||||||
|             // Relocate the offsets in the TGLP section
 |             // 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)); |             memcpy(data, &tglp, sizeof(tglp)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         data += section_size; |         current_offset += section_header.section_size; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,11 @@ struct CFNT { | ||||||
|     u32_le num_blocks; |     u32_le num_blocks; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct SectionHeader { | ||||||
|  |     u8 magic[4]; | ||||||
|  |     u32_le section_size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct FINF { | struct FINF { | ||||||
|     u8 magic[4]; |     u8 magic[4]; | ||||||
|     u32_le section_size; |     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 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. |  * @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 BCFNT
 | ||||||
| } // namespace APT
 | } // namespace APT
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Yuri Kunde Schlesner
						Yuri Kunde Schlesner