mirror of
https://github.com/libretro/parallel-gx1.git
synced 2026-11-07 04:26:01 -10:00
Boot executables lent from where they lie
A DOL or ELF on the host is read where it lies in its mapped file, or read once into a malloc'd buffer where it cannot be mapped; one handed over by the caller is used in place, freed by the reader only when it takes ownership. A DOL's sections are a fixed array of pointers into it, copied straight into emulated memory, and an ancast body is decrypted straight into emulated memory behind its header. An ELF, whose headers are swapped in place, is copied out of a mapping only then; the ARM binary IOS boots is swapped where it was read, its ELF never copied out.
This commit is contained in:
1 parent
ce91925b34
commit
7ac17da8f9
7 files changed
+161
-108
No files matched your search
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
@@ -651,23 +652,56 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
||||
}
|
||||
|
||||
BootExecutableReader::BootExecutableReader(const std::string& file_name)
|
||||
: BootExecutableReader(File::IOFile{file_name, "rb"})
|
||||
: m_file(file_name, "rb")
|
||||
{
|
||||
u64 size = 0;
|
||||
const u8* map = m_file.GetMappedPtr(&size);
|
||||
if (map)
|
||||
{
|
||||
m_bytes = map;
|
||||
m_size = size_t(size);
|
||||
return;
|
||||
}
|
||||
size = m_file.GetSize();
|
||||
if (!size || !(m_mutable = static_cast<u8*>(std::malloc(size_t(size)))))
|
||||
return;
|
||||
m_owned = true;
|
||||
if (!m_file.ReadBytes(m_mutable, size_t(size)))
|
||||
size = 0;
|
||||
m_file.Close();
|
||||
m_bytes = m_mutable;
|
||||
m_size = size_t(size);
|
||||
}
|
||||
|
||||
BootExecutableReader::BootExecutableReader(u8* data, size_t size, bool take_ownership)
|
||||
: m_bytes(data), m_size(data ? size : 0), m_mutable(data), m_owned(take_ownership)
|
||||
{
|
||||
}
|
||||
|
||||
BootExecutableReader::BootExecutableReader(File::IOFile file)
|
||||
BootExecutableReader::~BootExecutableReader()
|
||||
{
|
||||
file.Seek(0, File::SeekOrigin::Begin);
|
||||
m_bytes.resize(file.GetSize());
|
||||
file.ReadBytes(m_bytes.data(), m_bytes.size());
|
||||
if (m_owned)
|
||||
std::free(m_mutable);
|
||||
}
|
||||
|
||||
BootExecutableReader::BootExecutableReader(std::vector<u8> bytes) : m_bytes(std::move(bytes))
|
||||
u8* BootExecutableReader::MutableBytes()
|
||||
{
|
||||
if (!m_mutable && m_size)
|
||||
{
|
||||
m_mutable = static_cast<u8*>(std::malloc(m_size));
|
||||
if (!m_mutable)
|
||||
{
|
||||
m_size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
std::memcpy(m_mutable, m_bytes, m_size);
|
||||
m_owned = true;
|
||||
m_bytes = m_mutable;
|
||||
m_file.Close();
|
||||
}
|
||||
return m_mutable;
|
||||
}
|
||||
|
||||
BootExecutableReader::~BootExecutableReader() = default;
|
||||
|
||||
void StateFlags::UpdateChecksum()
|
||||
{
|
||||
constexpr size_t length_in_bytes = sizeof(StateFlags) - 4;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Core/IOS/IOSC.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
@@ -169,11 +170,16 @@ private:
|
||||
class BootExecutableReader
|
||||
{
|
||||
public:
|
||||
// The executable lent from the file's mapping where it has one, else read into memory.
|
||||
explicit BootExecutableReader(const std::string& file_name);
|
||||
explicit BootExecutableReader(File::IOFile file);
|
||||
explicit BootExecutableReader(std::vector<u8> buffer);
|
||||
// The executable at data, lent by the caller, who keeps it alive and lets the reader
|
||||
// rewrite it in place; freed with free() by the reader when take_ownership.
|
||||
BootExecutableReader(u8* data, size_t size, bool take_ownership);
|
||||
virtual ~BootExecutableReader();
|
||||
|
||||
BootExecutableReader(const BootExecutableReader&) = delete;
|
||||
BootExecutableReader& operator=(const BootExecutableReader&) = delete;
|
||||
|
||||
virtual u32 GetEntryPoint() const = 0;
|
||||
virtual bool IsValid() const = 0;
|
||||
virtual bool IsWii() const = 0;
|
||||
@@ -182,7 +188,16 @@ public:
|
||||
const std::string& filename) const = 0;
|
||||
|
||||
protected:
|
||||
std::vector<u8> m_bytes;
|
||||
// The executable's octets, read-only.
|
||||
const u8* m_bytes = nullptr;
|
||||
size_t m_size = 0;
|
||||
// The same octets, writable, copied out of a mapping on first use.
|
||||
u8* MutableBytes();
|
||||
|
||||
private:
|
||||
File::IOFile m_file;
|
||||
u8* m_mutable = nullptr;
|
||||
bool m_owned = false;
|
||||
};
|
||||
|
||||
struct StateFlags
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/BitUtils.h"
|
||||
@@ -16,29 +14,25 @@
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
DolReader::DolReader(std::vector<u8> buffer) : BootExecutableReader(std::move(buffer))
|
||||
{
|
||||
m_is_valid = Initialize(m_bytes);
|
||||
}
|
||||
|
||||
DolReader::DolReader(File::IOFile file) : BootExecutableReader(std::move(file))
|
||||
{
|
||||
m_is_valid = Initialize(m_bytes);
|
||||
}
|
||||
|
||||
DolReader::DolReader(const std::string& filename) : BootExecutableReader(filename)
|
||||
{
|
||||
m_is_valid = Initialize(m_bytes);
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
DolReader::DolReader(u8* data, size_t size, bool take_ownership)
|
||||
: BootExecutableReader(data, size, take_ownership)
|
||||
{
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
DolReader::~DolReader() = default;
|
||||
|
||||
bool DolReader::Initialize(std::span<const u8> buffer)
|
||||
bool DolReader::Initialize()
|
||||
{
|
||||
if (buffer.size() < sizeof(DolHeader) || buffer.size() > UINT32_MAX)
|
||||
if (m_size < sizeof(DolHeader) || m_size > UINT32_MAX)
|
||||
return false;
|
||||
|
||||
std::memcpy(&m_dolheader, buffer.data(), sizeof(DolHeader));
|
||||
std::memcpy(&m_dolheader, m_bytes, sizeof(DolHeader));
|
||||
|
||||
// swap memory
|
||||
u32* p = (u32*)&m_dolheader;
|
||||
@@ -67,15 +61,16 @@ bool DolReader::Initialize(std::span<const u8> buffer)
|
||||
i);
|
||||
}
|
||||
|
||||
if (buffer.size() < m_dolheader.m_text_offset[i] + section_size)
|
||||
if (m_size < m_dolheader.m_text_offset[i] + section_size)
|
||||
return false;
|
||||
|
||||
auto& section = m_sections.emplace_back();
|
||||
LoadableSection& section = m_sections[m_num_sections++];
|
||||
section.m_address = m_dolheader.m_text_address[i];
|
||||
section.m_header_section_size = m_dolheader.m_text_size[i];
|
||||
section.m_data = buffer.subspan(m_dolheader.m_text_offset[i], section_size);
|
||||
section.m_data = m_bytes + m_dolheader.m_text_offset[i];
|
||||
section.m_size = static_cast<u32>(section_size);
|
||||
|
||||
const u8* const begin = section.m_data.data();
|
||||
const u8* const begin = section.m_data;
|
||||
const u8* const end = begin + section_size;
|
||||
for (const u8* ptr = begin; ptr < end; ptr += 4)
|
||||
{
|
||||
@@ -102,21 +97,22 @@ bool DolReader::Initialize(std::span<const u8> buffer)
|
||||
i);
|
||||
}
|
||||
|
||||
if (buffer.size() < section_offset + section_size)
|
||||
if (m_size < section_offset + section_size)
|
||||
return false;
|
||||
|
||||
auto& section = m_sections.emplace_back();
|
||||
LoadableSection& section = m_sections[m_num_sections++];
|
||||
section.m_address = m_dolheader.m_data_address[i];
|
||||
section.m_header_section_size = m_dolheader.m_data_size[i];
|
||||
section.m_data = buffer.subspan(section_offset, section_size);
|
||||
section.m_data = m_bytes + section_offset;
|
||||
section.m_size = static_cast<u32>(section_size);
|
||||
|
||||
// Check if this dol contains an ancast image
|
||||
// The ancast image will always be in the first data section
|
||||
if (i == 0 && section.m_header_section_size > sizeof(EspressoAncastHeader) &&
|
||||
section.m_address == ESPRESSO_ANCAST_LOCATION_VIRT &&
|
||||
Common::swap32(section.m_data.data()) == ANCAST_MAGIC)
|
||||
Common::swap32(section.m_data) == ANCAST_MAGIC)
|
||||
{
|
||||
m_ancast_index = m_sections.size() - 1;
|
||||
m_ancast_index = m_num_sections - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,13 +129,14 @@ bool DolReader::LoadIntoMemory(Core::System& system, bool only_in_mem1) const
|
||||
|
||||
auto& memory = system.GetMemory();
|
||||
|
||||
// load all loadable sections
|
||||
for (auto& section : m_sections)
|
||||
// load all loadable sections, straight from the file's mapping where it has one
|
||||
for (int i = 0; i < m_num_sections; i++)
|
||||
{
|
||||
if (only_in_mem1 && section.m_address + section.m_data.size() >= memory.GetRamSizeReal())
|
||||
const LoadableSection& section = m_sections[i];
|
||||
if (only_in_mem1 && section.m_address + section.m_size >= memory.GetRamSizeReal())
|
||||
continue;
|
||||
|
||||
memory.CopyToEmu(section.m_address, section.m_data.data(), section.m_data.size());
|
||||
memory.CopyToEmu(section.m_address, section.m_data, section.m_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -148,10 +145,10 @@ bool DolReader::LoadIntoMemory(Core::System& system, bool only_in_mem1) const
|
||||
// On a real console this would be done in the Espresso bootrom
|
||||
bool DolReader::LoadAncastIntoMemory(Core::System& system) const
|
||||
{
|
||||
const LoadableSection& section = m_sections[m_ancast_index.value()];
|
||||
const LoadableSection& section = m_sections[m_ancast_index];
|
||||
const u32 section_address = m_dolheader.m_data_address[0];
|
||||
const EspressoAncastHeader header =
|
||||
Common::BitCastPtr<EspressoAncastHeader>(section.m_data.data());
|
||||
Common::BitCastPtr<EspressoAncastHeader>(section.m_data);
|
||||
|
||||
// Verify header block size
|
||||
if (Common::swap32(header.header_block.header_block_size) != sizeof(AncastHeaderBlock))
|
||||
@@ -187,7 +184,7 @@ bool DolReader::LoadAncastIntoMemory(Core::System& system) const
|
||||
|
||||
// Verify the body hash
|
||||
const auto digest = Common::SHA1::CalculateDigest(
|
||||
section.m_data.data() + sizeof(EspressoAncastHeader), body_size);
|
||||
section.m_data + sizeof(EspressoAncastHeader), body_size);
|
||||
if (digest != header.info_block.body_hash)
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Body hash mismatch");
|
||||
@@ -218,18 +215,17 @@ bool DolReader::LoadAncastIntoMemory(Core::System& system) const
|
||||
|
||||
static constexpr u8 vwii_ancast_iv[0x10] = {0x59, 0x6d, 0x5a, 0x9a, 0xd7, 0x05, 0xf9, 0x4f,
|
||||
0xe1, 0x58, 0x02, 0x6f, 0xea, 0xa7, 0xb8, 0x87};
|
||||
std::vector<u8> decrypted(body_size);
|
||||
if (!ctx->Crypt(vwii_ancast_iv, section.m_data.data() + sizeof(EspressoAncastHeader),
|
||||
decrypted.data(), body_size))
|
||||
return false;
|
||||
|
||||
auto& memory = system.GetMemory();
|
||||
|
||||
// Copy the Ancast header to the emu
|
||||
// The body is decrypted straight into emulated memory, behind its header.
|
||||
u8* const body =
|
||||
memory.GetPointerForRange(section_address + sizeof(EspressoAncastHeader), body_size);
|
||||
if (!body ||
|
||||
!ctx->Crypt(vwii_ancast_iv, section.m_data + sizeof(EspressoAncastHeader), body, body_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memory.CopyToEmu(section_address, &header, sizeof(EspressoAncastHeader));
|
||||
|
||||
// Copy the decrypted body to the emu
|
||||
memory.CopyToEmu(section_address + sizeof(EspressoAncastHeader), decrypted.data(), body_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3,30 +3,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Boot/Boot.h"
|
||||
|
||||
namespace File
|
||||
{
|
||||
class IOFile;
|
||||
}
|
||||
|
||||
class DolReader final : public BootExecutableReader
|
||||
{
|
||||
public:
|
||||
explicit DolReader(const std::string& filename);
|
||||
explicit DolReader(File::IOFile file);
|
||||
explicit DolReader(std::vector<u8> buffer);
|
||||
DolReader(u8* data, size_t size, bool take_ownership);
|
||||
~DolReader() override;
|
||||
|
||||
bool IsValid() const override { return m_is_valid; }
|
||||
bool IsWii() const override { return m_is_wii; }
|
||||
bool IsAncast() const { return m_ancast_index.has_value(); }
|
||||
bool IsAncast() const { return m_ancast_index >= 0; }
|
||||
u32 GetEntryPoint() const override { return m_dolheader.m_entrypoint; }
|
||||
bool LoadIntoMemory(Core::System& system, bool only_in_mem1 = false) const override;
|
||||
bool LoadSymbols(const Core::CPUThreadGuard& guard, PPCSymbolDB& ppc_symbol_db,
|
||||
@@ -61,19 +52,20 @@ private:
|
||||
|
||||
struct LoadableSection
|
||||
{
|
||||
const u8* m_data;
|
||||
u32 m_size;
|
||||
u32 m_address;
|
||||
u32 m_header_section_size;
|
||||
std::span<const u8> m_data;
|
||||
};
|
||||
|
||||
std::vector<LoadableSection> m_sections;
|
||||
LoadableSection m_sections[DOL_NUM_TEXT + DOL_NUM_DATA];
|
||||
int m_num_sections = 0;
|
||||
int m_ancast_index = -1;
|
||||
|
||||
bool m_is_valid;
|
||||
bool m_is_wii;
|
||||
std::optional<std::size_t> m_ancast_index;
|
||||
|
||||
// Copy sections to internal buffers
|
||||
bool Initialize(std::span<const u8> buffer);
|
||||
bool Initialize();
|
||||
|
||||
bool LoadAncastIntoMemory(Core::System& system) const;
|
||||
};
|
||||
@@ -69,34 +69,34 @@ static void byteswapSection(Elf32_Shdr& sec)
|
||||
bswap(sec.sh_type);
|
||||
}
|
||||
|
||||
ElfReader::ElfReader(std::vector<u8> buffer) : BootExecutableReader(std::move(buffer))
|
||||
{
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
ElfReader::ElfReader(File::IOFile file) : BootExecutableReader(std::move(file))
|
||||
{
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
ElfReader::ElfReader(const std::string& filename) : BootExecutableReader(filename)
|
||||
{
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
ElfReader::ElfReader(u8* data, size_t size, bool take_ownership)
|
||||
: BootExecutableReader(data, size, take_ownership)
|
||||
{
|
||||
m_is_valid = Initialize();
|
||||
}
|
||||
|
||||
ElfReader::~ElfReader() = default;
|
||||
|
||||
bool ElfReader::Initialize()
|
||||
{
|
||||
if (m_bytes.size() < sizeof(Elf32_Ehdr))
|
||||
if (m_size < sizeof(Elf32_Ehdr))
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "ELF file is too small.");
|
||||
return false;
|
||||
}
|
||||
|
||||
base = reinterpret_cast<char*>(m_bytes.data());
|
||||
base32 = reinterpret_cast<u32*>(m_bytes.data());
|
||||
header = reinterpret_cast<Elf32_Ehdr*>(m_bytes.data());
|
||||
// the headers are swapped in place
|
||||
u8* const bytes = MutableBytes();
|
||||
if (!bytes)
|
||||
return false;
|
||||
base = reinterpret_cast<char*>(bytes);
|
||||
base32 = reinterpret_cast<u32*>(bytes);
|
||||
header = reinterpret_cast<Elf32_Ehdr*>(bytes);
|
||||
if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3 ||
|
||||
header->e_ident[EI_CLASS] != ELFCLASS32 || header->e_ident[EI_DATA] != ELFDATA2MSB)
|
||||
@@ -108,7 +108,7 @@ bool ElfReader::Initialize()
|
||||
byteswapHeader(*header);
|
||||
|
||||
const auto is_range_valid = [this](size_t offset, size_t size) {
|
||||
return offset <= m_bytes.size() && size <= m_bytes.size() - offset;
|
||||
return offset <= m_size && size <= m_size - offset;
|
||||
};
|
||||
if (header->e_ehsize != sizeof(Elf32_Ehdr) ||
|
||||
(header->e_phnum != 0 && header->e_phentsize != sizeof(Elf32_Phdr)) ||
|
||||
|
||||
@@ -26,8 +26,7 @@ class ElfReader final : public BootExecutableReader
|
||||
{
|
||||
public:
|
||||
explicit ElfReader(const std::string& filename);
|
||||
explicit ElfReader(File::IOFile file);
|
||||
explicit ElfReader(std::vector<u8> buffer);
|
||||
ElfReader(u8* data, size_t size, bool take_ownership);
|
||||
~ElfReader() override;
|
||||
u32 Read32(int off) const { return base32[off >> 2]; }
|
||||
// Quick accessors
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Core/IOS/IOS.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -401,20 +402,29 @@ u16 EmulationKernel::GetGidForPPC() const
|
||||
return m_ppc_gid;
|
||||
}
|
||||
|
||||
static std::vector<u8> ReadBootContent(FSCore& fs, const std::string& path, size_t max_size,
|
||||
Ticks ticks = {})
|
||||
// The file, in memory from malloc() for the caller to free; nullptr when it cannot be read or
|
||||
// is larger than a nonzero max_size.
|
||||
static u8* ReadBootContent(FSCore& fs, const std::string& path, size_t max_size, size_t* size,
|
||||
Ticks ticks = {})
|
||||
{
|
||||
const auto fd = fs.Open(0, 0, path, FS::Mode::Read, {}, ticks);
|
||||
u8* buffer;
|
||||
if (fd.Get() < 0)
|
||||
return {};
|
||||
return nullptr;
|
||||
|
||||
const size_t file_size = fs.GetFileStatus(fd.Get(), ticks)->size;
|
||||
if (max_size != 0 && file_size > max_size)
|
||||
return {};
|
||||
if (!file_size || (max_size != 0 && file_size > max_size))
|
||||
return nullptr;
|
||||
|
||||
std::vector<u8> buffer(file_size);
|
||||
if (!fs.Read(fd.Get(), buffer.data(), buffer.size(), ticks))
|
||||
return {};
|
||||
buffer = static_cast<u8*>(std::malloc(file_size));
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
if (!fs.Read(fd.Get(), buffer, file_size, ticks))
|
||||
{
|
||||
std::free(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
*size = file_size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -425,7 +435,9 @@ bool EmulationKernel::BootstrapPPC(const std::string& boot_content_path)
|
||||
// Seeking and processing overhead is ignored as most time is spent reading from the NAND.
|
||||
u64 ticks = 0;
|
||||
|
||||
const DolReader dol{ReadBootContent(GetFSCore(), boot_content_path, 0, &ticks)};
|
||||
size_t dol_size = 0;
|
||||
u8* const dol_bytes = ReadBootContent(GetFSCore(), boot_content_path, 0, &dol_size, &ticks);
|
||||
const DolReader dol{dol_bytes, dol_size, true};
|
||||
|
||||
if (!dol.IsValid())
|
||||
return false;
|
||||
@@ -447,29 +459,32 @@ bool EmulationKernel::BootstrapPPC(const std::string& boot_content_path)
|
||||
return true;
|
||||
}
|
||||
|
||||
// An ARM boot binary: a header, then the ELF the PPC side loads.
|
||||
struct ARMBinary final
|
||||
{
|
||||
explicit ARMBinary(std::vector<u8>&& bytes) : m_bytes(std::move(bytes)) {}
|
||||
ARMBinary(u8* bytes, size_t size) : m_bytes(bytes), m_size(bytes ? size : 0) {}
|
||||
~ARMBinary() { std::free(m_bytes); }
|
||||
ARMBinary(const ARMBinary&) = delete;
|
||||
ARMBinary& operator=(const ARMBinary&) = delete;
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
// The header is at least 0x10.
|
||||
if (m_bytes.size() < 0x10)
|
||||
if (m_size < 0x10)
|
||||
return false;
|
||||
return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize());
|
||||
return m_size >= u64(GetHeaderSize()) + GetElfOffset() + GetElfSize();
|
||||
}
|
||||
|
||||
std::vector<u8> GetElf() const
|
||||
{
|
||||
const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset();
|
||||
return std::vector<u8>(iterator, iterator + GetElfSize());
|
||||
}
|
||||
// The ELF where it lies in the binary, for a reader to rewrite in place.
|
||||
u8* GetElf() { return m_bytes + GetHeaderSize() + GetElfOffset(); }
|
||||
|
||||
u32 GetHeaderSize() const { return Common::swap32(m_bytes.data()); }
|
||||
u32 GetElfOffset() const { return Common::swap32(m_bytes.data() + 0x4); }
|
||||
u32 GetElfSize() const { return Common::swap32(m_bytes.data() + 0x8); }
|
||||
u32 GetHeaderSize() const { return Common::swap32(m_bytes); }
|
||||
u32 GetElfOffset() const { return Common::swap32(m_bytes + 0x4); }
|
||||
u32 GetElfSize() const { return Common::swap32(m_bytes + 0x8); }
|
||||
|
||||
private:
|
||||
std::vector<u8> m_bytes;
|
||||
u8* m_bytes;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
static void FinishIOSBoot(Core::System& system, u64 ios_title_id)
|
||||
@@ -506,11 +521,13 @@ bool EmulationKernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc,
|
||||
// Load the ARM binary to memory (if possible).
|
||||
// Because we do not actually emulate the Starlet, only load the sections that are in MEM1.
|
||||
|
||||
ARMBinary binary{ReadBootContent(GetFSCore(), boot_content_path, 0xB00000)};
|
||||
size_t binary_size = 0;
|
||||
u8* const binary_bytes = ReadBootContent(GetFSCore(), boot_content_path, 0xB00000, &binary_size);
|
||||
ARMBinary binary{binary_bytes, binary_size};
|
||||
if (!binary.IsValid())
|
||||
return false;
|
||||
|
||||
ElfReader elf{binary.GetElf()};
|
||||
ElfReader elf{binary.GetElf(), binary.GetElfSize(), false};
|
||||
if (!elf.LoadIntoMemory(m_system, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user