ldr_ro: Implement UnloadNrr (command 3)

Includes initialization check, proper address check, alignment check, and actual unloading of a loaded NRR.
This commit is contained in:
Zach Hilman 2018-10-29 22:03:59 -04:00
parent 6cd504feb9
commit 5e8e7b6019

View File

@ -4,7 +4,9 @@
#include <memory> #include <memory>
#include <fmt/format.h> #include <fmt/format.h>
#include <mbedtls/sha256.h>
#include "common/hex_util.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/service/ldr/ldr.h" #include "core/hle/service/ldr/ldr.h"
@ -94,7 +96,7 @@ public:
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &RelocatableObject::LoadNro, "LoadNro"}, {0, &RelocatableObject::LoadNro, "LoadNro"},
{1, nullptr, "UnloadNro"}, {1, &RelocatableObject::UnloadNro, "UnloadNro"},
{2, &RelocatableObject::LoadNrr, "LoadNrr"}, {2, &RelocatableObject::LoadNrr, "LoadNrr"},
{3, nullptr, "UnloadNrr"}, {3, nullptr, "UnloadNrr"},
{4, &RelocatableObject::Initialize, "Initialize"}, {4, &RelocatableObject::Initialize, "Initialize"},
@ -187,9 +189,38 @@ public:
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void UnloadNrr(Kernel::HLERequestContext& ctx) {
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_NOT_INITIALIZED);
return;
}
IPC::RequestParser rp{ctx};
rp.Skip(2, false);
const auto nrr_addr{rp.Pop<VAddr>()};
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;
}
const auto iter = nrr.find(nrr_addr);
if (iter == nrr.end()) {
LOG_ERROR(Service_LDR,
"Attempting to unload NRR which has not been loaded! (addr={:016X})",
nrr_addr);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_NRR_ADDRESS);
return;
}
nrr.erase(iter);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_LDR, "(STUBBED) called");
} }
void LoadNro(Kernel::HLERequestContext& ctx) { void LoadNro(Kernel::HLERequestContext& ctx) {
@ -227,6 +258,57 @@ public:
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_LDR, "(STUBBED) called"); LOG_WARNING(Service_LDR, "(STUBBED) called");
} }
private:
using SHA256Hash = std::array<u8, 0x20>;
struct NROHeader {
u32_le entrypoint_insn;
u32_le mod_offset;
INSERT_PADDING_WORDS(2);
u32_le magic;
INSERT_PADDING_WORDS(1);
u32_le nro_size;
INSERT_PADDING_WORDS(1);
u32_le text_offset;
u32_le text_size;
u32_le ro_offset;
u32_le ro_size;
u32_le rw_offset;
u32_le rw_size;
u32_le bss_size;
INSERT_PADDING_WORDS(1);
std::array<u8, 0x20> build_id;
INSERT_PADDING_BYTES(0x20);
};
static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
struct NRRHeader {
u32_le magic;
INSERT_PADDING_BYTES(0x1C);
u64_le title_id_mask;
u64_le title_id_pattern;
std::array<u8, 0x100> modulus;
std::array<u8, 0x100> signature_1;
std::array<u8, 0x100> signature_2;
u64_le title_id;
u32_le size;
INSERT_PADDING_BYTES(4);
u32_le hash_offset;
u32_le hash_count;
INSERT_PADDING_BYTES(8);
};
static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size.");
struct NROInfo {
SHA256Hash hash;
u64 size;
};
bool initialized = false;
std::map<VAddr, NROInfo> nro;
std::map<VAddr, std::vector<SHA256Hash>> nrr;
}; };
void InstallInterfaces(SM::ServiceManager& sm) { void InstallInterfaces(SM::ServiceManager& sm) {