264 changes: 264 additions & 0 deletions Source/Core/Core/Src/HLE/HLE_Misc.cpp
Expand Up @@ -22,10 +22,25 @@
#include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h"
#include "../Host.h"
#include "IPC_HLE/WII_IPC_HLE_Device_DI.h"
#include "ConfigManager.h"
#include "VolumeCreator.h"
#include "Filesystem.h"
#include "../Boot/Boot_DOL.h"
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "HLE.h"
#include "PowerPC/PPCAnalyst.h"
#include "PowerPC/SignatureDB.h"
#include "PowerPC/PPCSymbolDB.h"
#include "CommonPaths.h"

namespace HLE_Misc
{

std::string args;
u32 argsPtr;
u32 bootType;

// Helper to quickly read the floating point value at a memory location.
inline float F(u32 addr)
{
Expand Down Expand Up @@ -282,4 +297,253 @@ void HBReload()
Host_Message(WM_USER_STOP);
}

void ExecuteDOL(u8* dolFile, u32 fileSize)
{
// Clear memory before loading the dol
for (u32 i = 0x80004000; i < Memory::Read_U32(0x00000034); i += 4)
{
// TODO: Should not write over the "save region"
Memory::Write_U32(0x00000000, i);
}
CDolLoader dolLoader(dolFile, fileSize);
dolLoader.Load();

// Scan for common HLE functions
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
{
g_symbolDB.Clear();
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
{
db.Apply(&g_symbolDB);
HLE::PatchFunctions();
db.Clear();
}
}

PowerPC::ppcState.iCache.Reset();

CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
size_t size = s_Usb->m_WiiMotes.size();
bool* wiiMoteConnected = new bool[size];
for (unsigned int i = 0; i < size; i++)
wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();

WII_IPC_HLE_Interface::Reset(true);
WII_IPC_HLE_Interface::Init();
s_Usb = GetUsbPointer();
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
{
if (wiiMoteConnected[i])
{
s_Usb->m_WiiMotes[i].Activate(false);
s_Usb->m_WiiMotes[i].Activate(true);
}
else
{
s_Usb->m_WiiMotes[i].Activate(false);
}
}

delete[] wiiMoteConnected;

if (argsPtr)
{
u32 args_base = Memory::Read_U32(0x800000f4);
u32 ptr_to_num_args = 0xc;
u32 num_args = 1;
u32 hi_ptr = args_base + ptr_to_num_args + 4;
u32 new_args_ptr = args_base + ptr_to_num_args + 8;

Memory::Write_U32(ptr_to_num_args, args_base + 8);
Memory::Write_U32(num_args, args_base + ptr_to_num_args);
Memory::Write_U32(0x14, hi_ptr);

for (unsigned int i = 0; i < args.length(); i++)
Memory::WriteUnchecked_U8(args[i], new_args_ptr+i);
}

NPC = dolLoader.GetEntryPoint() | 0x80000000;
}

void LoadDOLFromDisc(std::string dol)
{
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);

if (dol.length() > 1 && dol.compare(0, 1, "/") == 0)
dol = dol.substr(1);

u32 fileSize = (u32) pFileSystem->GetFileSize(dol.c_str());
u8* dolFile = new u8[fileSize];
if (fileSize > 0)
{
pFileSystem->ReadFile(dol.c_str(), dolFile, fileSize);
ExecuteDOL(dolFile, fileSize);
}
delete[] dolFile;
}

void LoadBootDOLFromDisc()
{
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);
u32 fileSize = pFileSystem->GetBootDOLSize();
u8* dolFile = new u8[fileSize];
if (fileSize > 0)
{
pFileSystem->GetBootDOL(dolFile, fileSize);
ExecuteDOL(dolFile, fileSize);
}
delete[] dolFile;
}

u32 GetDolFileSize(std::string dol)
{
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);

std::string dolFile;

if (dol.length() > 1 && dol.compare(0, 1, "/") == 0)
dolFile = dol.substr(1);
else
dolFile = dol;

return (u32)pFileSystem->GetFileSize(dolFile.c_str());
}

