Remove unnecessary Src/ folders

This commit is contained in:
Jasper St. Pierre
2013-12-07 15:14:29 -05:00
parent 43e618682e
commit 34692ab826
1026 changed files with 37648 additions and 37646 deletions

View File

@ -0,0 +1,432 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Common.h" // Common
#include "StringUtil.h"
#include "FileUtil.h"
#include "MathUtil.h"
#include "../HLE/HLE.h" // Core
#include "../PowerPC/PowerPC.h"
#include "../PowerPC/PPCAnalyst.h"
#include "../Core.h"
#include "../HW/EXI_DeviceIPL.h"
#include "../HW/Memmap.h"
#include "../HW/ProcessorInterface.h"
#include "../HW/DVDInterface.h"
#include "../HW/VideoInterface.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
#include "../Debugger/Debugger_SymbolMap.h" // Debugger
#include "Boot_DOL.h"
#include "Boot.h"
#include "../Host.h"
#include "../VolumeHandler.h"
#include "../PatchEngine.h"
#include "../PowerPC/SignatureDB.h"
#include "../PowerPC/PPCSymbolDB.h"
#include "../ConfigManager.h"
#include "VolumeCreator.h" // DiscIO
#include "NANDContentLoader.h"
#include "Hash.h"
#include "CommonPaths.h"
void CBoot::Load_FST(bool _bIsWii)
{
if (!VolumeHandler::IsValid())
return;
// copy first 20 bytes of disc to start of Mem 1
VolumeHandler::ReadToPtr(Memory::GetPointer(0x80000000), 0, 0x20);
// copy of game id
Memory::Write_U32(Memory::Read_U32(0x80000000), 0x80003180);
u32 shift = 0;
if (_bIsWii)
shift = 2;
u32 fstOffset = VolumeHandler::Read32(0x0424) << shift;
u32 fstSize = VolumeHandler::Read32(0x0428) << shift;
u32 maxFstSize = VolumeHandler::Read32(0x042c) << shift;
u32 arenaHigh = ROUND_DOWN(0x817FFFFF - maxFstSize, 0x20);
Memory::Write_U32(arenaHigh, 0x00000034);
// load FST
VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize);
Memory::Write_U32(arenaHigh, 0x00000038);
Memory::Write_U32(maxFstSize, 0x0000003c);
}
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
{
Host_NotifyMapLoaded();
}
bool CBoot::FindMapFile(std::string* existing_map_file,
std::string* writable_map_file)
{
std::string title_id_str;
SCoreStartupParameter& _StartupPara = SConfig::GetInstance().m_LocalCoreStartupParameter;
switch (_StartupPara.m_BootType)
{
case SCoreStartupParameter::BOOT_WII_NAND:
{
const DiscIO::INANDContentLoader& 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 SCoreStartupParameter::BOOT_ELF:
case SCoreStartupParameter::BOOT_DOL:
// Strip the .elf/.dol file extension
title_id_str = _StartupPara.m_strFilename.substr(
0, _StartupPara.m_strFilename.size() - 4);
break;
default:
title_id_str = _StartupPara.GetUniqueID();
break;
}
if (writable_map_file)
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";
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;
}
bool CBoot::LoadMapFromFilename()
{
std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, NULL);
if (found && g_symbolDB.LoadMap(strMapFilename.c_str()))
{
UpdateDebugger_MapLoaded();
return true;
}
return false;
}
// If ipl.bin is not found, this function does *some* of what BS1 does:
// loading IPL(BS2) and jumping to it.
// It does not initialize the hardware or anything else like BS1 does.
bool CBoot::Load_BS2(const std::string& _rBootROMFilename)
{
const u32 USA = 0x1FCE3FD6;
const u32 USA_v1_1 = 0x4D5935D1;
const u32 JAP = 0x87424396;
const u32 PAL = 0xA0EA7341;
//const u32 PanasonicQJ = 0xAEA8265C;
//const u32 PanasonicQU = 0x94015753;
// Load the whole ROM dump
std::string data;
if (!File::ReadFileToString(_rBootROMFilename.c_str(), data))
return false;
u32 ipl_hash = HashAdler32((const u8*)data.data(), data.size());
std::string ipl_region;
switch (ipl_hash)
{
case USA:
case USA_v1_1:
ipl_region = USA_DIR;
break;
case JAP:
ipl_region = JAP_DIR;
break;
case PAL:
ipl_region = EUR_DIR;
break;
default:
PanicAlert("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)
PanicAlert("%s IPL found in %s directory. The disc may 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);
Memory::WriteBigEData((const u8*)data.data() + 0x100, 0x81200000, 0x700);
Memory::WriteBigEData((const u8*)data.data() + 0x820, 0x81300000, 0x1AFE00);
PC = 0x81200000;
return true;
}
// Third boot step after BootManager and Core. See Call schedule in BootManager.cpp
bool CBoot::BootUp()
{
SCoreStartupParameter& _StartupPara =
SConfig::GetInstance().m_LocalCoreStartupParameter;
NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str());
g_symbolDB.Clear();
VideoInterface::Preset(_StartupPara.bNTSC);
switch (_StartupPara.m_BootType)
{
// GCM and Wii
case SCoreStartupParameter::BOOT_ISO:
{
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename);
if (pVolume == NULL)
break;
bool isoWii = DiscIO::IsVolumeWiiDisc(pVolume);
if (isoWii != _StartupPara.bWii)
{
PanicAlertT("Warning - starting ISO in wrong console mode!");
}
// setup the map from ISOFile ID
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
std::string unique_id = VolumeHandler::GetVolume()->GetUniqueID();
if (unique_id.size() >= 4)
VideoInterface::SetRegionReg(unique_id.at(3));
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
u32 _TMDsz = 0x208;
u8* _pTMD = new u8[_TMDsz];
pVolume->GetTMD(_pTMD, &_TMDsz);
if (_TMDsz)
{
WII_IPC_HLE_Interface::ES_DIVerify(_pTMD, _TMDsz);
}
delete []_pTMD;
_StartupPara.bWii = VolumeHandler::IsWii();
// 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);
}
// Scan for common HLE functions
if (_StartupPara.bSkipIdle && !_StartupPara.bEnableDebugging)
{
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
{
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();
// We don't need the volume any more
delete pVolume;
break;
}
// DOL
case SCoreStartupParameter::BOOT_DOL:
{
CDolLoader dolLoader(_StartupPara.m_strFilename.c_str());
// 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;
if (dolWii)
{
BS2Success = EmulatedBS2(dolWii);
}
else if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
{
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
BS2Success = EmulatedBS2(dolWii);
}
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii, _StartupPara.m_strApploader, _StartupPara.m_strFilename);
BS2Success = EmulatedBS2(dolWii);
}
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
if (!BS2Success)
{
dolLoader.Load();
PC = dolLoader.GetEntryPoint();
}
if (LoadMapFromFilename())
HLE::PatchFunctions();
break;
}
// ELF
case SCoreStartupParameter::BOOT_ELF:
{
if(!File::Exists(_StartupPara.m_strFilename))
{
PanicAlertT("The file you specified (%s) does not exist",
_StartupPara.m_strFilename.c_str());
return false;
}
// Check if we have gotten a Wii file or not
bool elfWii = IsElfWii(_StartupPara.m_strFilename.c_str());
if (elfWii != _StartupPara.bWii)
{
PanicAlertT("Warning - starting ELF in wrong console mode!");
}
bool BS2Success = false;
if (elfWii)
{
BS2Success = EmulatedBS2(elfWii);
}
else if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
{
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
BS2Success = EmulatedBS2(elfWii);
}
// load image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
{
NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str());
// TODO: auto-convert elf to dol, so we can load them :)
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, elfWii);
BS2Success = EmulatedBS2(elfWii);
}
else if (!_StartupPara.m_strDefaultGCM.empty())
{
NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultGCM.c_str());
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
}
else VolumeHandler::SetVolumeDirectory(_StartupPara.m_strFilename, elfWii);
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
if (BS2Success)
{
HLE::PatchFunctions();
}
else // Poor man's bootup
{
Load_FST(elfWii);
Boot_ELF(_StartupPara.m_strFilename.c_str());
}
UpdateDebugger_MapLoaded();
Dolphin_Debugger::AddAutoBreakpoints();
break;
}
// Wii WAD
case SCoreStartupParameter::BOOT_WII_NAND:
Boot_WiiWAD(_StartupPara.m_strFilename.c_str());
if (LoadMapFromFilename())
HLE::PatchFunctions();
// load default image or create virtual drive from directory
if (!_StartupPara.m_strDVDRoot.empty())
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true);
else if (!_StartupPara.m_strDefaultGCM.empty())
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
break;
// Bootstrap 2 (AKA: Initial Program Loader, "BIOS")
case SCoreStartupParameter::BOOT_BS2:
{
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
if (Load_BS2(_StartupPara.m_strBootROM))
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
return false;
}
break;
}
case SCoreStartupParameter::BOOT_DFF:
// do nothing
break;
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().m_LocalCoreStartupParameter.bEnableCheats)
{
HLE::Patch(0x80001800, "HBReload");
const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' };
Memory::WriteBigEData(stubstr, 0x80001804, 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");
Host_UpdateLogDisplay();
return true;
}

View File

@ -0,0 +1,51 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _BOOT_H
#define _BOOT_H
#include <cstdlib>
#include <string>
#include "../CoreParameter.h"
class CBoot
{
public:
static bool BootUp();
static bool IsElfWii(const char *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 NULL and a map file exists, it is set to the
// path to the existing map file.
//
// If writable_map_file is not NULL, it is set to the path to where a map
// file should be saved.
//
// 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);
private:
static void RunFunction(u32 _iAddr);
static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);
static bool LoadMapFromFilename();
static bool Boot_ELF(const char *filename);
static bool Boot_WiiWAD(const char *filename);
static bool EmulatedBS2_GC();
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(unsigned int _CountryCode);
};
#endif

View File

@ -0,0 +1,438 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Common.h"
#include "CommonPaths.h"
#include "FileUtil.h"
#include "NandPaths.h"
#include "../PowerPC/PowerPC.h"
#include "../Core.h"
#include "../HW/EXI_DeviceIPL.h"
#include "../HW/Memmap.h"
#include "../HW/DVDInterface.h"
#include "../HW/CPU.h"
#include "../VolumeHandler.h"
#include "../PatchEngine.h"
#include "../MemTools.h"
#include "../ConfigManager.h"
#include "VolumeCreator.h"
#include "Boot.h"
#include "HLE/HLE.h"
#include "SettingsHandler.h"
void CBoot::RunFunction(u32 _iAddr)
{
PC = _iAddr;
LR = 0x00;
while (PC != 0x00)
PowerPC::SingleStep();
}
// __________________________________________________________________________________________________
// GameCube Bootstrap 2 HLE:
// copy the apploader to 0x81200000
// execute the apploader, function by function, using the above utility.
bool CBoot::EmulatedBS2_GC()
{
INFO_LOG(BOOT, "Faking GC BS2...");
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
// Clear ALL memory
Memory::Clear();
// 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.
DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info
Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag
Memory::Write_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)
Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2
Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC
? 0 : 1, 0x800000CC); // fake the VI Init of the IPL (yagcd 4.2.1.4)
Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // preset time base ticks
// HIO checks this
//Memory::Write_U16(0x8200, 0x000030e6); // Console type
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
// 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.
u32 iAppLoaderOffset = 0x2440;
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14) + VolumeHandler::Read32(iAppLoaderOffset + 0x18);
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
{
INFO_LOG(BOOT, "GC BS2: Not running apploader!");
return false;
}
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
// Setup pointers like real BS2 does
if (SConfig::GetInstance().m_LocalCoreStartupParameter.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!!!
// 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(iAppLoaderEntry);
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0);
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4);
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8);
// 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;
RunFunction(iAppLoaderMain);
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
} while(PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
RunFunction(iAppLoaderClose);
// return
PC = PowerPC::ppcState.gpr[3];
// Load patches
PatchEngine::LoadPatches();
PowerPC::ppcState.DebugCount = 0;
// If we have any patches that need to be applied very early, here's a good place
PatchEngine::ApplyFramePatches();
return true;
}
bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
{
INFO_LOG(BOOT, "Setup Wii Memory...");
// Write the 256 byte setting.txt to memory.
std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_SETTING);
std::string area, model, code, video, game;
switch((DiscIO::IVolume::ECountry)_CountryCode)
{
case DiscIO::IVolume::COUNTRY_KOREA:
area = "KOR";
video = "NTSC";
game = "KR";
code = "LKH";
break;
case DiscIO::IVolume::COUNTRY_TAIWAN:
// TODO: Determine if Taiwan have their own specific settings.
case DiscIO::IVolume::COUNTRY_JAPAN:
area = "JPN";
video = "NTSC";
game = "JP";
code = "LJ";
break;
case DiscIO::IVolume::COUNTRY_USA:
area = "USA";
video = "NTSC";
game = "US";
code = "LU";
break;
case DiscIO::IVolume::COUNTRY_EUROPE:
area = "EUR";
video = "PAL";
game = "EU";
code = "LE";
break;
default:
// PanicAlertT("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings.");
area = "EUR";
video = "PAL";
game = "EU";
code = "LE";
break;
}
model = "RVL-001(" + area + ")";
SettingsHandler gen;
std::string serno = "";
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")
{
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());
}
gen.AddSetting("AREA", area.c_str());
gen.AddSetting("MODEL", model.c_str());
gen.AddSetting("DVD", "0");
gen.AddSetting("MPCH", "0x7FFE");
gen.AddSetting("CODE", code.c_str());
gen.AddSetting("SERNO", serno.c_str());
gen.AddSetting("VIDEO", video.c_str());
gen.AddSetting("GAME", game.c_str());
File::CreateFullPath(settings_Filename);
{
File::IOFile settingsFileHandle(settings_Filename, "wb");
if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE))
{
PanicAlertT("SetupWiiMem: Cant create setting file");
return false;
}
Memory::WriteBigEData(gen.GetData(), 0x3800, SettingsHandler::SETTINGS_SIZE);
}
/*
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
*/
DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // 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_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().m_LocalCoreStartupParameter.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, 0x80000000 + i);
}
return true;
}
// __________________________________________________________________________________________________
// Wii Bootstrap 2 HLE:
// copy the apploader to 0x81200000
// execute the apploader
bool CBoot::EmulatedBS2_Wii()
{
INFO_LOG(BOOT, "Faking Wii BS2...");
// setup wii memory
DiscIO::IVolume::ECountry CountryCode = DiscIO::IVolume::COUNTRY_UNKNOWN;
if (VolumeHandler::IsValid())
CountryCode = VolumeHandler::GetVolume()->GetCountry();
if (SetupWiiMemory(CountryCode) == false)
return false;
// This is some kind of consistency check that is compared to the 0x00
// values as the game boots. This location keep 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.
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
// Execute the apploader
bool apploaderRan = false;
if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
{
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
// Load Apploader to Memory
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
{
ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
return false;
}
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
//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(iAppLoaderEntry);
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
// 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;
RunFunction(iAppLoaderMain);
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
} while(PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
DEBUG_LOG(BOOT, "Run iAppLoaderClose");
RunFunction(iAppLoaderClose);
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 = Memory::Read_U32(0x80003188);
Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140);
// Load patches and run startup patches
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
PatchEngine::LoadPatches();
// return
PC = PowerPC::ppcState.gpr[3];
}
PowerPC::ppcState.DebugCount = 0;
return apploaderRan;
}
// Returns true if apploader has run successfully
bool CBoot::EmulatedBS2(bool _bIsWii)
{
return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC();
}

