Reformat all the things. Have fun with merge conflicts.

This commit is contained in:
Pierre Bourdon 2016-06-24 10:43:46 +02:00
commit 3570c7f03a
1116 changed files with 187405 additions and 180344 deletions

View file

@ -12,12 +12,10 @@
#include "Common/MathUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/PatchEngine.h"
#include "Core/Boot/Boot.h"
#include "Core/Boot/Boot_DOL.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/DVDInterface.h"
@ -25,10 +23,12 @@
#include "Core/HW/Memmap.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/VideoInterface.h"
#include "Core/Host.h"
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PatchEngine.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/SignatureDB.h"
#include "DiscIO/NANDContentLoader.h"
@ -36,129 +36,125 @@
bool CBoot::DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt)
{
std::vector<u8> buffer(length);
if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt))
return false;
Memory::CopyToEmu(output_address, buffer.data(), length);
return true;
std::vector<u8> buffer(length);
if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt))
return false;
Memory::CopyToEmu(output_address, buffer.data(), length);
return true;
}
void CBoot::Load_FST(bool _bIsWii)
{
if (!DVDInterface::VolumeIsValid())
return;
if (!DVDInterface::VolumeIsValid())
return;
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
// copy first 20 bytes of disc to start of Mem 1
DVDRead(/*offset*/0, /*address*/0, /*length*/0x20, false);
// copy first 20 bytes of disc to start of Mem 1
DVDRead(/*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false);
// copy of game id
Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);
// copy of game id
Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);
u32 shift = 0;
if (_bIsWii)
shift = 2;
u32 shift = 0;
if (_bIsWii)
shift = 2;
u32 fst_offset = 0;
u32 fst_size = 0;
u32 max_fst_size = 0;
u32 fst_offset = 0;
u32 fst_size = 0;
u32 max_fst_size = 0;
volume.ReadSwapped(0x0424, &fst_offset, _bIsWii);
volume.ReadSwapped(0x0428, &fst_size, _bIsWii);
volume.ReadSwapped(0x042c, &max_fst_size, _bIsWii);
volume.ReadSwapped(0x0424, &fst_offset, _bIsWii);
volume.ReadSwapped(0x0428, &fst_size, _bIsWii);
volume.ReadSwapped(0x042c, &max_fst_size, _bIsWii);
u32 arena_high = ROUND_DOWN(0x817FFFFF - (max_fst_size << shift), 0x20);
Memory::Write_U32(arena_high, 0x00000034);
u32 arena_high = ROUND_DOWN(0x817FFFFF - (max_fst_size << shift), 0x20);
Memory::Write_U32(arena_high, 0x00000034);
// load FST
DVDRead(fst_offset << shift, arena_high, fst_size << shift, _bIsWii);
Memory::Write_U32(arena_high, 0x00000038);
Memory::Write_U32(max_fst_size << shift, 0x0000003c);
// load FST
DVDRead(fst_offset << shift, arena_high, fst_size << shift, _bIsWii);
Memory::Write_U32(arena_high, 0x00000038);
Memory::Write_U32(max_fst_size << shift, 0x0000003c);
}
void CBoot::UpdateDebugger_MapLoaded()
{
Host_NotifyMapLoaded();
Host_NotifyMapLoaded();
}
bool CBoot::FindMapFile(std::string* existing_map_file,
std::string* writable_map_file,
bool CBoot::FindMapFile(std::string* existing_map_file, std::string* writable_map_file,
std::string* title_id)
{
std::string title_id_str;
size_t name_begin_index;
std::string title_id_str;
size_t name_begin_index;
SConfig& _StartupPara = SConfig::GetInstance();
switch (_StartupPara.m_BootType)
{
case SConfig::BOOT_WII_NAND:
{
const DiscIO::CNANDContentLoader& Loader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
if (Loader.IsValid())
{
u64 TitleID = Loader.GetTitleID();
title_id_str = StringFromFormat("%08X_%08X",
(u32)(TitleID >> 32) & 0xFFFFFFFF,
(u32)TitleID & 0xFFFFFFFF);
}
break;
}
SConfig& _StartupPara = SConfig::GetInstance();
switch (_StartupPara.m_BootType)
{
case SConfig::BOOT_WII_NAND:
{
const DiscIO::CNANDContentLoader& Loader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
if (Loader.IsValid())
{
u64 TitleID = Loader.GetTitleID();
title_id_str = StringFromFormat("%08X_%08X", (u32)(TitleID >> 32) & 0xFFFFFFFF,
(u32)TitleID & 0xFFFFFFFF);
}
break;
}
case SConfig::BOOT_ELF:
case SConfig::BOOT_DOL:
// Strip the .elf/.dol file extension and directories before the name
name_begin_index = _StartupPara.m_strFilename.find_last_of("/") + 1;
if ((_StartupPara.m_strFilename.find_last_of("\\") + 1) > name_begin_index)
{
name_begin_index = _StartupPara.m_strFilename.find_last_of("\\") + 1;
}
title_id_str = _StartupPara.m_strFilename.substr(
name_begin_index, _StartupPara.m_strFilename.size() - 4 - name_begin_index);
break;
case SConfig::BOOT_ELF:
case SConfig::BOOT_DOL:
// Strip the .elf/.dol file extension and directories before the name
name_begin_index = _StartupPara.m_strFilename.find_last_of("/") + 1;
if ((_StartupPara.m_strFilename.find_last_of("\\") + 1) > name_begin_index)
{
name_begin_index = _StartupPara.m_strFilename.find_last_of("\\") + 1;
}
title_id_str = _StartupPara.m_strFilename.substr(
name_begin_index, _StartupPara.m_strFilename.size() - 4 - name_begin_index);
break;
default:
title_id_str = _StartupPara.GetUniqueID();
break;
}
default:
title_id_str = _StartupPara.GetUniqueID();
break;
}
if (writable_map_file)
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";
if (writable_map_file)
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";
if (title_id)
*title_id = title_id_str;
if (title_id)
*title_id = title_id_str;
bool found = false;
static const std::string maps_directories[] = {
File::GetUserPath(D_MAPS_IDX),
File::GetSysDirectory() + MAPS_DIR DIR_SEP
};
for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i)
{
std::string path = maps_directories[i] + title_id_str + ".map";
if (File::Exists(path))
{
found = true;
if (existing_map_file)
*existing_map_file = path;
}
}
bool found = false;
static const std::string maps_directories[] = {File::GetUserPath(D_MAPS_IDX),
File::GetSysDirectory() + MAPS_DIR DIR_SEP};
for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i)
{
std::string path = maps_directories[i] + title_id_str + ".map";
if (File::Exists(path))
{
found = true;
if (existing_map_file)
*existing_map_file = path;
}
}
return found;
return found;
}
bool CBoot::LoadMapFromFilename()
{
std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, nullptr);
if (found && g_symbolDB.LoadMap(strMapFilename))
{
UpdateDebugger_MapLoaded();
return true;
}
std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, nullptr);
if (found && g_symbolDB.LoadMap(strMapFilename))
{
UpdateDebugger_MapLoaded();
return true;
}
return false;
return false;
}
// If ipl.bin is not found, this function does *some* of what BS1 does:
@ -166,314 +162,319 @@ bool CBoot::LoadMapFromFilename()
// It does not initialize the hardware or anything else like BS1 does.
bool CBoot::Load_BS2(const std::string& _rBootROMFilename)
{
// CRC32
const u32 USA_v1_0 = 0x6D740AE7; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385344#pid385344
const u32 USA_v1_1 = 0xD5E6FEEA; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385334#pid385334
const u32 USA_v1_2 = 0x86573808; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385399#pid385399
const u32 BRA_v1_0 = 0x667D0B64; // GameCubes sold in Brazil have this IPL. Same as USA v1.2 but localized
const u32 JAP_v1_0 = 0x6DAC1F2A; // Redump
const u32 JAP_v1_1 = 0xD235E3F9; // https://bugs.dolphin-emu.org/issues/8936
const u32 PAL_v1_0 = 0x4F319F43; // Redump
const u32 PAL_v1_2 = 0xAD1B7F16; // Redump
// CRC32
const u32 USA_v1_0 =
0x6D740AE7; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385344#pid385344
const u32 USA_v1_1 =
0xD5E6FEEA; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385334#pid385334
const u32 USA_v1_2 =
0x86573808; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385399#pid385399
const u32 BRA_v1_0 =
0x667D0B64; // GameCubes sold in Brazil have this IPL. Same as USA v1.2 but localized
const u32 JAP_v1_0 = 0x6DAC1F2A; // Redump
const u32 JAP_v1_1 = 0xD235E3F9; // https://bugs.dolphin-emu.org/issues/8936
const u32 PAL_v1_0 = 0x4F319F43; // Redump
const u32 PAL_v1_2 = 0xAD1B7F16; // Redump
// Load the whole ROM dump
std::string data;
if (!File::ReadFileToString(_rBootROMFilename, data))
return false;
// Load the whole ROM dump
std::string data;
if (!File::ReadFileToString(_rBootROMFilename, data))
return false;
// Use zlibs crc32 implementation to compute the hash
u32 ipl_hash = crc32(0L, Z_NULL, 0);
ipl_hash = crc32(ipl_hash, (const Bytef*)data.data(), (u32)data.size());
std::string ipl_region;
switch (ipl_hash)
{
case USA_v1_0:
case USA_v1_1:
case USA_v1_2:
case BRA_v1_0:
ipl_region = USA_DIR;
break;
case JAP_v1_0:
case JAP_v1_1:
ipl_region = JAP_DIR;
break;
case PAL_v1_0:
case PAL_v1_2:
ipl_region = EUR_DIR;
break;
default:
PanicAlertT("IPL with unknown hash %x", ipl_hash);
break;
}
// Use zlibs crc32 implementation to compute the hash
u32 ipl_hash = crc32(0L, Z_NULL, 0);
ipl_hash = crc32(ipl_hash, (const Bytef*)data.data(), (u32)data.size());
std::string ipl_region;
switch (ipl_hash)
{
case USA_v1_0:
case USA_v1_1:
case USA_v1_2:
case BRA_v1_0:
ipl_region = USA_DIR;
break;
case JAP_v1_0:
case JAP_v1_1:
ipl_region = JAP_DIR;
break;
case PAL_v1_0:
case PAL_v1_2:
ipl_region = EUR_DIR;
break;
default:
PanicAlertT("IPL with unknown hash %x", ipl_hash);
break;
}
std::string BootRegion = _rBootROMFilename.substr(_rBootROMFilename.find_last_of(DIR_SEP) - 3, 3);
if (BootRegion != ipl_region)
PanicAlertT("%s IPL found in %s directory. The disc might not be recognized",
ipl_region.c_str(), BootRegion.c_str());
std::string BootRegion = _rBootROMFilename.substr(_rBootROMFilename.find_last_of(DIR_SEP) - 3, 3);
if (BootRegion != ipl_region)
PanicAlertT("%s IPL found in %s directory. The disc might not be recognized",
ipl_region.c_str(), BootRegion.c_str());
// Run the descrambler over the encrypted section containing BS1/BS2
CEXIIPL::Descrambler((u8*)data.data() + 0x100, 0x1AFE00);
// Run the descrambler over the encrypted section containing BS1/BS2
CEXIIPL::Descrambler((u8*)data.data() + 0x100, 0x1AFE00);
// TODO: Execution is supposed to start at 0xFFF00000, not 0x81200000;
// copying the initial boot code to 0x81200000 is a hack.
// For now, HLE the first few instructions and start at 0x81200150
// to work around this.
Memory::CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
Memory::CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00);
PowerPC::ppcState.gpr[3] = 0xfff0001f;
PowerPC::ppcState.gpr[4] = 0x00002030;
PowerPC::ppcState.gpr[5] = 0x0000009c;
PowerPC::ppcState.msr = 0x00002030;
PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001;
PC = 0x81200150;
return true;
// TODO: Execution is supposed to start at 0xFFF00000, not 0x81200000;
// copying the initial boot code to 0x81200000 is a hack.
// For now, HLE the first few instructions and start at 0x81200150
// to work around this.
Memory::CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
Memory::CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00);
PowerPC::ppcState.gpr[3] = 0xfff0001f;
PowerPC::ppcState.gpr[4] = 0x00002030;
PowerPC::ppcState.gpr[5] = 0x0000009c;
PowerPC::ppcState.msr = 0x00002030;
PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001;
PC = 0x81200150;
return true;
}
// Third boot step after BootManager and Core. See Call schedule in BootManager.cpp
bool CBoot::BootUp()
{
SConfig& _StartupPara = SConfig::GetInstance();
SConfig& _StartupPara = SConfig::GetInstance();
NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str());
NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str());
g_symbolDB.Clear();
g_symbolDB.Clear();
// PAL Wii uses NTSC framerate and linecount in 60Hz modes
VideoInterface::Preset(_StartupPara.bNTSC || (_StartupPara.bWii && _StartupPara.bPAL60));
// PAL Wii uses NTSC framerate and linecount in 60Hz modes
VideoInterface::Preset(_StartupPara.bNTSC || (_StartupPara.bWii && _StartupPara.bPAL60));
switch (_StartupPara.m_BootType)
{
// GCM and Wii
case SConfig::BOOT_ISO:
{
DVDInterface::SetVolumeName(_StartupPara.m_strFilename);
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
if (!DVDInterface::VolumeIsValid())
return false;
switch (_StartupPara.m_BootType)
{
// GCM and Wii
case SConfig::BOOT_ISO:
{
DVDInterface::SetVolumeName(_StartupPara.m_strFilename);
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
if (!DVDInterface::VolumeIsValid())
return false;
const DiscIO::IVolume& pVolume = DVDInterface::GetVolume();
const DiscIO::IVolume& pVolume = DVDInterface::GetVolume();
if ((pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC) != _StartupPara.bWii)
{
PanicAlertT("Warning - starting ISO in wrong console mode!");
}
if ((pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC) != _StartupPara.bWii)
{
PanicAlertT("Warning - starting ISO in wrong console mode!");
}
std::string unique_id = DVDInterface::GetVolume().GetUniqueID();
if (unique_id.size() >= 4)
VideoInterface::SetRegionReg(unique_id.at(3));
std::string unique_id = DVDInterface::GetVolume().GetUniqueID();
if (unique_id.size() >= 4)
VideoInterface::SetRegionReg(unique_id.at(3));
std::vector<u8> tmd_buffer = pVolume.GetTMD();
if (!tmd_buffer.empty())
{
WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer);
}
std::vector<u8> tmd_buffer = pVolume.GetTMD();
if (!tmd_buffer.empty())
{
WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer);
}
_StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC;
_StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC;
// HLE BS2 or not
if (_StartupPara.bHLE_BS2)
{
EmulatedBS2(_StartupPara.bWii);
}
else if (!Load_BS2(_StartupPara.m_strBootROM))
{
// If we can't load the bootrom file we HLE it instead
EmulatedBS2(_StartupPara.bWii);
}
else
{
// Load patches if they weren't already
PatchEngine::LoadPatches();
}
// HLE BS2 or not
if (_StartupPara.bHLE_BS2)
{
EmulatedBS2(_StartupPara.bWii);
}
else if (!Load_BS2(_StartupPara.m_strBootROM))
{
// If we can't load the bootrom file we HLE it instead
EmulatedBS2(_StartupPara.bWii);
}
else
{
// Load patches if they weren't already
PatchEngine::LoadPatches();
}
// Scan for common HLE functions
if (_StartupPara.bSkipIdle && _StartupPara.bHLE_BS2 && !_StartupPara.bEnableDebugging)
{
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
SignatureDB db;
if (db.Load(File::GetSysDirectory() + TOTALDB))
{
db.Apply(&g_symbolDB);
HLE::PatchFunctions();
db.Clear();
}
}
// Scan for common HLE functions
if (_StartupPara.bSkipIdle && _StartupPara.bHLE_BS2 && !_StartupPara.bEnableDebugging)
{
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
SignatureDB db;
if (db.Load(File::GetSysDirectory() + TOTALDB))
{
db.Apply(&g_symbolDB);
HLE::PatchFunctions();
db.Clear();
}
}
// Try to load the symbol map if there is one, and then scan it for
// and eventually replace code
if (LoadMapFromFilename())
HLE::PatchFunctions();
// Try to load the symbol map if there is one, and then scan it for
// and eventually replace code
if (LoadMapFromFilename())
HLE::PatchFunctions();
break;
}
break;
}
// DOL
case SConfig::BOOT_DOL:
{
CDolLoader dolLoader(_StartupPara.m_strFilename);
if (!dolLoader.IsValid())
return false;
// DOL
case SConfig::BOOT_DOL:
{
CDolLoader dolLoader(_StartupPara.m_strFilename);
if (!dolLoader.IsValid())
return false;
// Check if we have gotten a Wii file or not
bool dolWii = dolLoader.IsWii();
if (dolWii != _StartupPara.bWii)
{
PanicAlertT("Warning - starting DOL in wrong console mode!");
}
// Check if we have gotten a Wii file or not
bool dolWii = dolLoader.IsWii();
if (dolWii != _StartupPara.bWii)
{
PanicAlertT("Warning - starting DOL in wrong console mode!");
}
bool BS2Success = false;
bool BS2Success = false;
if (dolWii)
{
BS2Success = EmulatedBS2(dolWii);
}
else if ((!DVDInterface::VolumeIsValid() || DVDInterface::GetVolume().GetVolumeType() != DiscIO::IVolume::WII_DISC) &&
!_StartupPara.m_strDefaultISO.empty())
{
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
BS2Success = EmulatedBS2(dolWii);
}
if (dolWii)
{
BS2Success = EmulatedBS2(dolWii);
}
else if ((!DVDInterface::VolumeIsValid() ||
DVDInterface::GetVolume().GetVolumeType() != DiscIO::IVolume::WII_DISC) &&
!_StartupPara.m_strDefaultISO.empty())
{
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
BS2Success = EmulatedBS2(dolWii);
}
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii, _StartupPara.m_strApploader, _StartupPara.m_strFilename);
BS2Success = EmulatedBS2(dolWii);
}
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii,
_StartupPara.m_strApploader, _StartupPara.m_strFilename);
BS2Success = EmulatedBS2(dolWii);
}
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
if (!BS2Success)
{
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
if (!BS2Success)
{
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
dolLoader.Load();
PC = dolLoader.GetEntryPoint();
}
dolLoader.Load();
PC = dolLoader.GetEntryPoint();
}
if (LoadMapFromFilename())
HLE::PatchFunctions();
if (LoadMapFromFilename())
HLE::PatchFunctions();
break;
}
break;
}
// ELF
case SConfig::BOOT_ELF:
{
// load image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii);
}
else if (!_StartupPara.m_strDefaultISO.empty())
{
NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str());
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
}
else
{
DVDInterface::SetVolumeDirectory(_StartupPara.m_strFilename, _StartupPara.bWii);
}
// ELF
case SConfig::BOOT_ELF:
{
// load image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii);
}
else if (!_StartupPara.m_strDefaultISO.empty())
{
NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str());
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
}
else
{
DVDInterface::SetVolumeDirectory(_StartupPara.m_strFilename, _StartupPara.bWii);
}
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
// Poor man's bootup
if(_StartupPara.bWii)
SetupWiiMemory(DiscIO::IVolume::COUNTRY_UNKNOWN);
else
EmulatedBS2_GC(true);
// Poor man's bootup
if (_StartupPara.bWii)
SetupWiiMemory(DiscIO::IVolume::COUNTRY_UNKNOWN);
else
EmulatedBS2_GC(true);
Load_FST(_StartupPara.bWii);
if(!Boot_ELF(_StartupPara.m_strFilename))
return false;
Load_FST(_StartupPara.bWii);
if (!Boot_ELF(_StartupPara.m_strFilename))
return false;
UpdateDebugger_MapLoaded();
Dolphin_Debugger::AddAutoBreakpoints();
break;
}
UpdateDebugger_MapLoaded();
Dolphin_Debugger::AddAutoBreakpoints();
break;
}
// Wii WAD
case SConfig::BOOT_WII_NAND:
Boot_WiiWAD(_StartupPara.m_strFilename);
// Wii WAD
case SConfig::BOOT_WII_NAND:
Boot_WiiWAD(_StartupPara.m_strFilename);
if (LoadMapFromFilename())
HLE::PatchFunctions();
if (LoadMapFromFilename())
HLE::PatchFunctions();
// load default image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true);
else if (!_StartupPara.m_strDefaultISO.empty())
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
// load default image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true);
else if (!_StartupPara.m_strDefaultISO.empty())
DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO);
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
break;
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
break;
// Bootstrap 2 (AKA: Initial Program Loader, "BIOS")
case SConfig::BOOT_BS2:
{
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
if (Load_BS2(_StartupPara.m_strBootROM))
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
return false;
}
break;
}
// Bootstrap 2 (AKA: Initial Program Loader, "BIOS")
case SConfig::BOOT_BS2:
{
DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid());
if (Load_BS2(_StartupPara.m_strBootROM))
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
return false;
}
break;
}
case SConfig::BOOT_DFF:
// do nothing
break;
case SConfig::BOOT_DFF:
// do nothing
break;
default:
{
PanicAlertT("Tried to load an unknown file type.");
return false;
}
}
default:
{
PanicAlertT("Tried to load an unknown file type.");
return false;
}
}
// HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code
// handler
if (!SConfig::GetInstance().bEnableCheats)
{
HLE::Patch(0x80001800, "HBReload");
Memory::CopyToEmu(0x00001804, "STUBHAXX", 8);
}
// HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler
if (!SConfig::GetInstance().bEnableCheats)
{
HLE::Patch(0x80001800, "HBReload");
Memory::CopyToEmu(0x00001804, "STUBHAXX", 8);
}
// Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly.
HLE::Patch(0x800018a8, "GeckoCodehandler");
return true;
// Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly.
HLE::Patch(0x800018a8, "GeckoCodehandler");
return true;
}

View file

@ -11,50 +11,48 @@
struct CountrySetting
{
const std::string area;
const std::string video;
const std::string game;
const std::string code;
const std::string area;
const std::string video;
const std::string game;
const std::string code;
};
class CBoot
{
public:
static bool BootUp();
static bool IsElfWii(const std::string& filename);
static bool BootUp();
static bool IsElfWii(const std::string& filename);
// Tries to find a map file for the current game by looking first in the
// local user directory, then in the shared user directory.
//
// If existing_map_file is not nullptr and a map file exists, it is set to the
// path to the existing map file.
//
// If writable_map_file is not nullptr, it is set to the path to where a map
// file should be saved.
//
// If title_id is not nullptr, it is set to the title id
//
// Returns true if a map file exists, false if none could be found.
static bool FindMapFile(std::string* existing_map_file,
std::string* writable_map_file,
std::string* title_id = nullptr);
// Tries to find a map file for the current game by looking first in the
// local user directory, then in the shared user directory.
//
// If existing_map_file is not nullptr and a map file exists, it is set to the
// path to the existing map file.
//
// If writable_map_file is not nullptr, it is set to the path to where a map
// file should be saved.
//
// If title_id is not nullptr, it is set to the title id
//
// Returns true if a map file exists, false if none could be found.
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file,
std::string* title_id = nullptr);
private:
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
static void RunFunction(u32 _iAddr);
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
static void RunFunction(u32 _iAddr);
static void UpdateDebugger_MapLoaded();
static void UpdateDebugger_MapLoaded();
static bool LoadMapFromFilename();
static bool Boot_ELF(const std::string& filename);
static bool Boot_WiiWAD(const std::string& filename);
static bool LoadMapFromFilename();
static bool Boot_ELF(const std::string& filename);
static bool Boot_WiiWAD(const std::string& filename);
static bool EmulatedBS2_GC(bool skipAppLoader = false);
static bool EmulatedBS2_Wii();
static bool EmulatedBS2(bool _bIsWii);
static bool Load_BS2(const std::string& _rBootROMFilename);
static void Load_FST(bool _bIsWii);
static bool EmulatedBS2_GC(bool skipAppLoader = false);
static bool EmulatedBS2_Wii();
static bool EmulatedBS2(bool _bIsWii);
static bool Load_BS2(const std::string& _rBootROMFilename);
static void Load_FST(bool _bIsWii);
static bool SetupWiiMemory(DiscIO::IVolume::ECountry country);
static bool SetupWiiMemory(DiscIO::IVolume::ECountry country);
};

View file

@ -8,25 +8,25 @@
#include "Common/NandPaths.h"
#include "Common/SettingsHandler.h"
#include "Core/Boot/Boot.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/MemTools.h"
#include "Core/PatchEngine.h"
#include "Core/Boot/Boot.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/CPU.h"
#include "Core/HW/DVDInterface.h"
#include "Core/HW/EXI_DeviceIPL.h"
#include "Core/HW/Memmap.h"
#include "Core/MemTools.h"
#include "Core/PatchEngine.h"
#include "Core/PowerPC/PowerPC.h"
void CBoot::RunFunction(u32 _iAddr)
{
PC = _iAddr;
LR = 0x00;
PC = _iAddr;
LR = 0x00;
while (PC != 0x00)
PowerPC::SingleStep();
while (PC != 0x00)
PowerPC::SingleStep();
}
// __________________________________________________________________________________________________
@ -35,282 +35,293 @@ void CBoot::RunFunction(u32 _iAddr)
// execute the apploader, function by function, using the above utility.
bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
{
INFO_LOG(BOOT, "Faking GC BS2...");
INFO_LOG(BOOT, "Faking GC BS2...");
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
// Write necessary values
// Here we write values to memory that the apploader does not take care of. Game info goes
// to 0x80000000 according to YAGCD 4.2.
// Write necessary values
// Here we write values to memory that the apploader does not take care of. Game info goes
// to 0x80000000 according to YAGCD 4.2.
// It's possible to boot DOL and ELF files without a disc inserted
if (DVDInterface::VolumeIsValid())
DVDRead(/*offset*/0x00000000, /*address*/0x00000000, 0x20, false); // write disc info
// It's possible to boot DOL and ELF files without a disc inserted
if (DVDInterface::VolumeIsValid())
DVDRead(/*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false); // write disc info
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag
PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
// TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths, see Ikaruga for example)
PowerPC::HostWrite_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
PowerPC::HostWrite_U32(0x0D15EA5E,
0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag
PowerPC::HostWrite_U32(Memory::REALRAM_SIZE,
0x80000028); // Physical Memory Size (24MB on retail)
// TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths,
// see Ikaruga for example)
PowerPC::HostWrite_U32(
0x10000006,
0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
PowerPC::HostWrite_U32(SConfig::GetInstance().bNTSC
? 0 : 1, 0x800000CC); // Fake the VI Init of the IPL (YAGCD 4.2.1.4)
PowerPC::HostWrite_U32(SConfig::GetInstance().bNTSC ? 0 : 1,
0x800000CC); // Fake the VI Init of the IPL (YAGCD 4.2.1.4)
PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external
// (retail consoles have no external ARAM)
PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // Preset time base ticks
// HIO checks this
//PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type
PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000,
0x800030D8); // Preset time base ticks
// HIO checks this
// PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
if (!DVDInterface::VolumeIsValid())
return false;
if (!DVDInterface::VolumeIsValid())
return false;
// Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
// but the size can differ between discs. Compare with YAGCD chap 13.
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
const u32 apploader_offset = 0x2440;
u32 apploader_entry, apploader_size, apploader_trailer;
if (skipAppLoader ||
!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, false) ||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, false) ||
!volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, false) ||
apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1)
{
INFO_LOG(BOOT, "GC BS2: Not running apploader!");
return false;
}
DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, false);
// Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
// but the size can differ between discs. Compare with YAGCD chap 13.
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
const u32 apploader_offset = 0x2440;
u32 apploader_entry, apploader_size, apploader_trailer;
if (skipAppLoader || !volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, false) ||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, false) ||
!volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, false) ||
apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1)
{
INFO_LOG(BOOT, "GC BS2: Not running apploader!");
return false;
}
DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, false);
// Setup pointers like real BS2 does
if (SConfig::GetInstance().bNTSC)
{
PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0
PowerPC::ppcState.gpr[2] = 0x81465cc0; // Global pointer to Small Data Area 2 Base (haven't seen anything use it...meh)
PowerPC::ppcState.gpr[13] = 0x81465320; // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
}
else
{
PowerPC::ppcState.gpr[1] = 0x815edca8;
PowerPC::ppcState.gpr[2] = 0x814b5b20;
PowerPC::ppcState.gpr[13] = 0x814b4fc0;
}
// Setup pointers like real BS2 does
if (SConfig::GetInstance().bNTSC)
{
PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0
PowerPC::ppcState.gpr[2] = 0x81465cc0; // Global pointer to Small Data Area 2 Base (haven't
// seen anything use it...meh)
PowerPC::ppcState.gpr[13] =
0x81465320; // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
}
else
{
PowerPC::ppcState.gpr[1] = 0x815edca8;
PowerPC::ppcState.gpr[2] = 0x814b5b20;
PowerPC::ppcState.gpr[13] = 0x814b4fc0;
}
// TODO - Make Apploader(or just RunFunction()) debuggable!!!
// TODO - Make Apploader(or just RunFunction()) debuggable!!!
// Call iAppLoaderEntry.
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry");
u32 iAppLoaderFuncAddr = 0x80003100;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(apploader_entry);
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
// Call iAppLoaderEntry.
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry");
u32 iAppLoaderFuncAddr = 0x80003100;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(apploader_entry);
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
// iAppLoaderInit
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
// iAppLoaderInit
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
// iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
// To give you an idea about where the stuff is located on the disc take a look at yagcd
// ch 13.
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
// iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
// To give you an idea about where the stuff is located on the disc take a look at yagcd
// ch 13.
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
RunFunction(iAppLoaderMain);
RunFunction(iAppLoaderMain);
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
u32 iLength = PowerPC::Read_U32(0x81300008);
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c);
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
u32 iLength = PowerPC::Read_U32(0x81300008);
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c);
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDRead(iDVDOffset, iRamAddress, iLength, false);
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset,
iRamAddress, iLength);
DVDRead(iDVDOffset, iRamAddress, iLength, false);
} while (PowerPC::ppcState.gpr[3] != 0x00);
} while (PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
RunFunction(iAppLoaderClose);
// iAppLoaderClose
DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
RunFunction(iAppLoaderClose);
// return
PC = PowerPC::ppcState.gpr[3];
// return
PC = PowerPC::ppcState.gpr[3];
// Load patches
PatchEngine::LoadPatches();
// Load patches
PatchEngine::LoadPatches();
// If we have any patches that need to be applied very early, here's a good place
PatchEngine::ApplyFramePatches();
// If we have any patches that need to be applied very early, here's a good place
PatchEngine::ApplyFramePatches();
return true;
return true;
}
bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country)
{
static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"};
static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"};
static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"};
static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"};
static const std::map<DiscIO::IVolume::ECountry, const CountrySetting> country_settings = {
{DiscIO::IVolume::COUNTRY_EUROPE, SETTING_EUROPE},
{DiscIO::IVolume::COUNTRY_USA, SETTING_USA},
{DiscIO::IVolume::COUNTRY_JAPAN, SETTING_JAPAN},
{DiscIO::IVolume::COUNTRY_KOREA, SETTING_KOREA},
//TODO: Determine if Taiwan have their own specific settings.
// Also determine if there are other specific settings
// for other countries.
{DiscIO::IVolume::COUNTRY_TAIWAN, SETTING_JAPAN}
};
auto entryPos = country_settings.find(country);
const CountrySetting& country_setting =
(entryPos != country_settings.end()) ?
entryPos->second :
(SConfig::GetInstance().bNTSC ? SETTING_USA : SETTING_EUROPE); // default to USA or EUR depending on game's video mode
static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"};
static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"};
static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"};
static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"};
static const std::map<DiscIO::IVolume::ECountry, const CountrySetting> country_settings = {
{DiscIO::IVolume::COUNTRY_EUROPE, SETTING_EUROPE},
{DiscIO::IVolume::COUNTRY_USA, SETTING_USA},
{DiscIO::IVolume::COUNTRY_JAPAN, SETTING_JAPAN},
{DiscIO::IVolume::COUNTRY_KOREA, SETTING_KOREA},
// TODO: Determine if Taiwan have their own specific settings.
// Also determine if there are other specific settings
// for other countries.
{DiscIO::IVolume::COUNTRY_TAIWAN, SETTING_JAPAN}};
auto entryPos = country_settings.find(country);
const CountrySetting& country_setting =
(entryPos != country_settings.end()) ?
entryPos->second :
(SConfig::GetInstance().bNTSC ?
SETTING_USA :
SETTING_EUROPE); // default to USA or EUR depending on game's video mode
SettingsHandler gen;
std::string serno;
std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING);
if (File::Exists(settings_Filename))
{
File::IOFile settingsFileHandle(settings_Filename, "rb");
if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE))
{
gen.Decrypt();
serno = gen.GetValue("SERNO");
gen.Reset();
}
File::Delete(settings_Filename);
}
SettingsHandler gen;
std::string serno;
std::string settings_Filename(
Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING);
if (File::Exists(settings_Filename))
{
File::IOFile settingsFileHandle(settings_Filename, "rb");
if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE))
{
gen.Decrypt();
serno = gen.GetValue("SERNO");
gen.Reset();
}
File::Delete(settings_Filename);
}
if (serno.empty() || serno == "000000000")
{
if (Core::g_want_determinism)
serno = "123456789";
else
serno = gen.generateSerialNumber();
INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str());
}
else
{
INFO_LOG(BOOT, "Using serial number: %s", serno.c_str());
}
if (serno.empty() || serno == "000000000")
{
if (Core::g_want_determinism)
serno = "123456789";
else
serno = gen.generateSerialNumber();
INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str());
}
else
{
INFO_LOG(BOOT, "Using serial number: %s", serno.c_str());
}
std::string model = "RVL-001(" + country_setting.area + ")";
gen.AddSetting("AREA", country_setting.area);
gen.AddSetting("MODEL", model);
gen.AddSetting("DVD", "0");
gen.AddSetting("MPCH", "0x7FFE");
gen.AddSetting("CODE", country_setting.code);
gen.AddSetting("SERNO", serno);
gen.AddSetting("VIDEO", country_setting.video);
gen.AddSetting("GAME", country_setting.game);
std::string model = "RVL-001(" + country_setting.area + ")";
gen.AddSetting("AREA", country_setting.area);
gen.AddSetting("MODEL", model);
gen.AddSetting("DVD", "0");
gen.AddSetting("MPCH", "0x7FFE");
gen.AddSetting("CODE", country_setting.code);
gen.AddSetting("SERNO", serno);
gen.AddSetting("VIDEO", country_setting.video);
gen.AddSetting("GAME", country_setting.game);
File::CreateFullPath(settings_Filename);
{
File::IOFile settingsFileHandle(settings_Filename, "wb");
File::CreateFullPath(settings_Filename);
{
File::IOFile settingsFileHandle(settings_Filename, "wb");
if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE))
{
PanicAlertT("SetupWiiMemory: Can't create setting.txt file");
return false;
}
// Write the 256 byte setting.txt to memory.
Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE);
}
if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE))
{
PanicAlertT("SetupWiiMemory: Can't create setting.txt file");
return false;
}
// Write the 256 byte setting.txt to memory.
Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE);
}
INFO_LOG(BOOT, "Setup Wii Memory...");
INFO_LOG(BOOT, "Setup Wii Memory...");
/*
Set hardcoded global variables to Wii memory. These are partly collected from
WiiBrew. These values are needed for the games to function correctly. A few
values in this region will also be placed here by the game as it boots.
They are:
0x80000038 Start of FST
0x8000003c Size of FST Size
0x80000060 Copyright code
*/
/*
Set hardcoded global variables to Wii memory. These are partly collected from
WiiBrew. These values are needed for the games to function correctly. A few
values in this region will also be placed here by the game as it boots.
They are:
0x80000038 Start of FST
0x8000003c Size of FST Size
0x80000060 Copyright code
*/
// When booting a WAD or the system menu, there will probably not be a disc inserted
if (DVDInterface::VolumeIsValid())
DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
// When booting a WAD or the system menu, there will probably not be a disc inserted
if (DVDInterface::VolumeIsValid())
DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
Memory::Write_U32(0x00000000, 0x00000030); // Init
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
// 38, 3C should get start, size of FST through apploader
Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
Memory::Write_U16(0x0000, 0x000030e6); // Console type
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
Memory::Write_U32(0x00000000, 0x000030dc); // Time
Memory::Write_U32(0x00000000, 0x000030d8); // Time
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
Memory::Write_U32(0x01800000, 0x00003100); // BAT
Memory::Write_U32(0x01800000, 0x00003104); // BAT
Memory::Write_U32(0x00000000, 0x0000310c); // Init
Memory::Write_U32(0x8179d500, 0x00003110); // Init
Memory::Write_U32(0x04000000, 0x00003118); // Unknown
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
Memory::Write_U32(0x93400000, 0x00003120); // BAT
Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high
Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low
Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high
Memory::Write_U32(0x00000012, 0x00003138); // Console type
// 40 is copied from 88 after running apploader
Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear)
Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
Memory::Write_U32(0x00000000, 0x00000030); // Init
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
// 38, 3C should get start, size of FST through apploader
Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
Memory::Write_U16(0x0000, 0x000030e6); // Console type
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
Memory::Write_U32(0x00000000, 0x000030dc); // Time
Memory::Write_U32(0x00000000, 0x000030d8); // Time
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
Memory::Write_U32(0x01800000, 0x00003100); // BAT
Memory::Write_U32(0x01800000, 0x00003104); // BAT
Memory::Write_U32(0x00000000, 0x0000310c); // Init
Memory::Write_U32(0x8179d500, 0x00003110); // Init
Memory::Write_U32(0x04000000, 0x00003118); // Unknown
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
Memory::Write_U32(0x93400000, 0x00003120); // BAT
Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high
Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low
Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high
Memory::Write_U32(0x00000012, 0x00003138); // Console type
// 40 is copied from 88 after running apploader
Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear)
Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision
Memory::Write_U8(0x80, 0x0000315c); // OSInit
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
Memory::Write_U32(0x80000000, 0x00003184); // GameID Address
Memory::Write_U8(0x80, 0x0000315c); // OSInit
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
Memory::Write_U32(0x80000000, 0x00003184); // GameID Address
// Fake the VI Init of the IPL
Memory::Write_U32(SConfig::GetInstance().bNTSC ? 0 : 1, 0x000000CC);
// Fake the VI Init of the IPL
Memory::Write_U32(SConfig::GetInstance().bNTSC ? 0 : 1, 0x000000CC);
// Clear exception handler. Why? Don't we begin with only zeros?
for (int i = 0x3000; i <= 0x3038; i += 4)
{
Memory::Write_U32(0x00000000, i);
}
return true;
// Clear exception handler. Why? Don't we begin with only zeros?
for (int i = 0x3000; i <= 0x3038; i += 4)
{
Memory::Write_U32(0x00000000, i);
}
return true;
}
// __________________________________________________________________________________________________
@ -319,129 +330,131 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country)
// execute the apploader
bool CBoot::EmulatedBS2_Wii()
{
INFO_LOG(BOOT, "Faking Wii BS2...");
INFO_LOG(BOOT, "Faking Wii BS2...");
// Setup Wii memory
DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN;
if (DVDInterface::VolumeIsValid())
country_code = DVDInterface::GetVolume().GetCountry();
if (SetupWiiMemory(country_code) == false)
return false;
// Setup Wii memory
DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN;
if (DVDInterface::VolumeIsValid())
country_code = DVDInterface::GetVolume().GetCountry();
if (SetupWiiMemory(country_code) == false)
return false;
// Execute the apploader
bool apploaderRan = false;
if (DVDInterface::VolumeIsValid() && DVDInterface::GetVolume().GetVolumeType() == DiscIO::IVolume::WII_DISC)
{
// This is some kind of consistency check that is compared to the 0x00
// values as the game boots. This location keeps the 4 byte ID for as long
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
// after this check during booting.
DVDRead(0, 0x3180, 4, true);
// Execute the apploader
bool apploaderRan = false;
if (DVDInterface::VolumeIsValid() &&
DVDInterface::GetVolume().GetVolumeType() == DiscIO::IVolume::WII_DISC)
{
// This is some kind of consistency check that is compared to the 0x00
// values as the game boots. This location keeps the 4 byte ID for as long
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
// after this check during booting.
DVDRead(0, 0x3180, 4, true);
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
Memory::Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi
Memory::Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi
Memory::Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi
Memory::Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
const u32 apploader_offset = 0x2440; // 0x1c40;
const u32 apploader_offset = 0x2440; // 0x1c40;
// Load Apploader to Memory
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
u32 apploader_entry, apploader_size;
if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, true) ||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, true) ||
apploader_entry == (u32)-1 || apploader_size == (u32)-1)
{
ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
return false;
}
DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size, true);
// Load Apploader to Memory
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
u32 apploader_entry, apploader_size;
if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, true) ||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, true) ||
apploader_entry == (u32)-1 || apploader_size == (u32)-1)
{
ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
return false;
}
DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size, true);
//call iAppLoaderEntry
DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
// call iAppLoaderEntry
DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
u32 iAppLoaderFuncAddr = 0x80004000;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(apploader_entry);
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
u32 iAppLoaderFuncAddr = 0x80004000;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(apploader_entry);
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
// iAppLoaderInit
DEBUG_LOG(BOOT, "Run iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
// iAppLoaderInit
DEBUG_LOG(BOOT, "Run iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
// Let the apploader load the exe to memory. At this point I get an unknown IPC command
// (command zero) when I load Wii Sports or other games a second time. I don't notice
// any side effects however. It's a little disconcerting however that Start after Stop
// behaves differently than the first Start after starting Dolphin. It means something
// was not reset correctly.
DEBUG_LOG(BOOT, "Run iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
// Let the apploader load the exe to memory. At this point I get an unknown IPC command
// (command zero) when I load Wii Sports or other games a second time. I don't notice
// any side effects however. It's a little disconcerting however that Start after Stop
// behaves differently than the first Start after starting Dolphin. It means something
// was not reset correctly.
DEBUG_LOG(BOOT, "Run iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
RunFunction(iAppLoaderMain);
RunFunction(iAppLoaderMain);
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
u32 iLength = PowerPC::Read_U32(0x81300008);
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2;
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
u32 iLength = PowerPC::Read_U32(0x81300008);
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2;
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDRead(iDVDOffset, iRamAddress, iLength, true);
} while (PowerPC::ppcState.gpr[3] != 0x00);
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset,
iRamAddress, iLength);
DVDRead(iDVDOffset, iRamAddress, iLength, true);
} while (PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
DEBUG_LOG(BOOT, "Run iAppLoaderClose");
RunFunction(iAppLoaderClose);
// iAppLoaderClose
DEBUG_LOG(BOOT, "Run iAppLoaderClose");
RunFunction(iAppLoaderClose);
apploaderRan = true;
apploaderRan = true;
// Pass the "#002 check"
// Apploader writes the IOS version and revision here, we copy it
// Fake IOSv9 r2.4 if no version is found (elf loading)
u32 firmwareVer = PowerPC::Read_U32(0x80003188);
PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140);
// Pass the "#002 check"
// Apploader writes the IOS version and revision here, we copy it
// Fake IOSv9 r2.4 if no version is found (elf loading)
u32 firmwareVer = PowerPC::Read_U32(0x80003188);
PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140);
// Load patches and run startup patches
PatchEngine::LoadPatches();
// Load patches and run startup patches
PatchEngine::LoadPatches();
// return
PC = PowerPC::ppcState.gpr[3];
}
// return
PC = PowerPC::ppcState.gpr[3];
}
return apploaderRan;
return apploaderRan;
}
// Returns true if apploader has run successfully
bool CBoot::EmulatedBS2(bool _bIsWii)
{
return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC();
return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC();
}

