summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/ldr/ldr.cpp112
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 @@
namespace Service::LDR {
+namespace ErrCodes {
+enum {
+ InvalidNRO = 52,
+ InvalidNRR = 53,
+ MissingNRRHash = 54,
+ MaximumNRO = 55,
+ MaximumNRR = 56,
+ AlreadyLoaded = 57,
+ InvalidAlignment = 81,
+ InvalidSize = 82,
+ InvalidNROAddress = 84,
+ InvalidNRRAddress = 85,
+ NotInitialized = 87,
+};
+}
+
+constexpr ResultCode ERROR_INVALID_NRO(ErrorModule::Loader, ErrCodes::InvalidNRO);
+constexpr ResultCode ERROR_INVALID_NRR(ErrorModule::Loader, ErrCodes::InvalidNRR);
+constexpr ResultCode ERROR_MISSING_NRR_HASH(ErrorModule::Loader, ErrCodes::MissingNRRHash);
+constexpr ResultCode ERROR_MAXIMUM_NRO(ErrorModule::Loader, ErrCodes::MaximumNRO);
+constexpr ResultCode ERROR_MAXIMUM_NRR(ErrorModule::Loader, ErrCodes::MaximumNRR);
+constexpr ResultCode ERROR_ALREADY_LOADED(ErrorModule::Loader, ErrCodes::AlreadyLoaded);
+constexpr ResultCode ERROR_INVALID_ALIGNMENT(ErrorModule::Loader, ErrCodes::InvalidAlignment);
+constexpr ResultCode ERROR_INVALID_SIZE(ErrorModule::Loader, ErrCodes::InvalidSize);
+constexpr ResultCode ERROR_INVALID_NRO_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNROAddress);
+constexpr ResultCode ERROR_INVALID_NRR_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNRRAddress);
+constexpr ResultCode ERROR_NOT_INITIALIZED(ErrorModule::Loader, ErrCodes::NotInitialized);
+
+constexpr u64 MAXIMUM_LOADED_RO = 0x40;
+
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
@@ -75,6 +105,88 @@ public:
}
void LoadNrr(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rp.Skip(2, false);
+ const VAddr nrr_addr{rp.Pop<VAddr>()};
+ const u64 nrr_size{rp.Pop<u64>()};
+
+ if (!initialized) {
+ LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_NOT_INITIALIZED);
+ return;
+ }
+
+ if (nro.size() >= MAXIMUM_LOADED_RO) {
+ LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
+ "(0x40)! Failing...");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_MAXIMUM_NRR);
+ return;
+ }
+
+ // NRR Address does not fall on 0x1000 byte boundary
+ if ((nrr_addr & 0xFFF) != 0) {
+ LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ALIGNMENT);
+ return;
+ }
+
+ // NRR Size is zero or causes overflow
+ if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || (nrr_size & 0xFFF) != 0) {
+ LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
+ nrr_addr, nrr_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_SIZE);
+ return;
+ }
+ // Read NRR data from memory
+ std::vector<u8> nrr_data(nrr_size);
+ Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
+ NRRHeader header;
+ std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
+
+ if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
+ LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRR);
+ return;
+ }
+
+ if (header.size != nrr_size) {
+ LOG_ERROR(Service_LDR,
+ "NRR header reported size did not match LoadNrr parameter size! "
+ "(header_size={:016X}, loadnrr_size={:016X})",
+ header.size, nrr_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_SIZE);
+ return;
+ }
+
+ if (Core::CurrentProcess()->GetTitleID() != header.title_id) {
+ LOG_ERROR(Service_LDR,
+ "Attempting to load NRR with title ID other than current process. (actual "
+ "{:016X})!",
+ header.title_id);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRR);
+ return;
+ }
+
+ std::vector<SHA256Hash> hashes;
+ for (std::size_t i = header.hash_offset;
+ i < (header.hash_offset + (header.hash_count << 5)); i += 8) {
+ hashes.emplace_back();
+ std::memcpy(hashes.back().data(), nrr_data.data() + i, sizeof(SHA256Hash));
+ }
+
+ nrr.insert_or_assign(nrr_addr, std::move(hashes));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_LDR, "(STUBBED) called");