void Loader::initialise(ppcsize_t maxCodeSize) { // Get the MEM2 Region be_val<uint32_t> mem2start, mem2size; OSGetMemBound(OSMemoryType::MEM2, &mem2start, &mem2size); // Allocate MEM2 Region gMemory.alloc(mem2start, mem2size); // Steal some space for code heap mCodeHeap = new TeenyHeap(gMemory.translate(mem2start), maxCodeSize); // Update MEM2 to ignore the code heap region OSSetMemBound(OSMemoryType::MEM2, mem2start + maxCodeSize, mem2size - maxCodeSize); }
bool Loader::loadRPL(UserModule &module, const char *buffer, size_t size) { auto in = BigEndianView { buffer, size }; auto header = elf::Header { }; auto info = elf::FileInfo { }; auto sections = std::vector<elf::Section> { }; // Read header if (!elf::readHeader(in, header)) { gLog->error("Failed elf::readHeader"); return false; } // Check it is a CAFE abi rpl if (header.abi != elf::EABI_CAFE) { gLog->error("Unexpected elf abi found {:02x} expected {:02x}", header.abi, elf::EABI_CAFE); return false; } // Read sections if (!elf::readSections(in, header, sections)) { gLog->error("Failed elf::readSections"); return false; } // Process sections, find our data and code sections processSections(module, sections, sections[header.shstrndx].data.data()); // Update EntryInfo loadFileInfo(info, sections); module.entryPoint = header.entry; module.defaultStackSize = info.stackSize; // Allocate code & data sections in memory auto codeStart = module.codeAddressRange.first; auto codeSize = module.maxCodeSize; gMemory.alloc(codeStart, codeSize); // TODO: Append code to end of other loaded code sections auto dataStart = alignUp(codeStart + codeSize, 4096); auto dataSize = alignUp(module.dataAddressRange.second - module.dataAddressRange.first, 4096); auto dataEnd = dataStart + dataSize; gMemory.alloc(dataStart, dataSize); // TODO: Use OSDynLoad_MemAlloc for data section allocation // Update MEM2 memory bounds be_val<uint32_t> mem2start, mem2size; OSGetMemBound(OSMemoryType::MEM2, &mem2start, &mem2size); OSSetMemBound(OSMemoryType::MEM2, dataEnd, mem2size - (dataEnd - mem2start)); // Relocate sections relocateSections(sections, module.codeAddressRange.first, codeStart, module.dataAddressRange.first, dataStart); module.codeAddressRange.first = codeStart; module.codeAddressRange.second = codeStart + codeSize; module.dataAddressRange.first = dataStart; module.dataAddressRange.second = dataStart + dataSize; // Relocate entry point for (auto i = 0u; i < sections.size(); ++i) { auto §ion = sections[i]; if (section.header.addr <= header.entry && section.header.addr + section.data.size() > header.entry) { auto offset = section.section->address - section.header.addr; module.entryPoint = header.entry + offset; break; } } // Load sections into memory loadSections(sections); // Process small data sections processSmallDataSections(module); // Process symbols // TODO: Support more than one symbol section? for (auto i = 0u; i < sections.size(); ++i) { auto §ion = sections[i]; if (section.header.type != elf::SHT_SYMTAB) { continue; } processSymbols(module, section, sections); } // Process relocations for (auto i = 0u; i < sections.size(); ++i) { auto §ion = sections[i]; if (section.header.type != elf::SHT_RELA) { continue; } processRelocations(module, section, sections); } if (0) { // Print address ranges gLog->debug("Loaded module!"); gLog->debug("Code {:08x} -> {:08x}", module.codeAddressRange.first, module.codeAddressRange.second); gLog->debug("Data {:08x} -> {:08x}", module.dataAddressRange.first, module.dataAddressRange.second); // Print all sections gLog->debug("Sections:"); for (auto i = 0u; i < module.sections.size(); ++i) { auto section = module.sections[i]; gLog->debug("{:08x} {} {:x}", section->address, section->name, section->size); } // Print all symbols gLog->debug("Symbols:"); for (auto i = 0u; i < module.symbols.size(); ++i) { auto symbol = module.symbols[i]; if (symbol && symbol->name.size()) { gLog->debug("{:08x} {}", symbol->address, symbol->name); } } } return true; }