void gc_memmove()
{
u32 dest = GPR(3);
u32 src = GPR(4);
u32 count = GPR(5);
memmove((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
NPC = LR;
}

void gc_memcpy()
{
u32 dest = GPR(3);
u32 src = GPR(4);
u32 count = GPR(5);
memcpy((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
NPC = LR;
}

void gc_memset()
{
u32 dest = GPR(3);
u32 ch = GPR(4);
u32 count = GPR(5);
memset((u8*)(Memory::base + dest), ch, count);
NPC = LR;
}

void gc_memcmp()
{
u32 dest = GPR(3);
u32 src = GPR(4);
u32 count = GPR(5);
GPR(3) = memcmp((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
NPC = LR;
}

void div2i()
{
s64 num = (s64)(GPR(3)) << 32 | GPR(4);
s64 den = (s64)(GPR(5)) << 32 | GPR(6);
s64 quo = num / den;
GPR(3) = quo >> 32;
GPR(4) = quo & 0xffffffff;
NPC = LR;
}

void div2u()
{
u64 num = (u64)(GPR(3)) << 32 | GPR(4);
u64 den = (u64)(GPR(5)) << 32 | GPR(6);
u64 quo = num / den;
GPR(3) = quo >> 32;
GPR(4) = quo & 0xffffffff;
NPC = LR;
}

void OSGetResetCode()
{
u32 resetCode = Memory::Read_U32(0xCC003024);

if ((resetCode & 0x1fffffff) != 0)
{
GPR(3) = resetCode | 0x80000000;
}
else
{
GPR(3) = 0;
}

NPC = LR;
}

u16 GetIOSVersion()
{
return Memory::Read_U16(0x00003140);
}

void OSBootDol()
{
if (GetIOSVersion() >= 30)
{
bootType = GPR(4);

if ((GPR(4) >> 28) == 0x8)
{
u32 resetCode = GPR(30);

// Reset game
Memory::Write_U32(resetCode, 0xCC003024);
LoadBootDOLFromDisc();
return;
}
else if ((GPR(4) >> 28) == 0xA)
{
// Boot from disc partition
PanicAlert("Boot Partition: %08x", GPR(26));
}
else if ((GPR(4) >> 28) == 0xC)
{
std::string dol;

// Boot DOL from disc
u32 ptr = GPR(28);
Memory::GetString(dol, ptr);

if (GetDolFileSize(dol) == 0)
{
ptr = GPR(30);
Memory::GetString(dol, ptr);
if (GetDolFileSize(dol) == 0)
{
// Cannot locate the dol file, exit.
HLE::UnPatch("__OSBootDol");
NPC = PC;
return;
}
}

argsPtr = Memory::Read_U32(GPR(5));
Memory::GetString(args, argsPtr);
LoadDOLFromDisc(dol);
return;
}
else
{
PanicAlert("Unknown boot type: %08x", GPR(4));
}
}
HLE::UnPatch("__OSBootDol");
NPC = PC;
}

}
9 changes: 9 additions & 0 deletions Source/Core/Core/Src/HLE/HLE_Misc.h
Expand Up @@ -39,6 +39,15 @@ namespace HLE_Misc
void FZ_sqrt_internal();
void FZ_rsqrt_internal();
void HBReload();
void OSBootDol();
void OSGetResetCode();
void memcpy();
void memset();
void memmove();
void memcmp();
void div2i();
void div2u();
void ExecuteDOL(u8* dolFile, u32 fileSize);
}

#endif
5 changes: 1 addition & 4 deletions Source/Core/Core/Src/HW/Memmap.cpp
Expand Up @@ -416,10 +416,7 @@ bool AreMemoryBreakpointsActivated()
u32 Read_Instruction(const u32 em_address)
{
UGeckoInstruction inst = ReadUnchecked_U32(em_address);
if (inst.OPCD == 1)
return HLE::GetOrigInstruction(em_address);
else
return inst.hex;
return inst.hex;
}

u32 Read_Opcode_JIT_Uncached(const u32 _Address)
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/Src/HW/ProcessorInterface.cpp
Expand Up @@ -96,8 +96,7 @@ void Init()
m_FlipperRev = 0x246500B1; // revision C
m_Unknown = 0;

// Bleh, why?
//m_ResetCode |= 0x80000000;
m_ResetCode = 0x80000000; // Cold reset
m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI;

toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", &ToggleResetButtonCallback);
Expand Down Expand Up @@ -199,6 +198,7 @@ void Write32(const u32 _uValue, const u32 _iAddress)

case PI_RESET_CODE:
DEBUG_LOG(PROCESSORINTERFACE, "Write %08x to PI_RESET_CODE", _uValue);
m_ResetCode = _uValue;
break;

case PI_FLIPPER_UNK:
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
Expand Up @@ -780,7 +780,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
// someone with an affected game should test
IOSv = TitleID & 0xffff;
}
if (!bSuccess)
if (!bSuccess && IOSv >= 30 && IOSv != 0xffff)
{
PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available in your nand dump\n"
"TitleID %016llx.\n Dolphin will likely hang now", TitleID);
Expand Down
98 changes: 59 additions & 39 deletions Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp
Expand Up @@ -26,6 +26,7 @@
#include "PowerPCDisasm.h"
#include "../../IPC_HLE/WII_IPC_HLE.h"
#include "Atomic.h"
#include "HLE/HLE.h"


namespace {
Expand Down Expand Up @@ -79,57 +80,63 @@ int startTrace = 0;

void Trace( UGeckoInstruction &instCode )
{
char regs[500]="";
char reg[25]="";
std::string regs = "";
for (int i=0; i<32; i++) {
sprintf(regs, "%sr%02d: %08x ", regs, i, PowerPC::ppcState.gpr[i]);
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
regs.append(reg);
}

char fregs[500]="";
char freg[25]="";
std::string fregs = "";
for (int i=0; i<32; i++) {
sprintf(fregs, "%sf%02d: %08llx %08llx ", fregs, i,
PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
sprintf(freg, "f%02d: %08llx %08llx ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
fregs.append(freg);
}

char ppcInst[256];
DisassembleGekko(instCode.hex, PC, ppcInst, 256);

DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, instCode.hex, ppcInst);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str(), instCode.hex, ppcInst);
}

int Interpreter::SingleStepInner(void)
{
static UGeckoInstruction instCode;

NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = Memory::Read_Opcode(PC);

// Uncomment to trace the interpreter
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
// startTrace = 1;
//else
// startTrace = 0;

if (startTrace)
{
Trace(instCode);
}

if (instCode.hex != 0)
u32 function = m_EndBlock ? HLE::GetFunctionIndex(PC) : 0; // Check for HLE functions after branches
if (function != 0)
{
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) //If FPU is enabled, just execute
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
PowerPC::CheckExceptions();
m_EndBlock = true;
HLEFunction(function);
}
}
else
}
else
{
NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = Memory::Read_Opcode(PC);

// Uncomment to trace the interpreter
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
// startTrace = 1;
//else
// startTrace = 0;

if (startTrace)
{
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
Trace(instCode);
}

if (instCode.hex != 0)
{
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) //If FPU is enabled, just execute
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
Expand All @@ -140,17 +147,30 @@ int Interpreter::SingleStepInner(void)
}
else
{
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
PowerPC::CheckExceptions();
m_EndBlock = true;
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
}
}
else
{
// Memory exception on instruction fetch
PowerPC::CheckExceptions();
m_EndBlock = true;
else
{
// Memory exception on instruction fetch
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
last_pc = PC;
PC = NPC;
Expand Down
37 changes: 35 additions & 2 deletions Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp
Expand Up @@ -252,8 +252,6 @@ void Jit64::HLEFunction(UGeckoInstruction _inst)
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInEAX();
}

void Jit64::DoNothing(UGeckoInstruction _inst)
Expand Down Expand Up @@ -566,6 +564,27 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
ABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
}

u32 function = HLE::GetFunctionIndex(ops[i].address);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
if (type == HLE::HLE_HOOK_REPLACE)
{
MOV(32, R(EAX), M(&NPC));
js.downcountAmount += js.st.numCycles;
WriteExitDestInEAX();
break;
}
}
}
}

