From 2642c3f73b567d2bc076e6d9c84af1e60e3241f7 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sat, 1 Nov 2014 21:03:14 +1300 Subject: [PATCH 1/5] BootElf: Use unique_ptr instead of vectors. --- Source/Core/Core/Boot/Boot_ELF.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index 0a14b24ad7..aa91cdf984 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "Common/FileUtil.h" +#include "Common/StdMakeUnique.h" #include "Core/Boot/Boot.h" #include "Core/Boot/ElfReader.h" @@ -14,12 +15,12 @@ bool CBoot::IsElfWii(const std::string& filename) /* We already check if filename existed before we called this function, so there is no need for another check, just read the file right away */ - const u64 filesize = File::GetSize(filename); - std::vector mem((size_t)filesize); + size_t filesize = File::GetSize(filename); + auto elf = std::make_unique(filesize); { File::IOFile f(filename, "rb"); - f.ReadBytes(mem.data(), (size_t)filesize); + f.ReadBytes(elf.get(), filesize); } // Use the same method as the DOL loader uses: search for mfspr from HID4, @@ -30,7 +31,7 @@ bool CBoot::IsElfWii(const std::string& filename) u32 HID4_pattern = 0x7c13fba6; u32 HID4_mask = 0xfc1fffff; - ElfReader reader(mem.data()); + ElfReader reader(elf.get()); for (int i = 0; i < reader.GetNumSections(); ++i) { @@ -53,16 +54,19 @@ bool CBoot::IsElfWii(const std::string& filename) bool CBoot::Boot_ELF(const std::string& filename) { - const u64 filesize = File::GetSize(filename); - std::vector mem((size_t)filesize); + // Read ELF from file + size_t filesize = File::GetSize(filename); + auto elf = std::make_unique(filesize); { File::IOFile f(filename, "rb"); - f.ReadBytes(mem.data(), (size_t)filesize); + f.ReadBytes(elf.get(), filesize); } - ElfReader reader(mem.data()); + // Load ELF into GameCube Memory + ElfReader reader(elf.get()); reader.LoadInto(0x80000000); + if (!reader.LoadSymbols()) { if (LoadMapFromFilename()) From 1e5762b163182d3b7fe7c8623c44d08be93c337f Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sat, 1 Nov 2014 22:20:56 +1300 Subject: [PATCH 2/5] BootUp: Clean up elf BootUp code. * The file already exsists, otherwise we wouldn't have gotten this far in the boot. * We have already checked if it's a Wii or GameCube elf, besides, it's too late to change our minds now anyway. * On Wii - Don't call EmulatedBS2, it can never succeed as it knows nothing about booting elfs. Just call the SetupWiiMemory directly if needed. * On GameCube - We still call EmulatedBS2_GC, but we stop it from running Apploader, which might boot something unexpected from the default iso or DVD root folder. --- Source/Core/Core/Boot/Boot.cpp | 53 +++++++-------------------- Source/Core/Core/Boot/Boot.h | 2 +- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 4 +- 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 9da2be25d3..7b019099c7 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -324,58 +324,33 @@ bool CBoot::BootUp() // ELF case SCoreStartupParameter::BOOT_ELF: { - if (!File::Exists(_StartupPara.m_strFilename)) - { - PanicAlertT("The file you specified (%s) does not exist", - _StartupPara.m_strFilename.c_str()); - return false; - } - - // Check if we have gotten a Wii file or not - bool elfWii = IsElfWii(_StartupPara.m_strFilename); - if (elfWii != _StartupPara.bWii) - { - PanicAlertT("Warning - starting ELF in wrong console mode!"); - } - - bool BS2Success = false; - - if (elfWii) - { - BS2Success = EmulatedBS2(elfWii); - } - else if (!VolumeHandler::IsWiiDisc() && !_StartupPara.m_strDefaultISO.empty()) - { - VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultISO); - BS2Success = EmulatedBS2(elfWii); - } - // load image or create virtual drive from directory if (!_StartupPara.m_strDVDRoot.empty()) { NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); - // TODO: auto-convert elf to dol, so we can load them :) - VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, elfWii); - BS2Success = EmulatedBS2(elfWii); + VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii); } else if (!_StartupPara.m_strDefaultISO.empty()) { NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str()); VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultISO); } - else VolumeHandler::SetVolumeDirectory(_StartupPara.m_strFilename, elfWii); + else + { + VolumeHandler::SetVolumeDirectory(_StartupPara.m_strFilename, _StartupPara.bWii); + } DVDInterface::SetDiscInside(VolumeHandler::IsValid()); - if (BS2Success) - { - HLE::PatchFunctions(); - } - else // Poor man's bootup - { - Load_FST(elfWii); - Boot_ELF(_StartupPara.m_strFilename); - } + // Poor man's bootup + if(_StartupPara.bWii) + SetupWiiMemory(DiscIO::IVolume::COUNTRY_UNKNOWN); + else + EmulatedBS2_GC(true); + + Load_FST(_StartupPara.bWii); + Boot_ELF(_StartupPara.m_strFilename); + UpdateDebugger_MapLoaded(); Dolphin_Debugger::AddAutoBreakpoints(); break; diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index c97099d24f..a562ba889a 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -52,7 +52,7 @@ private: static bool Boot_ELF(const std::string& filename); static bool Boot_WiiWAD(const std::string& filename); - static bool EmulatedBS2_GC(); + static bool EmulatedBS2_GC(bool skipAppLoader = false); static bool EmulatedBS2_Wii(); static bool EmulatedBS2(bool _bIsWii); static bool Load_BS2(const std::string& _rBootROMFilename); diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 21e057fc94..260ae4c67a 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -34,7 +34,7 @@ void CBoot::RunFunction(u32 _iAddr) // GameCube Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader, function by function, using the above utility. -bool CBoot::EmulatedBS2_GC() +bool CBoot::EmulatedBS2_GC(bool skipAppLoader) { INFO_LOG(BOOT, "Faking GC BS2..."); @@ -84,7 +84,7 @@ bool CBoot::EmulatedBS2_GC() u32 iAppLoaderOffset = 0x2440; u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10, false); u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14, false) + VolumeHandler::Read32(iAppLoaderOffset + 0x18, false); - if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1)) + if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1) || skipAppLoader) { INFO_LOG(BOOT, "GC BS2: Not running apploader!"); return false; From 2bf052d8b92ba055c16ca0c5cbcc15a820c5afc4 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sat, 1 Nov 2014 22:48:23 +1300 Subject: [PATCH 3/5] ElfReader: Clean up elf loader code. * Don't claim to support any features we don't, like relocation * Actually zero-out BSS sections, as memory might not be already zeroed. * Deleted commented out code. * Removed GetPointer, updated to more modern interface methods. * Updated pointer types style from "u32 *x" to "u32* x" --- Source/Core/Core/Boot/Boot_ELF.cpp | 2 +- Source/Core/Core/Boot/ElfReader.cpp | 81 ++++++++--------------------- Source/Core/Core/Boot/ElfReader.h | 22 ++++---- 3 files changed, 33 insertions(+), 72 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index aa91cdf984..f7f763a082 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -65,7 +65,7 @@ bool CBoot::Boot_ELF(const std::string& filename) // Load ELF into GameCube Memory ElfReader reader(elf.get()); - reader.LoadInto(0x80000000); + reader.LoadIntoMemory(); if (!reader.LoadSymbols()) { diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index d29b34a3d8..fa6499802c 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -61,7 +61,7 @@ static void byteswapSection(Elf32_Shdr &sec) ElfReader::ElfReader(void *ptr) { base = (char*)ptr; - base32 = (u32 *)ptr; + base32 = (u32*)ptr; header = (Elf32_Ehdr*)ptr; byteswapHeader(*header); @@ -80,13 +80,13 @@ ElfReader::ElfReader(void *ptr) entryPoint = header->e_entry; } -const char *ElfReader::GetSectionName(int section) const +const char* ElfReader::GetSectionName(int section) const { if (sections[section].sh_type == SHT_NULL) return nullptr; int nameOffset = sections[section].sh_name; - char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); + char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx); if (ptr) return ptr + nameOffset; @@ -94,84 +94,45 @@ const char *ElfReader::GetSectionName(int section) const return nullptr; } -bool ElfReader::LoadInto(u32 vaddr) +// This is just a simple elf loader, good enough to load elfs generated by devkitPPC +bool ElfReader::LoadIntoMemory() { DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); -// sectionOffsets = new u32[GetNumSections()]; -// sectionAddrs = new u32[GetNumSections()]; - // Should we relocate? bRelocate = (header->e_type != ET_EXEC); if (bRelocate) { - DEBUG_LOG(MASTER_LOG,"Relocatable module"); - entryPoint += vaddr; - } - else - { - DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); + PanicAlert("Error: Dolphin doesn't know to load a relocatable elf."); + return false; } INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); - // First pass : Get the bits into RAM - u32 segmentVAddr[32]; - - u32 baseAddress = bRelocate?vaddr:0; + // Copy segments into ram. for (int i = 0; i < header->e_phnum; i++) { - Elf32_Phdr *p = segments + i; + Elf32_Phdr* p = segments + i; - INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", + p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); if (p->p_type == PT_LOAD) { - segmentVAddr[i] = baseAddress + p->p_vaddr; - u32 writeAddr = segmentVAddr[i]; - - const u8 *src = GetSegmentPtr(i); - u8 *dst = Memory::GetPointer(writeAddr); + u32 writeAddr = p->p_vaddr; + const u8* src = GetSegmentPtr(i); u32 srcSize = p->p_filesz; u32 dstSize = p->p_memsz; - u32 *s = (u32*)src; - u32 *d = (u32*)dst; - for (int j = 0; j < (int)(srcSize + 3) / 4; j++) - { - *d++ = /*_byteswap_ulong*/(*s++); - } + + Memory::CopyToEmu(writeAddr, src, srcSize); if (srcSize < dstSize) - { - //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss - } + Memory::Memset(writeAddr + srcSize, 0, dstSize-srcSize); //zero out bss + INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); } } - /* - LOG(MASTER_LOG,"%i sections:", header->e_shnum); - - for (int i=0; ish_addr + baseAddress; - sectionOffsets[i] = writeAddr - vaddr; - sectionAddrs[i] = writeAddr; - - if (s->sh_flags & SHF_ALLOC) - { - LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size); - - } - else - { - LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags); - } - } -*/ INFO_LOG(MASTER_LOG,"Done loading."); return true; } @@ -180,7 +141,7 @@ SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { for (int i = firstSection; i < header->e_shnum; i++) { - const char *secname = GetSectionName(i); + const char* secname = GetSectionName(i); if (secname != nullptr && strcmp(name, secname) == 0) return i; @@ -195,10 +156,10 @@ bool ElfReader::LoadSymbols() if (sec != -1) { int stringSection = sections[sec].sh_link; - const char *stringBase = (const char *)GetSectionDataPtr(stringSection); + const char* stringBase = (const char *)GetSectionDataPtr(stringSection); //We have a symbol table! - Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); + Elf32_Sym* symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); for (int sym = 0; sym < numSymbols; sym++) { @@ -210,7 +171,7 @@ bool ElfReader::LoadSymbols() int type = symtab[sym].st_info & 0xF; int sectionIndex = Common::swap16(symtab[sym].st_shndx); int value = Common::swap32(symtab[sym].st_value); - const char *name = stringBase + Common::swap32(symtab[sym].st_name); + const char* name = stringBase + Common::swap32(symtab[sym].st_name); if (bRelocate) value += sectionAddrs[sectionIndex]; diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 292cd488ff..d4920eb513 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -19,19 +19,19 @@ typedef int SectionID; class ElfReader { private: - char *base; - u32 *base32; + char* base; + u32* base32; - Elf32_Ehdr *header; - Elf32_Phdr *segments; - Elf32_Shdr *sections; + Elf32_Ehdr* header; + Elf32_Phdr* segments; + Elf32_Shdr* sections; u32 *sectionAddrs; bool bRelocate; u32 entryPoint; public: - ElfReader(void *ptr); + ElfReader(void* ptr); ~ElfReader() { } u32 Read32(int off) const { return base32[off>>2]; } @@ -41,13 +41,13 @@ public: ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } u32 GetEntryPoint() const { return entryPoint; } u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadInto(u32 vaddr); + bool LoadIntoMemory(); bool LoadSymbols(); int GetNumSegments() const { return (int)(header->e_phnum); } int GetNumSections() const { return (int)(header->e_shnum); } - const u8 *GetPtr(int offset) const { return (u8*)base + offset; } - const char *GetSectionName(int section) const; + const u8* GetPtr(int offset) const { return (u8*)base + offset; } + const char* GetSectionName(int section) const; const u8 *GetSectionDataPtr(int section) const { if (section < 0 || section >= header->e_shnum) @@ -61,13 +61,13 @@ public: { return sections[section].sh_type == SHT_PROGBITS; } - const u8 *GetSegmentPtr(int segment) + const u8* GetSegmentPtr(int segment) { return GetPtr(segments[segment].p_offset); } u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } int GetSectionSize(SectionID section) const { return sections[section].sh_size; } - SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found + SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found bool DidRelocate() { From b7d4ff679a40007438bb74525cb516031f1d95b8 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sat, 1 Nov 2014 23:15:58 +1300 Subject: [PATCH 4/5] IsWiiElf: Optimise inner loop. Instead of swaping each word of the elf code section(s) looking for a match to our pattern, we swap the pattern just once (at compile time) and test against our swapped pattern. --- Source/Core/Core/Boot/Boot_ELF.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index f7f763a082..8565aa9cc0 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -29,21 +29,20 @@ bool CBoot::IsElfWii(const std::string& filename) // Likely to have some false positives/negatives, patches implementing a // better heuristic are welcome. - u32 HID4_pattern = 0x7c13fba6; - u32 HID4_mask = 0xfc1fffff; + // Swap these once, instead of swapping every word in the file. + u32 HID4_pattern = Common::swap32(0x7c13fba6); + u32 HID4_mask = Common::swap32(0xfc1fffff); ElfReader reader(elf.get()); for (int i = 0; i < reader.GetNumSections(); ++i) { if (reader.IsCodeSection(i)) { - for (unsigned int j = 0; j < reader.GetSectionSize(i) / sizeof (u32); ++j) + u32* code = (u32*)reader.GetSectionDataPtr(i); + for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j) { - u32 word = Common::swap32(((u32*)reader.GetSectionDataPtr(i))[j]); - if ((word & HID4_mask) == HID4_pattern) - { + if ((code[j] & HID4_mask) == HID4_pattern) return true; - } } } } From 5c34766809a95c3148a7b98a3054f1a6c4e89953 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 2 Nov 2014 20:34:59 +1300 Subject: [PATCH 5/5] Propagate elf loading failure up. Also fix mistake in error message. --- Source/Core/Core/Boot/Boot.cpp | 3 ++- Source/Core/Core/Boot/Boot_ELF.cpp | 3 ++- Source/Core/Core/Boot/ElfReader.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 7b019099c7..cfb5fc81a9 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -349,7 +349,8 @@ bool CBoot::BootUp() EmulatedBS2_GC(true); Load_FST(_StartupPara.bWii); - Boot_ELF(_StartupPara.m_strFilename); + if(!Boot_ELF(_StartupPara.m_strFilename)) + return false; UpdateDebugger_MapLoaded(); Dolphin_Debugger::AddAutoBreakpoints(); diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index 8565aa9cc0..d41c95c1ba 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -64,7 +64,8 @@ bool CBoot::Boot_ELF(const std::string& filename) // Load ELF into GameCube Memory ElfReader reader(elf.get()); - reader.LoadIntoMemory(); + if(!reader.LoadIntoMemory()) + return false; if (!reader.LoadSymbols()) { diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index fa6499802c..c913decfa1 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -104,7 +104,7 @@ bool ElfReader::LoadIntoMemory() if (bRelocate) { - PanicAlert("Error: Dolphin doesn't know to load a relocatable elf."); + PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf."); return false; }