diff options
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/3dsx.cpp | 37 | ||||
| -rw-r--r-- | src/core/loader/elf.cpp | 81 | ||||
| -rw-r--r-- | src/core/loader/ncch.cpp | 32 |
3 files changed, 123 insertions, 27 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index e57d7274c..055661363 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -101,7 +101,10 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) | |||
| 101 | return loadinfo->seg_addrs[2] + addr - offsets[1]; | 101 | return loadinfo->seg_addrs[2] + addr - offsets[1]; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | 104 | using Kernel::SharedPtr; |
| 105 | using Kernel::CodeSet; | ||
| 106 | |||
| 107 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset) | ||
| 105 | { | 108 | { |
| 106 | if (!file.IsOpen()) | 109 | if (!file.IsOpen()) |
| 107 | return ERROR_FILE; | 110 | return ERROR_FILE; |
| @@ -201,13 +204,29 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 201 | } | 204 | } |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 204 | // Write the data | 207 | // Create the CodeSet |
| 205 | memcpy(Memory::GetPointer(base_addr), program_image.data(), program_image.size()); | 208 | SharedPtr<CodeSet> code_set = CodeSet::Create("", 0); |
| 209 | |||
| 210 | code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data(); | ||
| 211 | code_set->code.addr = loadinfo.seg_addrs[0]; | ||
| 212 | code_set->code.size = loadinfo.seg_sizes[0]; | ||
| 213 | |||
| 214 | code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data(); | ||
| 215 | code_set->rodata.addr = loadinfo.seg_addrs[1]; | ||
| 216 | code_set->rodata.size = loadinfo.seg_sizes[1]; | ||
| 217 | |||
| 218 | code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data(); | ||
| 219 | code_set->data.addr = loadinfo.seg_addrs[2]; | ||
| 220 | code_set->data.size = loadinfo.seg_sizes[2]; | ||
| 221 | |||
| 222 | code_set->entrypoint = code_set->code.addr; | ||
| 223 | code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 206 | 224 | ||
| 207 | LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); | 225 | LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); |
| 208 | LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); | 226 | LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); |
| 209 | LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size); | 227 | LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size); |
| 210 | 228 | ||
| 229 | *out_codeset = code_set; | ||
| 211 | return ERROR_NONE; | 230 | return ERROR_NONE; |
| 212 | } | 231 | } |
| 213 | 232 | ||
| @@ -230,17 +249,19 @@ ResultStatus AppLoader_THREEDSX::Load() { | |||
| 230 | if (!file->IsOpen()) | 249 | if (!file->IsOpen()) |
| 231 | return ResultStatus::Error; | 250 | return ResultStatus::Error; |
| 232 | 251 | ||
| 233 | Kernel::g_current_process = Kernel::Process::Create(filename, 0); | 252 | SharedPtr<CodeSet> codeset; |
| 253 | if (Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE) | ||
| 254 | return ResultStatus::Error; | ||
| 255 | codeset->name = filename; | ||
| 256 | |||
| 257 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | ||
| 234 | Kernel::g_current_process->svc_access_mask.set(); | 258 | Kernel::g_current_process->svc_access_mask.set(); |
| 235 | Kernel::g_current_process->address_mappings = default_address_mappings; | 259 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 236 | 260 | ||
| 237 | // Attach the default resource limit (APPLICATION) to the process | 261 | // Attach the default resource limit (APPLICATION) to the process |
| 238 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 262 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 239 | 263 | ||
| 240 | if (Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR) != ERROR_NONE) | 264 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 241 | return ResultStatus::Error; | ||
| 242 | |||
| 243 | Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); | ||
| 244 | 265 | ||
| 245 | is_loaded = true; | 266 | is_loaded = true; |
| 246 | return ResultStatus::Success; | 267 | return ResultStatus::Success; |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index a7eea78aa..ca3c18a9f 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -16,6 +16,9 @@ | |||
| 16 | #include "core/loader/elf.h" | 16 | #include "core/loader/elf.h" |
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 18 | 18 | ||
| 19 | using Kernel::SharedPtr; | ||
| 20 | using Kernel::CodeSet; | ||
| 21 | |||
| 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 20 | // ELF Header Constants | 23 | // ELF Header Constants |
| 21 | 24 | ||
| @@ -97,6 +100,12 @@ enum ElfSectionFlags | |||
| 97 | #define PT_LOPROC 0x70000000 | 100 | #define PT_LOPROC 0x70000000 |
| 98 | #define PT_HIPROC 0x7FFFFFFF | 101 | #define PT_HIPROC 0x7FFFFFFF |
| 99 | 102 | ||
| 103 | // Segment flags | ||
| 104 | #define PF_X 0x1 | ||
| 105 | #define PF_W 0x2 | ||
| 106 | #define PF_R 0x4 | ||
| 107 | #define PF_MASKPROC 0xF0000000 | ||
| 108 | |||
| 100 | typedef unsigned int Elf32_Addr; | 109 | typedef unsigned int Elf32_Addr; |
| 101 | typedef unsigned short Elf32_Half; | 110 | typedef unsigned short Elf32_Half; |
| 102 | typedef unsigned int Elf32_Off; | 111 | typedef unsigned int Elf32_Off; |
| @@ -193,7 +202,7 @@ public: | |||
| 193 | ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } | 202 | ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } |
| 194 | u32 GetEntryPoint() const { return entryPoint; } | 203 | u32 GetEntryPoint() const { return entryPoint; } |
| 195 | u32 GetFlags() const { return (u32)(header->e_flags); } | 204 | u32 GetFlags() const { return (u32)(header->e_flags); } |
| 196 | void LoadInto(u32 vaddr); | 205 | SharedPtr<CodeSet> LoadInto(u32 vaddr); |
| 197 | bool LoadSymbols(); | 206 | bool LoadSymbols(); |
| 198 | 207 | ||
| 199 | int GetNumSegments() const { return (int)(header->e_phnum); } | 208 | int GetNumSegments() const { return (int)(header->e_phnum); } |
| @@ -249,7 +258,7 @@ const char *ElfReader::GetSectionName(int section) const { | |||
| 249 | return nullptr; | 258 | return nullptr; |
| 250 | } | 259 | } |
| 251 | 260 | ||
| 252 | void ElfReader::LoadInto(u32 vaddr) { | 261 | SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { |
| 253 | LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); | 262 | LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); |
| 254 | 263 | ||
| 255 | // Should we relocate? | 264 | // Should we relocate? |
| @@ -267,19 +276,61 @@ void ElfReader::LoadInto(u32 vaddr) { | |||
| 267 | u32 segment_addr[32]; | 276 | u32 segment_addr[32]; |
| 268 | u32 base_addr = relocate ? vaddr : 0; | 277 | u32 base_addr = relocate ? vaddr : 0; |
| 269 | 278 | ||
| 270 | for (unsigned i = 0; i < header->e_phnum; i++) { | 279 | u32 total_image_size = 0; |
| 271 | Elf32_Phdr* p = segments + i; | 280 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 272 | LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, | 281 | Elf32_Phdr* p = &segments[i]; |
| 282 | if (p->p_type == PT_LOAD) { | ||
| 283 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | std::vector<u8> program_image(total_image_size); | ||
| 288 | size_t current_image_position = 0; | ||
| 289 | |||
| 290 | SharedPtr<CodeSet> codeset = CodeSet::Create("", 0); | ||
| 291 | |||
| 292 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | ||
| 293 | Elf32_Phdr* p = &segments[i]; | ||
| 294 | LOG_DEBUG(Loader, "Type: %i Vaddr: %08X Filesz: %8X Memsz: %8X ", p->p_type, p->p_vaddr, | ||
| 273 | p->p_filesz, p->p_memsz); | 295 | p->p_filesz, p->p_memsz); |
| 274 | 296 | ||
| 275 | if (p->p_type == PT_LOAD) { | 297 | if (p->p_type == PT_LOAD) { |
| 276 | segment_addr[i] = base_addr + p->p_vaddr; | 298 | CodeSet::Segment* codeset_segment; |
| 277 | memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); | 299 | u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); |
| 278 | LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], | 300 | if (permission_flags == (PF_R | PF_X)) { |
| 279 | p->p_memsz); | 301 | codeset_segment = &codeset->code; |
| 302 | } else if (permission_flags == (PF_R)) { | ||
| 303 | codeset_segment = &codeset->rodata; | ||
| 304 | } else if (permission_flags == (PF_R | PF_W)) { | ||
| 305 | codeset_segment = &codeset->data; | ||
| 306 | } else { | ||
| 307 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags); | ||
| 308 | continue; | ||
| 309 | } | ||
| 310 | |||
| 311 | if (codeset_segment->size != 0) { | ||
| 312 | LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i); | ||
| 313 | continue; | ||
| 314 | } | ||
| 315 | |||
| 316 | u32 segment_addr = base_addr + p->p_vaddr; | ||
| 317 | u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; | ||
| 318 | |||
| 319 | codeset_segment->offset = current_image_position; | ||
| 320 | codeset_segment->addr = segment_addr; | ||
| 321 | codeset_segment->size = aligned_size; | ||
| 322 | |||
| 323 | memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz); | ||
| 324 | current_image_position += aligned_size; | ||
| 280 | } | 325 | } |
| 281 | } | 326 | } |
| 327 | |||
| 328 | codeset->entrypoint = base_addr + header->e_entry; | ||
| 329 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 330 | |||
| 282 | LOG_DEBUG(Loader, "Done loading."); | 331 | LOG_DEBUG(Loader, "Done loading."); |
| 332 | |||
| 333 | return codeset; | ||
| 283 | } | 334 | } |
| 284 | 335 | ||
| 285 | SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { | 336 | SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { |
| @@ -352,18 +403,18 @@ ResultStatus AppLoader_ELF::Load() { | |||
| 352 | if (file->ReadBytes(&buffer[0], size) != size) | 403 | if (file->ReadBytes(&buffer[0], size) != size) |
| 353 | return ResultStatus::Error; | 404 | return ResultStatus::Error; |
| 354 | 405 | ||
| 355 | Kernel::g_current_process = Kernel::Process::Create(filename, 0); | 406 | ElfReader elf_reader(&buffer[0]); |
| 407 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | ||
| 408 | codeset->name = filename; | ||
| 409 | |||
| 410 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | ||
| 356 | Kernel::g_current_process->svc_access_mask.set(); | 411 | Kernel::g_current_process->svc_access_mask.set(); |
| 357 | Kernel::g_current_process->address_mappings = default_address_mappings; | 412 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 358 | 413 | ||
| 359 | // Attach the default resource limit (APPLICATION) to the process | 414 | // Attach the default resource limit (APPLICATION) to the process |
| 360 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 415 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 361 | 416 | ||
| 362 | ElfReader elf_reader(&buffer[0]); | 417 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 363 | elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | ||
| 364 | // TODO: Fill application title | ||
| 365 | |||
| 366 | Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE); | ||
| 367 | 418 | ||
| 368 | is_loaded = true; | 419 | is_loaded = true; |
| 369 | return ResultStatus::Success; | 420 | return ResultStatus::Success; |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 2b26b31cf..87603d198 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -118,6 +118,9 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { | |||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | ResultStatus AppLoader_NCCH::LoadExec() const { | 120 | ResultStatus AppLoader_NCCH::LoadExec() const { |
| 121 | using Kernel::SharedPtr; | ||
| 122 | using Kernel::CodeSet; | ||
| 123 | |||
| 121 | if (!is_loaded) | 124 | if (!is_loaded) |
| 122 | return ResultStatus::ErrorNotLoaded; | 125 | return ResultStatus::ErrorNotLoaded; |
| 123 | 126 | ||
| @@ -126,7 +129,30 @@ ResultStatus AppLoader_NCCH::LoadExec() const { | |||
| 126 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( | 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 127 | (const char*)exheader_header.codeset_info.name, 8); | 130 | (const char*)exheader_header.codeset_info.name, 8); |
| 128 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); | 131 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); |
| 129 | Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); | 132 | |
| 133 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id); | ||
| 134 | |||
| 135 | codeset->code.offset = 0; | ||
| 136 | codeset->code.addr = exheader_header.codeset_info.text.address; | ||
| 137 | codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE; | ||
| 138 | |||
| 139 | codeset->rodata.offset = codeset->code.offset + codeset->code.size; | ||
| 140 | codeset->rodata.addr = exheader_header.codeset_info.ro.address; | ||
| 141 | codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE; | ||
| 142 | |||
| 143 | // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just | ||
| 144 | // to the regular size. Playing it safe for now. | ||
| 145 | u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF; | ||
| 146 | code.resize(code.size() + bss_page_size, 0); | ||
| 147 | |||
| 148 | codeset->data.offset = codeset->rodata.offset + codeset->rodata.size; | ||
| 149 | codeset->data.addr = exheader_header.codeset_info.data.address; | ||
| 150 | codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size; | ||
| 151 | |||
| 152 | codeset->entrypoint = codeset->code.addr; | ||
| 153 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); | ||
| 154 | |||
| 155 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | ||
| 130 | 156 | ||
| 131 | // Attach a resource limit to the process based on the resource limit category | 157 | // Attach a resource limit to the process based on the resource limit category |
| 132 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( | 158 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( |
| @@ -137,11 +163,9 @@ ResultStatus AppLoader_NCCH::LoadExec() const { | |||
| 137 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); | 163 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); |
| 138 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); | 164 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); |
| 139 | 165 | ||
| 140 | Memory::WriteBlock(entry_point, &code[0], code.size()); | ||
| 141 | |||
| 142 | s32 priority = exheader_header.arm11_system_local_caps.priority; | 166 | s32 priority = exheader_header.arm11_system_local_caps.priority; |
| 143 | u32 stack_size = exheader_header.codeset_info.stack_size; | 167 | u32 stack_size = exheader_header.codeset_info.stack_size; |
| 144 | Kernel::g_current_process->Run(entry_point, priority, stack_size); | 168 | Kernel::g_current_process->Run(priority, stack_size); |
| 145 | return ResultStatus::Success; | 169 | return ResultStatus::Success; |
| 146 | } | 170 | } |
| 147 | return ResultStatus::Error; | 171 | return ResultStatus::Error; |