mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 17:19:44 -06:00
Remove unnecessary Src/ folders
This commit is contained in:
432
Source/Core/Core/Boot/Boot.cpp
Normal file
432
Source/Core/Core/Boot/Boot.cpp
Normal 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;
|
||||
}
|
51
Source/Core/Core/Boot/Boot.h
Normal file
51
Source/Core/Core/Boot/Boot.h
Normal 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
|
438
Source/Core/Core/Boot/Boot_BS2Emu.cpp
Normal file
438
Source/Core/Core/Boot/Boot_BS2Emu.cpp
Normal 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();
|
||||
}
|
112
Source/Core/Core/Boot/Boot_DOL.cpp
Normal file
112
Source/Core/Core/Boot/Boot_DOL.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
57
Source/Core/Core/Boot/Boot_DOL.h
Normal file
57
Source/Core/Core/Boot/Boot_DOL.h
Normal 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
|
83
Source/Core/Core/Boot/Boot_ELF.cpp
Normal file
83
Source/Core/Core/Boot/Boot_ELF.cpp
Normal 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;
|
||||
}
|
5
Source/Core/Core/Boot/Boot_ELF.h
Normal file
5
Source/Core/Core/Boot/Boot_ELF.h
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
125
Source/Core/Core/Boot/Boot_WiiWAD.cpp
Normal file
125
Source/Core/Core/Boot/Boot_WiiWAD.cpp
Normal 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;
|
||||
}
|
||||
|
19
Source/Core/Core/Boot/Boot_WiiWAD.h
Normal file
19
Source/Core/Core/Boot/Boot_WiiWAD.h
Normal 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
|
||||
|
231
Source/Core/Core/Boot/ElfReader.cpp
Normal file
231
Source/Core/Core/Boot/ElfReader.cpp
Normal 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 = §ions[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;
|
||||
}
|
79
Source/Core/Core/Boot/ElfReader.h
Normal file
79
Source/Core/Core/Boot/ElfReader.h
Normal 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
|
||||
|
285
Source/Core/Core/Boot/ElfTypes.h
Normal file
285
Source/Core/Core/Boot/ElfTypes.h
Normal 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
|
||||
|
Reference in New Issue
Block a user