diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 6ad3be1b3..9f376657c 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -39,42 +39,61 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; | |||
| 39 | constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; | 39 | constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; |
| 40 | constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; | 40 | constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; |
| 41 | 41 | ||
| 42 | constexpr std::size_t TEXT_INDEX{0}; | ||
| 43 | constexpr std::size_t RO_INDEX{1}; | ||
| 44 | constexpr std::size_t DATA_INDEX{2}; | ||
| 45 | |||
| 46 | struct NRRCertification { | ||
| 47 | u64_le application_id_mask; | ||
| 48 | u64_le application_id_pattern; | ||
| 49 | std::array<u8, 0x10> reserved; | ||
| 50 | std::array<u8, 0x100> public_key; // Also known as modulus | ||
| 51 | std::array<u8, 0x100> signature; | ||
| 52 | }; | ||
| 53 | static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size."); | ||
| 54 | |||
| 42 | struct NRRHeader { | 55 | struct NRRHeader { |
| 43 | u32_le magic; | 56 | u32_le magic; |
| 44 | INSERT_PADDING_BYTES(12); | 57 | u32_le certification_signature_key_generation; // 9.0.0+ |
| 45 | u64_le title_id_mask; | 58 | u64_le reserved; |
| 46 | u64_le title_id_pattern; | 59 | NRRCertification certification; |
| 47 | INSERT_PADDING_BYTES(16); | 60 | std::array<u8, 0x100> signature; |
| 48 | std::array<u8, 0x100> modulus; | 61 | u64_le application_id; |
| 49 | std::array<u8, 0x100> signature_1; | ||
| 50 | std::array<u8, 0x100> signature_2; | ||
| 51 | u64_le title_id; | ||
| 52 | u32_le size; | 62 | u32_le size; |
| 53 | INSERT_PADDING_BYTES(4); | 63 | u8 nrr_kind; // 7.0.0+ |
| 64 | std::array<u8, 3> reserved_2; | ||
| 54 | u32_le hash_offset; | 65 | u32_le hash_offset; |
| 55 | u32_le hash_count; | 66 | u32_le hash_count; |
| 56 | INSERT_PADDING_BYTES(8); | 67 | u64_le reserved_3; |
| 57 | }; | 68 | }; |
| 58 | static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size."); | 69 | static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size."); |
| 70 | |||
| 71 | struct SegmentHeader { | ||
| 72 | u32_le memory_offset; | ||
| 73 | u32_le memory_size; | ||
| 74 | }; | ||
| 75 | static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size."); | ||
| 59 | 76 | ||
| 60 | struct NROHeader { | 77 | struct NROHeader { |
| 61 | INSERT_PADDING_WORDS(1); | 78 | // Switchbrew calls this "Start" (0x10) |
| 79 | u32_le unused; | ||
| 62 | u32_le mod_offset; | 80 | u32_le mod_offset; |
| 63 | INSERT_PADDING_WORDS(2); | 81 | u64_le padding; |
| 82 | |||
| 83 | // Switchbrew calls this "Header" (0x70) | ||
| 64 | u32_le magic; | 84 | u32_le magic; |
| 65 | u32_le version; | 85 | u32_le version; |
| 66 | u32_le nro_size; | 86 | u32_le nro_size; |
| 67 | u32_le flags; | 87 | u32_le flags; |
| 68 | u32_le text_offset; | 88 | // .text, .ro, .data |
| 69 | u32_le text_size; | 89 | std::array<SegmentHeader, 3> segment_headers; |
| 70 | u32_le ro_offset; | ||
| 71 | u32_le ro_size; | ||
| 72 | u32_le rw_offset; | ||
| 73 | u32_le rw_size; | ||
| 74 | u32_le bss_size; | 90 | u32_le bss_size; |
| 75 | INSERT_PADDING_WORDS(1); | 91 | u32_le reserved; |
| 76 | std::array<u8, 0x20> build_id; | 92 | std::array<u8, 0x20> build_id; |
| 77 | INSERT_PADDING_BYTES(0x20); | 93 | u32_le dso_handle_offset; |
| 94 | u32_le unused_2; | ||
| 95 | // .apiInfo, .dynstr, .dynsym | ||
| 96 | std::array<SegmentHeader, 3> segment_headers_2; | ||
| 78 | }; | 97 | }; |
| 79 | static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); | 98 | static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); |
| 80 | 99 | ||
| @@ -91,6 +110,7 @@ struct NROInfo { | |||
| 91 | std::size_t data_size{}; | 110 | std::size_t data_size{}; |
| 92 | VAddr src_addr{}; | 111 | VAddr src_addr{}; |
| 93 | }; | 112 | }; |
| 113 | static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size."); | ||
| 94 | 114 | ||
| 95 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 115 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 96 | public: | 116 | public: |
| @@ -226,11 +246,11 @@ public: | |||
| 226 | return; | 246 | return; |
| 227 | } | 247 | } |
| 228 | 248 | ||
| 229 | if (system.CurrentProcess()->GetTitleID() != header.title_id) { | 249 | if (system.CurrentProcess()->GetTitleID() != header.application_id) { |
| 230 | LOG_ERROR(Service_LDR, | 250 | LOG_ERROR(Service_LDR, |
| 231 | "Attempting to load NRR with title ID other than current process. (actual " | 251 | "Attempting to load NRR with title ID other than current process. (actual " |
| 232 | "{:016X})!", | 252 | "{:016X})!", |
| 233 | header.title_id); | 253 | header.application_id); |
| 234 | IPC::ResponseBuilder rb{ctx, 2}; | 254 | IPC::ResponseBuilder rb{ctx, 2}; |
| 235 | rb.Push(ERROR_INVALID_NRR); | 255 | rb.Push(ERROR_INVALID_NRR); |
| 236 | return; | 256 | return; |
| @@ -348,10 +368,10 @@ public: | |||
| 348 | 368 | ||
| 349 | ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, | 369 | ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, |
| 350 | VAddr start) const { | 370 | VAddr start) const { |
| 351 | const VAddr text_start{start + nro_header.text_offset}; | 371 | const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset}; |
| 352 | const VAddr ro_start{start + nro_header.ro_offset}; | 372 | const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset}; |
| 353 | const VAddr data_start{start + nro_header.rw_offset}; | 373 | const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset}; |
| 354 | const VAddr bss_start{data_start + nro_header.rw_size}; | 374 | const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size}; |
| 355 | const VAddr bss_end_addr{ | 375 | const VAddr bss_end_addr{ |
| 356 | Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; | 376 | Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; |
| 357 | 377 | ||
| @@ -360,9 +380,12 @@ public: | |||
| 360 | system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); | 380 | system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); |
| 361 | system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); | 381 | system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); |
| 362 | }}; | 382 | }}; |
| 363 | CopyCode(nro_addr + nro_header.text_offset, text_start, nro_header.text_size); | 383 | CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, |
| 364 | CopyCode(nro_addr + nro_header.ro_offset, ro_start, nro_header.ro_size); | 384 | nro_header.segment_headers[TEXT_INDEX].memory_size); |
| 365 | CopyCode(nro_addr + nro_header.rw_offset, data_start, nro_header.rw_size); | 385 | CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start, |
| 386 | nro_header.segment_headers[RO_INDEX].memory_size); | ||
| 387 | CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, | ||
| 388 | nro_header.segment_headers[DATA_INDEX].memory_size); | ||
| 366 | 389 | ||
| 367 | CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( | 390 | CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( |
| 368 | text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); | 391 | text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); |
| @@ -484,9 +507,11 @@ public: | |||
| 484 | } | 507 | } |
| 485 | 508 | ||
| 486 | // Track the loaded NRO | 509 | // Track the loaded NRO |
| 487 | nro.insert_or_assign(*map_result, NROInfo{hash, *map_result, nro_size, bss_address, | 510 | nro.insert_or_assign(*map_result, |
| 488 | bss_size, header.text_size, header.ro_size, | 511 | NROInfo{hash, *map_result, nro_size, bss_address, bss_size, |
| 489 | header.rw_size, nro_address}); | 512 | header.segment_headers[TEXT_INDEX].memory_size, |
| 513 | header.segment_headers[RO_INDEX].memory_size, | ||
| 514 | header.segment_headers[DATA_INDEX].memory_size, nro_address}); | ||
| 490 | 515 | ||
| 491 | // Invalidate JIT caches for the newly mapped process code | 516 | // Invalidate JIT caches for the newly mapped process code |
| 492 | system.InvalidateCpuInstructionCaches(); | 517 | system.InvalidateCpuInstructionCaches(); |
| @@ -584,11 +609,21 @@ private: | |||
| 584 | static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { | 609 | static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { |
| 585 | return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && | 610 | return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && |
| 586 | header.nro_size == nro_size && header.bss_size == bss_size && | 611 | header.nro_size == nro_size && header.bss_size == bss_size && |
| 587 | header.ro_offset == header.text_offset + header.text_size && | 612 | |
| 588 | header.rw_offset == header.ro_offset + header.ro_size && | 613 | header.segment_headers[RO_INDEX].memory_offset == |
| 589 | nro_size == header.rw_offset + header.rw_size && | 614 | header.segment_headers[TEXT_INDEX].memory_offset + |
| 590 | Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && | 615 | header.segment_headers[TEXT_INDEX].memory_size && |
| 591 | Common::Is4KBAligned(header.rw_size); | 616 | |
| 617 | header.segment_headers[DATA_INDEX].memory_offset == | ||
| 618 | header.segment_headers[RO_INDEX].memory_offset + | ||
| 619 | header.segment_headers[RO_INDEX].memory_size && | ||
| 620 | |||
| 621 | nro_size == header.segment_headers[DATA_INDEX].memory_offset + | ||
| 622 | header.segment_headers[DATA_INDEX].memory_size && | ||
| 623 | |||
| 624 | Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) && | ||
| 625 | Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && | ||
| 626 | Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); | ||
| 592 | } | 627 | } |
| 593 | Core::System& system; | 628 | Core::System& system; |
| 594 | }; | 629 | }; |