1
1
Fork 0
forked from suyu/suyu

Merge pull request #4026 from VolcaEM/ldr

ldr: Update NRR/NRO structs
This commit is contained in:
David 2020-06-28 20:46:42 +10:00 committed by GitHub
commit d67c7d9a82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -39,42 +39,61 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
constexpr std::size_t TEXT_INDEX{0};
constexpr std::size_t RO_INDEX{1};
constexpr std::size_t DATA_INDEX{2};
struct NRRCertification {
u64_le application_id_mask;
u64_le application_id_pattern;
std::array<u8, 0x10> reserved;
std::array<u8, 0x100> public_key; // Also known as modulus
std::array<u8, 0x100> signature;
};
static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size.");
struct NRRHeader { struct NRRHeader {
u32_le magic; u32_le magic;
INSERT_PADDING_BYTES(12); u32_le certification_signature_key_generation; // 9.0.0+
u64_le title_id_mask; u64_le reserved;
u64_le title_id_pattern; NRRCertification certification;
INSERT_PADDING_BYTES(16); std::array<u8, 0x100> signature;
std::array<u8, 0x100> modulus; u64_le application_id;
std::array<u8, 0x100> signature_1;
std::array<u8, 0x100> signature_2;
u64_le title_id;
u32_le size; u32_le size;
INSERT_PADDING_BYTES(4); u8 nrr_kind; // 7.0.0+
std::array<u8, 3> reserved_2;
u32_le hash_offset; u32_le hash_offset;
u32_le hash_count; u32_le hash_count;
INSERT_PADDING_BYTES(8); u64_le reserved_3;
}; };
static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size."); static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size.");
struct SegmentHeader {
u32_le memory_offset;
u32_le memory_size;
};
static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size.");
struct NROHeader { struct NROHeader {
INSERT_PADDING_WORDS(1); // Switchbrew calls this "Start" (0x10)
u32_le unused;
u32_le mod_offset; u32_le mod_offset;
INSERT_PADDING_WORDS(2); u64_le padding;
// Switchbrew calls this "Header" (0x70)
u32_le magic; u32_le magic;
u32_le version; u32_le version;
u32_le nro_size; u32_le nro_size;
u32_le flags; u32_le flags;
u32_le text_offset; // .text, .ro, .data
u32_le text_size; std::array<SegmentHeader, 3> segment_headers;
u32_le ro_offset;
u32_le ro_size;
u32_le rw_offset;
u32_le rw_size;
u32_le bss_size; u32_le bss_size;
INSERT_PADDING_WORDS(1); u32_le reserved;
std::array<u8, 0x20> build_id; std::array<u8, 0x20> build_id;
INSERT_PADDING_BYTES(0x20); u32_le dso_handle_offset;
u32_le unused_2;
// .apiInfo, .dynstr, .dynsym
std::array<SegmentHeader, 3> segment_headers_2;
}; };
static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
@ -91,6 +110,7 @@ struct NROInfo {
std::size_t data_size{}; std::size_t data_size{};
VAddr src_addr{}; VAddr src_addr{};
}; };
static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
class DebugMonitor final : public ServiceFramework<DebugMonitor> { class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public: public:
@ -226,11 +246,11 @@ public:
return; return;
} }
if (system.CurrentProcess()->GetTitleID() != header.title_id) { if (system.CurrentProcess()->GetTitleID() != header.application_id) {
LOG_ERROR(Service_LDR, LOG_ERROR(Service_LDR,
"Attempting to load NRR with title ID other than current process. (actual " "Attempting to load NRR with title ID other than current process. (actual "
"{:016X})!", "{:016X})!",
header.title_id); header.application_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_NRR); rb.Push(ERROR_INVALID_NRR);
return; return;
@ -348,10 +368,10 @@ public:
ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr,
VAddr start) const { VAddr start) const {
const VAddr text_start{start + nro_header.text_offset}; const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
const VAddr ro_start{start + nro_header.ro_offset}; const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
const VAddr data_start{start + nro_header.rw_offset}; const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset};
const VAddr bss_start{data_start + nro_header.rw_size}; const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size};
const VAddr bss_end_addr{ const VAddr bss_end_addr{
Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)};
@ -360,9 +380,12 @@ public:
system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size());
system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
}}; }};
CopyCode(nro_addr + nro_header.text_offset, text_start, nro_header.text_size); CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
CopyCode(nro_addr + nro_header.ro_offset, ro_start, nro_header.ro_size); nro_header.segment_headers[TEXT_INDEX].memory_size);
CopyCode(nro_addr + nro_header.rw_offset, data_start, nro_header.rw_size); CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
nro_header.segment_headers[RO_INDEX].memory_size);
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute));
@ -484,9 +507,11 @@ public:
} }
// Track the loaded NRO // Track the loaded NRO
nro.insert_or_assign(*map_result, NROInfo{hash, *map_result, nro_size, bss_address, nro.insert_or_assign(*map_result,
bss_size, header.text_size, header.ro_size, NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
header.rw_size, nro_address}); header.segment_headers[TEXT_INDEX].memory_size,
header.segment_headers[RO_INDEX].memory_size,
header.segment_headers[DATA_INDEX].memory_size, nro_address});
// Invalidate JIT caches for the newly mapped process code // Invalidate JIT caches for the newly mapped process code
system.InvalidateCpuInstructionCaches(); system.InvalidateCpuInstructionCaches();
@ -584,11 +609,21 @@ private:
static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
header.nro_size == nro_size && header.bss_size == bss_size && header.nro_size == nro_size && header.bss_size == bss_size &&
header.ro_offset == header.text_offset + header.text_size &&
header.rw_offset == header.ro_offset + header.ro_size && header.segment_headers[RO_INDEX].memory_offset ==
nro_size == header.rw_offset + header.rw_size && header.segment_headers[TEXT_INDEX].memory_offset +
Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && header.segment_headers[TEXT_INDEX].memory_size &&
Common::Is4KBAligned(header.rw_size);
header.segment_headers[DATA_INDEX].memory_offset ==
header.segment_headers[RO_INDEX].memory_offset +
header.segment_headers[RO_INDEX].memory_size &&
nro_size == header.segment_headers[DATA_INDEX].memory_offset +
header.segment_headers[DATA_INDEX].memory_size &&
Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) &&
Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) &&
Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
} }
Core::System& system; Core::System& system;
}; };