if (!ops[i].skip)
{
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
Expand Down Expand Up @@ -668,6 +687,20 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
break;
}

u32 function = HLE::GetFunctionIndex(js.blockStart);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_END)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
}
}
}

if (memory_exception)
{
// Address of instruction could not be translated
Expand Down
39 changes: 37 additions & 2 deletions Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
Expand Up @@ -199,7 +199,7 @@ namespace JitILProfiler
static u64 beginTime;
static Block& Add(u64 codeHash)
{
const u32 _blockIndex = blocks.size();
const u32 _blockIndex = (u32)blocks.size();
blocks.push_back(Block());
Block& block = blocks.back();
block.index = _blockIndex;
Expand Down Expand Up @@ -649,6 +649,27 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
js.next_compilerPC = ops[i + 1].address;
}

u32 function = HLE::GetFunctionIndex(ops[i].address);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
if (type == HLE::HLE_HOOK_REPLACE)
{
MOV(32, R(EAX), M(&NPC));
jit->js.downcountAmount += jit->js.st.numCycles;
WriteExitDestInOpArg(R(EAX));
break;
}
}
}
}

if (!ops[i].skip)
{
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
Expand All @@ -665,7 +686,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{
ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
}

JitILTables::CompileInstruction(ops[i]);

if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
Expand All @@ -681,6 +702,20 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
}
}

