1 // Copyright 2019 yuzu emulator team
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <cstring>
6 #include "core/file_sys/kernel_executable.h"
7 #include "core/file_sys/program_metadata.h"
8 #include "core/hle/kernel/code_set.h"
9 #include "core/hle/kernel/memory/page_table.h"
10 #include "core/hle/kernel/process.h"
11 #include "core/loader/kip.h"
12 #include "core/memory.h"
13
14 namespace Loader {
15
16 namespace {
PageAlignSize(u32 size)17 constexpr u32 PageAlignSize(u32 size) {
18 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
19 }
20 } // Anonymous namespace
21
AppLoader_KIP(FileSys::VirtualFile file_)22 AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
23 : AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
24
25 AppLoader_KIP::~AppLoader_KIP() = default;
26
IdentifyType(const FileSys::VirtualFile & file)27 FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& file) {
28 u32_le magic{};
29 if (file->GetSize() < sizeof(u32) || file->ReadObject(&magic) != sizeof(u32)) {
30 return FileType::Error;
31 }
32
33 if (magic == Common::MakeMagic('K', 'I', 'P', '1')) {
34 return FileType::KIP;
35 }
36
37 return FileType::Error;
38 }
39
GetFileType() const40 FileType AppLoader_KIP::GetFileType() const {
41 return (kip != nullptr && kip->GetStatus() == ResultStatus::Success) ? FileType::KIP
42 : FileType::Error;
43 }
44
Load(Kernel::Process & process,Core::System & system)45 AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
46 [[maybe_unused]] Core::System& system) {
47 if (is_loaded) {
48 return {ResultStatus::ErrorAlreadyLoaded, {}};
49 }
50
51 if (kip == nullptr) {
52 return {ResultStatus::ErrorNullFile, {}};
53 }
54
55 if (kip->GetStatus() != ResultStatus::Success) {
56 return {kip->GetStatus(), {}};
57 }
58
59 const auto get_kip_address_space_type = [](const auto& kip) {
60 return kip.Is64Bit()
61 ? (kip.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit
62 : FileSys::ProgramAddressSpaceType::Is36Bit)
63 : FileSys::ProgramAddressSpaceType::Is32Bit;
64 };
65
66 const auto address_space = get_kip_address_space_type(*kip);
67
68 FileSys::ProgramMetadata metadata;
69 metadata.LoadManual(kip->Is64Bit(), address_space, kip->GetMainThreadPriority(),
70 kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(),
71 kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, kip->GetKernelCapabilities());
72
73 const VAddr base_address = process.PageTable().GetCodeRegionStart();
74 Kernel::CodeSet codeset;
75 Kernel::PhysicalMemory program_image;
76
77 const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment,
78 const std::vector<u8>& data, u32 offset) {
79 segment.addr = offset;
80 segment.offset = offset;
81 segment.size = PageAlignSize(static_cast<u32>(data.size()));
82 program_image.resize(offset + data.size());
83 std::memcpy(program_image.data() + offset, data.data(), data.size());
84 };
85
86 load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
87 load_segment(codeset.RODataSegment(), kip->GetRODataSection(), kip->GetRODataOffset());
88 load_segment(codeset.DataSegment(), kip->GetDataSection(), kip->GetDataOffset());
89
90 program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
91 codeset.DataSegment().size += kip->GetBSSSize();
92
93 codeset.memory = std::move(program_image);
94 process.LoadModule(std::move(codeset), base_address);
95
96 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
97
98 is_loaded = true;
99 return {ResultStatus::Success,
100 LoadParameters{kip->GetMainThreadPriority(), kip->GetMainThreadStackSize()}};
101 }
102
103 } // namespace Loader
104