View file

@ -14,20 +14,20 @@
CDolLoader::CDolLoader(const std::vector<u8>& buffer)
{
m_is_valid = Initialize(buffer);
m_is_valid = Initialize(buffer);
}
CDolLoader::CDolLoader(const std::string& filename)
{
const u64 size = File::GetSize(filename);
std::vector<u8> temp_buffer(size);
const u64 size = File::GetSize(filename);
std::vector<u8> temp_buffer(size);
{
File::IOFile pStream(filename, "rb");
pStream.ReadBytes(temp_buffer.data(), temp_buffer.size());
}
{
File::IOFile pStream(filename, "rb");
pStream.ReadBytes(temp_buffer.data(), temp_buffer.size());
}
m_is_valid = Initialize(temp_buffer);
m_is_valid = Initialize(temp_buffer);
}
CDolLoader::~CDolLoader()
@ -36,76 +36,78 @@ CDolLoader::~CDolLoader()
bool CDolLoader::Initialize(const std::vector<u8>& buffer)
{
if (buffer.size() < sizeof(SDolHeader))
return false;
if (buffer.size() < sizeof(SDolHeader))
return false;
memcpy(&m_dolheader, buffer.data(), sizeof(SDolHeader));
memcpy(&m_dolheader, buffer.data(), sizeof(SDolHeader));
// swap memory
u32* p = (u32*)&m_dolheader;
for (size_t i = 0; i < (sizeof(SDolHeader) / sizeof(u32)); i++)
p[i] = Common::swap32(p[i]);
// swap memory
u32* p = (u32*)&m_dolheader;
for (size_t i = 0; i < (sizeof(SDolHeader) / sizeof(u32)); i++)
p[i] = Common::swap32(p[i]);
const u32 HID4_pattern = Common::swap32(0x7c13fba6);
const u32 HID4_mask = Common::swap32(0xfc1fffff);
const u32 HID4_pattern = Common::swap32(0x7c13fba6);
const u32 HID4_mask = Common::swap32(0xfc1fffff);
m_is_wii = false;
m_is_wii = false;
m_text_sections.reserve(DOL_NUM_TEXT);
for (int i = 0; i < DOL_NUM_TEXT; ++i)
{
if (m_dolheader.textSize[i] != 0)
{
if (buffer.size() < m_dolheader.textOffset[i] + m_dolheader.textSize[i])
return false;
m_text_sections.reserve(DOL_NUM_TEXT);
for (int i = 0; i < DOL_NUM_TEXT; ++i)
{
if (m_dolheader.textSize[i] != 0)
{
if (buffer.size() < m_dolheader.textOffset[i] + m_dolheader.textSize[i])
return false;
const u8* text_start = &buffer[m_dolheader.textOffset[i]];
m_text_sections.emplace_back(text_start, &text_start[m_dolheader.textSize[i]]);
const u8* text_start = &buffer[m_dolheader.textOffset[i]];
m_text_sections.emplace_back(text_start, &text_start[m_dolheader.textSize[i]]);
for (unsigned int j = 0; !m_is_wii && j < (m_dolheader.textSize[i] / sizeof(u32)); ++j)
{
u32 word = ((u32*)text_start)[j];
if ((word & HID4_mask) == HID4_pattern)
m_is_wii = true;
}
}
else
{
// Make sure that m_text_sections indexes match header indexes
m_text_sections.emplace_back();
}
}
for (unsigned int j = 0; !m_is_wii && j < (m_dolheader.textSize[i] / sizeof(u32)); ++j)
{
u32 word = ((u32*)text_start)[j];
if ((word & HID4_mask) == HID4_pattern)
m_is_wii = true;
}
}
else
{
// Make sure that m_text_sections indexes match header indexes
m_text_sections.emplace_back();
}
}
m_data_sections.reserve(DOL_NUM_DATA);
for (int i = 0; i < DOL_NUM_DATA; ++i)
{
if (m_dolheader.dataSize[i] != 0)
{
if (buffer.size() < m_dolheader.dataOffset[i] + m_dolheader.dataSize[i])
return false;
m_data_sections.reserve(DOL_NUM_DATA);
for (int i = 0; i < DOL_NUM_DATA; ++i)
{
if (m_dolheader.dataSize[i] != 0)
{
if (buffer.size() < m_dolheader.dataOffset[i] + m_dolheader.dataSize[i])
return false;
const u8* data_start = &buffer[m_dolheader.dataOffset[i]];
m_data_sections.emplace_back(data_start, &data_start[m_dolheader.dataSize[i]]);
}
else
{
// Make sure that m_data_sections indexes match header indexes
m_data_sections.emplace_back();
}
}
const u8* data_start = &buffer[m_dolheader.dataOffset[i]];
m_data_sections.emplace_back(data_start, &data_start[m_dolheader.dataSize[i]]);
}
else
{
// Make sure that m_data_sections indexes match header indexes
m_data_sections.emplace_back();
}
}
return true;
return true;
}
void CDolLoader::Load() const
{
// load all text (code) sections
for (size_t i = 0; i < m_text_sections.size(); ++i)
if (!m_text_sections[i].empty())
Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(), m_text_sections[i].size());
// load all text (code) sections
for (size_t i = 0; i < m_text_sections.size(); ++i)
if (!m_text_sections[i].empty())
Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(),
m_text_sections[i].size());
// load all data sections
for (size_t i = 0; i < m_data_sections.size(); ++i)
if (!m_data_sections[i].empty())
Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(), m_data_sections[i].size());
// load all data sections
for (size_t i = 0; i < m_data_sections.size(); ++i)
if (!m_data_sections[i].empty())
Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(),
m_data_sections[i].size());
}

