diff options
| author | 2018-10-29 21:58:11 -0400 | |
|---|---|---|
| committer | 2018-11-15 12:48:09 -0500 | |
| commit | 6cd504feb921b442ab079bd2be638180e3e61c04 (patch) | |
| tree | 557a5efd7249ecbe54c47dd661724c5f54ac75d8 /src | |
| parent | process: Make MirrorMemory take state to map new memory as (diff) | |
| download | yuzu-6cd504feb921b442ab079bd2be638180e3e61c04.tar.gz yuzu-6cd504feb921b442ab079bd2be638180e3e61c04.tar.xz yuzu-6cd504feb921b442ab079bd2be638180e3e61c04.zip | |
ldr_ro: Fully implement LoadNrr (command 2)
Includes parameter error checking, hash enforcement, initialization check, and max NRR load check.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d607d985e..7804913fa 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -13,6 +13,36 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::LDR { | 14 | namespace Service::LDR { |
| 15 | 15 | ||
| 16 | namespace ErrCodes { | ||
| 17 | enum { | ||
| 18 | InvalidNRO = 52, | ||
| 19 | InvalidNRR = 53, | ||
| 20 | MissingNRRHash = 54, | ||
| 21 | MaximumNRO = 55, | ||
| 22 | MaximumNRR = 56, | ||
| 23 | AlreadyLoaded = 57, | ||
| 24 | InvalidAlignment = 81, | ||
| 25 | InvalidSize = 82, | ||
| 26 | InvalidNROAddress = 84, | ||
| 27 | InvalidNRRAddress = 85, | ||
| 28 | NotInitialized = 87, | ||
| 29 | }; | ||
| 30 | } | ||
| 31 | |||
| 32 | constexpr ResultCode ERROR_INVALID_NRO(ErrorModule::Loader, ErrCodes::InvalidNRO); | ||
| 33 | constexpr ResultCode ERROR_INVALID_NRR(ErrorModule::Loader, ErrCodes::InvalidNRR); | ||
| 34 | constexpr ResultCode ERROR_MISSING_NRR_HASH(ErrorModule::Loader, ErrCodes::MissingNRRHash); | ||
| 35 | constexpr ResultCode ERROR_MAXIMUM_NRO(ErrorModule::Loader, ErrCodes::MaximumNRO); | ||
| 36 | constexpr ResultCode ERROR_MAXIMUM_NRR(ErrorModule::Loader, ErrCodes::MaximumNRR); | ||
| 37 | constexpr ResultCode ERROR_ALREADY_LOADED(ErrorModule::Loader, ErrCodes::AlreadyLoaded); | ||
| 38 | constexpr ResultCode ERROR_INVALID_ALIGNMENT(ErrorModule::Loader, ErrCodes::InvalidAlignment); | ||
| 39 | constexpr ResultCode ERROR_INVALID_SIZE(ErrorModule::Loader, ErrCodes::InvalidSize); | ||
| 40 | constexpr ResultCode ERROR_INVALID_NRO_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNROAddress); | ||
| 41 | constexpr ResultCode ERROR_INVALID_NRR_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNRRAddress); | ||
| 42 | constexpr ResultCode ERROR_NOT_INITIALIZED(ErrorModule::Loader, ErrCodes::NotInitialized); | ||
| 43 | |||
| 44 | constexpr u64 MAXIMUM_LOADED_RO = 0x40; | ||
| 45 | |||
| 16 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 46 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 17 | public: | 47 | public: |
| 18 | explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { | 48 | explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { |
| @@ -75,6 +105,88 @@ public: | |||
| 75 | } | 105 | } |
| 76 | 106 | ||
| 77 | void LoadNrr(Kernel::HLERequestContext& ctx) { | 107 | void LoadNrr(Kernel::HLERequestContext& ctx) { |
| 108 | IPC::RequestParser rp{ctx}; | ||
| 109 | rp.Skip(2, false); | ||
| 110 | const VAddr nrr_addr{rp.Pop<VAddr>()}; | ||
| 111 | const u64 nrr_size{rp.Pop<u64>()}; | ||
| 112 | |||
| 113 | if (!initialized) { | ||
| 114 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 116 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | |||
| 120 | if (nro.size() >= MAXIMUM_LOADED_RO) { | ||
| 121 | LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs " | ||
| 122 | "(0x40)! Failing..."); | ||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 124 | rb.Push(ERROR_MAXIMUM_NRR); | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | |||
| 128 | // NRR Address does not fall on 0x1000 byte boundary | ||
| 129 | if ((nrr_addr & 0xFFF) != 0) { | ||
| 130 | LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); | ||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 132 | rb.Push(ERROR_INVALID_ALIGNMENT); | ||
| 133 | return; | ||
| 134 | } | ||
| 135 | |||
| 136 | // NRR Size is zero or causes overflow | ||
| 137 | if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || (nrr_size & 0xFFF) != 0) { | ||
| 138 | LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})", | ||
| 139 | nrr_addr, nrr_size); | ||
| 140 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 141 | rb.Push(ERROR_INVALID_SIZE); | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | // Read NRR data from memory | ||
| 145 | std::vector<u8> nrr_data(nrr_size); | ||
| 146 | Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size); | ||
| 147 | NRRHeader header; | ||
| 148 | std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); | ||
| 149 | |||
| 150 | if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) { | ||
| 151 | LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic); | ||
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 153 | rb.Push(ERROR_INVALID_NRR); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (header.size != nrr_size) { | ||
| 158 | LOG_ERROR(Service_LDR, | ||
| 159 | "NRR header reported size did not match LoadNrr parameter size! " | ||
| 160 | "(header_size={:016X}, loadnrr_size={:016X})", | ||
| 161 | header.size, nrr_size); | ||
| 162 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 163 | rb.Push(ERROR_INVALID_SIZE); | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 167 | if (Core::CurrentProcess()->GetTitleID() != header.title_id) { | ||
| 168 | LOG_ERROR(Service_LDR, | ||
| 169 | "Attempting to load NRR with title ID other than current process. (actual " | ||
| 170 | "{:016X})!", | ||
| 171 | header.title_id); | ||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 173 | rb.Push(ERROR_INVALID_NRR); | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | std::vector<SHA256Hash> hashes; | ||
| 178 | for (std::size_t i = header.hash_offset; | ||
| 179 | i < (header.hash_offset + (header.hash_count << 5)); i += 8) { | ||
| 180 | hashes.emplace_back(); | ||
| 181 | std::memcpy(hashes.back().data(), nrr_data.data() + i, sizeof(SHA256Hash)); | ||
| 182 | } | ||
| 183 | |||
| 184 | nrr.insert_or_assign(nrr_addr, std::move(hashes)); | ||
| 185 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 187 | rb.Push(RESULT_SUCCESS); | ||
| 188 | } | ||
| 189 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | 190 | IPC::ResponseBuilder rb{ctx, 2}; |
| 79 | rb.Push(RESULT_SUCCESS); | 191 | rb.Push(RESULT_SUCCESS); |
| 80 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | 192 | LOG_WARNING(Service_LDR, "(STUBBED) called"); |