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/group_mgr.cpp
${ZENITH_DIR}/hle/bios_class.cpp
${ZENITH_DIR}/hle/syscall_gate.cpp
${ZENITH_DIR}/fs/bios_loader.cpp
${ZENITH_DIR}/iop/iop_core.cpp
${ZENITH_DIR}/iop/iop_cop.cpp
@ -63,6 +64,7 @@ target_sources(zenith PRIVATE
${ZENITH_DIR}/console/emu_thread.cpp
${ZENITH_DIR}/console/sched_logical.cpp
${ZENITH_DIR}/console/intc.cpp
${ZENITH_DIR}/console/backdoor.cpp
${ZENITH_MISC_DIR}/jvm_comm.cpp
${ZENITH_MISC_DIR}/drivers_glvk_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
// 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 <console/emu_vm.h>
#include <console/backdoor.h>
#include <eeiv/ee_info.h>
#define TestBiosAccess 0
namespace zenith::console {
EmuVM::EmuVM(JNIEnv* env,
@ -22,6 +24,8 @@ namespace zenith::console {
frames = 30;
intc = std::make_shared<INTCInfra>(*this);
// Our way to perform interconnection between different isolated components
redBox = std::make_shared<RedPillow>(*this);
}
void EmuVM::startVM() {
@ -55,4 +59,20 @@ namespace zenith::console {
mips->resetCore();
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 <gpu/hw_render.h>
#include <hle/bios_patch.h>
#include <hle/syscall_gate.h>
#include <gpu/exhibition_engine.h>
#include <console/emu_thread.h>
@ -18,6 +19,7 @@ namespace zenith::console {
void resetVM();
void startVM();
void dealWithSyscalls();
std::shared_ptr<hle::BiosPatcher> biosHLE;
@ -33,5 +35,7 @@ namespace zenith::console {
private:
EmuThread emuThread;
std::shared_ptr<INTCInfra> intc;
hle::SyscallDealer dealer;
};
}

View File

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

View File

@ -1,5 +1,6 @@
#include <fuji/iop_interpreter.h>
#include <iop/iop_core.h>
#include <console/backdoor.h>
#include <console/emu_vm.h>
#define SwOpcode(op)\
op(Operands(opcode, opeRegs));\
@ -39,7 +40,7 @@ namespace zenith::fuji {
u32* gprSrc = &ioMips.IOGPRs[ops.thi];
u32* gprDest = &ioMips.IOGPRs[ops.sec];
u8 opp{ops.operation.pa8[3]};
if (opp == Slti) {
if (opp == IopSlti) {
i32 imm{ops.operation.sins & 0xffff};
*gprDest = *gprSrc < imm;
} else if (opp == Sltiu) {
@ -57,6 +58,13 @@ namespace zenith::fuji {
orSMips(ops);
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) {
u16 cop{static_cast<u16>((opcode >> 21) & 0x1f)};
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) {
u8 specialOp{static_cast<u8>(opcode & 0x3f)};
switch (specialOp) {
case SpecialMfhi: SwOpcode(mfhi);
case SpecialMthi: SwOpcode(mthi);
case SpecialOr: SwOpcode(orSMips);
case SpecialXor: SwOpcode(xorSMips);
case IopSpecialSyscall: SwOpcode(syscall);
case SpecialMfhi: SwOpcode(mfhi);
case SpecialMthi: SwOpcode(mthi);
case SpecialOr: SwOpcode(orSMips);
case IopSpecialXor: SwOpcode(xorSMips);
}
return opcode;
}
@ -85,7 +94,7 @@ namespace zenith::fuji {
case 0x10 ... 0x13:
execCopRow(opcode, opeRegs);
break;
case Slti:
case IopSlti:
case Sltiu:
SwOpcode(sltBy);
default:

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#include <fuji/mipsiv_interpreter.h>
#include <eeiv/ee_engine.h>
#include <eeiv/ee_assembler.h>
#include <console/backdoor.h>
#include <console/emu_vm.h>
namespace zenith::fuji {
IvFujiSuperAsm(addi) {
mainMips.GPRs[ops.sec].words[0] = ops.operation.pa16[0] +
@ -107,4 +109,11 @@ namespace zenith::fuji {
IvFujiSuperAsm(iBreak) {
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 {
u32 MipsIVInterpreter::decMipsIvS(u32 opcode, InvokeOpInfo& decode) {
switch (opcode & 0x3f) {
case SpecialBreak: SWCached(iBreak);
case SpecialXor: SWCached(ivXor);
case SpecialSlt: SWCached(slt);
case EeSpecialSyscall: SWCached(syscall);
case SpecialBreak: SWCached(iBreak);
case EeSpecialXor: SWCached(ivXor);
case SpecialSlt: SWCached(slt);
}
return opcode & 0x3f;
}
@ -66,8 +67,8 @@ namespace zenith::fuji {
case RegImmOpcodes:
decMipsIvRegImm(opcode, decode);
break;
case Addi: SWCached(addi);
case Slti: SWCached(slti);
case Addi: SWCached(addi);
case EeSlti: SWCached(slti);
case CopOpcodes:
decMipsIvCop0(opcode, decode);
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;
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();
void intByINTC(bool isInt);
void handleException(u32 vec, u8 code);
std::array<u32, 32> IOGPRs;
std::array<IOPCache, 128> iCache;
std::shared_ptr<mio::GlobalMemory> iopMem;
@ -42,6 +44,8 @@ namespace zenith::iop {
ioPc,
cyclesToIO;
IopCop cop;
bool onBranch{false};
private:
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.
plugins {
id("com.android.application") version "8.1.3" apply false
id("com.android.library") version "8.1.3" apply false
id("com.android.application") version "8.1.4" apply false
id("com.android.library") version "8.1.4" apply false
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
}