summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/ldr/ldr.cpp95
1 files changed, 59 insertions, 36 deletions
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 69caf3aae..5b372b7db 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -39,22 +39,27 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
39constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; 39constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
40constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; 40constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
41 41
42struct Certification { 42constexpr std::size_t TEXT_INDEX{0};
43constexpr std::size_t RO_INDEX{1};
44constexpr std::size_t DATA_INDEX{2};
45
46struct NRRCertification {
43 u64_le application_id_mask; 47 u64_le application_id_mask;
44 u64_le application_id_pattern; 48 u64_le application_id_pattern;
45 std::array<u8, 0x10> reserved; 49 std::array<u8, 0x10> reserved;
46 std::array<u8, 0x100> public_key; // Also known as modulus 50 std::array<u8, 0x100> public_key; // Also known as modulus
47 std::array<u8, 0x100> signature; 51 std::array<u8, 0x100> signature;
48}; 52};
49static_assert(sizeof(Certification) == 0x220, "Certification has invalid size!"); 53static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size!");
50 54
51using SHA256Hash = std::array<u8, 0x20>; 55using SHA256Hash = std::array<u8, 0x20>;
52 56
57#pragma pack(1)
53struct NRRHeader { 58struct NRRHeader {
54 u32_le magic; 59 u32_le magic;
55 u32_le certification_signature_key_generation; // 9.0.0+ 60 u32_le certification_signature_key_generation; // 9.0.0+
56 u64_le reserved; 61 u64_le reserved;
57 Certification certification; 62 NRRCertification certification;
58 std::array<u8, 0x100> signature; 63 std::array<u8, 0x100> signature;
59 u64_le application_id; 64 u64_le application_id;
60 u32_le size; 65 u32_le size;
@@ -63,21 +68,19 @@ struct NRRHeader {
63 u32_le hash_offset; 68 u32_le hash_offset;
64 u32_le hash_count; 69 u32_le hash_count;
65 u64_le reserved_3; 70 u64_le reserved_3;
66
67 // Must be dynamically allocated because, according to
68 // SwitchBrew, its size is (0x20 * hash_count) and
69 // it's impossible to determine the value of hash_count
70 // (SwitchBrew calls it "NumHash") before runtime,
71 // therefore it's not possible to calculate a SHA-256
72 std::vector<SHA256Hash> NroHashList;
73}; 71};
72#pragma pack()
73static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size!");
74 74
75#pragma pack(1)
75struct SegmentHeader { 76struct SegmentHeader {
76 u32_le memory_offset; 77 u32_le memory_offset;
77 u32_le memory_size; 78 u32_le memory_size;
78}; 79};
80#pragma pack()
79static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!"); 81static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!");
80 82
83#pragma pack(1)
81struct NROHeader { 84struct NROHeader {
82 // Switchbrew calls this "Start" (0x10) 85 // Switchbrew calls this "Start" (0x10)
83 u32_le unused; 86 u32_le unused;
@@ -99,8 +102,10 @@ struct NROHeader {
99 // .apiInfo, .dynstr, .dynsym 102 // .apiInfo, .dynstr, .dynsym
100 std::array<SegmentHeader, 3> segment_headers_2; 103 std::array<SegmentHeader, 3> segment_headers_2;
101}; 104};
105#pragma pack()
102static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); 106static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
103 107
108#pragma pack(1)
104struct NROInfo { 109struct NROInfo {
105 SHA256Hash hash{}; 110 SHA256Hash hash{};
106 VAddr nro_address{}; 111 VAddr nro_address{};
@@ -112,6 +117,8 @@ struct NROInfo {
112 std::size_t data_size{}; 117 std::size_t data_size{};
113 VAddr src_addr{}; 118 VAddr src_addr{};
114}; 119};
120#pragma pack()
121static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
115 122
116class DebugMonitor final : public ServiceFramework<DebugMonitor> { 123class DebugMonitor final : public ServiceFramework<DebugMonitor> {
117public: 124public:
@@ -369,10 +376,10 @@ public:
369 376
370 ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, 377 ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr,
371 VAddr start) const { 378 VAddr start) const {
372 const VAddr text_start{start + nro_header.segment_headers[0].memory_offset}; 379 const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
373 const VAddr ro_start{start + nro_header.segment_headers[1].memory_offset}; 380 const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
374 const VAddr data_start{start + nro_header.segment_headers[2].memory_offset}; 381 const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset};
375 const VAddr bss_start{data_start + nro_header.segment_headers[2].memory_size}; 382 const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size};
376 const VAddr bss_end_addr{ 383 const VAddr bss_end_addr{
377 Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; 384 Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)};
378 385
@@ -381,12 +388,12 @@ public:
381 system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); 388 system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size());
382 system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); 389 system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
383 }}; 390 }};
384 CopyCode(nro_addr + nro_header.segment_headers[0].memory_offset, text_start, 391 CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
385 nro_header.segment_headers[0].memory_size); 392 nro_header.segment_headers[TEXT_INDEX].memory_size);
386 CopyCode(nro_addr + nro_header.segment_headers[1].memory_offset, ro_start, 393 CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
387 nro_header.segment_headers[1].memory_size); 394 nro_header.segment_headers[RO_INDEX].memory_size);
388 CopyCode(nro_addr + nro_header.segment_headers[2].memory_offset, data_start, 395 CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
389 nro_header.segment_headers[2].memory_size); 396 nro_header.segment_headers[DATA_INDEX].memory_size);
390 397
391 CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( 398 CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
392 text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); 399 text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute));
@@ -510,9 +517,9 @@ public:
510 // Track the loaded NRO 517 // Track the loaded NRO
511 nro.insert_or_assign(*map_result, 518 nro.insert_or_assign(*map_result,
512 NROInfo{hash, *map_result, nro_size, bss_address, bss_size, 519 NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
513 header.segment_headers[0].memory_size, 520 header.segment_headers[TEXT_INDEX].memory_size,
514 header.segment_headers[1].memory_size, 521 header.segment_headers[RO_INDEX].memory_size,
515 header.segment_headers[2].memory_size, nro_address}); 522 header.segment_headers[DATA_INDEX].memory_size, nro_address});
516 523
517 // Invalidate JIT caches for the newly mapped process code 524 // Invalidate JIT caches for the newly mapped process code
518 system.InvalidateCpuInstructionCaches(); 525 system.InvalidateCpuInstructionCaches();
@@ -608,19 +615,35 @@ private:
608 } 615 }
609 616
610 static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { 617 static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
611 return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && 618
612 header.nro_size == nro_size && header.bss_size == bss_size && 619 const bool valid_magic = header.magic == Common::MakeMagic('N', 'R', 'O', '0');
613 header.segment_headers[1].memory_offset == 620
614 header.segment_headers[0].memory_offset + 621 const bool valid_nro_size = header.nro_size == nro_size;
615 header.segment_headers[0].memory_size && 622
616 header.segment_headers[2].memory_offset == 623 const bool valid_bss_size = header.bss_size == bss_size;
617 header.segment_headers[1].memory_offset + 624
618 header.segment_headers[1].memory_size && 625 const bool valid_ro_offset = header.segment_headers[RO_INDEX].memory_offset ==
619 nro_size == header.segment_headers[2].memory_offset + 626 header.segment_headers[TEXT_INDEX].memory_offset +
620 header.segment_headers[2].memory_size && 627 header.segment_headers[TEXT_INDEX].memory_size;
621 Common::Is4KBAligned(header.segment_headers[0].memory_size) && 628
622 Common::Is4KBAligned(header.segment_headers[1].memory_size) && 629 const bool valid_rw_offset = header.segment_headers[DATA_INDEX].memory_offset ==
623 Common::Is4KBAligned(header.segment_headers[2].memory_size); 630 header.segment_headers[RO_INDEX].memory_offset +
631 header.segment_headers[RO_INDEX].memory_size;
632
633 const bool valid_nro_calculated_size =
634 nro_size == header.segment_headers[DATA_INDEX].memory_offset +
635 header.segment_headers[DATA_INDEX].memory_size;
636
637 const bool text_aligned =
638 Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size);
639
640 const bool ro_aligned = Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size);
641
642 const bool rw_aligned =
643 Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
644
645 return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset &&
646 valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && rw_aligned;
624 } 647 }
625 Core::System& system; 648 Core::System& system;
626}; 649};