2020-06-25 17:51:05 +02:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
|
|
|
|
|
|
#include <lz4.h>
|
|
|
|
#include <nce.h>
|
2020-10-07 17:41:13 +02:00
|
|
|
#include <kernel/types/KProcess.h>
|
2020-06-25 17:51:05 +02:00
|
|
|
#include "nso.h"
|
|
|
|
|
|
|
|
namespace skyline::loader {
|
2020-06-26 14:23:29 +02:00
|
|
|
NsoLoader::NsoLoader(const std::shared_ptr<vfs::Backing> &backing) : backing(backing) {
|
2020-09-29 14:46:17 +02:00
|
|
|
u32 magic{backing->Read<u32>()};
|
2020-06-25 17:51:05 +02:00
|
|
|
|
|
|
|
if (magic != util::MakeMagic<u32>("NSO0"))
|
|
|
|
throw exception("Invalid NSO magic! 0x{0:X}", magic);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<u8> NsoLoader::GetSegment(const std::shared_ptr<vfs::Backing> &backing, const NsoSegmentHeader &segment, u32 compressedSize) {
|
|
|
|
std::vector<u8> outputBuffer(segment.decompressedSize);
|
|
|
|
|
|
|
|
if (compressedSize) {
|
|
|
|
std::vector<u8> compressedBuffer(compressedSize);
|
2020-09-29 14:46:17 +02:00
|
|
|
backing->Read(compressedBuffer, segment.fileOffset);
|
2020-06-25 17:51:05 +02:00
|
|
|
|
|
|
|
LZ4_decompress_safe(reinterpret_cast<char *>(compressedBuffer.data()), reinterpret_cast<char *>(outputBuffer.data()), compressedSize, segment.decompressedSize);
|
|
|
|
} else {
|
2020-09-29 14:46:17 +02:00
|
|
|
backing->Read(outputBuffer, segment.fileOffset);
|
2020-06-25 17:51:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return outputBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
Loader::ExecutableLoadInfo NsoLoader::LoadNso(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, size_t offset) {
|
2020-09-29 14:46:17 +02:00
|
|
|
auto header{backing->Read<NsoHeader>()};
|
2020-06-25 17:51:05 +02:00
|
|
|
|
|
|
|
if (header.magic != util::MakeMagic<u32>("NSO0"))
|
|
|
|
throw exception("Invalid NSO magic! 0x{0:X}", header.magic);
|
|
|
|
|
|
|
|
Executable nsoExecutable{};
|
|
|
|
|
|
|
|
nsoExecutable.text.contents = GetSegment(backing, header.text, header.flags.textCompressed ? header.textCompressedSize : 0);
|
|
|
|
nsoExecutable.text.contents.resize(util::AlignUp(nsoExecutable.text.contents.size(), PAGE_SIZE));
|
|
|
|
nsoExecutable.text.offset = header.text.memoryOffset;
|
|
|
|
|
2020-10-11 21:51:20 +02:00
|
|
|
nsoExecutable.ro.contents = GetSegment(backing, header.ro, header.flags.roCompressed ? header.roCompressedSize : 0);
|
2020-06-25 17:51:05 +02:00
|
|
|
nsoExecutable.ro.contents.resize(util::AlignUp(nsoExecutable.ro.contents.size(), PAGE_SIZE));
|
|
|
|
nsoExecutable.ro.offset = header.ro.memoryOffset;
|
|
|
|
|
2020-10-11 21:51:20 +02:00
|
|
|
nsoExecutable.data.contents = GetSegment(backing, header.data, header.flags.dataCompressed ? header.dataCompressedSize : 0);
|
2020-06-25 17:51:05 +02:00
|
|
|
nsoExecutable.data.contents.resize(util::AlignUp(nsoExecutable.data.contents.size(), PAGE_SIZE));
|
|
|
|
nsoExecutable.data.offset = header.data.memoryOffset;
|
|
|
|
|
|
|
|
nsoExecutable.bssSize = util::AlignUp(header.bssSize, PAGE_SIZE);
|
|
|
|
|
|
|
|
return LoadExecutable(process, state, nsoExecutable, offset);
|
|
|
|
}
|
|
|
|
|
2020-10-13 22:43:52 +02:00
|
|
|
void* NsoLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
2020-10-07 17:41:13 +02:00
|
|
|
state.process->memory.InitializeVmm(memory::AddressSpaceType::AddressSpace39Bit);
|
2020-09-26 07:17:57 +02:00
|
|
|
auto loadInfo{LoadNso(backing, process, state)};
|
2020-10-07 17:41:13 +02:00
|
|
|
state.process->memory.InitializeRegions(loadInfo.base, loadInfo.size);
|
2020-10-13 22:43:52 +02:00
|
|
|
return loadInfo.entry;
|
2020-06-25 17:51:05 +02:00
|
|
|
}
|
|
|
|
}
|