diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/ldr_ro/cro_helper.cpp | 1495 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro/cro_helper.h | 714 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro/ldr_ro.cpp | 718 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro/ldr_ro.h | 22 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro/memory_synchronizer.cpp | 42 | ||||
-rw-r--r-- | src/core/hle/service/ldr_ro/memory_synchronizer.h | 42 |
6 files changed, 0 insertions, 3033 deletions
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp deleted file mode 100644 index 6128f8a6c..000000000 --- a/src/core/hle/service/ldr_ro/cro_helper.cpp +++ /dev/null @@ -1,1495 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/alignment.h" -#include "common/logging/log.h" -#include "common/scope_exit.h" -#include "core/hle/service/ldr_ro/cro_helper.h" - -namespace Service { -namespace LDR { - -static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F - ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, - ErrorLevel::Usage); - -static ResultCode CROFormatError(u32 description) { - return ResultCode(static_cast<ErrorDescription>(description), ErrorModule::RO, - ErrorSummary::WrongArgument, ErrorLevel::Permanent); -} - -const std::array<int, 17> CROHelper::ENTRY_SIZE{{ - 1, // code - 1, // data - 1, // module name - sizeof(SegmentEntry), sizeof(ExportNamedSymbolEntry), sizeof(ExportIndexedSymbolEntry), - 1, // export strings - sizeof(ExportTreeEntry), sizeof(ImportModuleEntry), sizeof(ExternalRelocationEntry), - sizeof(ImportNamedSymbolEntry), sizeof(ImportIndexedSymbolEntry), - sizeof(ImportAnonymousSymbolEntry), - 1, // import strings - sizeof(StaticAnonymousSymbolEntry), sizeof(InternalRelocationEntry), - sizeof(StaticRelocationEntry), -}}; - -const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS{{ - Fix0Barrier, Fix1Barrier, Fix2Barrier, Fix3Barrier, -}}; - -VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const { - u32 segment_num = GetField(SegmentNum); - - if (segment_tag.segment_index >= segment_num) - return 0; - - SegmentEntry entry; - GetEntry(segment_tag.segment_index, entry); - - if (segment_tag.offset_into_segment >= entry.size) - return 0; - - return entry.offset + segment_tag.offset_into_segment; -} - -ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType relocation_type, - u32 addend, u32 symbol_address, u32 target_future_address) { - - switch (relocation_type) { - case RelocationType::Nothing: - break; - case RelocationType::AbsoluteAddress: - case RelocationType::AbsoluteAddress2: - Memory::Write32(target_address, symbol_address + addend); - break; - case RelocationType::RelativeAddress: - Memory::Write32(target_address, symbol_address + addend - target_future_address); - break; - case RelocationType::ThumbBranch: - case RelocationType::ArmBranch: - case RelocationType::ModifyArmBranch: - case RelocationType::AlignedRelativeAddress: - // TODO(wwylele): implement other types - UNIMPLEMENTED(); - break; - default: - return CROFormatError(0x22); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType relocation_type) { - switch (relocation_type) { - case RelocationType::Nothing: - break; - case RelocationType::AbsoluteAddress: - case RelocationType::AbsoluteAddress2: - case RelocationType::RelativeAddress: - Memory::Write32(target_address, 0); - break; - case RelocationType::ThumbBranch: - case RelocationType::ArmBranch: - case RelocationType::ModifyArmBranch: - case RelocationType::AlignedRelativeAddress: - // TODO(wwylele): implement other types - UNIMPLEMENTED(); - break; - default: - return CROFormatError(0x22); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset) { - if (symbol_address == 0 && !reset) - return CROFormatError(0x10); - - VAddr relocation_address = batch; - while (true) { - RelocationEntry relocation; - Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry)); - - VAddr relocation_target = SegmentTagToAddress(relocation.target_position); - if (relocation_target == 0) { - return CROFormatError(0x12); - } - - ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, - symbol_address, relocation_target); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); - return result; - } - - if (relocation.is_batch_end) - break; - - relocation_address += sizeof(RelocationEntry); - } - - RelocationEntry relocation; - Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry)); - relocation.is_batch_resolved = reset ? 0 : 1; - Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry)); - return RESULT_SUCCESS; -} - -VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const { - if (!GetField(ExportTreeNum)) - return 0; - - std::size_t len = name.size(); - ExportTreeEntry entry; - GetEntry(0, entry); - ExportTreeEntry::Child next; - next.raw = entry.left.raw; - u32 found_id; - - while (true) { - GetEntry(next.next_index, entry); - - if (next.is_end) { - found_id = entry.export_table_index; - break; - } - - u16 test_byte = entry.test_bit >> 3; - u16 test_bit_in_byte = entry.test_bit & 7; - - if (test_byte >= len) { - next.raw = entry.left.raw; - } else if ((name[test_byte] >> test_bit_in_byte) & 1) { - next.raw = entry.right.raw; - } else { - next.raw = entry.left.raw; - } - } - - u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); - - if (found_id >= export_named_symbol_num) - return 0; - - u32 export_strings_size = GetField(ExportStringsSize); - ExportNamedSymbolEntry symbol_entry; - GetEntry(found_id, symbol_entry); - - if (Memory::ReadCString(symbol_entry.name_offset, export_strings_size) != name) - return 0; - - return SegmentTagToAddress(symbol_entry.symbol_position); -} - -ResultCode CROHelper::RebaseHeader(u32 cro_size) { - ResultCode error = CROFormatError(0x11); - - // verifies magic - if (GetField(Magic) != MAGIC_CRO0) - return error; - - // verifies not registered - if (GetField(NextCRO) != 0 || GetField(PreviousCRO) != 0) - return error; - - // This seems to be a hard limit set by the RO module - if (GetField(FileSize) > 0x10000000 || GetField(BssSize) > 0x10000000) - return error; - - // verifies not fixed - if (GetField(FixedSize) != 0) - return error; - - if (GetField(CodeOffset) < CRO_HEADER_SIZE) - return error; - - // verifies that all offsets are in the correct order - constexpr std::array<HeaderField, 18> OFFSET_ORDER = {{ - CodeOffset, ModuleNameOffset, SegmentTableOffset, ExportNamedSymbolTableOffset, - ExportTreeTableOffset, ExportIndexedSymbolTableOffset, ExportStringsOffset, - ImportModuleTableOffset, ExternalRelocationTableOffset, ImportNamedSymbolTableOffset, - ImportIndexedSymbolTableOffset, ImportAnonymousSymbolTableOffset, ImportStringsOffset, - StaticAnonymousSymbolTableOffset, InternalRelocationTableOffset, - StaticRelocationTableOffset, DataOffset, FileSize, - }}; - - u32 prev_offset = GetField(OFFSET_ORDER[0]); - u32 cur_offset; - for (std::size_t i = 1; i < OFFSET_ORDER.size(); ++i) { - cur_offset = GetField(OFFSET_ORDER[i]); - if (cur_offset < prev_offset) - return error; - prev_offset = cur_offset; - } - - // rebases offsets - u32 offset = GetField(NameOffset); - if (offset != 0) - SetField(NameOffset, offset + module_address); - - for (int field = CodeOffset; field < Fix0Barrier; field += 2) { - HeaderField header_field = static_cast<HeaderField>(field); - offset = GetField(header_field); - if (offset != 0) - SetField(header_field, offset + module_address); - } - - // verifies everything is not beyond the buffer - u32 file_end = module_address + cro_size; - for (int field = CodeOffset, i = 0; field < Fix0Barrier; field += 2, ++i) { - HeaderField offset_field = static_cast<HeaderField>(field); - HeaderField size_field = static_cast<HeaderField>(field + 1); - if (GetField(offset_field) + GetField(size_field) * ENTRY_SIZE[i] > file_end) - return error; - } - - return RESULT_SUCCESS; -} - -ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_address, - u32 data_segment_size, VAddr bss_segment_address, - u32 bss_segment_size) { - - u32 prev_data_segment = 0; - u32 segment_num = GetField(SegmentNum); - for (u32 i = 0; i < segment_num; ++i) { - SegmentEntry segment; - GetEntry(i, segment); - if (segment.type == SegmentType::Data) { - if (segment.size != 0) { - if (segment.size > data_segment_size) - return ERROR_BUFFER_TOO_SMALL; - prev_data_segment = segment.offset; - segment.offset = data_segment_address; - } - } else if (segment.type == SegmentType::BSS) { - if (segment.size != 0) { - if (segment.size > bss_segment_size) - return ERROR_BUFFER_TOO_SMALL; - segment.offset = bss_segment_address; - } - } else if (segment.offset != 0) { - segment.offset += module_address; - if (segment.offset > module_address + cro_size) - return CROFormatError(0x19); - } - SetEntry(i, segment); - } - return MakeResult<VAddr>(prev_data_segment + module_address); -} - -ResultCode CROHelper::RebaseExportNamedSymbolTable() { - VAddr export_strings_offset = GetField(ExportStringsOffset); - VAddr export_strings_end = export_strings_offset + GetField(ExportStringsSize); - - u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); - for (u32 i = 0; i < export_named_symbol_num; ++i) { - ExportNamedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset += module_address; - if (entry.name_offset < export_strings_offset || - entry.name_offset >= export_strings_end) { - return CROFormatError(0x11); - } - } - - SetEntry(i, entry); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::VerifyExportTreeTable() const { - u32 tree_num = GetField(ExportTreeNum); - for (u32 i = 0; i < tree_num; ++i) { - ExportTreeEntry entry; - GetEntry(i, entry); - - if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) { - return CROFormatError(0x11); - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::RebaseImportModuleTable() { - VAddr import_strings_offset = GetField(ImportStringsOffset); - VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); - VAddr import_indexed_symbol_table_offset = GetField(ImportIndexedSymbolTableOffset); - VAddr index_import_table_end = - import_indexed_symbol_table_offset + - GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry); - VAddr import_anonymous_symbol_table_offset = GetField(ImportAnonymousSymbolTableOffset); - VAddr offset_import_table_end = - import_anonymous_symbol_table_offset + - GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry); - - u32 module_num = GetField(ImportModuleNum); - for (u32 i = 0; i < module_num; ++i) { - ImportModuleEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset += module_address; - if (entry.name_offset < import_strings_offset || - entry.name_offset >= import_strings_end) { - return CROFormatError(0x18); - } - } - - if (entry.import_indexed_symbol_table_offset != 0) { - entry.import_indexed_symbol_table_offset += module_address; - if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset || - entry.import_indexed_symbol_table_offset > index_import_table_end) { - return CROFormatError(0x18); - } - } - - if (entry.import_anonymous_symbol_table_offset != 0) { - entry.import_anonymous_symbol_table_offset += module_address; - if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset || - entry.import_anonymous_symbol_table_offset > offset_import_table_end) { - return CROFormatError(0x18); - } - } - - SetEntry(i, entry); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::RebaseImportNamedSymbolTable() { - VAddr import_strings_offset = GetField(ImportStringsOffset); - VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); - VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); - VAddr external_relocation_table_end = - external_relocation_table_offset + - GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); - - u32 num = GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportNamedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset += module_address; - if (entry.name_offset < import_strings_offset || - entry.name_offset >= import_strings_end) { - return CROFormatError(0x1B); - } - } - - if (entry.relocation_batch_offset != 0) { - entry.relocation_batch_offset += module_address; - if (entry.relocation_batch_offset < external_relocation_table_offset || - entry.relocation_batch_offset > external_relocation_table_end) { - return CROFormatError(0x1B); - } - } - - SetEntry(i, entry); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::RebaseImportIndexedSymbolTable() { - VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); - VAddr external_relocation_table_end = - external_relocation_table_offset + - GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); - - u32 num = GetField(ImportIndexedSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportIndexedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.relocation_batch_offset != 0) { - entry.relocation_batch_offset += module_address; - if (entry.relocation_batch_offset < external_relocation_table_offset || - entry.relocation_batch_offset > external_relocation_table_end) { - return CROFormatError(0x14); - } - } - - SetEntry(i, entry); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::RebaseImportAnonymousSymbolTable() { - VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); - VAddr external_relocation_table_end = - external_relocation_table_offset + - GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); - - u32 num = GetField(ImportAnonymousSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportAnonymousSymbolEntry entry; - GetEntry(i, entry); - - if (entry.relocation_batch_offset != 0) { - entry.relocation_batch_offset += module_address; - if (entry.relocation_batch_offset < external_relocation_table_offset || - entry.relocation_batch_offset > external_relocation_table_end) { - return CROFormatError(0x17); - } - } - - SetEntry(i, entry); - } - return RESULT_SUCCESS; -} - -VAddr CROHelper::GetOnUnresolvedAddress() { - return SegmentTagToAddress(SegmentTag(GetField(OnUnresolvedSegmentTag))); -} - -ResultCode CROHelper::ResetExternalRelocations() { - u32 unresolved_symbol = GetOnUnresolvedAddress(); - u32 external_relocation_num = GetField(ExternalRelocationNum); - ExternalRelocationEntry relocation; - - // Verifies that the last relocation is the end of a batch - GetEntry(external_relocation_num - 1, relocation); - if (!relocation.is_batch_end) { - return CROFormatError(0x12); - } - - bool batch_begin = true; - for (u32 i = 0; i < external_relocation_num; ++i) { - GetEntry(i, relocation); - VAddr relocation_target = SegmentTagToAddress(relocation.target_position); - - if (relocation_target == 0) { - return CROFormatError(0x12); - } - - ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, - unresolved_symbol, relocation_target); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); - return result; - } - - if (batch_begin) { - // resets to unresolved state - relocation.is_batch_resolved = 0; - SetEntry(i, relocation); - } - - // if current is an end, then the next is a beginning - batch_begin = relocation.is_batch_end != 0; - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ClearExternalRelocations() { - u32 external_relocation_num = GetField(ExternalRelocationNum); - ExternalRelocationEntry relocation; - - bool batch_begin = true; - for (u32 i = 0; i < external_relocation_num; ++i) { - GetEntry(i, relocation); - VAddr relocation_target = SegmentTagToAddress(relocation.target_position); - - if (relocation_target == 0) { - return CROFormatError(0x12); - } - - ResultCode result = ClearRelocation(relocation_target, relocation.type); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); - return result; - } - - if (batch_begin) { - // resets to unresolved state - relocation.is_batch_resolved = 0; - SetEntry(i, relocation); - } - - // if current is an end, then the next is a beginning - batch_begin = relocation.is_batch_end != 0; - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) { - VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset); - VAddr static_relocation_table_end = - static_relocation_table_offset + - GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry); - - CROHelper crs(crs_address); - u32 offset_export_num = GetField(StaticAnonymousSymbolNum); - LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(), - offset_export_num); - for (u32 i = 0; i < offset_export_num; ++i) { - StaticAnonymousSymbolEntry entry; - GetEntry(i, entry); - u32 batch_address = entry.relocation_batch_offset + module_address; - - if (batch_address < static_relocation_table_offset || - batch_address > static_relocation_table_end) { - return CROFormatError(0x16); - } - - u32 symbol_address = SegmentTagToAddress(entry.symbol_position); - LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", - ModuleName().data(), symbol_address); - ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) { - u32 segment_num = GetField(SegmentNum); - u32 internal_relocation_num = GetField(InternalRelocationNum); - for (u32 i = 0; i < internal_relocation_num; ++i) { - InternalRelocationEntry relocation; - GetEntry(i, relocation); - VAddr target_addressB = SegmentTagToAddress(relocation.target_position); - if (target_addressB == 0) { - return CROFormatError(0x15); - } - - VAddr target_address; - SegmentEntry target_segment; - GetEntry(relocation.target_position.segment_index, target_segment); - - if (target_segment.type == SegmentType::Data) { - // If the relocation is to the .data segment, we need to relocate it in the old buffer - target_address = - old_data_segment_address + relocation.target_position.offset_into_segment; - } else { - target_address = target_addressB; - } - - if (relocation.symbol_segment >= segment_num) { - return CROFormatError(0x15); - } - - SegmentEntry symbol_segment; - GetEntry(relocation.symbol_segment, symbol_segment); - LOG_TRACE(Service_LDR, "Internally relocates 0x%08X with 0x%08X", target_address, - symbol_segment.offset); - ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend, - symbol_segment.offset, target_addressB); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ClearInternalRelocations() { - u32 internal_relocation_num = GetField(InternalRelocationNum); - for (u32 i = 0; i < internal_relocation_num; ++i) { - InternalRelocationEntry relocation; - GetEntry(i, relocation); - VAddr target_address = SegmentTagToAddress(relocation.target_position); - - if (target_address == 0) { - return CROFormatError(0x15); - } - - ResultCode result = ClearRelocation(target_address, relocation.type); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -void CROHelper::UnrebaseImportAnonymousSymbolTable() { - u32 num = GetField(ImportAnonymousSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportAnonymousSymbolEntry entry; - GetEntry(i, entry); - - if (entry.relocation_batch_offset != 0) { - entry.relocation_batch_offset -= module_address; - } - - SetEntry(i, entry); - } -} - -void CROHelper::UnrebaseImportIndexedSymbolTable() { - u32 num = GetField(ImportIndexedSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportIndexedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.relocation_batch_offset != 0) { - entry.relocation_batch_offset -= module_address; - } - - SetEntry(i, entry); - } -} - -void CROHelper::UnrebaseImportNamedSymbolTable() { - u32 num = GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < num; ++i) { - ImportNamedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset -= module_address; - } - - if (entry.relocation_batch_offset) { - entry.relocation_batch_offset -= module_address; - } - - SetEntry(i, entry); - } -} - -void CROHelper::UnrebaseImportModuleTable() { - u32 module_num = GetField(ImportModuleNum); - for (u32 i = 0; i < module_num; ++i) { - ImportModuleEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset -= module_address; - } - - if (entry.import_indexed_symbol_table_offset) { - entry.import_indexed_symbol_table_offset -= module_address; - } - - if (entry.import_anonymous_symbol_table_offset) { - entry.import_anonymous_symbol_table_offset -= module_address; - } - - SetEntry(i, entry); - } -} - -void CROHelper::UnrebaseExportNamedSymbolTable() { - u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); - for (u32 i = 0; i < export_named_symbol_num; ++i) { - ExportNamedSymbolEntry entry; - GetEntry(i, entry); - - if (entry.name_offset != 0) { - entry.name_offset -= module_address; - } - - SetEntry(i, entry); - } -} - -void CROHelper::UnrebaseSegmentTable() { - u32 segment_num = GetField(SegmentNum); - for (u32 i = 0; i < segment_num; ++i) { - SegmentEntry segment; - GetEntry(i, segment); - - if (segment.type == SegmentType::BSS) { - segment.offset = 0; - } else if (segment.offset != 0) { - segment.offset -= module_address; - } - - SetEntry(i, segment); - } -} - -void CROHelper::UnrebaseHeader() { - u32 offset = GetField(NameOffset); - if (offset != 0) - SetField(NameOffset, offset - module_address); - - for (int field = CodeOffset; field < Fix0Barrier; field += 2) { - HeaderField header_field = static_cast<HeaderField>(field); - offset = GetField(header_field); - if (offset != 0) - SetField(header_field, offset - module_address); - } -} - -ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) { - u32 import_strings_size = GetField(ImportStringsSize); - u32 symbol_import_num = GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < symbol_import_num; ++i) { - ImportNamedSymbolEntry entry; - GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - if (!relocation_entry.is_batch_resolved) { - ResultCode result = - ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { - std::string symbol_name = - Memory::ReadCString(entry.name_offset, import_strings_size); - u32 symbol_address = source.FindExportNamedSymbol(symbol_name); - - if (symbol_address != 0) { - LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"", - ModuleName().data(), symbol_name.data(), - source.ModuleName().data()); - - ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", - result.raw); - return result; - } - - return MakeResult<bool>(false); - } - - return MakeResult<bool>(true); - }); - if (result.IsError()) { - return result; - } - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ResetImportNamedSymbol() { - u32 unresolved_symbol = GetOnUnresolvedAddress(); - - u32 symbol_import_num = GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < symbol_import_num; ++i) { - ImportNamedSymbolEntry entry; - GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ResetImportIndexedSymbol() { - u32 unresolved_symbol = GetOnUnresolvedAddress(); - - u32 import_num = GetField(ImportIndexedSymbolNum); - for (u32 i = 0; i < import_num; ++i) { - ImportIndexedSymbolEntry entry; - GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ResetImportAnonymousSymbol() { - u32 unresolved_symbol = GetOnUnresolvedAddress(); - - u32 import_num = GetField(ImportAnonymousSymbolNum); - for (u32 i = 0; i < import_num; ++i) { - ImportAnonymousSymbolEntry entry; - GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) { - u32 import_strings_size = GetField(ImportStringsSize); - - u32 import_module_num = GetField(ImportModuleNum); - for (u32 i = 0; i < import_module_num; ++i) { - ImportModuleEntry entry; - GetEntry(i, entry); - std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size); - - ResultCode result = - ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { - if (want_cro_name == source.ModuleName()) { - LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"", - ModuleName().data(), entry.import_indexed_symbol_num, - source.ModuleName().data()); - for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { - ImportIndexedSymbolEntry im; - entry.GetImportIndexedSymbolEntry(j, im); - ExportIndexedSymbolEntry ex; - source.GetEntry(im.index, ex); - u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position); - LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); - ResultCode result = - ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", - result.raw); - return result; - } - } - LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"", - ModuleName().data(), entry.import_anonymous_symbol_num, - source.ModuleName().data()); - for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { - ImportAnonymousSymbolEntry im; - entry.GetImportAnonymousSymbolEntry(j, im); - u32 symbol_address = source.SegmentTagToAddress(im.symbol_position); - LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); - ResultCode result = - ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", - result.raw); - return result; - } - } - return MakeResult<bool>(false); - } - return MakeResult<bool>(true); - }); - if (result.IsError()) { - return result; - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) { - LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"", ModuleName().data(), - target.ModuleName().data()); - u32 target_import_strings_size = target.GetField(ImportStringsSize); - u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < target_symbol_import_num; ++i) { - ImportNamedSymbolEntry entry; - target.GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - if (!relocation_entry.is_batch_resolved) { - std::string symbol_name = - Memory::ReadCString(entry.name_offset, target_import_strings_size); - u32 symbol_address = FindExportNamedSymbol(symbol_name); - if (symbol_address != 0) { - LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data()); - ResultCode result = target.ApplyRelocationBatch(relocation_addr, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) { - LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"", ModuleName().data(), - target.ModuleName().data()); - u32 unresolved_symbol = target.GetOnUnresolvedAddress(); - u32 target_import_strings_size = target.GetField(ImportStringsSize); - u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < target_symbol_import_num; ++i) { - ImportNamedSymbolEntry entry; - target.GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - if (relocation_entry.is_batch_resolved) { - std::string symbol_name = - Memory::ReadCString(entry.name_offset, target_import_strings_size); - u32 symbol_address = FindExportNamedSymbol(symbol_name); - if (symbol_address != 0) { - LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data()); - ResultCode result = - target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - } - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyModuleExport(CROHelper target) { - std::string module_name = ModuleName(); - u32 target_import_string_size = target.GetField(ImportStringsSize); - u32 target_import_module_num = target.GetField(ImportModuleNum); - for (u32 i = 0; i < target_import_module_num; ++i) { - ImportModuleEntry entry; - target.GetEntry(i, entry); - - if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) - continue; - - LOG_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"", module_name.data(), - entry.import_indexed_symbol_num, target.ModuleName().data()); - for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { - ImportIndexedSymbolEntry im; - entry.GetImportIndexedSymbolEntry(j, im); - ExportIndexedSymbolEntry ex; - GetEntry(im.index, ex); - u32 symbol_address = SegmentTagToAddress(ex.symbol_position); - LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); - ResultCode result = - target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - - LOG_INFO(Service_LDR, "CRO \"%s\" exports %d anonymous symbols to \"%s\"", - module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data()); - for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { - ImportAnonymousSymbolEntry im; - entry.GetImportAnonymousSymbolEntry(j, im); - u32 symbol_address = SegmentTagToAddress(im.symbol_position); - LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); - ResultCode result = - target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ResetModuleExport(CROHelper target) { - u32 unresolved_symbol = target.GetOnUnresolvedAddress(); - - std::string module_name = ModuleName(); - u32 target_import_string_size = target.GetField(ImportStringsSize); - u32 target_import_module_num = target.GetField(ImportModuleNum); - for (u32 i = 0; i < target_import_module_num; ++i) { - ImportModuleEntry entry; - target.GetEntry(i, entry); - - if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) - continue; - - LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"", module_name.data(), - target.ModuleName().data()); - for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { - ImportIndexedSymbolEntry im; - entry.GetImportIndexedSymbolEntry(j, im); - ResultCode result = - target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - - LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports anonymous symbols to \"%s\"", - module_name.data(), target.ModuleName().data()); - for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { - ImportAnonymousSymbolEntry im; - entry.GetImportAnonymousSymbolEntry(j, im); - ResultCode result = - target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); - return result; - } - } - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) { - u32 import_strings_size = GetField(ImportStringsSize); - u32 symbol_import_num = GetField(ImportNamedSymbolNum); - for (u32 i = 0; i < symbol_import_num; ++i) { - ImportNamedSymbolEntry entry; - GetEntry(i, entry); - VAddr relocation_addr = entry.relocation_batch_offset; - ExternalRelocationEntry relocation_entry; - Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); - - if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") { - ResultCode result = - ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { - u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_"); - - if (symbol_address != 0) { - LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"", - ModuleName().data(), source.ModuleName().data()); - - ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", - result.raw); - return result; - } - - return MakeResult<bool>(false); - } - - return MakeResult<bool>(true); - }); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw); - return result; - } - } - } - return RESULT_SUCCESS; -} - -/** - * Verifies a string or a string table matching a predicted size (i.e. terminated by 0) - * if it is not empty. There can be many other nulls in the string table because - * they are composed by many sub strings. This function is to check whether the - * whole string (table) is terminated properly, despite that it is not actually one string. - * @param address the virtual address of the string (table) - * @param size the size of the string (table), including the terminating 0 - * @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code. - */ -static ResultCode VerifyStringTableLength(VAddr address, u32 size) { - if (size != 0) { - if (Memory::Read8(address + size - 1) != 0) - return CROFormatError(0x0B); - } - return RESULT_SUCCESS; -} - -ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_addresss, - u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size, - bool is_crs) { - - ResultCode result = RebaseHeader(cro_size); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing header %08X", result.raw); - return result; - } - - result = VerifyStringTableLength(GetField(ModuleNameOffset), GetField(ModuleNameSize)); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error verifying module name %08X", result.raw); - return result; - } - - u32 prev_data_segment_address = 0; - if (!is_crs) { - auto result_val = RebaseSegmentTable(cro_size, data_segment_addresss, data_segment_size, - bss_segment_address, bss_segment_size); - if (result_val.Failed()) { - LOG_ERROR(Service_LDR, "Error rebasing segment table %08X", result_val.Code().raw); - return result_val.Code(); - } - prev_data_segment_address = *result_val; - } - - result = RebaseExportNamedSymbolTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing symbol export table %08X", result.raw); - return result; - } - - result = VerifyExportTreeTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error verifying export tree %08X", result.raw); - return result; - } - - result = VerifyStringTableLength(GetField(ExportStringsOffset), GetField(ExportStringsSize)); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error verifying export strings %08X", result.raw); - return result; - } - - result = RebaseImportModuleTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing object table %08X", result.raw); - return result; - } - - result = ResetExternalRelocations(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error resetting all external relocations %08X", result.raw); - return result; - } - - result = RebaseImportNamedSymbolTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing symbol import table %08X", result.raw); - return result; - } - - result = RebaseImportIndexedSymbolTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing index import table %08X", result.raw); - return result; - } - - result = RebaseImportAnonymousSymbolTable(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing offset import table %08X", result.raw); - return result; - } - - result = VerifyStringTableLength(GetField(ImportStringsOffset), GetField(ImportStringsSize)); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error verifying import strings %08X", result.raw); - return result; - } - - if (!is_crs) { - result = ApplyStaticAnonymousSymbolToCRS(crs_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying offset export to CRS %08X", result.raw); - return result; - } - } - - result = ApplyInternalRelocations(prev_data_segment_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying internal relocations %08X", result.raw); - return result; - } - - if (!is_crs) { - result = ApplyExitRelocations(crs_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying exit relocations %08X", result.raw); - return result; - } - } - - return RESULT_SUCCESS; -} - -void CROHelper::Unrebase(bool is_crs) { - UnrebaseImportAnonymousSymbolTable(); - UnrebaseImportIndexedSymbolTable(); - UnrebaseImportNamedSymbolTable(); - UnrebaseImportModuleTable(); - UnrebaseExportNamedSymbolTable(); - - if (!is_crs) - UnrebaseSegmentTable(); - - SetNextModule(0); - SetPreviousModule(0); - - SetField(FixedSize, 0); - - UnrebaseHeader(); -} - -ResultCode CROHelper::VerifyHash(u32 cro_size, VAddr crr) const { - // TODO(wwylele): actually verify the hash - return RESULT_SUCCESS; -} - -ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) { - ResultCode result = RESULT_SUCCESS; - - { - VAddr data_segment_address; - if (link_on_load_bug_fix) { - // this is a bug fix introduced by 7.2.0-17's LoadCRO_New - // The bug itself is: - // If a relocation target is in .data segment, it will relocate to the - // user-specified buffer. But if this is linking during loading, - // the .data segment hasn't been transfer from CRO to the buffer, - // thus the relocation will be overwritten by data transfer. - // To fix this bug, we need temporarily restore the old .data segment - // offset and apply imported symbols. - - // RO service seems assuming segment_index == segment_type, - // so we do the same - if (GetField(SegmentNum) >= 2) { // means we have .data segment - SegmentEntry entry; - GetEntry(2, entry); - ASSERT(entry.type == SegmentType::Data); - data_segment_address = entry.offset; - entry.offset = GetField(DataOffset); - SetEntry(2, entry); - } - } - SCOPE_EXIT({ - // Restore the new .data segment address after importing - if (link_on_load_bug_fix) { - if (GetField(SegmentNum) >= 2) { - SegmentEntry entry; - GetEntry(2, entry); - entry.offset = data_segment_address; - SetEntry(2, entry); - } - } - }); - - // Imports named symbols from other modules - result = ApplyImportNamedSymbol(crs_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying symbol import %08X", result.raw); - return result; - } - - // Imports indexed and anonymous symbols from other modules - result = ApplyModuleImport(crs_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying module import %08X", result.raw); - return result; - } - } - - // Exports symbols to other modules - result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { - ResultCode result = ApplyExportNamedSymbol(target); - if (result.IsError()) - return result; - - result = ApplyModuleExport(target); - if (result.IsError()) - return result; - - return MakeResult<bool>(true); - }); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error applying export %08X", result.raw); - return result; - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::Unlink(VAddr crs_address) { - - // Resets all imported named symbols - ResultCode result = ResetImportNamedSymbol(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error resetting symbol import %08X", result.raw); - return result; - } - - // Resets all imported indexed symbols - result = ResetImportIndexedSymbol(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error resetting indexed import %08X", result.raw); - return result; - } - - // Resets all imported anonymous symbols - result = ResetImportAnonymousSymbol(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error resetting anonymous import %08X", result.raw); - return result; - } - - // Resets all symbols in other modules imported from this module - // Note: the RO service seems only searching in auto-link modules - result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { - ResultCode result = ResetExportNamedSymbol(target); - if (result.IsError()) - return result; - - result = ResetModuleExport(target); - if (result.IsError()) - return result; - - return MakeResult<bool>(true); - }); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error resetting export %08X", result.raw); - return result; - } - - return RESULT_SUCCESS; -} - -ResultCode CROHelper::ClearRelocations() { - ResultCode result = ClearExternalRelocations(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error clearing external relocations %08X", result.raw); - return result; - } - - result = ClearInternalRelocations(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error clearing internal relocations %08X", result.raw); - return result; - } - return RESULT_SUCCESS; -} - -void CROHelper::InitCRS() { - SetNextModule(0); - SetPreviousModule(0); -} - -void CROHelper::Register(VAddr crs_address, bool auto_link) { - CROHelper crs(crs_address); - CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule()); - - if (head.module_address) { - // there are already CROs registered - // register as the new tail - CROHelper tail(head.PreviousModule()); - - // link with the old tail - ASSERT(tail.NextModule() == 0); - SetPreviousModule(tail.module_address); - tail.SetNextModule(module_address); - - // set previous of the head pointing to the new tail - head.SetPreviousModule(module_address); - } else { - // register as the first CRO - // set previous to self as tail - SetPreviousModule(module_address); - - // set self as head - if (auto_link) - crs.SetNextModule(module_address); - else - crs.SetPreviousModule(module_address); - } - - // the new one is the tail - SetNextModule(0); -} - -void CROHelper::Unregister(VAddr crs_address) { - CROHelper crs(crs_address); - CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule()); - CROHelper next(NextModule()), previous(PreviousModule()); - - if (module_address == next_head.module_address || - module_address == previous_head.module_address) { - // removing head - if (next.module_address) { - // the next is new head - // let its previous point to the tail - next.SetPreviousModule(previous.module_address); - } - - // set new head - if (module_address == previous_head.module_address) { - crs.SetPreviousModule(next.module_address); - } else { - crs.SetNextModule(next.module_address); - } - } else if (next.module_address) { - // link previous and next - previous.SetNextModule(next.module_address); - next.SetPreviousModule(previous.module_address); - } else { - // removing tail - // set previous as new tail - previous.SetNextModule(0); - - // let head's previous point to the new tail - if (next_head.module_address && next_head.PreviousModule() == module_address) { - next_head.SetPreviousModule(previous.module_address); - } else if (previous_head.module_address && - previous_head.PreviousModule() == module_address) { - previous_head.SetPreviousModule(previous.module_address); - } else { - UNREACHABLE(); - } - } - - // unlink self - SetNextModule(0); - SetPreviousModule(0); -} - -u32 CROHelper::GetFixEnd(u32 fix_level) const { - u32 end = CRO_HEADER_SIZE; - end = std::max<u32>(end, GetField(CodeOffset) + GetField(CodeSize)); - - u32 entry_size_i = 2; - int field = ModuleNameOffset; - while (true) { - end = std::max<u32>(end, GetField(static_cast<HeaderField>(field)) + - GetField(static_cast<HeaderField>(field + 1)) * - ENTRY_SIZE[entry_size_i]); - - ++entry_size_i; - field += 2; - - if (field == FIX_BARRIERS[fix_level]) - return end; - } -} - -u32 CROHelper::Fix(u32 fix_level) { - u32 fix_end = GetFixEnd(fix_level); - - if (fix_level != 0) { - SetField(Magic, MAGIC_FIXD); - - for (int field = FIX_BARRIERS[fix_level]; field < Fix0Barrier; field += 2) { - SetField(static_cast<HeaderField>(field), fix_end); - SetField(static_cast<HeaderField>(field + 1), 0); - } - } - - fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE); - - u32 fixed_size = fix_end - module_address; - SetField(FixedSize, fixed_size); - return fixed_size; -} - -bool CROHelper::IsLoaded() const { - u32 magic = GetField(Magic); - if (magic != MAGIC_CRO0 && magic != MAGIC_FIXD) - return false; - - // TODO(wwylele): verify memory state here after memory aliasing is implemented - - return true; -} - -std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const { - u32 segment_num = GetField(SegmentNum); - for (u32 i = 0; i < segment_num; ++i) { - SegmentEntry entry; - GetEntry(i, entry); - if (entry.type == SegmentType::Code && entry.size != 0) { - VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); - VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); - return std::make_tuple(begin, end - begin); - } - } - return std::make_tuple(0, 0); -} - -} // namespace LDR -} // namespace Service diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h deleted file mode 100644 index 57b4fb6df..000000000 --- a/src/core/hle/service/ldr_ro/cro_helper.h +++ /dev/null @@ -1,714 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <tuple> -#include "common/common_types.h" -#include "common/swap.h" -#include "core/hle/result.h" -#include "core/memory.h" - -namespace Service { -namespace LDR { - -// GCC versions < 5.0 do not implement std::is_trivially_copyable. -// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable. -#if (__GNUC__ >= 5) || defined(__clang__) -#define ASSERT_CRO_STRUCT(name, size) \ - static_assert(std::is_standard_layout<name>::value, \ - "CRO structure " #name " doesn't use standard layout"); \ - static_assert(std::is_trivially_copyable<name>::value, \ - "CRO structure " #name " isn't trivially copyable"); \ - static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) -#else -#define ASSERT_CRO_STRUCT(name, size) \ - static_assert(std::is_standard_layout<name>::value, \ - "CRO structure " #name " doesn't use standard layout"); \ - static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) -#endif - -static constexpr u32 CRO_HEADER_SIZE = 0x138; -static constexpr u32 CRO_HASH_SIZE = 0x80; - -/// Represents a loaded module (CRO) with interfaces manipulating it. -class CROHelper final { -public: - explicit CROHelper(VAddr cro_address) : module_address(cro_address) {} - - std::string ModuleName() const { - return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize)); - } - - u32 GetFileSize() const { - return GetField(FileSize); - } - - /** - * Rebases the module according to its address. - * @param crs_address the virtual address of the static module - * @param cro_size the size of the CRO file - * @param data_segment_address buffer address for .data segment - * @param data_segment_size the buffer size for .data segment - * @param bss_segment_address the buffer address for .bss segment - * @param bss_segment_size the buffer size for .bss segment - * @param is_crs true if the module itself is the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_address, - u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size, - bool is_crs); - - /** - * Unrebases the module. - * @param is_crs true if the module itself is the static module - */ - void Unrebase(bool is_crs); - - /** - * Verifies module hash by CRR. - * @param cro_size the size of the CRO - * @param crr the virtual address of the CRR - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode VerifyHash(u32 cro_size, VAddr crr) const; - - /** - * Links this module with all registered auto-link module. - * @param crs_address the virtual address of the static module - * @param link_on_load_bug_fix true if links when loading and fixes the bug - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix); - - /** - * Unlinks this module with other modules. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Unlink(VAddr crs_address); - - /** - * Clears all relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearRelocations(); - - /// Initialize this module as the static module (CRS) - void InitCRS(); - - /** - * Registers this module and adds it to the module list. - * @param crs_address the virtual address of the static module - * @param auto_link whether to register as an auto link module - */ - void Register(VAddr crs_address, bool auto_link); - - /** - * Unregisters this module and removes from the module list. - * @param crs_address the virtual address of the static module - */ - void Unregister(VAddr crs_address); - - /** - * Gets the end of reserved data according to the fix level. - * @param fix_level fix level from 0 to 3 - * @returns the end of reserved data. - */ - u32 GetFixEnd(u32 fix_level) const; - - /** - * Zeros offsets to cropped data according to the fix level and marks as fixed. - * @param fix_level fix level from 0 to 3 - * @returns page-aligned size of the module after fixing. - */ - u32 Fix(u32 fix_level); - - bool IsFixed() const { - return GetField(Magic) == MAGIC_FIXD; - } - - u32 GetFixedSize() const { - return GetField(FixedSize); - } - - bool IsLoaded() const; - - /** - * Gets the page address and size of the code segment. - * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist. - */ - std::tuple<VAddr, u32> GetExecutablePages() const; - -private: - const VAddr module_address; ///< the virtual address of this module - - /** - * Each item in this enum represents a u32 field in the header begin from address+0x80, - * successively. We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or - * Read/WriteBlock repeatedly. - */ - enum HeaderField { - Magic = 0, - NameOffset, - NextCRO, - PreviousCRO, - FileSize, - BssSize, - FixedSize, - UnknownZero, - UnkSegmentTag, - OnLoadSegmentTag, - OnExitSegmentTag, - OnUnresolvedSegmentTag, - - CodeOffset, - CodeSize, - DataOffset, - DataSize, - ModuleNameOffset, - ModuleNameSize, - SegmentTableOffset, - SegmentNum, - - ExportNamedSymbolTableOffset, - ExportNamedSymbolNum, - ExportIndexedSymbolTableOffset, - ExportIndexedSymbolNum, - ExportStringsOffset, - ExportStringsSize, - ExportTreeTableOffset, - ExportTreeNum, - - ImportModuleTableOffset, - ImportModuleNum, - ExternalRelocationTableOffset, - ExternalRelocationNum, - ImportNamedSymbolTableOffset, - ImportNamedSymbolNum, - ImportIndexedSymbolTableOffset, - ImportIndexedSymbolNum, - ImportAnonymousSymbolTableOffset, - ImportAnonymousSymbolNum, - ImportStringsOffset, - ImportStringsSize, - - StaticAnonymousSymbolTableOffset, - StaticAnonymousSymbolNum, - InternalRelocationTableOffset, - InternalRelocationNum, - StaticRelocationTableOffset, - StaticRelocationNum, - Fix0Barrier, - - Fix3Barrier = ExportNamedSymbolTableOffset, - Fix2Barrier = ImportModuleTableOffset, - Fix1Barrier = StaticAnonymousSymbolTableOffset, - }; - static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4, - "CRO Header fields are wrong!"); - - enum class SegmentType : u32 { - Code = 0, - ROData = 1, - Data = 2, - BSS = 3, - }; - - /** - * Identifies a program location inside of a segment. - * Required to refer to program locations because individual segments may be relocated - * independently of each other. - */ - union SegmentTag { - u32_le raw; - BitField<0, 4, u32_le> segment_index; - BitField<4, 28, u32_le> offset_into_segment; - - SegmentTag() = default; - explicit SegmentTag(u32 raw_) : raw(raw_) {} - }; - - /// Information of a segment in this module. - struct SegmentEntry { - u32_le offset; - u32_le size; - SegmentType type; - - static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset; - }; - ASSERT_CRO_STRUCT(SegmentEntry, 12); - - /// Identifies a named symbol exported from this module. - struct ExportNamedSymbolEntry { - u32_le name_offset; // pointing to a substring in ExportStrings - SegmentTag symbol_position; // to self's segment - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8); - - /// Identifies an indexed symbol exported from this module. - struct ExportIndexedSymbolEntry { - SegmentTag symbol_position; // to self's segment - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4); - - /// A tree node in the symbol lookup tree. - struct ExportTreeEntry { - u16_le test_bit; // bit address into the name to test - union Child { - u16_le raw; - BitField<0, 15, u16_le> next_index; - BitField<15, 1, u16_le> is_end; - } left, right; - u16_le export_table_index; // index of an ExportNamedSymbolEntry - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset; - }; - ASSERT_CRO_STRUCT(ExportTreeEntry, 8); - - /// Identifies a named symbol imported from another module. - struct ImportNamedSymbolEntry { - u32_le name_offset; // pointing to a substring in ImportStrings - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8); - - /// Identifies an indexed symbol imported from another module. - struct ImportIndexedSymbolEntry { - u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8); - - /// Identifies an anonymous symbol imported from another module. - struct ImportAnonymousSymbolEntry { - SegmentTag symbol_position; // in the exporting segment - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8); - - /// Information of a imported module and symbols imported from it. - struct ImportModuleEntry { - u32_le name_offset; // pointing to a substring in ImportStrings - u32_le import_indexed_symbol_table_offset; // pointing to a subtable in - // ImportIndexedSymbolTable - u32_le import_indexed_symbol_num; - u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in - // ImportAnonymousSymbolTable - u32_le import_anonymous_symbol_num; - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset; - - void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) { - Memory::ReadBlock(import_indexed_symbol_table_offset + - index * sizeof(ImportIndexedSymbolEntry), - &entry, sizeof(ImportIndexedSymbolEntry)); - } - - void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) { - Memory::ReadBlock(import_anonymous_symbol_table_offset + - index * sizeof(ImportAnonymousSymbolEntry), - &entry, sizeof(ImportAnonymousSymbolEntry)); - } - }; - ASSERT_CRO_STRUCT(ImportModuleEntry, 20); - - enum class RelocationType : u8 { - Nothing = 0, - AbsoluteAddress = 2, - RelativeAddress = 3, - ThumbBranch = 10, - ArmBranch = 28, - ModifyArmBranch = 29, - AbsoluteAddress2 = 38, - AlignedRelativeAddress = 42, - }; - - struct RelocationEntry { - SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static - // module segment as a StaticRelocationEntry - RelocationType type; - u8 is_batch_end; - u8 is_batch_resolved; // set at a batch beginning if the batch is resolved - INSERT_PADDING_BYTES(1); - u32_le addend; - }; - - /// Identifies a normal cross-module relocation. - struct ExternalRelocationEntry : RelocationEntry { - static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12); - - /// Identifies a special static relocation (no game is known using this). - struct StaticRelocationEntry : RelocationEntry { - static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(StaticRelocationEntry, 12); - - /// Identifies a in-module relocation. - struct InternalRelocationEntry { - SegmentTag target_position; // to self's segment - RelocationType type; - u8 symbol_segment; - INSERT_PADDING_BYTES(2); - u32_le addend; - - static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(InternalRelocationEntry, 12); - - /// Identifies a special static anonymous symbol (no game is known using this). - struct StaticAnonymousSymbolEntry { - SegmentTag symbol_position; // to self's segment - u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8); - - /** - * Entry size of each table, from Code to StaticRelocationTable. - * Byte string contents (such as Code) are treated with entries of size 1. - * This is used for verifying the size of each table and calculating the fix end. - */ - static const std::array<int, 17> ENTRY_SIZE; - - /// The offset field of the table where to crop for each fix level - static const std::array<HeaderField, 4> FIX_BARRIERS; - - static constexpr u32 MAGIC_CRO0 = 0x304F5243; - static constexpr u32 MAGIC_FIXD = 0x44584946; - - VAddr Field(HeaderField field) const { - return module_address + CRO_HASH_SIZE + field * 4; - } - - u32 GetField(HeaderField field) const { - return Memory::Read32(Field(field)); - } - - void SetField(HeaderField field, u32 value) { - Memory::Write32(Field(field), value); - } - - /** - * Reads an entry in one of module tables. - * @param index index of the entry - * @param data where to put the read entry - * @note the entry type must have the static member TABLE_OFFSET_FIELD - * indicating which table the entry is in. - */ - template <typename T> - void GetEntry(std::size_t index, T& data) const { - Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), - &data, sizeof(T)); - } - - /** - * Writes an entry to one of module tables. - * @param index index of the entry - * @param data the entry data to write - * @note the entry type must have the static member TABLE_OFFSET_FIELD - * indicating which table the entry is in. - */ - template <typename T> - void SetEntry(std::size_t index, const T& data) { - Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), - &data, sizeof(T)); - } - - /** - * Converts a segment tag to virtual address in this module. - * @param segment_tag the segment tag to convert - * @returns VAddr the virtual address the segment tag points to; 0 if invalid. - */ - VAddr SegmentTagToAddress(SegmentTag segment_tag) const; - - VAddr NextModule() const { - return GetField(NextCRO); - } - - VAddr PreviousModule() const { - return GetField(PreviousCRO); - } - - void SetNextModule(VAddr next) { - SetField(NextCRO, next); - } - - void SetPreviousModule(VAddr previous) { - SetField(PreviousCRO, previous); - } - - /** - * A helper function iterating over all registered auto-link modules, including the static - * module. - * @param crs_address the virtual address of the static module - * @param func a function object to operate on a module. It accepts one parameter - * CROHelper and returns ResultVal<bool>. It should return true to continue the - * iteration, - * false to stop the iteration, or an error code (which will also stop the iteration). - * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration - * success, - * otherwise error code of the last iteration. - */ - template <typename FunctionObject> - static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) { - VAddr current = crs_address; - while (current != 0) { - CROHelper cro(current); - CASCADE_RESULT(bool next, func(cro)); - if (!next) - break; - current = cro.NextModule(); - } - return RESULT_SUCCESS; - } - - /** - * Applies a relocation - * @param target_address where to apply the relocation - * @param relocation_type the type of the relocation - * @param addend address addend applied to the relocated symbol - * @param symbol_address the symbol address to be relocated with - * @param target_future_address the future address of the target. - * Usually equals to target_address, but will be different for a target in .data segment - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend, - u32 symbol_address, u32 target_future_address); - - /** - * Clears a relocation to zero - * @param target_address where to apply the relocation - * @param relocation_type the type of the relocation - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type); - - /** - * Applies or resets a batch of relocations - * @param batch the virtual address of the first relocation in the batch - * @param symbol_address the symbol address to be relocated with - * @param reset false to set the batch to resolved state, true to reset the batch to unresolved - * state - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false); - - /** - * Finds an exported named symbol in this module. - * @param name the name of the symbol to find - * @return VAddr the virtual address of the symbol; 0 if not found. - */ - VAddr FindExportNamedSymbol(const std::string& name) const; - - /** - * Rebases offsets in module header according to module address. - * @param cro_size the size of the CRO file - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseHeader(u32 cro_size); - - /** - * Rebases offsets in segment table according to module address. - * @param cro_size the size of the CRO file - * @param data_segment_address the buffer address for .data segment - * @param data_segment_size the buffer size for .data segment - * @param bss_segment_address the buffer address for .bss segment - * @param bss_segment_size the buffer size for .bss segment - * @returns ResultVal<VAddr> with the virtual address of .data segment in CRO. - */ - ResultVal<VAddr> RebaseSegmentTable(u32 cro_size, VAddr data_segment_address, - u32 data_segment_size, VAddr bss_segment_address, - u32 bss_segment_size); - - /** - * Rebases offsets in exported named symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseExportNamedSymbolTable(); - - /** - * Verifies indices in export tree table. - * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error - * code. - */ - ResultCode VerifyExportTreeTable() const; - - /** - * Rebases offsets in exported module table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportModuleTable(); - - /** - * Rebases offsets in imported named symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportNamedSymbolTable(); - - /** - * Rebases offsets in imported indexed symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportIndexedSymbolTable(); - - /** - * Rebases offsets in imported anonymous symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportAnonymousSymbolTable(); - - /** - * Gets the address of OnUnresolved function in this module. - * Used as the applied symbol for reset relocation. - * @returns the virtual address of OnUnresolved. 0 if not provided. - */ - VAddr GetOnUnresolvedAddress(); - - /** - * Resets all external relocations to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetExternalRelocations(); - - /** - * Clears all external relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearExternalRelocations(); - - /** - * Applies all static anonymous symbol to the static module. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address); - - /** - * Applies all internal relocations to the module itself. - * @param old_data_segment_address the virtual address of data segment in CRO buffer - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyInternalRelocations(u32 old_data_segment_address); - - /** - * Clears all internal relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearInternalRelocations(); - - /// Unrebases offsets in imported anonymous symbol table - void UnrebaseImportAnonymousSymbolTable(); - - /// Unrebases offsets in imported indexed symbol table - void UnrebaseImportIndexedSymbolTable(); - - /// Unrebases offsets in imported named symbol table - void UnrebaseImportNamedSymbolTable(); - - /// Unrebases offsets in imported module table - void UnrebaseImportModuleTable(); - - /// Unrebases offsets in exported named symbol table - void UnrebaseExportNamedSymbolTable(); - - /// Unrebases offsets in segment table - void UnrebaseSegmentTable(); - - /// Unrebases offsets in module header - void UnrebaseHeader(); - - /** - * Looks up all imported named symbols of this module in all registered auto-link modules, and - * resolves them if found. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyImportNamedSymbol(VAddr crs_address); - - /** - * Resets all imported named symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportNamedSymbol(); - - /** - * Resets all imported indexed symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportIndexedSymbol(); - - /** - * Resets all imported anonymous symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportAnonymousSymbol(); - - /** - * Finds registered auto-link modules that this module imports, and resolves indexed and - * anonymous symbols exported by them. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyModuleImport(VAddr crs_address); - - /** - * Resolves target module's imported named symbols that exported by this module. - * @param target the module to resolve. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyExportNamedSymbol(CROHelper target); - - /** - * Resets target's named symbols imported from this module to unresolved state. - * @param target the module to reset. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetExportNamedSymbol(CROHelper target); - - /** - * Resolves imported indexed and anonymous symbols in the target module which imports this - * module. - * @param target the module to resolve. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyModuleExport(CROHelper target); - - /** - * Resets target's indexed and anonymous symbol imported from this module to unresolved state. - * @param target the module to reset. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetModuleExport(CROHelper target); - - /** - * Resolves the exit function in this module - * @param crs_address the virtual address of the static module. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyExitRelocations(VAddr crs_address); -}; - -} // namespace LDR -} // namespace Service diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp deleted file mode 100644 index 7255ea026..000000000 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/alignment.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/vm_manager.h" -#include "core/hle/service/ldr_ro/cro_helper.h" -#include "core/hle/service/ldr_ro/ldr_ro.h" -#include "core/hle/service/ldr_ro/memory_synchronizer.h" - -namespace Service { -namespace LDR { - -static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9 - ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal, - ErrorLevel::Permanent); -static const ResultCode ERROR_NOT_INITIALIZED = // 0xD9612FF8 - ResultCode(ErrorDescription::NotInitialized, ErrorModule::RO, ErrorSummary::Internal, - ErrorLevel::Permanent); -static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F - ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, - ErrorLevel::Usage); -static const ResultCode ERROR_MISALIGNED_ADDRESS = // 0xD9012FF1 - ResultCode(ErrorDescription::MisalignedAddress, ErrorModule::RO, ErrorSummary::WrongArgument, - ErrorLevel::Permanent); -static const ResultCode ERROR_MISALIGNED_SIZE = // 0xD9012FF2 - ResultCode(ErrorDescription::MisalignedSize, ErrorModule::RO, ErrorSummary::WrongArgument, - ErrorLevel::Permanent); -static const ResultCode ERROR_ILLEGAL_ADDRESS = // 0xE1612C0F - ResultCode(static_cast<ErrorDescription>(15), ErrorModule::RO, ErrorSummary::Internal, - ErrorLevel::Usage); -static const ResultCode ERROR_INVALID_MEMORY_STATE = // 0xD8A12C08 - ResultCode(static_cast<ErrorDescription>(8), ErrorModule::RO, ErrorSummary::InvalidState, - ErrorLevel::Permanent); -static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D - ResultCode(static_cast<ErrorDescription>(13), ErrorModule::RO, ErrorSummary::InvalidState, - ErrorLevel::Permanent); - -static MemorySynchronizer memory_synchronizer; - -// TODO(wwylele): this should be in the per-client storage when we implement multi-process -static VAddr loaded_crs; ///< the virtual address of the static module - -static bool VerifyBufferState(VAddr buffer_ptr, u32 size) { - auto vma = Kernel::g_current_process->vm_manager.FindVMA(buffer_ptr); - return vma != Kernel::g_current_process->vm_manager.vma_map.end() && - vma->second.base + vma->second.size >= buffer_ptr + size && - vma->second.permissions == Kernel::VMAPermission::ReadWrite && - vma->second.meminfo_state == Kernel::MemoryState::Private; -} - -/** - * LDR_RO::Initialize service function - * Inputs: - * 0 : 0x000100C2 - * 1 : CRS buffer pointer - * 2 : CRS Size - * 3 : Process memory address where the CRS will be mapped - * 4 : handle translation descriptor (zero) - * 5 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void Initialize(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 3, 2); - VAddr crs_buffer_ptr = rp.Pop<u32>(); - u32 crs_size = rp.Pop<u32>(); - VAddr crs_address = rp.Pop<u32>(); - // TODO (wwylele): RO service checks the descriptor here and return error 0xD9001830 for - // incorrect descriptor. This error return should be probably built in IPC::RequestParser. - // All other service functions below have the same issue. - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, - "called, crs_buffer_ptr=0x%08X, crs_address=0x%08X, crs_size=0x%X, process=0x%08X", - crs_buffer_ptr, crs_address, crs_size, process); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - if (loaded_crs != 0) { - LOG_ERROR(Service_LDR, "Already initialized"); - rb.Push(ERROR_ALREADY_INITIALIZED); - return; - } - - if (crs_size < CRO_HEADER_SIZE) { - LOG_ERROR(Service_LDR, "CRS is too small"); - rb.Push(ERROR_BUFFER_TOO_SMALL); - return; - } - - if (crs_buffer_ptr & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRS original address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - return; - } - - if (crs_address & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - return; - } - - if (crs_size & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRS size is not aligned"); - rb.Push(ERROR_MISALIGNED_SIZE); - return; - } - - if (!VerifyBufferState(crs_buffer_ptr, crs_size)) { - LOG_ERROR(Service_LDR, "CRS original buffer is in invalid state"); - rb.Push(ERROR_INVALID_MEMORY_STATE); - return; - } - - if (crs_address < Memory::PROCESS_IMAGE_VADDR || - crs_address + crs_size > Memory::PROCESS_IMAGE_VADDR_END) { - LOG_ERROR(Service_LDR, "CRS mapping address is not in the process image region"); - rb.Push(ERROR_ILLEGAL_ADDRESS); - return; - } - - ResultCode result = RESULT_SUCCESS; - - if (crs_buffer_ptr != crs_address) { - // TODO(wwylele): should be memory aliasing - std::shared_ptr<std::vector<u8>> crs_mem = std::make_shared<std::vector<u8>>(crs_size); - Memory::ReadBlock(crs_buffer_ptr, crs_mem->data(), crs_size); - result = Kernel::g_current_process->vm_manager - .MapMemoryBlock(crs_address, crs_mem, 0, crs_size, Kernel::MemoryState::Code) - .Code(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); - rb.Push(result); - return; - } - - result = Kernel::g_current_process->vm_manager.ReprotectRange(crs_address, crs_size, - Kernel::VMAPermission::Read); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); - rb.Push(result); - return; - } - - memory_synchronizer.AddMemoryBlock(crs_address, crs_buffer_ptr, crs_size); - } else { - // Do nothing if buffer_ptr == address - // TODO(wwylele): verify this behaviour. This is only seen in the web browser app, - // and the actual behaviour is unclear. "Do nothing" is probably an incorrect implement. - // There is also a chance that another issue causes the app passing wrong arguments. - LOG_WARNING(Service_LDR, "crs_buffer_ptr == crs_address (0x%08X)", crs_address); - } - - CROHelper crs(crs_address); - crs.InitCRS(); - - result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing CRS 0x%08X", result.raw); - rb.Push(result); - return; - } - - memory_synchronizer.SynchronizeOriginalMemory(); - - loaded_crs = crs_address; - - rb.Push(RESULT_SUCCESS); -} - -/** - * LDR_RO::LoadCRR service function - * Inputs: - * 0 : 0x00020082 - * 1 : CRR buffer pointer - * 2 : CRR Size - * 3 : handle translation descriptor (zero) - * 4 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void LoadCRR(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 2); - VAddr crr_buffer_ptr = rp.Pop<u32>(); - u32 crr_size = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); - - LOG_WARNING(Service_LDR, - "(STUBBED) called, crr_buffer_ptr=0x%08X, crr_size=0x%08X, process=0x%08X", - crr_buffer_ptr, crr_size, process); -} - -/** - * LDR_RO::UnloadCRR service function - * Inputs: - * 0 : 0x00030042 - * 1 : CRR buffer pointer - * 2 : handle translation descriptor (zero) - * 3 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void UnloadCRR(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 2); - u32 crr_buffer_ptr = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); - - LOG_WARNING(Service_LDR, "(STUBBED) called, crr_buffer_ptr=0x%08X, process=0x%08X", - crr_buffer_ptr, process); -} - -/** - * LDR_RO::LoadCRO service function - * Inputs: - * 0 : 0x000402C2 (old) / 0x000902C2 (new) - * 1 : CRO buffer pointer - * 2 : memory address where the CRO will be mapped - * 3 : CRO Size - * 4 : .data segment buffer pointer - * 5 : must be zero - * 6 : .data segment buffer size - * 7 : .bss segment buffer pointer - * 8 : .bss segment buffer size - * 9 : (bool) register CRO as auto-link module - * 10 : fix level - * 11 : CRR address (zero if use loaded CRR) - * 12 : handle translation descriptor (zero) - * 13 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : CRO fixed size - * Note: - * This service function has two versions. The function defined here is a - * unified one of two, with an additional parameter link_on_load_bug_fix. - * There is a dispatcher template below. - */ -static void LoadCRO(Interface* self, bool link_on_load_bug_fix) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), link_on_load_bug_fix ? 0x09 : 0x04, 11, 2); - VAddr cro_buffer_ptr = rp.Pop<u32>(); - VAddr cro_address = rp.Pop<u32>(); - u32 cro_size = rp.Pop<u32>(); - VAddr data_segment_address = rp.Pop<u32>(); - u32 zero = rp.Pop<u32>(); - u32 data_segment_size = rp.Pop<u32>(); - u32 bss_segment_address = rp.Pop<u32>(); - u32 bss_segment_size = rp.Pop<u32>(); - bool auto_link = rp.Pop<bool>(); - u32 fix_level = rp.Pop<u32>(); - VAddr crr_address = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, "called (%s), cro_buffer_ptr=0x%08X, cro_address=0x%08X, cro_size=0x%X, " - "data_segment_address=0x%08X, zero=%d, data_segment_size=0x%X, " - "bss_segment_address=0x%08X, bss_segment_size=0x%X, auto_link=%s, " - "fix_level=%d, crr_address=0x%08X, process=0x%08X", - link_on_load_bug_fix ? "new" : "old", cro_buffer_ptr, cro_address, cro_size, - data_segment_address, zero, data_segment_size, bss_segment_address, bss_segment_size, - auto_link ? "true" : "false", fix_level, crr_address, process); - - IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); - - if (loaded_crs == 0) { - LOG_ERROR(Service_LDR, "Not initialized"); - rb.Push(ERROR_NOT_INITIALIZED); - rb.Push<u32>(0); - return; - } - - if (cro_size < CRO_HEADER_SIZE) { - LOG_ERROR(Service_LDR, "CRO too small"); - rb.Push(ERROR_BUFFER_TOO_SMALL); - rb.Push<u32>(0); - return; - } - - if (cro_buffer_ptr & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO original address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - rb.Push<u32>(0); - return; - } - - if (cro_address & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - rb.Push<u32>(0); - return; - } - - if (cro_size & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO size is not aligned"); - rb.Push(ERROR_MISALIGNED_SIZE); - rb.Push<u32>(0); - return; - } - - if (!VerifyBufferState(cro_buffer_ptr, cro_size)) { - LOG_ERROR(Service_LDR, "CRO original buffer is in invalid state"); - rb.Push(ERROR_INVALID_MEMORY_STATE); - rb.Push<u32>(0); - return; - } - - if (cro_address < Memory::PROCESS_IMAGE_VADDR || - cro_address + cro_size > Memory::PROCESS_IMAGE_VADDR_END) { - LOG_ERROR(Service_LDR, "CRO mapping address is not in the process image region"); - rb.Push(ERROR_ILLEGAL_ADDRESS); - rb.Push<u32>(0); - return; - } - - if (zero) { - LOG_ERROR(Service_LDR, "Zero is not zero %d", zero); - rb.Push(ResultCode(static_cast<ErrorDescription>(29), ErrorModule::RO, - ErrorSummary::Internal, ErrorLevel::Usage)); - rb.Push<u32>(0); - return; - } - - ResultCode result = RESULT_SUCCESS; - - if (cro_buffer_ptr != cro_address) { - // TODO(wwylele): should be memory aliasing - std::shared_ptr<std::vector<u8>> cro_mem = std::make_shared<std::vector<u8>>(cro_size); - Memory::ReadBlock(cro_buffer_ptr, cro_mem->data(), cro_size); - result = Kernel::g_current_process->vm_manager - .MapMemoryBlock(cro_address, cro_mem, 0, cro_size, Kernel::MemoryState::Code) - .Code(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); - rb.Push(result); - rb.Push<u32>(0); - return; - } - - result = Kernel::g_current_process->vm_manager.ReprotectRange(cro_address, cro_size, - Kernel::VMAPermission::Read); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - - memory_synchronizer.AddMemoryBlock(cro_address, cro_buffer_ptr, cro_size); - } else { - // Do nothing if buffer_ptr == address - // TODO(wwylele): verify this behaviour. - // This is derived from the case of LoadCRS with buffer_ptr==address, - // and is never seen in any game. "Do nothing" is probably an incorrect implement. - // There is also a chance that this case is just prohibited. - LOG_WARNING(Service_LDR, "cro_buffer_ptr == cro_address (0x%08X)", cro_address); - } - - CROHelper cro(cro_address); - - result = cro.VerifyHash(cro_size, crr_address); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error verifying CRO in CRR %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - - result = cro.Rebase(loaded_crs, cro_size, data_segment_address, data_segment_size, - bss_segment_address, bss_segment_size, false); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error rebasing CRO %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - - result = cro.Link(loaded_crs, link_on_load_bug_fix); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - - cro.Register(loaded_crs, auto_link); - - u32 fix_size = cro.Fix(fix_level); - - memory_synchronizer.SynchronizeOriginalMemory(); - - // TODO(wwylele): verify the behaviour when buffer_ptr == address - if (cro_buffer_ptr != cro_address) { - if (fix_size != cro_size) { - result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address + fix_size, - cro_size - fix_size); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error unmapping memory block %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - } - - // Changes the block size - memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size); - } - - VAddr exe_begin; - u32 exe_size; - std::tie(exe_begin, exe_size) = cro.GetExecutablePages(); - if (exe_begin) { - result = Kernel::g_current_process->vm_manager.ReprotectRange( - exe_begin, exe_size, Kernel::VMAPermission::ReadExecute); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); - Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fix_size); - rb.Push(result); - rb.Push<u32>(0); - return; - } - } - - Core::CPU().ClearInstructionCache(); - - LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(), - cro_address, cro_address + fix_size); - - rb.Push(RESULT_SUCCESS, fix_size); -} - -template <bool link_on_load_bug_fix> -static void LoadCRO(Interface* self) { - LoadCRO(self, link_on_load_bug_fix); -} - -/** - * LDR_RO::UnloadCRO service function - * Inputs: - * 0 : 0x000500C2 - * 1 : mapped CRO pointer - * 2 : zero? (RO service doesn't care) - * 3 : original CRO pointer - * 4 : handle translation descriptor (zero) - * 5 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void UnloadCRO(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 3, 2); - VAddr cro_address = rp.Pop<u32>(); - u32 zero = rp.Pop<u32>(); - VAddr cro_buffer_ptr = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, - "called, cro_address=0x%08X, zero=%d, cro_buffer_ptr=0x%08X, process=0x%08X", - cro_address, zero, cro_buffer_ptr, process); - - CROHelper cro(cro_address); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - if (loaded_crs == 0) { - LOG_ERROR(Service_LDR, "Not initialized"); - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - if (cro_address & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - return; - } - - if (!cro.IsLoaded()) { - LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); - rb.Push(ERROR_NOT_LOADED); - return; - } - - LOG_INFO(Service_LDR, "Unloading CRO \"%s\"", cro.ModuleName().data()); - - u32 fixed_size = cro.GetFixedSize(); - - cro.Unregister(loaded_crs); - - ResultCode result = cro.Unlink(loaded_crs); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); - rb.Push(result); - return; - } - - // If the module is not fixed, clears all external/internal relocations - // to restore the state before loading, so that it can be loaded again(?) - if (!cro.IsFixed()) { - result = cro.ClearRelocations(); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error clearing relocations %08X", result.raw); - rb.Push(result); - return; - } - } - - cro.Unrebase(false); - - memory_synchronizer.SynchronizeOriginalMemory(); - - // TODO(wwylele): verify the behaviour when buffer_ptr == address - if (cro_address != cro_buffer_ptr) { - result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fixed_size); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw); - } - memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr); - } - - Core::CPU().ClearInstructionCache(); - - rb.Push(result); -} - -/** - * LDR_RO::LinkCRO service function - * Inputs: - * 0 : 0x00060042 - * 1 : mapped CRO pointer - * 2 : handle translation descriptor (zero) - * 3 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void LinkCRO(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 2); - VAddr cro_address = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process); - - CROHelper cro(cro_address); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - if (loaded_crs == 0) { - LOG_ERROR(Service_LDR, "Not initialized"); - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - if (cro_address & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - return; - } - - if (!cro.IsLoaded()) { - LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); - rb.Push(ERROR_NOT_LOADED); - return; - } - - LOG_INFO(Service_LDR, "Linking CRO \"%s\"", cro.ModuleName().data()); - - ResultCode result = cro.Link(loaded_crs, false); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); - } - - memory_synchronizer.SynchronizeOriginalMemory(); - Core::CPU().ClearInstructionCache(); - - rb.Push(result); -} - -/** - * LDR_RO::UnlinkCRO service function - * Inputs: - * 0 : 0x00070042 - * 1 : mapped CRO pointer - * 2 : handle translation descriptor (zero) - * 3 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void UnlinkCRO(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 1, 2); - VAddr cro_address = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process); - - CROHelper cro(cro_address); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - if (loaded_crs == 0) { - LOG_ERROR(Service_LDR, "Not initialized"); - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - if (cro_address & Memory::PAGE_MASK) { - LOG_ERROR(Service_LDR, "CRO address is not aligned"); - rb.Push(ERROR_MISALIGNED_ADDRESS); - return; - } - - if (!cro.IsLoaded()) { - LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); - rb.Push(ERROR_NOT_LOADED); - return; - } - - LOG_INFO(Service_LDR, "Unlinking CRO \"%s\"", cro.ModuleName().data()); - - ResultCode result = cro.Unlink(loaded_crs); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); - } - - memory_synchronizer.SynchronizeOriginalMemory(); - Core::CPU().ClearInstructionCache(); - - rb.Push(result); -} - -/** - * LDR_RO::Shutdown service function - * Inputs: - * 0 : 0x00080042 - * 1 : original CRS buffer pointer - * 2 : handle translation descriptor (zero) - * 3 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void Shutdown(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 2); - VAddr crs_buffer_ptr = rp.Pop<u32>(); - Kernel::Handle process = rp.PopHandle(); - - LOG_DEBUG(Service_LDR, "called, crs_buffer_ptr=0x%08X, process=0x%08X", crs_buffer_ptr, - process); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - if (loaded_crs == 0) { - LOG_ERROR(Service_LDR, "Not initialized"); - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - CROHelper crs(loaded_crs); - crs.Unrebase(true); - - memory_synchronizer.SynchronizeOriginalMemory(); - - ResultCode result = RESULT_SUCCESS; - - // TODO(wwylele): verify the behaviour when buffer_ptr == address - if (loaded_crs != crs_buffer_ptr) { - result = Kernel::g_current_process->vm_manager.UnmapRange(loaded_crs, crs.GetFileSize()); - if (result.IsError()) { - LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw); - } - memory_synchronizer.RemoveMemoryBlock(loaded_crs, crs_buffer_ptr); - } - - loaded_crs = 0; - rb.Push(result); -} - -const Interface::FunctionInfo FunctionTable[] = { - // clang-format off - {0x000100C2, Initialize, "Initialize"}, - {0x00020082, LoadCRR, "LoadCRR"}, - {0x00030042, UnloadCRR, "UnloadCRR"}, - {0x000402C2, LoadCRO<false>, "LoadCRO"}, - {0x000500C2, UnloadCRO, "UnloadCRO"}, - {0x00060042, LinkCRO, "LinkCRO"}, - {0x00070042, UnlinkCRO, "UnlinkCRO"}, - {0x00080042, Shutdown, "Shutdown"}, - {0x000902C2, LoadCRO<true>, "LoadCRO_New"}, - // clang-format on -}; - -LDR_RO::LDR_RO() { - Register(FunctionTable); - - loaded_crs = 0; - memory_synchronizer.Clear(); -} - -} // namespace LDR -} // namespace Service diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h deleted file mode 100644 index 0f6fe7b60..000000000 --- a/src/core/hle/service/ldr_ro/ldr_ro.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Service { -namespace LDR { - -class LDR_RO final : public Interface { -public: - LDR_RO(); - - std::string GetPortName() const override { - return "ldr:ro"; - } -}; - -} // namespace LDR -} // namespace Service diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp deleted file mode 100644 index 0d44bf6bd..000000000 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include "common/assert.h" -#include "core/hle/service/ldr_ro/memory_synchronizer.h" - -namespace Service { -namespace LDR { - -auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) { - auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(), - [=](MemoryBlock& b) { return b.original == original; }); - ASSERT(block->mapping == mapping); - return block; -} - -void MemorySynchronizer::Clear() { - memory_blocks.clear(); -} - -void MemorySynchronizer::AddMemoryBlock(VAddr mapping, VAddr original, u32 size) { - memory_blocks.push_back(MemoryBlock{mapping, original, size}); -} - -void MemorySynchronizer::ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size) { - FindMemoryBlock(mapping, original)->size = size; -} - -void MemorySynchronizer::RemoveMemoryBlock(VAddr mapping, VAddr original) { - memory_blocks.erase(FindMemoryBlock(mapping, original)); -} - -void MemorySynchronizer::SynchronizeOriginalMemory() { - for (auto& block : memory_blocks) { - Memory::CopyBlock(block.original, block.mapping, block.size); - } -} - -} // namespace LDR -} // namespace Service diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h deleted file mode 100644 index 438293a58..000000000 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <vector> -#include "core/memory.h" - -namespace Service { -namespace LDR { - -/** - * This is a work-around before we implement memory aliasing. - * CRS and CRO are mapped (aliased) to another memory when loading. Games can read - * from both the original buffer and the mapping memory. So we use this to synchronize - * all original buffers with mapping memory after modifying the content. - */ -class MemorySynchronizer { -public: - void Clear(); - - void AddMemoryBlock(VAddr mapping, VAddr original, u32 size); - void ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size); - void RemoveMemoryBlock(VAddr mapping, VAddr original); - - void SynchronizeOriginalMemory(); - -private: - struct MemoryBlock { - VAddr mapping; - VAddr original; - u32 size; - }; - - std::vector<MemoryBlock> memory_blocks; - - auto FindMemoryBlock(VAddr mapping, VAddr original); -}; - -} // namespace LDR -} // namespace Service |