mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-27 03:39:57 +00:00
Boot: Unify the ELF and DOL code paths
They're essentially the same. To achieve this, this commit unifies DolReader and ElfReader into a common interface for boot executable readers, so the only remaining difference between ELF and DOL is how which volume is inserted.
This commit is contained in:
parent
22992ae41e
commit
065261dbad
@ -21,7 +21,8 @@
|
|||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
#include "Core/Boot/Boot_DOL.h"
|
#include "Core/Boot/DolReader.h"
|
||||||
|
#include "Core/Boot/ElfReader.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Debugger/Debugger_SymbolMap.h"
|
#include "Core/Debugger/Debugger_SymbolMap.h"
|
||||||
@ -86,11 +87,11 @@ std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(const std::stri
|
|||||||
return std::make_unique<BootParameters>(Disc{path, std::move(volume)});
|
return std::make_unique<BootParameters>(Disc{path, std::move(volume)});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension == ".elf" || extension == ".dol")
|
if (extension == ".elf")
|
||||||
{
|
return std::make_unique<BootParameters>(Executable{path, std::make_unique<ElfReader>(path)});
|
||||||
return std::make_unique<BootParameters>(
|
|
||||||
Executable{path, extension == ".elf" ? Executable::Type::ELF : Executable::Type::DOL});
|
if (extension == ".dol")
|
||||||
}
|
return std::make_unique<BootParameters>(Executable{path, std::make_unique<DolReader>(path)});
|
||||||
|
|
||||||
if (extension == ".dff")
|
if (extension == ".dff")
|
||||||
return std::make_unique<BootParameters>(DFF{path});
|
return std::make_unique<BootParameters>(DFF{path});
|
||||||
@ -371,14 +372,13 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
|
|||||||
{
|
{
|
||||||
NOTICE_LOG(BOOT, "Booting from executable: %s", executable.path.c_str());
|
NOTICE_LOG(BOOT, "Booting from executable: %s", executable.path.c_str());
|
||||||
|
|
||||||
// TODO: needs more cleanup.
|
if (!executable.reader->IsValid())
|
||||||
if (executable.type == BootParameters::Executable::Type::DOL)
|
return false;
|
||||||
{
|
|
||||||
CDolLoader dolLoader(executable.path);
|
|
||||||
if (!dolLoader.IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const DiscIO::Volume* volume = nullptr;
|
const DiscIO::Volume* volume = nullptr;
|
||||||
|
// VolumeDirectory only works with DOLs.
|
||||||
|
if (StringEndsWith(executable.path, ".dol"))
|
||||||
|
{
|
||||||
if (!config.m_strDVDRoot.empty())
|
if (!config.m_strDVDRoot.empty())
|
||||||
{
|
{
|
||||||
NOTICE_LOG(BOOT, "Setting DVDRoot %s", config.m_strDVDRoot.c_str());
|
NOTICE_LOG(BOOT, "Setting DVDRoot %s", config.m_strDVDRoot.c_str());
|
||||||
@ -390,57 +390,41 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
|
|||||||
NOTICE_LOG(BOOT, "Loading default ISO %s", config.m_strDefaultISO.c_str());
|
NOTICE_LOG(BOOT, "Loading default ISO %s", config.m_strDefaultISO.c_str());
|
||||||
volume = SetDisc(DiscIO::CreateVolumeFromFilename(config.m_strDefaultISO));
|
volume = SetDisc(DiscIO::CreateVolumeFromFilename(config.m_strDefaultISO));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poor man's bootup
|
|
||||||
if (config.bWii)
|
|
||||||
{
|
|
||||||
HID4.SBE = 1;
|
|
||||||
SetupMSR();
|
|
||||||
SetupBAT(config.bWii);
|
|
||||||
|
|
||||||
// Because there is no TMD to get the requested system (IOS) version from,
|
|
||||||
// we default to IOS58, which is the version used by the Homebrew Channel.
|
|
||||||
SetupWiiMemory(volume, 0x000000010000003a);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EmulatedBS2_GC(volume, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Load_FST(config.bWii, volume);
|
|
||||||
dolLoader.Load();
|
|
||||||
PC = dolLoader.GetEntryPoint();
|
|
||||||
|
|
||||||
if (LoadMapFromFilename())
|
|
||||||
HLE::PatchFunctions();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (executable.type == BootParameters::Executable::Type::ELF)
|
|
||||||
{
|
{
|
||||||
const DiscIO::Volume* volume = SetDefaultDisc();
|
volume = SetDefaultDisc();
|
||||||
|
|
||||||
// Poor man's bootup
|
|
||||||
if (config.bWii)
|
|
||||||
{
|
|
||||||
// Because there is no TMD to get the requested system (IOS) version from,
|
|
||||||
// we default to IOS58, which is the version used by the Homebrew Channel.
|
|
||||||
SetupWiiMemory(volume, 0x000000010000003a);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EmulatedBS2_GC(volume, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Load_FST(config.bWii, volume);
|
|
||||||
if (!Boot_ELF(executable.path))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Note: Boot_ELF calls HLE::PatchFunctions()
|
|
||||||
|
|
||||||
UpdateDebugger_MapLoaded();
|
|
||||||
Dolphin_Debugger::AddAutoBreakpoints();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!executable.reader->LoadIntoMemory())
|
||||||
|
{
|
||||||
|
PanicAlertT("Failed to load the executable to memory.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poor man's bootup
|
||||||
|
if (config.bWii)
|
||||||
|
{
|
||||||
|
HID4.SBE = 1;
|
||||||
|
SetupMSR();
|
||||||
|
SetupBAT(config.bWii);
|
||||||
|
// Because there is no TMD to get the requested system (IOS) version from,
|
||||||
|
// we default to IOS58, which is the version used by the Homebrew Channel.
|
||||||
|
SetupWiiMemory(volume, 0x000000010000003a);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmulatedBS2_GC(volume, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Load_FST(config.bWii, volume);
|
||||||
|
PC = executable.reader->GetEntryPoint();
|
||||||
|
|
||||||
|
if (executable.reader->LoadSymbols() || LoadMapFromFilename())
|
||||||
|
{
|
||||||
|
UpdateDebugger_MapLoaded();
|
||||||
|
HLE::PatchFunctions();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,3 +479,16 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
|
|||||||
HLE::PatchFixedFunctions();
|
HLE::PatchFixedFunctions();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BootExecutableReader::BootExecutableReader(const std::string& file_name)
|
||||||
|
{
|
||||||
|
m_bytes.resize(File::GetSize(file_name));
|
||||||
|
File::IOFile file{file_name, "rb"};
|
||||||
|
file.ReadBytes(m_bytes.data(), m_bytes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
BootExecutableReader::BootExecutableReader(const std::vector<u8>& bytes) : m_bytes(bytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BootExecutableReader::~BootExecutableReader() = default;
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
@ -21,6 +23,8 @@ struct RegionSetting
|
|||||||
const std::string code;
|
const std::string code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BootExecutableReader;
|
||||||
|
|
||||||
struct BootParameters
|
struct BootParameters
|
||||||
{
|
{
|
||||||
struct Disc
|
struct Disc
|
||||||
@ -31,13 +35,8 @@ struct BootParameters
|
|||||||
|
|
||||||
struct Executable
|
struct Executable
|
||||||
{
|
{
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
DOL,
|
|
||||||
ELF,
|
|
||||||
};
|
|
||||||
std::string path;
|
std::string path;
|
||||||
Type type;
|
std::unique_ptr<BootExecutableReader> reader;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAND
|
struct NAND
|
||||||
@ -72,7 +71,6 @@ class CBoot
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool BootUp(std::unique_ptr<BootParameters> boot);
|
static bool BootUp(std::unique_ptr<BootParameters> boot);
|
||||||
static bool IsElfWii(const std::string& filename);
|
|
||||||
|
|
||||||
// Tries to find a map file for the current game by looking first in the
|
// Tries to find a map file for the current game by looking first in the
|
||||||
// local user directory, then in the shared user directory.
|
// local user directory, then in the shared user directory.
|
||||||
@ -97,7 +95,6 @@ private:
|
|||||||
|
|
||||||
static void UpdateDebugger_MapLoaded();
|
static void UpdateDebugger_MapLoaded();
|
||||||
|
|
||||||
static bool Boot_ELF(const std::string& filename);
|
|
||||||
static bool Boot_WiiWAD(const std::string& filename);
|
static bool Boot_WiiWAD(const std::string& filename);
|
||||||
|
|
||||||
static void SetupMSR();
|
static void SetupMSR();
|
||||||
@ -111,3 +108,20 @@ private:
|
|||||||
|
|
||||||
static bool SetupWiiMemory(const DiscIO::Volume* volume, u64 ios_title_id);
|
static bool SetupWiiMemory(const DiscIO::Volume* volume, u64 ios_title_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BootExecutableReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BootExecutableReader(const std::string& file_name);
|
||||||
|
BootExecutableReader(const std::vector<u8>& buffer);
|
||||||
|
virtual ~BootExecutableReader();
|
||||||
|
|
||||||
|
virtual u32 GetEntryPoint() const = 0;
|
||||||
|
virtual bool IsValid() const = 0;
|
||||||
|
virtual bool IsWii() const = 0;
|
||||||
|
virtual bool LoadIntoMemory(bool only_in_mem1 = false) const = 0;
|
||||||
|
virtual bool LoadSymbols() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<u8> m_bytes;
|
||||||
|
};
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "Common/FileUtil.h"
|
|
||||||
#include "Common/Swap.h"
|
|
||||||
#include "Core/Boot/Boot.h"
|
|
||||||
#include "Core/Boot/ElfReader.h"
|
|
||||||
#include "Core/HLE/HLE.h"
|
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
size_t filesize = File::GetSize(filename);
|
|
||||||
auto elf = std::make_unique<u8[]>(filesize);
|
|
||||||
|
|
||||||
{
|
|
||||||
File::IOFile f(filename, "rb");
|
|
||||||
f.ReadBytes(elf.get(), filesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the same method as the DOL loader uses: search for mfspr from HID4,
|
|
||||||
// which should only be used in Wii ELFs.
|
|
||||||
//
|
|
||||||
// Likely to have some false positives/negatives, patches implementing a
|
|
||||||
// better heuristic are welcome.
|
|
||||||
|
|
||||||
// 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.GetNumSegments(); ++i)
|
|
||||||
{
|
|
||||||
if (reader.IsCodeSegment(i))
|
|
||||||
{
|
|
||||||
u32* code = (u32*)reader.GetSegmentPtr(i);
|
|
||||||
for (u32 j = 0; j < reader.GetSegmentSize(i) / sizeof(u32); ++j)
|
|
||||||
{
|
|
||||||
if ((code[j] & HID4_mask) == HID4_pattern)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CBoot::Boot_ELF(const std::string& filename)
|
|
||||||
{
|
|
||||||
// Read ELF from file
|
|
||||||
size_t filesize = File::GetSize(filename);
|
|
||||||
auto elf = std::make_unique<u8[]>(filesize);
|
|
||||||
|
|
||||||
{
|
|
||||||
File::IOFile f(filename, "rb");
|
|
||||||
f.ReadBytes(elf.get(), filesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load ELF into GameCube Memory
|
|
||||||
ElfReader reader(elf.get());
|
|
||||||
if (!reader.LoadIntoMemory())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const bool is_wii = IsElfWii(filename);
|
|
||||||
if (is_wii)
|
|
||||||
HID4.SBE = 1;
|
|
||||||
SetupMSR();
|
|
||||||
SetupBAT(is_wii);
|
|
||||||
|
|
||||||
if (!reader.LoadSymbols())
|
|
||||||
{
|
|
||||||
if (LoadMapFromFilename())
|
|
||||||
HLE::PatchFunctions();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HLE::PatchFunctions();
|
|
||||||
}
|
|
||||||
|
|
||||||
PC = reader.GetEntryPoint();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/Boot/Boot_DOL.h"
|
#include "Core/Boot/DolReader.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -12,29 +12,19 @@
|
|||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
|
||||||
CDolLoader::CDolLoader(const std::vector<u8>& buffer)
|
DolReader::DolReader(const std::vector<u8>& buffer) : BootExecutableReader(buffer)
|
||||||
{
|
{
|
||||||
m_is_valid = Initialize(buffer);
|
m_is_valid = Initialize(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDolLoader::CDolLoader(const std::string& filename)
|
DolReader::DolReader(const std::string& filename) : BootExecutableReader(filename)
|
||||||
{
|
{
|
||||||
const u64 size = File::GetSize(filename);
|
m_is_valid = Initialize(m_bytes);
|
||||||
std::vector<u8> temp_buffer(size);
|
|
||||||
|
|
||||||
{
|
|
||||||
File::IOFile pStream(filename, "rb");
|
|
||||||
pStream.ReadBytes(temp_buffer.data(), temp_buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_is_valid = Initialize(temp_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDolLoader::~CDolLoader()
|
DolReader::~DolReader() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDolLoader::Initialize(const std::vector<u8>& buffer)
|
bool DolReader::Initialize(const std::vector<u8>& buffer)
|
||||||
{
|
{
|
||||||
if (buffer.size() < sizeof(SDolHeader))
|
if (buffer.size() < sizeof(SDolHeader))
|
||||||
return false;
|
return false;
|
||||||
@ -97,17 +87,30 @@ bool CDolLoader::Initialize(const std::vector<u8>& buffer)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDolLoader::Load() const
|
bool DolReader::LoadIntoMemory(bool only_in_mem1) const
|
||||||
{
|
{
|
||||||
|
if (!m_is_valid)
|
||||||
|
return false;
|
||||||
|
|
||||||
// load all text (code) sections
|
// load all text (code) sections
|
||||||
for (size_t i = 0; i < m_text_sections.size(); ++i)
|
for (size_t i = 0; i < m_text_sections.size(); ++i)
|
||||||
if (!m_text_sections[i].empty())
|
if (!m_text_sections[i].empty() &&
|
||||||
|
!(only_in_mem1 &&
|
||||||
|
m_dolheader.textAddress[i] + m_text_sections[i].size() >= Memory::REALRAM_SIZE))
|
||||||
|
{
|
||||||
Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(),
|
Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(),
|
||||||
m_text_sections[i].size());
|
m_text_sections[i].size());
|
||||||
|
}
|
||||||
|
|
||||||
// load all data sections
|
// load all data sections
|
||||||
for (size_t i = 0; i < m_data_sections.size(); ++i)
|
for (size_t i = 0; i < m_data_sections.size(); ++i)
|
||||||
if (!m_data_sections[i].empty())
|
if (!m_data_sections[i].empty() &&
|
||||||
|
!(only_in_mem1 &&
|
||||||
|
m_dolheader.dataAddress[i] + m_data_sections[i].size() >= Memory::REALRAM_SIZE))
|
||||||
|
{
|
||||||
Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(),
|
Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(),
|
||||||
m_data_sections[i].size());
|
m_data_sections[i].size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
@ -8,20 +8,20 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/Boot/Boot.h"
|
||||||
|
|
||||||
class CDolLoader
|
class DolReader final : public BootExecutableReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDolLoader(const std::string& filename);
|
DolReader(const std::string& filename);
|
||||||
CDolLoader(const std::vector<u8>& buffer);
|
DolReader(const std::vector<u8>& buffer);
|
||||||
~CDolLoader();
|
~DolReader();
|
||||||
|
|
||||||
bool IsValid() const { return m_is_valid; }
|
|
||||||
bool IsWii() const { return m_is_wii; }
|
|
||||||
u32 GetEntryPoint() const { return m_dolheader.entryPoint; }
|
|
||||||
// Load into emulated memory
|
|
||||||
void Load() const;
|
|
||||||
|
|
||||||
|
bool IsValid() const override { return m_is_valid; }
|
||||||
|
bool IsWii() const override { return m_is_wii; }
|
||||||
|
u32 GetEntryPoint() const override { return m_dolheader.entryPoint; }
|
||||||
|
bool LoadIntoMemory(bool only_in_mem1 = false) const override;
|
||||||
|
bool LoadSymbols() const override { return false; }
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
@ -66,7 +66,17 @@ static void byteswapSection(Elf32_Shdr& sec)
|
|||||||
bswap(sec.sh_type);
|
bswap(sec.sh_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfReader::ElfReader(void* ptr)
|
ElfReader::ElfReader(const std::vector<u8>& buffer) : BootExecutableReader(buffer)
|
||||||
|
{
|
||||||
|
Initialize(m_bytes.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfReader::ElfReader(const std::string& filename) : BootExecutableReader(filename)
|
||||||
|
{
|
||||||
|
Initialize(m_bytes.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElfReader::Initialize(u8* ptr)
|
||||||
{
|
{
|
||||||
base = (char*)ptr;
|
base = (char*)ptr;
|
||||||
base32 = (u32*)ptr;
|
base32 = (u32*)ptr;
|
||||||
@ -86,6 +96,8 @@ ElfReader::ElfReader(void* ptr)
|
|||||||
byteswapSection(sections[i]);
|
byteswapSection(sections[i]);
|
||||||
}
|
}
|
||||||
entryPoint = header->e_entry;
|
entryPoint = header->e_entry;
|
||||||
|
|
||||||
|
bRelocate = (header->e_type != ET_EXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ElfReader::GetSectionName(int section) const
|
const char* ElfReader::GetSectionName(int section) const
|
||||||
@ -103,13 +115,10 @@ const char* ElfReader::GetSectionName(int section) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is just a simple elf loader, good enough to load elfs generated by devkitPPC
|
// This is just a simple elf loader, good enough to load elfs generated by devkitPPC
|
||||||
bool ElfReader::LoadIntoMemory(bool only_in_mem1)
|
bool ElfReader::LoadIntoMemory(bool only_in_mem1) const
|
||||||
{
|
{
|
||||||
INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
|
INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
|
||||||
|
|
||||||
// Should we relocate?
|
|
||||||
bRelocate = (header->e_type != ET_EXEC);
|
|
||||||
|
|
||||||
if (bRelocate)
|
if (bRelocate)
|
||||||
{
|
{
|
||||||
PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf.");
|
PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf.");
|
||||||
@ -160,7 +169,7 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElfReader::LoadSymbols()
|
bool ElfReader::LoadSymbols() const
|
||||||
{
|
{
|
||||||
bool hasSymbols = false;
|
bool hasSymbols = false;
|
||||||
SectionID sec = GetSectionByName(".symtab");
|
SectionID sec = GetSectionByName(".symtab");
|
||||||
@ -205,3 +214,31 @@ bool ElfReader::LoadSymbols()
|
|||||||
g_symbolDB.Index();
|
g_symbolDB.Index();
|
||||||
return hasSymbols;
|
return hasSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ElfReader::IsWii() const
|
||||||
|
{
|
||||||
|
// Use the same method as the DOL loader uses: search for mfspr from HID4,
|
||||||
|
// which should only be used in Wii ELFs.
|
||||||
|
//
|
||||||
|
// Likely to have some false positives/negatives, patches implementing a
|
||||||
|
// better heuristic are welcome.
|
||||||
|
|
||||||
|
// Swap these once, instead of swapping every word in the file.
|
||||||
|
u32 HID4_pattern = Common::swap32(0x7c13fba6);
|
||||||
|
u32 HID4_mask = Common::swap32(0xfc1fffff);
|
||||||
|
|
||||||
|
for (int i = 0; i < GetNumSegments(); ++i)
|
||||||
|
{
|
||||||
|
if (IsCodeSegment(i))
|
||||||
|
{
|
||||||
|
u32* code = (u32*)GetSegmentPtr(i);
|
||||||
|
for (u32 j = 0; j < GetSegmentSize(i) / sizeof(u32); ++j)
|
||||||
|
{
|
||||||
|
if ((code[j] & HID4_mask) == HID4_pattern)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/Boot/ElfTypes.h"
|
#include "Core/Boot/ElfTypes.h"
|
||||||
|
|
||||||
enum KnownElfTypes
|
enum KnownElfTypes
|
||||||
@ -17,31 +18,23 @@ enum KnownElfTypes
|
|||||||
|
|
||||||
typedef int SectionID;
|
typedef int SectionID;
|
||||||
|
|
||||||
class ElfReader
|
class ElfReader final : public BootExecutableReader
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
char* base;
|
|
||||||
u32* base32;
|
|
||||||
|
|
||||||
Elf32_Ehdr* header;
|
|
||||||
Elf32_Phdr* segments;
|
|
||||||
Elf32_Shdr* sections;
|
|
||||||
|
|
||||||
u32* sectionAddrs;
|
|
||||||
bool bRelocate;
|
|
||||||
u32 entryPoint;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ElfReader(void* ptr);
|
ElfReader(const std::string& filename);
|
||||||
|
ElfReader(const std::vector<u8>& buffer);
|
||||||
~ElfReader() {}
|
~ElfReader() {}
|
||||||
u32 Read32(int off) const { return base32[off >> 2]; }
|
u32 Read32(int off) const { return base32[off >> 2]; }
|
||||||
// Quick accessors
|
// Quick accessors
|
||||||
ElfType GetType() const { return (ElfType)(header->e_type); }
|
ElfType GetType() const { return (ElfType)(header->e_type); }
|
||||||
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
|
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
|
||||||
u32 GetEntryPoint() const { return entryPoint; }
|
u32 GetEntryPoint() const override { return entryPoint; }
|
||||||
u32 GetFlags() const { return (u32)(header->e_flags); }
|
u32 GetFlags() const { return (u32)(header->e_flags); }
|
||||||
bool LoadIntoMemory(bool only_in_mem1 = false);
|
bool LoadIntoMemory(bool only_in_mem1 = false) const override;
|
||||||
bool LoadSymbols();
|
bool LoadSymbols() const override;
|
||||||
|
// TODO: actually check for validity.
|
||||||
|
bool IsValid() const override { return true; }
|
||||||
|
bool IsWii() const override;
|
||||||
|
|
||||||
int GetNumSegments() const { return (int)(header->e_phnum); }
|
int GetNumSegments() const { return (int)(header->e_phnum); }
|
||||||
int GetNumSections() const { return (int)(header->e_shnum); }
|
int GetNumSections() const { return (int)(header->e_shnum); }
|
||||||
@ -57,11 +50,24 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
bool IsCodeSegment(int segment) const { return segments[segment].p_flags & PF_X; }
|
bool IsCodeSegment(int segment) const { return segments[segment].p_flags & PF_X; }
|
||||||
const u8* GetSegmentPtr(int segment) { return GetPtr(segments[segment].p_offset); }
|
const u8* GetSegmentPtr(int segment) const { return GetPtr(segments[segment].p_offset); }
|
||||||
int GetSegmentSize(int segment) const { return segments[segment].p_filesz; }
|
int GetSegmentSize(int segment) const { return segments[segment].p_filesz; }
|
||||||
u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; }
|
u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; }
|
||||||
int GetSectionSize(SectionID section) const { return sections[section].sh_size; }
|
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() const { return bRelocate; }
|
bool DidRelocate() const { return bRelocate; }
|
||||||
|
private:
|
||||||
|
void Initialize(u8* bytes);
|
||||||
|
|
||||||
|
char* base;
|
||||||
|
u32* base32;
|
||||||
|
|
||||||
|
Elf32_Ehdr* header;
|
||||||
|
Elf32_Phdr* segments;
|
||||||
|
Elf32_Shdr* sections;
|
||||||
|
|
||||||
|
u32* sectionAddrs;
|
||||||
|
bool bRelocate;
|
||||||
|
u32 entryPoint;
|
||||||
};
|
};
|
||||||
|
@ -21,9 +21,8 @@ set(SRCS
|
|||||||
WiiRoot.cpp
|
WiiRoot.cpp
|
||||||
Boot/Boot_BS2Emu.cpp
|
Boot/Boot_BS2Emu.cpp
|
||||||
Boot/Boot.cpp
|
Boot/Boot.cpp
|
||||||
Boot/Boot_DOL.cpp
|
|
||||||
Boot/Boot_ELF.cpp
|
|
||||||
Boot/Boot_WiiWAD.cpp
|
Boot/Boot_WiiWAD.cpp
|
||||||
|
Boot/DolReader.cpp
|
||||||
Boot/ElfReader.cpp
|
Boot/ElfReader.cpp
|
||||||
Config/Config.cpp
|
Config/Config.cpp
|
||||||
Config/GraphicsSettings.cpp
|
Config/GraphicsSettings.cpp
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include "Core/Analytics.h"
|
#include "Core/Analytics.h"
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/Boot/Boot_DOL.h"
|
|
||||||
#include "Core/Config/Config.h"
|
#include "Core/Config/Config.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
@ -896,10 +895,10 @@ struct SetGameMetadata
|
|||||||
|
|
||||||
bool operator()(const BootParameters::Executable& executable) const
|
bool operator()(const BootParameters::Executable& executable) const
|
||||||
{
|
{
|
||||||
if (executable.type == BootParameters::Executable::Type::DOL)
|
if (!executable.reader->IsValid())
|
||||||
config->bWii = CDolLoader{executable.path}.IsWii();
|
return false;
|
||||||
if (executable.type == BootParameters::Executable::Type::ELF)
|
|
||||||
config->bWii = CBoot::IsElfWii(executable.path);
|
config->bWii = executable.reader->IsWii();
|
||||||
|
|
||||||
// TODO: Right now GC homebrew boots in NTSC and Wii homebrew in PAL.
|
// TODO: Right now GC homebrew boots in NTSC and Wii homebrew in PAL.
|
||||||
// This is intentional so that Wii homebrew can boot in both 50Hz and 60Hz,
|
// This is intentional so that Wii homebrew can boot in both 50Hz and 60Hz,
|
||||||
|
@ -52,9 +52,8 @@
|
|||||||
<ClCompile Include="BootManager.cpp" />
|
<ClCompile Include="BootManager.cpp" />
|
||||||
<ClCompile Include="Boot\Boot.cpp" />
|
<ClCompile Include="Boot\Boot.cpp" />
|
||||||
<ClCompile Include="Boot\Boot_BS2Emu.cpp" />
|
<ClCompile Include="Boot\Boot_BS2Emu.cpp" />
|
||||||
<ClCompile Include="Boot\Boot_DOL.cpp" />
|
|
||||||
<ClCompile Include="Boot\Boot_ELF.cpp" />
|
|
||||||
<ClCompile Include="Boot\Boot_WiiWAD.cpp" />
|
<ClCompile Include="Boot\Boot_WiiWAD.cpp" />
|
||||||
|
<ClCompile Include="Boot\DolReader.cpp" />
|
||||||
<ClCompile Include="Boot\ElfReader.cpp" />
|
<ClCompile Include="Boot\ElfReader.cpp" />
|
||||||
<ClCompile Include="Config\Config.cpp" />
|
<ClCompile Include="Config\Config.cpp" />
|
||||||
<ClCompile Include="Config\GraphicsSettings.cpp" />
|
<ClCompile Include="Config\GraphicsSettings.cpp" />
|
||||||
@ -308,7 +307,7 @@
|
|||||||
<ClInclude Include="ARDecrypt.h" />
|
<ClInclude Include="ARDecrypt.h" />
|
||||||
<ClInclude Include="BootManager.h" />
|
<ClInclude Include="BootManager.h" />
|
||||||
<ClInclude Include="Boot\Boot.h" />
|
<ClInclude Include="Boot\Boot.h" />
|
||||||
<ClInclude Include="Boot\Boot_DOL.h" />
|
<ClInclude Include="Boot\DolReader.h" />
|
||||||
<ClInclude Include="Boot\ElfReader.h" />
|
<ClInclude Include="Boot\ElfReader.h" />
|
||||||
<ClInclude Include="Boot\ElfTypes.h" />
|
<ClInclude Include="Boot\ElfTypes.h" />
|
||||||
<ClInclude Include="Config\Config.h" />
|
<ClInclude Include="Config\Config.h" />
|
||||||
@ -583,4 +582,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -182,15 +182,12 @@
|
|||||||
<ClCompile Include="Boot\Boot_BS2Emu.cpp">
|
<ClCompile Include="Boot\Boot_BS2Emu.cpp">
|
||||||
<Filter>Boot</Filter>
|
<Filter>Boot</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Boot\Boot_DOL.cpp">
|
|
||||||
<Filter>Boot</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Boot\Boot_ELF.cpp">
|
|
||||||
<Filter>Boot</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Boot\Boot_WiiWAD.cpp">
|
<ClCompile Include="Boot\Boot_WiiWAD.cpp">
|
||||||
<Filter>Boot</Filter>
|
<Filter>Boot</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Boot\DolReader.cpp">
|
||||||
|
<Filter>Boot</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="Boot\ElfReader.cpp">
|
<ClCompile Include="Boot\ElfReader.cpp">
|
||||||
<Filter>Boot</Filter>
|
<Filter>Boot</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -888,7 +885,7 @@
|
|||||||
<ClInclude Include="Boot\Boot.h">
|
<ClInclude Include="Boot\Boot.h">
|
||||||
<Filter>Boot</Filter>
|
<Filter>Boot</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Boot\Boot_DOL.h">
|
<ClInclude Include="Boot\DolReader.h">
|
||||||
<Filter>Boot</Filter>
|
<Filter>Boot</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Boot\ElfReader.h">
|
<ClInclude Include="Boot\ElfReader.h">
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/Boot/Boot_DOL.h"
|
#include "Core/Boot/DolReader.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
@ -282,14 +282,15 @@ bool Kernel::BootstrapPPC(const DiscIO::NANDContentLoader& content_loader)
|
|||||||
if (!content)
|
if (!content)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto dol_loader = std::make_unique<CDolLoader>(content->m_Data->Get());
|
const auto dol_loader = std::make_unique<DolReader>(content->m_Data->Get());
|
||||||
if (!dol_loader->IsValid())
|
if (!dol_loader->IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!SetupMemory(m_title_id, MemorySetupType::Full))
|
if (!SetupMemory(m_title_id, MemorySetupType::Full))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dol_loader->Load();
|
if (!dol_loader->LoadIntoMemory())
|
||||||
|
return false;
|
||||||
|
|
||||||
// NAND titles start with address translation off at 0x3400 (via the PPC bootstub)
|
// NAND titles start with address translation off at 0x3400 (via the PPC bootstub)
|
||||||
// The state of other CPU registers (like the BAT registers) doesn't matter much
|
// The state of other CPU registers (like the BAT registers) doesn't matter much
|
||||||
|
@ -134,8 +134,7 @@ bool Load()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> elf_bytes = mios.GetElf();
|
ElfReader elf{mios.GetElf()};
|
||||||
ElfReader elf{elf_bytes.data()};
|
|
||||||
if (!elf.LoadIntoMemory(true))
|
if (!elf.LoadIntoMemory(true))
|
||||||
{
|
{
|
||||||
PanicAlertT("Failed to load MIOS ELF into memory.");
|
PanicAlertT("Failed to load MIOS ELF into memory.");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user