| 96 | } |
| 97 | |
| 98 | ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) { |
| 99 | using Kernel::CodeSet; |
| 100 | |
| 101 | if (!is_loaded) |
| 102 | return ResultStatus::ErrorNotLoaded; |
| 103 | |
| 104 | std::vector<u8> code; |
| 105 | u64_le program_id; |
| 106 | if (ResultStatus::Success == ReadCode(code) && |
| 107 | ResultStatus::Success == ReadProgramId(program_id)) { |
| 108 | if (IsGbaVirtualConsole(code)) { |
| 109 | LOG_ERROR(Loader, "Encountered unsupported GBA Virtual Console code section."); |
| 110 | return ResultStatus::ErrorGbaTitle; |
| 111 | } |
| 112 | |
| 113 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 114 | (const char*)overlay_ncch->exheader_header.codeset_info.name, 8); |
| 115 | |
| 116 | std::shared_ptr<CodeSet> codeset = system.Kernel().CreateCodeSet(process_name, program_id); |
| 117 | |
| 118 | codeset->CodeSegment().offset = 0; |
| 119 | codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; |
| 120 | codeset->CodeSegment().size = |
| 121 | overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::CITRA_PAGE_SIZE; |
| 122 | |
| 123 | codeset->RODataSegment().offset = |
| 124 | codeset->CodeSegment().offset + codeset->CodeSegment().size; |
| 125 | codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address; |
| 126 | codeset->RODataSegment().size = |
| 127 | overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::CITRA_PAGE_SIZE; |
| 128 | |
| 129 | // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just |
| 130 | // to the regular size. Playing it safe for now. |
| 131 | u32 bss_page_size = (overlay_ncch->exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF; |
| 132 | code.resize(code.size() + bss_page_size, 0); |
| 133 | |
| 134 | codeset->DataSegment().offset = |
| 135 | codeset->RODataSegment().offset + codeset->RODataSegment().size; |
| 136 | codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; |
| 137 | codeset->DataSegment().size = |
| 138 | overlay_ncch->exheader_header.codeset_info.data.num_max_pages * |
| 139 | Memory::CITRA_PAGE_SIZE + |
| 140 | bss_page_size; |
| 141 | |
| 142 | // Apply patches now that the entire codeset (including .bss) has been allocated |
| 143 | const ResultStatus patch_result = overlay_ncch->ApplyCodePatch(code); |
| 144 | if (patch_result != ResultStatus::Success && patch_result != ResultStatus::ErrorNotUsed) |
| 145 | return patch_result; |
| 146 | |
| 147 | codeset->entrypoint = codeset->CodeSegment().addr; |
| 148 | codeset->memory = std::move(code); |
| 149 | |
| 150 | process = system.Kernel().CreateProcess(std::move(codeset)); |
| 151 | |
| 152 | // Attach a resource limit to the process based on the resource limit category |
| 153 | const auto category = static_cast<Kernel::ResourceLimitCategory>( |
| 154 | overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category); |
| 155 | process->resource_limit = system.Kernel().ResourceLimit().GetForCategory(category); |
nothing calls this directly
no test coverage detected