View File

@ -0,0 +1,112 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Boot_DOL.h"
#include "FileUtil.h"
#include "../HW/Memmap.h"
#include "CommonFuncs.h"
CDolLoader::CDolLoader(u8* _pBuffer, u32 _Size)
: m_isWii(false)
{
Initialize(_pBuffer, _Size);
}
CDolLoader::CDolLoader(const char* _szFilename)
: m_isWii(false)
{
const u64 size = File::GetSize(_szFilename);
u8* const tmpBuffer = new u8[(size_t)size];
{
File::IOFile pStream(_szFilename, "rb");
pStream.ReadBytes(tmpBuffer, (size_t)size);
}
Initialize(tmpBuffer, (u32)size);
delete[] tmpBuffer;
}
CDolLoader::~CDolLoader()
{
for (auto& sect : text_section)
{
delete [] sect;
sect = NULL;
}
for (auto& sect : data_section)
{
delete [] sect;
sect = NULL;
}
}
void CDolLoader::Initialize(u8* _pBuffer, u32 _Size)
{
memcpy(&m_dolheader, _pBuffer, 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]);
for (auto& sect : text_section)
sect = NULL;
for (auto& sect : data_section)
sect = NULL;
u32 HID4_pattern = 0x7c13fba6;
u32 HID4_mask = 0xfc1fffff;
for (int i = 0; i < DOL_NUM_TEXT; i++)
{
if (m_dolheader.textOffset[i] != 0)
{
text_section[i] = new u8[m_dolheader.textSize[i]];
memcpy(text_section[i], _pBuffer + m_dolheader.textOffset[i], m_dolheader.textSize[i]);
for (unsigned int j = 0; j < (m_dolheader.textSize[i]/sizeof(u32)); j++)
{
u32 word = Common::swap32(((u32*)text_section[i])[j]);
if ((word & HID4_mask) == HID4_pattern)
{
m_isWii = true;
break;
}
}
}
}
for (int i = 0; i < DOL_NUM_DATA; i++)
{
if (m_dolheader.dataOffset[i] != 0)
{
data_section[i] = new u8[m_dolheader.dataSize[i]];
memcpy(data_section[i], _pBuffer + m_dolheader.dataOffset[i], m_dolheader.dataSize[i]);
}
}
}
void CDolLoader::Load()
{
// load all text (code) sections
for (int i = 0; i < DOL_NUM_TEXT; i++)
{
if (m_dolheader.textOffset[i] != 0)
{
for (u32 num = 0; num < m_dolheader.textSize[i]; num++)
Memory::Write_U8(text_section[i][num], m_dolheader.textAddress[i] + num);
}
}
// load all data sections
for (int i = 0; i < DOL_NUM_DATA; i++)
{
if (m_dolheader.dataOffset[i] != 0)
{
for (u32 num = 0; num < m_dolheader.dataSize[i]; num++)
Memory::Write_U8(data_section[i][num], m_dolheader.dataAddress[i] + num);
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _BOOT_DOL_H
#define _BOOT_DOL_H
#include "CommonTypes.h"
class CDolLoader
{
public:
CDolLoader(const char* _szFilename);
CDolLoader(u8* _pBuffer, u32 _Size);
~CDolLoader();
bool IsWii() { return m_isWii; }
u32 GetEntryPoint() { return m_dolheader.entryPoint; }
// Load into emulated memory
void Load();
private:
enum
{
DOL_NUM_TEXT = 7,
DOL_NUM_DATA = 11
};
struct SDolHeader
{
u32 textOffset[DOL_NUM_TEXT];
u32 dataOffset[DOL_NUM_DATA];
u32 textAddress[DOL_NUM_TEXT];
u32 dataAddress[DOL_NUM_DATA];
u32 textSize[DOL_NUM_TEXT];
u32 dataSize[DOL_NUM_DATA];
u32 bssAddress;
u32 bssSize;
u32 entryPoint;
u32 padd[7];
};
SDolHeader m_dolheader;
u8 *data_section[DOL_NUM_DATA];
u8 *text_section[DOL_NUM_TEXT];
bool m_isWii;
// Copy sections to internal buffers
void Initialize(u8* _pBuffer, u32 _Size);
};
#endif

View File

@ -0,0 +1,83 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "../PowerPC/PowerPC.h"
#include "Boot.h"
#include "../HLE/HLE.h"
#include "Boot_ELF.h"
#include "ElfReader.h"
#include "FileUtil.h"
bool CBoot::IsElfWii(const char *filename)
{
/* We already check if filename existed before we called this function, so
there is no need for another check, just read the file right away */
const u64 filesize = File::GetSize(filename);
u8 *const mem = new u8[(size_t)filesize];
{
File::IOFile f(filename, "rb");
f.ReadBytes(mem, (size_t)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.
u32 HID4_pattern = 0x7c13fba6;
u32 HID4_mask = 0xfc1fffff;
ElfReader reader(mem);
bool isWii = false;
for (int i = 0; i < reader.GetNumSections(); ++i)
{
if (reader.IsCodeSection(i))
{
for (unsigned int j = 0; j < reader.GetSectionSize(i) / sizeof (u32); ++j)
{
u32 word = Common::swap32(((u32*)reader.GetSectionDataPtr(i))[j]);
if ((word & HID4_mask) == HID4_pattern)
{
isWii = true;
break;
}
}
}
}
delete[] mem;
return isWii;
}
bool CBoot::Boot_ELF(const char *filename)
{
const u64 filesize = File::GetSize(filename);
u8 *mem = new u8[(size_t)filesize];
{
File::IOFile f(filename, "rb");
f.ReadBytes(mem, (size_t)filesize);
}
ElfReader reader(mem);
reader.LoadInto(0x80000000);
if (!reader.LoadSymbols())
{
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else
{
HLE::PatchFunctions();
}
PC = reader.GetEntryPoint();
delete[] mem;
return true;
}

View File

@ -0,0 +1,5 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once

View File

@ -0,0 +1,125 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Boot.h"
#include "../PowerPC/PowerPC.h"
#include "../HLE/HLE.h"
#include "../HW/Memmap.h"
#include "../ConfigManager.h"
#include "../PatchEngine.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
#include "../IPC_HLE/WII_IPC_HLE_Device_FileIO.h"
#include "WiiWad.h"
#include "NANDContentLoader.h"
#include "FileUtil.h"
#include "Boot_DOL.h"
#include "Volume.h"
#include "VolumeCreator.h"
#include "CommonPaths.h"
#include <memory>
static u32 state_checksum(u32 *buf, int len)
{
u32 checksum = 0;
len = len>>2;
for(int i=0; i<len; i++)
{
checksum += buf[i];
}
return checksum;
}
typedef struct {
u32 checksum;
u8 flags;
u8 type;
u8 discstate;
u8 returnto;
u32 unknown[6];
} StateFlags;
bool CBoot::Boot_WiiWAD(const char* _pFilename)
{
std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_STATE);
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_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::INANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename);
if (!ContentLoader.IsValid())
return false;
u64 titleID = ContentLoader.GetTitleID();
// create data directory
File::CreateFullPath(Common::GetTitleDataPath(titleID));
if (titleID == TITLEID_SYSMENU)
HLE_IPC_CreateVirtualFATFilesystem();
// setup wii mem
if (!SetupWiiMemory(ContentLoader.GetCountry()))
return false;
// DOL
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex());
if (pContent == NULL)
return false;
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
std::unique_ptr<CDolLoader> pDolLoader;
if (pContent->m_pData)
{
pDolLoader.reset(new CDolLoader(pContent->m_pData, pContent->m_Size));
}
else
{
pDolLoader.reset(new CDolLoader(pContent->m_Filename.c_str()));
}
pDolLoader->Load();
PC = pDolLoader->GetEntryPoint() | 0x80000000;
// 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);
// Load patches and run startup patches
const DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_pFilename);
if (pVolume != NULL)
PatchEngine::LoadPatches();
return true;
}

View File

@ -0,0 +1,19 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once

View File

@ -0,0 +1,231 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <string>
#include "Common.h"
#include "../Debugger/Debugger_SymbolMap.h"
#include "../HW/Memmap.h"
#include "../PowerPC/PPCSymbolDB.h"
#include "ElfReader.h"
void bswap(Elf32_Word &w) {w = Common::swap32(w);}
void bswap(Elf32_Half &w) {w = Common::swap16(w);}
static void byteswapHeader(Elf32_Ehdr &ELF_H)
{
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 byteswapSegment(Elf32_Phdr &sec)
{
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);
}
static void byteswapSection(Elf32_Shdr &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);
}
ElfReader::ElfReader(void *ptr)
{
base = (char*)ptr;
base32 = (u32 *)ptr;
header = (Elf32_Ehdr*)ptr;
byteswapHeader(*header);
segments = (Elf32_Phdr *)(base + header->e_phoff);
sections = (Elf32_Shdr *)(base + header->e_shoff);
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 NULL;
int nameOffset = sections[section].sh_name;
char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
if (ptr)
return ptr + nameOffset;
else
return NULL;
}
bool ElfReader::LoadInto(u32 vaddr)
{
DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
// sectionOffsets = new u32[GetNumSections()];
// sectionAddrs = new u32[GetNumSections()];
// Should we relocate?
bRelocate = (header->e_type != ET_EXEC);
if (bRelocate)
{
DEBUG_LOG(MASTER_LOG,"Relocatable module");
entryPoint += vaddr;
}
else
{
DEBUG_LOG(MASTER_LOG,"Prerelocated executable");
}
INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum);
// First pass : Get the bits into RAM
u32 segmentVAddr[32];
u32 baseAddress = bRelocate?vaddr:0;
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);
if (p->p_type == PT_LOAD)
{
segmentVAddr[i] = baseAddress + p->p_vaddr;
u32 writeAddr = segmentVAddr[i];
const u8 *src = GetSegmentPtr(i);
u8 *dst = Memory::GetPointer(writeAddr);
u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz;
u32 *s = (u32*)src;
u32 *d = (u32*)dst;
for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
{
*d++ = /*_byteswap_ulong*/(*s++);
}
if (srcSize < dstSize)
{
//memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
}
INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
}
}
/*
LOG(MASTER_LOG,"%i sections:", header->e_shnum);
for (int i=0; i<GetNumSections(); i++)
{
Elf32_Shdr *s = &sections[i];
const char *name = GetSectionName(i);
u32 writeAddr = s->sh_addr + baseAddress;
sectionOffsets[i] = writeAddr - vaddr;
sectionAddrs[i] = writeAddr;
if (s->sh_flags & SHF_ALLOC)
{
LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size);
}
else
{
LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags);
}
}
*/
INFO_LOG(MASTER_LOG,"Done loading.");
return true;
}
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
{
for (int i = firstSection; i < header->e_shnum; i++)
{
const char *secname = GetSectionName(i);
if (secname != NULL && 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);
//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 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

@ -0,0 +1,79 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _ELFREADER_H
#define _ELFREADER_H
#include "ElfTypes.h"
enum KnownElfTypes
{
KNOWNELF_PSP = 0,
KNOWNELF_DS = 1,
KNOWNELF_GBA = 2,
KNOWNELF_GC = 3,
};
typedef int SectionID;
class ElfReader
{
private:
char *base;
u32 *base32;
Elf32_Ehdr *header;
Elf32_Phdr *segments;
Elf32_Shdr *sections;
u32 *sectionAddrs;
bool bRelocate;
u32 entryPoint;
public:
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 LoadInto(u32 vaddr);
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 0;
if (sections[section].sh_type != SHT_NOBITS)
return GetPtr(sections[section].sh_offset);
else
return 0;
}
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() {
return bRelocate;
}
};
#endif

View File

@ -0,0 +1,285 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _ELFTYPES_H
#define _ELFTYPES_H
// ELF Header Constants
// 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,
};
// 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
};
// File version
#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_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16
// Magic number
#define ELFMAG0 0x7F
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
// File class
#define ELFCLASSNONE 0
#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_LORESERVE 0xFF00
#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_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xFFFFFFFF
// Custom section types
#define SHT_PSPREL 0x700000a0
// Section flags
enum ElfSectionFlags
{
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_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
// 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
// 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
// Segment flags
#define PF_X 1
#define PF_W 2
#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
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;
// ELF file header
struct Elf32_Ehdr
{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
};
// Section header
struct Elf32_Shdr
{
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
};
// Segment header
struct Elf32_Phdr
{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
};
// Symbol table entry
struct Elf32_Sym
{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half 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))
// Relocation entries
struct Elf32_Rel
{
Elf32_Addr r_offset;
Elf32_Word r_info;
};
struct Elf32_Rela
{
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
};
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t))
struct Elf32_Dyn
{
Elf32_Sword d_tag;
union
{
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
};
#endif