View file

@ -12,47 +12,46 @@
class CDolLoader
{
public:
CDolLoader(const std::string& filename);
CDolLoader(const std::vector<u8>& buffer);
~CDolLoader();
CDolLoader(const std::string& filename);
CDolLoader(const std::vector<u8>& buffer);
~CDolLoader();
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 { 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;
private:
enum
{
DOL_NUM_TEXT = 7,
DOL_NUM_DATA = 11
};
enum
{
DOL_NUM_TEXT = 7,
DOL_NUM_DATA = 11
};
struct SDolHeader
{
u32 textOffset[DOL_NUM_TEXT];
u32 dataOffset[DOL_NUM_DATA];
struct SDolHeader
{
u32 textOffset[DOL_NUM_TEXT];
u32 dataOffset[DOL_NUM_DATA];
u32 textAddress[DOL_NUM_TEXT];
u32 dataAddress[DOL_NUM_DATA];
u32 textAddress[DOL_NUM_TEXT];
u32 dataAddress[DOL_NUM_DATA];
u32 textSize[DOL_NUM_TEXT];
u32 dataSize[DOL_NUM_DATA];
u32 textSize[DOL_NUM_TEXT];
u32 dataSize[DOL_NUM_DATA];
u32 bssAddress;
u32 bssSize;
u32 entryPoint;
};
SDolHeader m_dolheader;
u32 bssAddress;
u32 bssSize;
u32 entryPoint;
};
SDolHeader m_dolheader;
std::vector<std::vector<u8>> m_data_sections;
std::vector<std::vector<u8>> m_text_sections;
std::vector<std::vector<u8>> m_data_sections;
std::vector<std::vector<u8>> m_text_sections;
bool m_is_valid;
bool m_is_wii;
bool m_is_valid;
bool m_is_wii;
// Copy sections to internal buffers
bool Initialize(const std::vector<u8>& buffer);
// Copy sections to internal buffers
bool Initialize(const std::vector<u8>& buffer);
};

View file

@ -12,91 +12,90 @@
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 */
/* 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);
size_t filesize = File::GetSize(filename);
auto elf = std::make_unique<u8[]>(filesize);
{
File::IOFile f(filename, "rb");
f.ReadBytes(elf.get(), 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.
// 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());
// 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))
{
u32* code = (u32*)reader.GetSectionDataPtr(i);
for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j)
{
if ((code[j] & HID4_mask) == HID4_pattern)
return true;
}
}
}
for (int i = 0; i < reader.GetNumSections(); ++i)
{
if (reader.IsCodeSection(i))
{
u32* code = (u32*)reader.GetSectionDataPtr(i);
for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j)
{
if ((code[j] & HID4_mask) == HID4_pattern)
return true;
}
}
}
return false;
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);
// 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);
}
{
File::IOFile f(filename, "rb");
f.ReadBytes(elf.get(), filesize);
}
// Load ELF into GameCube Memory
ElfReader reader(elf.get());
if (!reader.LoadIntoMemory())
return false;
// Load ELF into GameCube Memory
ElfReader reader(elf.get());
if (!reader.LoadIntoMemory())
return false;
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
// Set up MSR and the BAT SPR registers.
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
m_MSR.DR = 1;
m_MSR.IR = 1;
m_MSR.EE = 1;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
if (!reader.LoadSymbols())
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
HLE::PatchFunctions();
}
if (!reader.LoadSymbols())
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
HLE::PatchFunctions();
}
PC = reader.GetEntryPoint();
PC = reader.GetEntryPoint();
return true;
return true;
}

View file

@ -9,15 +9,15 @@
#include "Common/FileUtil.h"
#include "Common/NandPaths.h"
#include "Core/ConfigManager.h"
#include "Core/PatchEngine.h"
#include "Core/Boot/Boot.h"
#include "Core/Boot/Boot_DOL.h"
#include "Core/ConfigManager.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h"
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h"
#include "Core/PatchEngine.h"
#include "Core/PowerPC/PowerPC.h"
#include "DiscIO/NANDContentLoader.h"
@ -25,104 +25,106 @@
#include "DiscIO/VolumeCreator.h"
#include "DiscIO/WiiWad.h"
static u32 state_checksum(u32 *buf, int len)
static u32 state_checksum(u32* buf, int len)
{
u32 checksum = 0;
len = len >> 2;
u32 checksum = 0;
len = len >> 2;
for (int i = 0; i < len; i++)
{
checksum += buf[i];
}
for (int i = 0; i < len; i++)
{
checksum += buf[i];
}
return checksum;
return checksum;
}
struct StateFlags
{
u32 checksum;
u8 flags;
u8 type;
u8 discstate;
u8 returnto;
u32 unknown[6];
u32 checksum;
u8 flags;
u8 type;
u8 discstate;
u8 returnto;
u32 unknown[6];
};
bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
{
std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_STATE);
std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) +
WII_STATE);
if (File::Exists(state_filename))
{
File::IOFile state_file(state_filename, "r+b");
StateFlags state;
state_file.ReadBytes(&state, sizeof(StateFlags));
if (File::Exists(state_filename))
{
File::IOFile state_file(state_filename, "r+b");
StateFlags state;
state_file.ReadBytes(&state, sizeof(StateFlags));
state.type = 0x03; // TYPE_RETURN
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4);
state.type = 0x03; // TYPE_RETURN
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4);
state_file.Seek(0, SEEK_SET);
state_file.WriteBytes(&state, sizeof(StateFlags));
}
else
{
File::CreateFullPath(state_filename);
File::IOFile state_file(state_filename, "a+b");
StateFlags state;
memset(&state, 0, sizeof(StateFlags));
state.type = 0x03; // TYPE_RETURN
state.discstate = 0x01; // DISCSTATE_WII
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4);
state_file.WriteBytes(&state, sizeof(StateFlags));
}
state_file.Seek(0, SEEK_SET);
state_file.WriteBytes(&state, sizeof(StateFlags));
}
else
{
File::CreateFullPath(state_filename);
File::IOFile state_file(state_filename, "a+b");
StateFlags state;
memset(&state, 0, sizeof(StateFlags));
state.type = 0x03; // TYPE_RETURN
state.discstate = 0x01; // DISCSTATE_WII
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4);
state_file.WriteBytes(&state, sizeof(StateFlags));
}
const DiscIO::CNANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename);
if (!ContentLoader.IsValid())
return false;
const DiscIO::CNANDContentLoader& ContentLoader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename);
if (!ContentLoader.IsValid())
return false;
u64 titleID = ContentLoader.GetTitleID();
// create data directory
File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT));
u64 titleID = ContentLoader.GetTitleID();
// create data directory
File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT));
if (titleID == TITLEID_SYSMENU)
HLE_IPC_CreateVirtualFATFilesystem();
// setup Wii memory
if (!SetupWiiMemory(ContentLoader.GetCountry()))
return false;
// this sets a bit that is used to detect NTSC-J
if (ContentLoader.GetCountry() == DiscIO::IVolume::COUNTRY_JAPAN)
{
VideoInterface::SetRegionReg('J');
}
// DOL
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex());
if (pContent == nullptr)
return false;
if (titleID == TITLEID_SYSMENU)
HLE_IPC_CreateVirtualFATFilesystem();
// setup Wii memory
if (!SetupWiiMemory(ContentLoader.GetCountry()))
return false;
// this sets a bit that is used to detect NTSC-J
if (ContentLoader.GetCountry() == DiscIO::IVolume::COUNTRY_JAPAN)
{
VideoInterface::SetRegionReg('J');
}
// DOL
const DiscIO::SNANDContent* pContent =
ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex());
if (pContent == nullptr)
return false;
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
if (!pDolLoader->IsValid())
return false;
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
if (!pDolLoader->IsValid())
return false;
pDolLoader->Load();
PC = pDolLoader->GetEntryPoint();
pDolLoader->Load();
PC = pDolLoader->GetEntryPoint();
// Pass the "#002 check"
// Apploader should write the IOS version and revision to 0x3140, and compare it
// to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
// Currently we just write 0xFFFF for the revision, copy manually and it works fine :p
// Pass the "#002 check"
// Apploader should write the IOS version and revision to 0x3140, and compare it
// to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
// Currently we just write 0xFFFF for the revision, copy manually and it works fine :p
// TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ?
Memory::Write_U16(ContentLoader.GetIosVersion(), 0x00003140);
Memory::Write_U16(0xFFFF, 0x00003142);
Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188);
// TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ?
Memory::Write_U16(ContentLoader.GetIosVersion(), 0x00003140);
Memory::Write_U16(0xFFFF, 0x00003142);
Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188);
// Load patches and run startup patches
const std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(_pFilename));
if (pVolume != nullptr)
PatchEngine::LoadPatches();
// Load patches and run startup patches
const std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(_pFilename));
if (pVolume != nullptr)
PatchEngine::LoadPatches();
return true;
return true;
}

View file

@ -13,183 +13,191 @@
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PPCSymbolDB.h"
static void bswap(u32 &w) {w = Common::swap32(w);}
static void bswap(u16 &w) {w = Common::swap16(w);}
static void byteswapHeader(Elf32_Ehdr &ELF_H)
static void bswap(u32& w)
{
bswap(ELF_H.e_type);
bswap(ELF_H.e_machine);
bswap(ELF_H.e_ehsize);
bswap(ELF_H.e_phentsize);
bswap(ELF_H.e_phnum);
bswap(ELF_H.e_shentsize);
bswap(ELF_H.e_shnum);
bswap(ELF_H.e_shstrndx);
bswap(ELF_H.e_version);
bswap(ELF_H.e_entry);
bswap(ELF_H.e_phoff);
bswap(ELF_H.e_shoff);
bswap(ELF_H.e_flags);
w = Common::swap32(w);
}
static void bswap(u16& w)
{
w = Common::swap16(w);
}
static void byteswapSegment(Elf32_Phdr &sec)
static void byteswapHeader(Elf32_Ehdr& ELF_H)
{
bswap(sec.p_align);
bswap(sec.p_filesz);
bswap(sec.p_flags);
bswap(sec.p_memsz);
bswap(sec.p_offset);
bswap(sec.p_paddr);
bswap(sec.p_vaddr);
bswap(sec.p_type);
bswap(ELF_H.e_type);
bswap(ELF_H.e_machine);
bswap(ELF_H.e_ehsize);
bswap(ELF_H.e_phentsize);
bswap(ELF_H.e_phnum);
bswap(ELF_H.e_shentsize);
bswap(ELF_H.e_shnum);
bswap(ELF_H.e_shstrndx);
bswap(ELF_H.e_version);
bswap(ELF_H.e_entry);
bswap(ELF_H.e_phoff);
bswap(ELF_H.e_shoff);
bswap(ELF_H.e_flags);
}
static void byteswapSection(Elf32_Shdr &sec)
static void byteswapSegment(Elf32_Phdr& sec)
{
bswap(sec.sh_addr);
bswap(sec.sh_addralign);
bswap(sec.sh_entsize);
bswap(sec.sh_flags);
bswap(sec.sh_info);
bswap(sec.sh_link);
bswap(sec.sh_name);
bswap(sec.sh_offset);
bswap(sec.sh_size);
bswap(sec.sh_type);
bswap(sec.p_align);
bswap(sec.p_filesz);
bswap(sec.p_flags);
bswap(sec.p_memsz);
bswap(sec.p_offset);
bswap(sec.p_paddr);
bswap(sec.p_vaddr);
bswap(sec.p_type);
}
ElfReader::ElfReader(void *ptr)
static void byteswapSection(Elf32_Shdr& sec)
{
base = (char*)ptr;
base32 = (u32*)ptr;
header = (Elf32_Ehdr*)ptr;
byteswapHeader(*header);
bswap(sec.sh_addr);
bswap(sec.sh_addralign);
bswap(sec.sh_entsize);
bswap(sec.sh_flags);
bswap(sec.sh_info);
bswap(sec.sh_link);
bswap(sec.sh_name);
bswap(sec.sh_offset);
bswap(sec.sh_size);
bswap(sec.sh_type);
}
segments = (Elf32_Phdr *)(base + header->e_phoff);
sections = (Elf32_Shdr *)(base + header->e_shoff);
ElfReader::ElfReader(void* ptr)
{
base = (char*)ptr;
base32 = (u32*)ptr;
header = (Elf32_Ehdr*)ptr;
byteswapHeader(*header);
for (int i = 0; i < GetNumSegments(); i++)
{
byteswapSegment(segments[i]);
}
segments = (Elf32_Phdr*)(base + header->e_phoff);
sections = (Elf32_Shdr*)(base + header->e_shoff);
for (int i = 0; i < GetNumSections(); i++)
{
byteswapSection(sections[i]);
}
entryPoint = header->e_entry;
for (int i = 0; i < GetNumSegments(); i++)
{
byteswapSegment(segments[i]);
}
for (int i = 0; i < GetNumSections(); i++)
{
byteswapSection(sections[i]);
}
entryPoint = header->e_entry;
}
const char* ElfReader::GetSectionName(int section) const
{
if (sections[section].sh_type == SHT_NULL)
return nullptr;
if (sections[section].sh_type == SHT_NULL)
return nullptr;
int nameOffset = sections[section].sh_name;
char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
int nameOffset = sections[section].sh_name;
char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
if (ptr)
return ptr + nameOffset;
else
return nullptr;
if (ptr)
return ptr + nameOffset;
else
return nullptr;
}
// 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);
DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
// Should we relocate?
bRelocate = (header->e_type != ET_EXEC);
// Should we relocate?
bRelocate = (header->e_type != ET_EXEC);
if (bRelocate)
{
PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf.");
return false;
}
if (bRelocate)
{
PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf.");
return false;
}
INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum);
INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum);
// Copy segments into ram.
for (int i = 0; i < header->e_phnum; i++)
{
Elf32_Phdr* p = segments + i;
// Copy segments into ram.
for (int i = 0; i < header->e_phnum; 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)
{
u32 writeAddr = p->p_vaddr;
const u8* src = GetSegmentPtr(i);
u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz;
if (p->p_type == PT_LOAD)
{
u32 writeAddr = p->p_vaddr;
const u8* src = GetSegmentPtr(i);
u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz;
Memory::CopyToEmu(writeAddr, src, srcSize);
if (srcSize < dstSize)
Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); //zero out bss
Memory::CopyToEmu(writeAddr, src, srcSize);
if (srcSize < dstSize)
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);
}
}
INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
}
}
INFO_LOG(MASTER_LOG, "Done loading.");
return true;
INFO_LOG(MASTER_LOG, "Done loading.");
return true;
}
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
{
for (int i = firstSection; i < header->e_shnum; i++)
{
const char* secname = GetSectionName(i);
for (int i = firstSection; i < header->e_shnum; i++)
{
const char* secname = GetSectionName(i);
if (secname != nullptr && strcmp(name, secname) == 0)
return i;
}
return -1;
if (secname != nullptr && strcmp(name, secname) == 0)
return i;
}
return -1;
}
bool ElfReader::LoadSymbols()
{
bool hasSymbols = false;
SectionID sec = GetSectionByName(".symtab");
if (sec != -1)
{
int stringSection = sections[sec].sh_link;
const char* stringBase = (const char *)GetSectionDataPtr(stringSection);
bool hasSymbols = false;
SectionID sec = GetSectionByName(".symtab");
if (sec != -1)
{
int stringSection = sections[sec].sh_link;
const char* stringBase = (const char*)GetSectionDataPtr(stringSection);
//We have a symbol table!
Elf32_Sym* symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
for (int sym = 0; sym < numSymbols; sym++)
{
int size = Common::swap32(symtab[sym].st_size);
if (size == 0)
continue;
// We have a symbol table!
Elf32_Sym* symtab = (Elf32_Sym*)(GetSectionDataPtr(sec));
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
for (int sym = 0; sym < numSymbols; sym++)
{
int size = Common::swap32(symtab[sym].st_size);
if (size == 0)
continue;
// int bind = symtab[sym].st_info >> 4;
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);
if (bRelocate)
value += sectionAddrs[sectionIndex];
// int bind = symtab[sym].st_info >> 4;
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);
if (bRelocate)
value += sectionAddrs[sectionIndex];
int symtype = Symbol::SYMBOL_DATA;
switch (type)
{
case STT_OBJECT:
symtype = Symbol::SYMBOL_DATA; break;
case STT_FUNC:
symtype = Symbol::SYMBOL_FUNCTION; break;
default:
continue;
}
g_symbolDB.AddKnownSymbol(value, size, name, symtype);
hasSymbols = true;
}
}
g_symbolDB.Index();
return hasSymbols;
int symtype = Symbol::SYMBOL_DATA;
switch (type)
{
case STT_OBJECT:
symtype = Symbol::SYMBOL_DATA;
break;
case STT_FUNC:
symtype = Symbol::SYMBOL_FUNCTION;
break;
default:
continue;
}
g_symbolDB.AddKnownSymbol(value, size, name, symtype);
hasSymbols = true;
}
}
g_symbolDB.Index();
return hasSymbols;
}

View file

@ -8,10 +8,10 @@
enum KnownElfTypes
{
KNOWNELF_PSP = 0,
KNOWNELF_DS = 1,
KNOWNELF_GBA = 2,
KNOWNELF_GC = 3,
KNOWNELF_PSP = 0,
KNOWNELF_DS = 1,
KNOWNELF_GBA = 2,
KNOWNELF_GC = 3,
};
typedef int SectionID;
@ -19,58 +19,47 @@ 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;
u32* sectionAddrs;
bool bRelocate;
u32 entryPoint;
public:
ElfReader(void* ptr);
~ElfReader() { }
ElfReader(void* ptr);
~ElfReader() {}
u32 Read32(int off) const { return base32[off >> 2]; }
// Quick accessors
ElfType GetType() const { return (ElfType)(header->e_type); }
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
u32 GetEntryPoint() const { return entryPoint; }
u32 GetFlags() const { return (u32)(header->e_flags); }
bool LoadIntoMemory();
bool LoadSymbols();
u32 Read32(int off) const { return base32[off>>2]; }
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* GetSectionDataPtr(int section) const
{
if (section < 0 || section >= header->e_shnum)
return nullptr;
if (sections[section].sh_type != SHT_NOBITS)
return GetPtr(sections[section].sh_offset);
else
return nullptr;
}
bool IsCodeSection(int section) const { return sections[section].sh_type == SHT_PROGBITS; }
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
// Quick accessors
ElfType GetType() const { return (ElfType)(header->e_type); }
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
u32 GetEntryPoint() const { return entryPoint; }
u32 GetFlags() const { return (u32)(header->e_flags); }
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 *GetSectionDataPtr(int section) const
{
if (section < 0 || section >= header->e_shnum)
return nullptr;
if (sections[section].sh_type != SHT_NOBITS)
return GetPtr(sections[section].sh_offset);
else
return nullptr;
}
bool IsCodeSection(int section) const
{
return sections[section].sh_type == SHT_PROGBITS;
}
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
bool DidRelocate() const
{
return bRelocate;
}
bool DidRelocate() const { return bRelocate; }
};

View file

@ -11,85 +11,83 @@
// File type
enum ElfType
{
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOPROC = 0xFF00,
ET_HIPROC = 0xFFFF,
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOPROC = 0xFF00,
ET_HIPROC = 0xFFFF,
};
// Machine/Architecture
enum ElfMachine
{
EM_NONE = 0,
EM_M32 = 1,
EM_SPARC = 2,
EM_386 = 3,
EM_68K = 4,
EM_88K = 5,
EM_860 = 7,
EM_MIPS = 8
EM_NONE = 0,
EM_M32 = 1,
EM_SPARC = 2,
EM_386 = 3,
EM_68K = 4,
EM_88K = 5,
EM_860 = 7,
EM_MIPS = 8
};
// File version
#define EV_NONE 0
#define EV_NONE 0
#define EV_CURRENT 1
// Identification index
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_PAD 7
#define EI_NIDENT 16
// Magic number
#define ELFMAG0 0x7F
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
// File class
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASS32 1
#define ELFCLASS64 2
// Encoding
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
// Sections constants
// Section indexes
#define SHN_UNDEF 0
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xFF00
#define SHN_LOPROC 0xFF00
#define SHN_HIPROC 0xFF1F
#define SHN_ABS 0xFFF1
#define SHN_COMMON 0xFFF2
#define SHN_LOPROC 0xFF00
#define SHN_HIPROC 0xFF1F
#define SHN_ABS 0xFFF1
#define SHN_COMMON 0xFFF2
#define SHN_HIRESERVE 0xFFFF
// Section types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
@ -98,58 +96,57 @@ enum ElfMachine
// Custom section types
#define SHT_PSPREL 0x700000a0
// Section flags
enum ElfSectionFlags
{
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKPROC = 0xF0000000,
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKPROC = 0xF0000000,
};
// Symbol binding
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_LOPROC 13
#define STB_HIPROC 15
// Symbol types
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
// Undefined name
#define STN_UNDEF 0
// Relocation types
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_COPY 5
#define R_386_GLOB_DAT 6
#define R_386_JMP_SLOT 7
#define R_386_RELATIVE 8
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_COPY 5
#define R_386_GLOB_DAT 6
#define R_386_JMP_SLOT 7
#define R_386_RELATIVE 8
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
// Segment types
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
// Segment flags
#define PF_X 1
@ -157,120 +154,118 @@ enum ElfSectionFlags
#define PF_R 4
// Dynamic Array Tags
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7FFFFFFF
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7FFFFFFF
// ELF file header
struct Elf32_Ehdr
{
u8 e_ident[EI_NIDENT];
u16 e_type;
u16 e_machine;
u32 e_version;
u32 e_entry;
u32 e_phoff;
u32 e_shoff;
u32 e_flags;
u16 e_ehsize;
u16 e_phentsize;
u16 e_phnum;
u16 e_shentsize;
u16 e_shnum;
u16 e_shstrndx;
u8 e_ident[EI_NIDENT];
u16 e_type;
u16 e_machine;
u32 e_version;
u32 e_entry;
u32 e_phoff;
u32 e_shoff;
u32 e_flags;
u16 e_ehsize;
u16 e_phentsize;
u16 e_phnum;
u16 e_shentsize;
u16 e_shnum;
u16 e_shstrndx;
};
// Section header
struct Elf32_Shdr
{
u32 sh_name;
u32 sh_type;
u32 sh_flags;
u32 sh_addr;
u32 sh_offset;
u32 sh_size;
u32 sh_link;
u32 sh_info;
u32 sh_addralign;
u32 sh_entsize;
u32 sh_name;
u32 sh_type;
u32 sh_flags;
u32 sh_addr;
u32 sh_offset;
u32 sh_size;
u32 sh_link;
u32 sh_info;
u32 sh_addralign;
u32 sh_entsize;
};
// Segment header
struct Elf32_Phdr
{
u32 p_type;
u32 p_offset;
u32 p_vaddr;
u32 p_paddr;
u32 p_filesz;
u32 p_memsz;
u32 p_flags;
u32 p_align;
u32 p_type;
u32 p_offset;
u32 p_vaddr;
u32 p_paddr;
u32 p_filesz;
u32 p_memsz;
u32 p_flags;
u32 p_align;
};
// Symbol table entry
struct Elf32_Sym
{
u32 st_name;
u32 st_value;
u32 st_size;
u8 st_info;
u8 st_other;
u16 st_shndx;
u32 st_name;
u32 st_value;
u32 st_size;
u8 st_info;
u8 st_other;
u16 st_shndx;
};
#define ELF32_ST_BIND(i) ((i)>>4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
#define ELF32_ST_BIND(i) ((i) >> 4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
// Relocation entries
struct Elf32_Rel
{
u32 r_offset;
u32 r_info;
u32 r_offset;
u32 r_info;
};
struct Elf32_Rela
{
u32 r_offset;
u32 r_info;
s32 r_addend;
u32 r_offset;
u32 r_info;
s32 r_addend;
};
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((u8)(i))
#define ELF32_R_INFO(s,t) (((s)<<8 )+(u8)(t))
#define ELF32_R_INFO(s, t) (((s) << 8) + (u8)(t))
struct Elf32_Dyn
{
s32 d_tag;
union
{
u32 d_val;
u32 d_ptr;
} d_un;
s32 d_tag;
union {
u32 d_val;
u32 d_ptr;
} d_un;
};