2019-06-04 21:21:17 -07:00
|
|
|
// Copyright 2019 yuzu emulator team
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2020-01-12 07:51:07 -08:00
|
|
|
#include <cstring>
|
2019-06-04 21:21:17 -07:00
|
|
|
#include "core/file_sys/kernel_executable.h"
|
|
|
|
#include "core/file_sys/program_metadata.h"
|
|
|
|
#include "core/hle/kernel/code_set.h"
|
2021-02-12 17:58:31 -08:00
|
|
|
#include "core/hle/kernel/k_page_table.h"
|
2021-04-23 22:04:28 -07:00
|
|
|
#include "core/hle/kernel/k_process.h"
|
2019-06-04 21:21:17 -07:00
|
|
|
#include "core/loader/kip.h"
|
2020-04-09 11:01:34 -07:00
|
|
|
#include "core/memory.h"
|
2019-06-04 21:21:17 -07:00
|
|
|
|
|
|
|
namespace Loader {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
constexpr u32 PageAlignSize(u32 size) {
|
2020-10-13 05:10:50 -07:00
|
|
|
return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
|
2019-06-04 21:21:17 -07:00
|
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
|
|
|
|
: AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
|
|
|
|
|
|
|
|
AppLoader_KIP::~AppLoader_KIP() = default;
|
|
|
|
|
2021-04-27 09:05:34 -07:00
|
|
|
FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& in_file) {
|
2019-06-04 21:21:17 -07:00
|
|
|
u32_le magic{};
|
2021-04-27 09:05:34 -07:00
|
|
|
if (in_file->GetSize() < sizeof(u32) || in_file->ReadObject(&magic) != sizeof(u32)) {
|
2019-06-04 21:21:17 -07:00
|
|
|
return FileType::Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (magic == Common::MakeMagic('K', 'I', 'P', '1')) {
|
|
|
|
return FileType::KIP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FileType::Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileType AppLoader_KIP::GetFileType() const {
|
|
|
|
return (kip != nullptr && kip->GetStatus() == ResultStatus::Success) ? FileType::KIP
|
|
|
|
: FileType::Error;
|
|
|
|
}
|
|
|
|
|
2021-04-23 22:04:28 -07:00
|
|
|
AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
2020-09-16 05:19:25 -07:00
|
|
|
[[maybe_unused]] Core::System& system) {
|
2019-06-04 21:21:17 -07:00
|
|
|
if (is_loaded) {
|
|
|
|
return {ResultStatus::ErrorAlreadyLoaded, {}};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (kip == nullptr) {
|
|
|
|
return {ResultStatus::ErrorNullFile, {}};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (kip->GetStatus() != ResultStatus::Success) {
|
|
|
|
return {kip->GetStatus(), {}};
|
|
|
|
}
|
|
|
|
|
2021-04-27 09:05:34 -07:00
|
|
|
const auto get_kip_address_space_type = [](const auto& kip_type) {
|
|
|
|
return kip_type.Is64Bit()
|
|
|
|
? (kip_type.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit
|
|
|
|
: FileSys::ProgramAddressSpaceType::Is36Bit)
|
2019-06-06 16:20:15 -07:00
|
|
|
: FileSys::ProgramAddressSpaceType::Is32Bit;
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto address_space = get_kip_address_space_type(*kip);
|
2019-06-04 21:21:17 -07:00
|
|
|
|
|
|
|
FileSys::ProgramMetadata metadata;
|
|
|
|
metadata.LoadManual(kip->Is64Bit(), address_space, kip->GetMainThreadPriority(),
|
|
|
|
kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(),
|
2021-04-23 06:37:35 -07:00
|
|
|
kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, 0x1FE00000,
|
|
|
|
kip->GetKernelCapabilities());
|
2019-06-04 21:21:17 -07:00
|
|
|
|
2020-04-09 11:01:34 -07:00
|
|
|
const VAddr base_address = process.PageTable().GetCodeRegionStart();
|
2019-06-04 21:21:17 -07:00
|
|
|
Kernel::CodeSet codeset;
|
2019-07-18 15:15:53 -07:00
|
|
|
Kernel::PhysicalMemory program_image;
|
2019-06-04 21:21:17 -07:00
|
|
|
|
|
|
|
const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment,
|
|
|
|
const std::vector<u8>& data, u32 offset) {
|
|
|
|
segment.addr = offset;
|
|
|
|
segment.offset = offset;
|
|
|
|
segment.size = PageAlignSize(static_cast<u32>(data.size()));
|
2020-01-12 07:51:07 -08:00
|
|
|
program_image.resize(offset + data.size());
|
|
|
|
std::memcpy(program_image.data() + offset, data.data(), data.size());
|
2019-06-04 21:21:17 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
|
|
|
|
load_segment(codeset.RODataSegment(), kip->GetRODataSection(), kip->GetRODataOffset());
|
|
|
|
load_segment(codeset.DataSegment(), kip->GetDataSection(), kip->GetDataOffset());
|
|
|
|
|
|
|
|
program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
|
|
|
|
codeset.DataSegment().size += kip->GetBSSSize();
|
|
|
|
|
|
|
|
codeset.memory = std::move(program_image);
|
|
|
|
process.LoadModule(std::move(codeset), base_address);
|
|
|
|
|
|
|
|
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
|
|
|
|
|
|
|
|
is_loaded = true;
|
|
|
|
return {ResultStatus::Success,
|
|
|
|
LoadParameters{kip->GetMainThreadPriority(), kip->GetMainThreadStackSize()}};
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Loader
|