u32 function = HLE::GetFunctionIndex(jit->js.blockStart);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_END)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
}
}
}

if (memory_exception)
{
ibuild.EmitISIException(ibuild.EmitIntConst(em_address));
Expand Down
6 changes: 5 additions & 1 deletion Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
Expand Up @@ -135,7 +135,11 @@ bool JitBlock::ContainsAddress(u32 em_address)
// is full and when saving and loading states.
void JitBlockCache::Clear()
{
Core::DisplayMessage("Clearing code cache.", 3000);
if (IsFull())
Core::DisplayMessage("Clearing block cache.", 3000);
else
Core::DisplayMessage("Clearing code cache.", 3000);

for (int i = 0; i < num_blocks; i++)
{
DestroyBlock(i, false);
Expand Down
21 changes: 8 additions & 13 deletions Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp
Expand Up @@ -269,23 +269,18 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce

void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
{
u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;
if (false && cpu_info.bSSSE3) {
// This path should be faster but for some reason it causes errors so I've disabled it.
u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;

if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack)
{
mem_mask |= Memory::ADDR_MASK_MEM1;
}
if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack)
mem_mask |= Memory::ADDR_MASK_MEM1;

#ifdef ENABLE_MEM_CHECK
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
mem_mask |= Memory::EXRAM_MASK;
}
if (Core::g_CoreStartupParameter.bEnableDebugging)
mem_mask |= Memory::EXRAM_MASK;
#endif

TEST(32, R(reg_addr), Imm32(mem_mask));
if (false && cpu_info.bSSSE3) {
// This path should be faster but for some reason it causes errors so I've disabled it.
TEST(32, R(reg_addr), Imm32(mem_mask));
FixupBranch argh = J_CC(CC_Z);
MOVSS(M(&float_buffer), xmm_value);
MOV(32, R(EAX), M(&float_buffer));
Expand Down
15 changes: 14 additions & 1 deletion Source/Core/DiscIO/Src/FileSystemGCWii.cpp
Expand Up @@ -153,7 +153,7 @@ bool CFileSystemGCWii::ExportApploader(const char* _rExportFolder) const
return false;
}

bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
u32 CFileSystemGCWii::GetBootDOLSize() const
{
u32 DolOffset = Read32(0x420) << m_OffsetShift;
u32 DolSize = 0, offset = 0, size = 0;
Expand All @@ -175,6 +175,19 @@ bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
if (offset + size > DolSize)
DolSize = offset + size;
}
return DolSize;
}

bool CFileSystemGCWii::GetBootDOL(u8* &buffer, u32 DolSize) const
{
u32 DolOffset = Read32(0x420) << m_OffsetShift;
return m_rVolume->Read(DolOffset, DolSize, buffer);
}

bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
{
u32 DolOffset = Read32(0x420) << m_OffsetShift;
u32 DolSize = GetBootDOLSize();

std::vector<u8> buffer(DolSize);
if (m_rVolume->Read(DolOffset, DolSize, &buffer[0]))
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/Src/FileSystemGCWii.h
Expand Up @@ -38,6 +38,8 @@ class CFileSystemGCWii : public IFileSystem
virtual bool ExportFile(const char* _rFullPath, const char* _rExportFilename);
virtual bool ExportApploader(const char* _rExportFolder) const;
virtual bool ExportDOL(const char* _rExportFolder) const;
virtual bool GetBootDOL(u8* &buffer, u32 DolSize) const;
virtual u32 GetBootDOLSize() const;

private:
bool m_Initialized;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/Src/Filesystem.h
Expand Up @@ -57,6 +57,8 @@ class IFileSystem
virtual bool ExportApploader(const char* _rExportFolder) const = 0;
virtual bool ExportDOL(const char* _rExportFolder) const = 0;
virtual const char* GetFileName(u64 _Address) = 0;
virtual bool GetBootDOL(u8* &buffer, u32 DolSize) const = 0;
virtual u32 GetBootDOLSize() const = 0;

virtual const IVolume *GetVolume() const { return m_rVolume; }
protected:
Expand Down