Fuji,EE,IOP: Now our MIPS can make SYSCALL

This commit is contained in:
Gabriel Correia 2023-11-18 03:09:45 -03:00
parent 52fe114081
commit 7e9694a119
16 changed files with 208 additions and 20 deletions

View File

@ -48,6 +48,7 @@ target_sources(zenith PRIVATE
${ZENITH_DIR}/hle/bios_patch.cpp ${ZENITH_DIR}/hle/bios_patch.cpp
${ZENITH_DIR}/hle/group_mgr.cpp ${ZENITH_DIR}/hle/group_mgr.cpp
${ZENITH_DIR}/hle/bios_class.cpp ${ZENITH_DIR}/hle/bios_class.cpp
${ZENITH_DIR}/hle/syscall_gate.cpp
${ZENITH_DIR}/fs/bios_loader.cpp ${ZENITH_DIR}/fs/bios_loader.cpp
${ZENITH_DIR}/iop/iop_core.cpp ${ZENITH_DIR}/iop/iop_core.cpp
${ZENITH_DIR}/iop/iop_cop.cpp ${ZENITH_DIR}/iop/iop_cop.cpp
@ -63,6 +64,7 @@ target_sources(zenith PRIVATE
${ZENITH_DIR}/console/emu_thread.cpp ${ZENITH_DIR}/console/emu_thread.cpp
${ZENITH_DIR}/console/sched_logical.cpp ${ZENITH_DIR}/console/sched_logical.cpp
${ZENITH_DIR}/console/intc.cpp ${ZENITH_DIR}/console/intc.cpp
${ZENITH_DIR}/console/backdoor.cpp
${ZENITH_MISC_DIR}/jvm_comm.cpp ${ZENITH_MISC_DIR}/jvm_comm.cpp
${ZENITH_MISC_DIR}/drivers_glvk_jni.cpp ${ZENITH_MISC_DIR}/drivers_glvk_jni.cpp
${ZENITH_MISC_DIR}/bios_jni.cpp ${ZENITH_MISC_DIR}/bios_jni.cpp

View File

@ -0,0 +1,46 @@
#include <console/backdoor.h>
namespace zenith {
std::shared_ptr<console::RedPillow> redBox;
}
namespace zenith::console {
RedPillow::RedPillow(EmuVM& aliveVm) {
vm = std::make_unique<raw_reference<EmuVM>>(std::ref(aliveVm));
mutual = std::unique_lock<std::mutex>();
vmRefs = 1;
}
raw_reference<EmuVM> RedPillow::openVm() {
std::thread::id nub{};
if (owner != std::this_thread::get_id()) {
mutual.lock();
owner = nub;
}
if (owner != nub) {
if (owner != std::this_thread::get_id())
throw AppFail("This resource should have the lock held until the object is released");
} else {
owner = std::this_thread::get_id();
}
raw_reference<EmuVM> vmRef{};
if (vmRefs) {
vmRef = *vm;
vmRefs++;
}
return vmRef;
}
void RedPillow::leaveVm(raw_reference<EmuVM> lvm) {
if (!mutual.try_lock()) {
if (owner != std::this_thread::get_id())
throw AppFail("The program flow is broken, review the usage of RedPillow in the code");
}
vmRefs--;
if (!vm || vmRefs <= 0) {
vm.reset();
vm = std::make_unique<raw_reference<EmuVM>>(lvm);
vmRefs = 1;
}
owner = {};
mutual.unlock();
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <common/types.h>
#include <thread>
#include <mutex>
namespace zenith::console {
class EmuVM;
class RedPillow {
public:
RedPillow(EmuVM& aliveVm);
raw_reference<EmuVM> openVm();
void leaveVm(raw_reference<EmuVM> lvm);
private:
std::thread::id owner;
std::unique_lock<std::mutex> mutual;
std::unique_ptr<raw_reference<EmuVM>> vm;
i32 vmRefs;
};
}
namespace zenith {
extern std::shared_ptr<console::RedPillow> redBox;
}

View File

@ -1,8 +1,10 @@
// SPDX-short-identifier: MIT, Version N/A // SPDX-short-identifier: MIT, Version N/A
// This file is protected by the MIT license (please refer to LICENSE.md before making any changes, copying, or redistributing this software) // This file is protected by the MIT license (please refer to LICENSE.md before making any changes, copying, or redistributing this software)
#include <console/emu_vm.h>
#include <common/global.h> #include <common/global.h>
#include <console/emu_vm.h>
#include <console/backdoor.h>
#include <eeiv/ee_info.h>
#define TestBiosAccess 0 #define TestBiosAccess 0
namespace zenith::console { namespace zenith::console {
EmuVM::EmuVM(JNIEnv* env, EmuVM::EmuVM(JNIEnv* env,
@ -22,6 +24,8 @@ namespace zenith::console {
frames = 30; frames = 30;
intc = std::make_shared<INTCInfra>(*this); intc = std::make_shared<INTCInfra>(*this);
// Our way to perform interconnection between different isolated components
redBox = std::make_shared<RedPillow>(*this);
} }
void EmuVM::startVM() { void EmuVM::startVM() {
@ -55,4 +59,20 @@ namespace zenith::console {
mips->resetCore(); mips->resetCore();
iop->resetIOP(); iop->resetIOP();
} }
void EmuVM::dealWithSyscalls() {
hle::SyscallOrigin ori{};
// 08: Syscall Generated unconditionally by syscall instruction
if (mips->cop0.cause.exCode == 0x8)
ori = hle::SysEmotionEngine;
else if (iop->cop.cause.code == 0x8)
ori = hle::SysIop;
if (ori == hle::SysEmotionEngine) {
i16 eeSystem{*mips->gprAt<i16*>(eeiv::$v1)};
dealer.doSyscall(ori, eeSystem);
mips->cop0.cause.exCode = 0;
} else {
iop->handleException(0x80000080, 0x8);
}
}
} }

View File

@ -4,6 +4,7 @@
#include <mio/main_memory.h> #include <mio/main_memory.h>
#include <gpu/hw_render.h> #include <gpu/hw_render.h>
#include <hle/bios_patch.h> #include <hle/bios_patch.h>
#include <hle/syscall_gate.h>
#include <gpu/exhibition_engine.h> #include <gpu/exhibition_engine.h>
#include <console/emu_thread.h> #include <console/emu_thread.h>
@ -18,6 +19,7 @@ namespace zenith::console {
void resetVM(); void resetVM();
void startVM(); void startVM();
void dealWithSyscalls();
std::shared_ptr<hle::BiosPatcher> biosHLE; std::shared_ptr<hle::BiosPatcher> biosHLE;
@ -33,5 +35,7 @@ namespace zenith::console {
private: private:
EmuThread emuThread; EmuThread emuThread;
std::shared_ptr<INTCInfra> intc; std::shared_ptr<INTCInfra> intc;
hle::SyscallDealer dealer;
}; };
} }

View File

@ -26,7 +26,8 @@ namespace zenith::fuji {
Cop0Mtc = 0x4, Cop0Mtc = 0x4,
Cop0Bc0 = 0x8, Cop0Bc0 = 0x8,
Addi = 0x8, Addi = 0x8,
Slti = 0xa, EeSlti = 0xa,
EeSpecialSyscall = 0xc,
SpecialBreak = 0xd, SpecialBreak = 0xd,
RegImmBltzal = 0x10, RegImmBltzal = 0x10,
CopOpcodes = 0x10, CopOpcodes = 0x10,
@ -44,7 +45,7 @@ namespace zenith::fuji {
Nop = 0x33, Nop = 0x33,
Ld = 0x37, Ld = 0x37,
SpecialXor = 0x26, EeSpecialXor = 0x26,
SpecialSlt = 0x2a, SpecialSlt = 0x2a,
Sw = 0x2b, Sw = 0x2b,
}; };

View File

@ -1,5 +1,6 @@
#include <fuji/iop_interpreter.h> #include <fuji/iop_interpreter.h>
#include <iop/iop_core.h> #include <console/backdoor.h>
#include <console/emu_vm.h>
#define SwOpcode(op)\ #define SwOpcode(op)\
op(Operands(opcode, opeRegs));\ op(Operands(opcode, opeRegs));\
@ -39,7 +40,7 @@ namespace zenith::fuji {
u32* gprSrc = &ioMips.IOGPRs[ops.thi]; u32* gprSrc = &ioMips.IOGPRs[ops.thi];
u32* gprDest = &ioMips.IOGPRs[ops.sec]; u32* gprDest = &ioMips.IOGPRs[ops.sec];
u8 opp{ops.operation.pa8[3]}; u8 opp{ops.operation.pa8[3]};
if (opp == Slti) { if (opp == IopSlti) {
i32 imm{ops.operation.sins & 0xffff}; i32 imm{ops.operation.sins & 0xffff};
*gprDest = *gprSrc < imm; *gprDest = *gprSrc < imm;
} else if (opp == Sltiu) { } else if (opp == Sltiu) {
@ -57,6 +58,13 @@ namespace zenith::fuji {
orSMips(ops); orSMips(ops);
ioMips.IOGPRs[ops.fir] = ~ioMips.IOGPRs[ops.fir]; ioMips.IOGPRs[ops.fir] = ~ioMips.IOGPRs[ops.fir];
} }
IvFujiIopAsm(syscall) {
ioMips.cop.cause.code = 0x8;
raw_reference<console::EmuVM> vm{redBox->openVm()};
vm->dealWithSyscalls();
redBox->leaveVm(vm);
}
u32 IOPInterpreter::execCopRow(u32 opcode, std::array<u8, 3> opeRegs) { u32 IOPInterpreter::execCopRow(u32 opcode, std::array<u8, 3> opeRegs) {
u16 cop{static_cast<u16>((opcode >> 21) & 0x1f)}; u16 cop{static_cast<u16>((opcode >> 21) & 0x1f)};
cop |= static_cast<u16>((opcode >> 26) & 0x3) << 8; cop |= static_cast<u16>((opcode >> 26) & 0x3) << 8;
@ -70,10 +78,11 @@ namespace zenith::fuji {
u32 IOPInterpreter::execIO3S(u32 opcode, std::array<u8, 3> opeRegs) { u32 IOPInterpreter::execIO3S(u32 opcode, std::array<u8, 3> opeRegs) {
u8 specialOp{static_cast<u8>(opcode & 0x3f)}; u8 specialOp{static_cast<u8>(opcode & 0x3f)};
switch (specialOp) { switch (specialOp) {
case SpecialMfhi: SwOpcode(mfhi); case IopSpecialSyscall: SwOpcode(syscall);
case SpecialMthi: SwOpcode(mthi); case SpecialMfhi: SwOpcode(mfhi);
case SpecialOr: SwOpcode(orSMips); case SpecialMthi: SwOpcode(mthi);
case SpecialXor: SwOpcode(xorSMips); case SpecialOr: SwOpcode(orSMips);
case IopSpecialXor: SwOpcode(xorSMips);
} }
return opcode; return opcode;
} }
@ -85,7 +94,7 @@ namespace zenith::fuji {
case 0x10 ... 0x13: case 0x10 ... 0x13:
execCopRow(opcode, opeRegs); execCopRow(opcode, opeRegs);
break; break;
case Slti: case IopSlti:
case Sltiu: case Sltiu:
SwOpcode(sltBy); SwOpcode(sltBy);
default: default:

View File

@ -9,13 +9,14 @@ namespace zenith::fuji {
SpecialOp = 0x0, SpecialOp = 0x0,
CopMfc = 0x0, CopMfc = 0x0,
CopMtc = 0x4, CopMtc = 0x4,
Slti = 0x0a, IopSlti = 0x0a,
Sltiu = 0x0b, Sltiu = 0x0b,
IopSpecialSyscall = 0xc,
SpecialMfhi = 0x10, SpecialMfhi = 0x10,
CopRfe = 0x10, CopRfe = 0x10,
SpecialMthi = 0x11, SpecialMthi = 0x11,
SpecialOr = 0x25, SpecialOr = 0x25,
SpecialXor = 0x26, IopSpecialXor = 0x26,
SpecialNor = 0x27 SpecialNor = 0x27
}; };
@ -32,6 +33,7 @@ namespace zenith::fuji {
u32 fetchPcInst() override; u32 fetchPcInst() override;
IvFujiOp(sltBy); IvFujiOp(sltBy);
IvFujiOp(syscall);
IvFujiOp(mfhi); IvFujiOp(mfhi);
IvFujiOp(mthi); IvFujiOp(mthi);

View File

@ -16,7 +16,6 @@ namespace zenith::fuji {
Eret = 0x10, Eret = 0x10,
Cop0 = 0x12 Cop0 = 0x12
}; };
friend EffectivePipeline operator^(EffectivePipeline dest, EffectivePipeline src) { friend EffectivePipeline operator^(EffectivePipeline dest, EffectivePipeline src) {
return static_cast<EffectivePipeline>(static_cast<u16>(dest) ^ static_cast<u16>(src)); return static_cast<EffectivePipeline>(static_cast<u16>(dest) ^ static_cast<u16>(src));
} }
@ -77,6 +76,7 @@ namespace zenith::fuji {
IvFujiOp(bltzal); IvFujiOp(bltzal);
IvFujiOp(bgez); IvFujiOp(bgezl); IvFujiOp(bgezall); IvFujiOp(bgez); IvFujiOp(bgezl); IvFujiOp(bgezall);
IvFujiOp(mtsab); IvFujiOp(mtsah); IvFujiOp(mtsab); IvFujiOp(mtsah);
IvFujiOp(syscall);
// Memory read functions through direct translation // Memory read functions through direct translation
IvFujiOp(lb); IvFujiOp(lbu); IvFujiOp(lb); IvFujiOp(lbu);

View File

@ -1,6 +1,8 @@
#include <fuji/mipsiv_interpreter.h> #include <fuji/mipsiv_interpreter.h>
#include <eeiv/ee_engine.h> #include <eeiv/ee_engine.h>
#include <eeiv/ee_assembler.h> #include <eeiv/ee_assembler.h>
#include <console/backdoor.h>
#include <console/emu_vm.h>
namespace zenith::fuji { namespace zenith::fuji {
IvFujiSuperAsm(addi) { IvFujiSuperAsm(addi) {
mainMips.GPRs[ops.sec].words[0] = ops.operation.pa16[0] + mainMips.GPRs[ops.sec].words[0] = ops.operation.pa16[0] +
@ -107,4 +109,11 @@ namespace zenith::fuji {
IvFujiSuperAsm(iBreak) { IvFujiSuperAsm(iBreak) {
mainMips.handleException(1, 0x80000180, 0x9); mainMips.handleException(1, 0x80000180, 0x9);
} }
IvFujiSuperAsm(syscall) {
mainMips.cop0.cause.exCode = 0x8;
// We need to directly handle these syscall, instead of mainMips.chPC(0x80000180);
auto vm{redBox->openVm()};
vm->dealWithSyscalls();
redBox->leaveVm(vm);
}
} }

View File

@ -10,9 +10,10 @@
namespace zenith::fuji { namespace zenith::fuji {
u32 MipsIVInterpreter::decMipsIvS(u32 opcode, InvokeOpInfo& decode) { u32 MipsIVInterpreter::decMipsIvS(u32 opcode, InvokeOpInfo& decode) {
switch (opcode & 0x3f) { switch (opcode & 0x3f) {
case SpecialBreak: SWCached(iBreak); case EeSpecialSyscall: SWCached(syscall);
case SpecialXor: SWCached(ivXor); case SpecialBreak: SWCached(iBreak);
case SpecialSlt: SWCached(slt); case EeSpecialXor: SWCached(ivXor);
case SpecialSlt: SWCached(slt);
} }
return opcode & 0x3f; return opcode & 0x3f;
} }
@ -66,8 +67,8 @@ namespace zenith::fuji {
case RegImmOpcodes: case RegImmOpcodes:
decMipsIvRegImm(opcode, decode); decMipsIvRegImm(opcode, decode);
break; break;
case Addi: SWCached(addi); case Addi: SWCached(addi);
case Slti: SWCached(slti); case EeSlti: SWCached(slti);
case CopOpcodes: case CopOpcodes:
decMipsIvCop0(opcode, decode); decMipsIvCop0(opcode, decode);
break; break;

View File

@ -0,0 +1,20 @@
#include <hle/syscall_gate.h>
#include <console/emu_vm.h>
namespace zenith::hle {
void SyscallDealer::hleResetEE(raw_reference<console::EmuVM> vm) {
i32 resetParam{*vm->mips->gprAt<i32*>(Param0)};
if (resetParam == 0) {}
else if (resetParam == 1) {}
}
void SyscallDealer::doSyscall(SyscallOrigin origin, i16 sys) {
auto vm{redBox->openVm()};
if (origin == SysEmotionEngine) {
switch (sys) {
case 0x01: // void ResetEE(i32 resetFlag);
hleResetEE(vm); break;
}
}
redBox->leaveVm(vm);
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <common/types.h>
#include <console/backdoor.h>
#include <eeiv/ee_info.h>
namespace zenith::hle {
enum CallParams {
Return = eeiv::$v0,
Param0 = eeiv::$a0,
Param1 = eeiv::$a1,
Param2 = eeiv::$a2,
Param3 = eeiv::$a3,
Param4 = eeiv::$t0,
Param5 = eeiv::$t1
};
enum SyscallOrigin {
SysEmotionEngine,
SysIop
};
class SyscallDealer {
public:
void doSyscall(SyscallOrigin origin, i16 sys);
private:
void hleResetEE(raw_reference<console::EmuVM> vm);
};
}

View File

@ -47,4 +47,19 @@ namespace zenith::iop {
ioPc += 4; ioPc += 4;
return ioOpcode; return ioOpcode;
} }
void IOMipsCore::handleException(u32 vec, u8 code) {
cop.cause.code = code;
if (onBranch)
cop.ePC = ioPc - 4;
else
cop.ePC = ioPc;
cop.cause.bd = onBranch;
cop.status.ieo = cop.status.iep;
cop.status.iep = cop.status.iec;
cop.status.iec = false;
// We do this to offset PC being incremented
ioPc = vec - 4;
onBranch = false;
}
} }

View File

@ -19,6 +19,8 @@ namespace zenith::iop {
u32 fetchByPC(); u32 fetchByPC();
void intByINTC(bool isInt); void intByINTC(bool isInt);
void handleException(u32 vec, u8 code);
std::array<u32, 32> IOGPRs; std::array<u32, 32> IOGPRs;
std::array<IOPCache, 128> iCache; std::array<IOPCache, 128> iCache;
std::shared_ptr<mio::GlobalMemory> iopMem; std::shared_ptr<mio::GlobalMemory> iopMem;
@ -42,6 +44,8 @@ namespace zenith::iop {
ioPc, ioPc,
cyclesToIO; cyclesToIO;
IopCop cop; IopCop cop;
bool onBranch{false};
private: private:
u8* iopPrivateAddrSolver(u32 address); u8* iopPrivateAddrSolver(u32 address);

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.1.3" apply false id("com.android.application") version "8.1.4" apply false
id("com.android.library") version "8.1.3" apply false id("com.android.library") version "8.1.4" apply false
id("org.jetbrains.kotlin.android") version "1.8.20" apply false id("org.jetbrains.kotlin.android") version "1.8.20" apply false
} }