mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Support for loading Ancast images
This commit is contained in:
@ -10,6 +10,7 @@
|
||||
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/Swap.h"
|
||||
#include "Core/Boot/AncastTypes.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
DolReader::DolReader(std::vector<u8> buffer) : BootExecutableReader(std::move(buffer))
|
||||
@ -94,6 +95,17 @@ bool DolReader::Initialize(const std::vector<u8>& buffer)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this dol contains an ancast image
|
||||
// The ancast image will always be in the first data section
|
||||
m_is_ancast = false;
|
||||
if (m_data_sections[0].size() > sizeof(EspressoAncastHeader) &&
|
||||
m_dolheader.dataAddress[0] == ESPRESSO_ANCAST_LOCATION_VIRT)
|
||||
{
|
||||
// Check for the ancast magic
|
||||
if (Common::swap32(m_data_sections[0].data()) == ANCAST_MAGIC)
|
||||
m_is_ancast = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -102,6 +114,9 @@ bool DolReader::LoadIntoMemory(bool only_in_mem1) const
|
||||
if (!m_is_valid)
|
||||
return false;
|
||||
|
||||
if (m_is_ancast)
|
||||
return LoadAncastIntoMemory();
|
||||
|
||||
// load all text (code) sections
|
||||
for (size_t i = 0; i < m_text_sections.size(); ++i)
|
||||
if (!m_text_sections[i].empty() &&
|
||||
@ -124,3 +139,91 @@ bool DolReader::LoadIntoMemory(bool only_in_mem1) const
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// On a real console this would be done in the Espresso bootrom
|
||||
bool DolReader::LoadAncastIntoMemory() const
|
||||
{
|
||||
// The ancast image will always be in data section 0
|
||||
const auto& section = m_data_sections[0];
|
||||
const u32 section_address = m_dolheader.dataAddress[0];
|
||||
|
||||
const auto* header = reinterpret_cast<const EspressoAncastHeader*>(section.data());
|
||||
|
||||
// Verify header block size
|
||||
if (Common::swap32(header->header_block.header_block_size) != sizeof(AncastHeaderBlock))
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Invalid header block size: 0x{:x}",
|
||||
Common::swap32(header->header_block.header_block_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this is a PPC ancast image
|
||||
if (Common::swap32(header->signature_block.signature_type) != 0x01)
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Invalid signature type: 0x{:x}",
|
||||
Common::swap32(header->signature_block.signature_type));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this is a Wii-Mode ancast image
|
||||
if (Common::swap32(header->info_block.image_type) != ANCAST_IMAGE_TYPE_ESPRESSO_WII)
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Invalid image type: 0x{:x}",
|
||||
Common::swap32(header->info_block.image_type));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the body size
|
||||
const u32 body_size = Common::swap32(header->info_block.body_size);
|
||||
if (body_size + sizeof(EspressoAncastHeader) > section.size())
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Invalid body size: 0x{:x}", body_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the body hash
|
||||
const auto digest =
|
||||
Common::SHA1::CalculateDigest(section.data() + sizeof(EspressoAncastHeader), body_size);
|
||||
if (digest != header->info_block.body_hash)
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Body hash mismatch");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is a retail or dev image
|
||||
bool is_dev = false;
|
||||
if (Common::swap32(header->info_block.console_type) == ANCAST_CONSOLE_TYPE_DEV)
|
||||
{
|
||||
is_dev = true;
|
||||
}
|
||||
else if (Common::swap32(header->info_block.console_type) != ANCAST_CONSOLE_TYPE_RETAIL)
|
||||
{
|
||||
ERROR_LOG_FMT(BOOT, "Ancast: Invalid console type: 0x{:x}",
|
||||
Common::swap32(header->info_block.console_type));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decrypt the Ancast image
|
||||
static constexpr u8 vwii_ancast_retail_key[0x10] = {0x2e, 0xfe, 0x8a, 0xbc, 0xed, 0xbb,
|
||||
0x7b, 0xaa, 0xe3, 0xc0, 0xed, 0x92,
|
||||
0xfa, 0x29, 0xf8, 0x66};
|
||||
static constexpr u8 vwii_ancast_dev_key[0x10] = {0x26, 0xaf, 0xf4, 0xbb, 0xac, 0x88, 0xbb, 0x76,
|
||||
0x9d, 0xfc, 0x54, 0xdd, 0x56, 0xd8, 0xef, 0xbd};
|
||||
std::unique_ptr<Common::AES::Context> ctx =
|
||||
Common::AES::CreateContextDecrypt(is_dev ? vwii_ancast_dev_key : vwii_ancast_retail_key);
|
||||
|
||||
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.data() + sizeof(EspressoAncastHeader), decrypted.data(),
|
||||
body_size))
|
||||
return false;
|
||||
|
||||
// Copy the Ancast header to the emu
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user