mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 09:45:24 +02:00
Merge pull request #22069 from hrydgard/read-u32-cleanups
Tech debt: Start cleaning up HLE memory access
This commit is contained in:
+72
-4
@@ -602,9 +602,11 @@ const char *MemoryExceptionTypeAsString(MemoryExceptionType type) {
|
||||
switch (type) {
|
||||
case MemoryExceptionType::UNKNOWN: return "Unknown";
|
||||
case MemoryExceptionType::READ_WORD: return "Read Word";
|
||||
case MemoryExceptionType::WRITE_WORD: return "Write Word";
|
||||
case MemoryExceptionType::READ_BLOCK: return "Read Block";
|
||||
case MemoryExceptionType::WRITE_WORD: return "Write Word";
|
||||
case MemoryExceptionType::WRITE_BLOCK: return "Read/Write Block";
|
||||
case MemoryExceptionType::HLE_READ: return "HLE Read";
|
||||
case MemoryExceptionType::HLE_WRITE: return "HLE Write";
|
||||
case MemoryExceptionType::ALIGNMENT: return "Alignment";
|
||||
default:
|
||||
return "N/A";
|
||||
@@ -638,14 +640,13 @@ static std::string ModuleAddressSuffix(u32 address) {
|
||||
}
|
||||
}
|
||||
|
||||
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string_view additionalInfo, bool forceReport) {
|
||||
const char *desc = MemoryExceptionTypeAsString(type);
|
||||
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string_view additionalInfo) {
|
||||
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
|
||||
|
||||
char pcDetails[128];
|
||||
pcDetails[0] = 0;
|
||||
if ((CPUCore)g_Config.iCpuCore == CPUCore::INTERPRETER) {
|
||||
snprintf(pcDetails, sizeof(pcDetails), " PC %08x%s LR %08x%s", currentMIPS->pc, ModuleAddressSuffix(currentMIPS->pc).c_str(), currentMIPS->r[MIPS_REG_RA], ModuleAddressSuffix(currentMIPS->r[MIPS_REG_RA]).c_str());
|
||||
snprintf(pcDetails, sizeof(pcDetails), " PC %08x%s RA %08x%s", currentMIPS->pc, ModuleAddressSuffix(currentMIPS->pc).c_str(), currentMIPS->r[MIPS_REG_RA], ModuleAddressSuffix(currentMIPS->r[MIPS_REG_RA]).c_str());
|
||||
}
|
||||
|
||||
const std::string addressSuffix = ModuleAddressSuffix(address);
|
||||
@@ -663,6 +664,7 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy
|
||||
break;
|
||||
}
|
||||
|
||||
const char *desc = MemoryExceptionTypeAsString(type);
|
||||
if (action == ExceptionAction::Ignore) {
|
||||
// Simplest logging and continue.
|
||||
WARN_LOG(Log::MemMap, "%s: Invalid access at %08x%s (size %08x) %s%.*s", desc, address, addressSuffix.c_str(), accessSize, pcDetails, (int)additionalInfo.length(), additionalInfo.data());
|
||||
@@ -686,6 +688,72 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy
|
||||
}
|
||||
}
|
||||
|
||||
void Core_MemoryExceptionHLE(MIPSState *mips, u32 address, u32 accessSize, MemoryExceptionType type) {
|
||||
ExceptionAction action;
|
||||
switch (type) {
|
||||
case MemoryExceptionType::HLE_WRITE:
|
||||
action = ResolveExceptionAction((ExceptionAction)g_Config.iExceptionActionMemWrite);
|
||||
break;
|
||||
case MemoryExceptionType::HLE_READ:
|
||||
action = ResolveExceptionAction((ExceptionAction)g_Config.iExceptionActionMemRead);
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_(false);
|
||||
action = ExceptionAction::Break;
|
||||
break;
|
||||
}
|
||||
|
||||
const HLEFunction *func = HLEGetFunctionBeingCalled();
|
||||
const char *funcName = func ? func->name : "unknown";
|
||||
|
||||
char args[512] = "";
|
||||
if (func) {
|
||||
HLEFormatLogArgs(mips, args, sizeof(args), func->argmask);
|
||||
}
|
||||
|
||||
const char *extra = "";
|
||||
// We do report some unaligned addresses. There are probably more that should report.
|
||||
// We try to derive the reason here, though maybe it should be passed in explicitly?
|
||||
// TODO: This check should probably be added to regular memory accesses too.
|
||||
if (Memory::IsValidAddress(address)) {
|
||||
if (accessSize == 2 || accessSize == 4 || accessSize == 8 || (address & (accessSize - 1))) {
|
||||
extra = " (unaligned)";
|
||||
} else if (accessSize > 8 && (accessSize & 3)) {
|
||||
extra = " (unaligned struct)";
|
||||
}
|
||||
}
|
||||
|
||||
const u32 pc = mips->pc;
|
||||
char msg[512];
|
||||
snprintf(msg, sizeof(msg), "Invalid access in %s(%s) %s at %08x%s (size %08x) PC %08x%s RA %08x%s",
|
||||
funcName, args,
|
||||
extra, address, ModuleAddressSuffix(address).c_str(), accessSize,
|
||||
pc, ModuleAddressSuffix(pc).c_str(),
|
||||
mips->r[MIPS_REG_RA], ModuleAddressSuffix(mips->r[MIPS_REG_RA]).c_str());
|
||||
|
||||
const char *desc = MemoryExceptionTypeAsString(type);
|
||||
if (action == ExceptionAction::Ignore) {
|
||||
// Simplest logging and continue.
|
||||
WARN_LOG(Log::MemMap, "HLE %s: %s", MemoryExceptionTypeAsString(type), msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string stackTrace = FormatStackTrace(WalkCurrentStack(-1));
|
||||
ERROR_LOG(Log::MemMap, "%s: %s\n%s", desc, msg, stackTrace.c_str());
|
||||
if (action == ExceptionAction::Break) {
|
||||
MIPSExceptionInfo &e = g_exceptionInfo;
|
||||
e = {};
|
||||
e.type = MIPSExceptionType::MEMORY;
|
||||
e.info.clear();
|
||||
e.memory_type = type;
|
||||
e.address = address;
|
||||
e.accessSize = accessSize;
|
||||
e.stackTrace = stackTrace;
|
||||
e.pc = pc;
|
||||
Core_Break(BreakReason::MemoryException, address);
|
||||
}
|
||||
}
|
||||
|
||||
// Can't be ignored, must break. Not sure we can get a meaningful stack trace here (since the PC is invalid).
|
||||
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
|
||||
const char *desc = ExecExceptionTypeAsString(type);
|
||||
|
||||
+7
-2
@@ -20,7 +20,6 @@
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
@@ -199,6 +198,8 @@ enum class MemoryExceptionType {
|
||||
UNKNOWN,
|
||||
READ_WORD,
|
||||
WRITE_WORD,
|
||||
HLE_READ,
|
||||
HLE_WRITE,
|
||||
READ_BLOCK,
|
||||
WRITE_BLOCK,
|
||||
ALIGNMENT,
|
||||
@@ -208,12 +209,16 @@ enum class ExecExceptionType {
|
||||
THREAD,
|
||||
};
|
||||
|
||||
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string_view additionalInfo = "", bool forceReport = false);
|
||||
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string_view additionalInfo = "");
|
||||
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type);
|
||||
void Core_BreakException(u32 pc);
|
||||
// Call when loading save states, etc.
|
||||
void Core_ResetException();
|
||||
|
||||
class MIPSState;
|
||||
// Shortcut, just calls Core_MemoryException with automatically determined parameters (function name, etc).
|
||||
void Core_MemoryExceptionHLE(MIPSState *mips, u32 address, u32 accessSize, MemoryExceptionType type);
|
||||
|
||||
enum class MIPSExceptionType {
|
||||
NONE,
|
||||
MEMORY,
|
||||
|
||||
+5
-2
@@ -919,7 +919,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
|
||||
float f;
|
||||
uint32_t u;
|
||||
} value;
|
||||
value.u = Memory::Read_U32(op.addr);
|
||||
value.u = Memory::ReadUnchecked_U32(op.addr); // we check the range above
|
||||
std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section;
|
||||
switch (op.PostShaderUniform.format) {
|
||||
case 0:
|
||||
@@ -1035,8 +1035,11 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
|
||||
|
||||
case CheatOp::CwCheatPointerCommands:
|
||||
{
|
||||
if (!Memory::IsValidAddress(op.addr + op.pointerCommands.baseOffset)) {
|
||||
break;
|
||||
}
|
||||
InvalidateICache(op.addr + op.pointerCommands.baseOffset, 4); // See note at top of file
|
||||
u32 base = Memory::Read_U32(op.addr + op.pointerCommands.baseOffset);
|
||||
u32 base = Memory::ReadUnchecked_U32(op.addr + op.pointerCommands.baseOffset);
|
||||
u32 val = op.val;
|
||||
int type = op.pointerCommands.type;
|
||||
for (int a = 0; a < op.pointerCommands.count; ++a) {
|
||||
|
||||
@@ -790,7 +790,12 @@ void DisassemblyData::createLines()
|
||||
lineAddresses.clear();
|
||||
|
||||
u32 pos = address;
|
||||
const u32 end = address+size;
|
||||
const u32 end = address + size;
|
||||
|
||||
if (!Memory::IsValidRange(address, size)) {
|
||||
ERROR_LOG(Log::CPU, "DisassemblyData can't create lines for invalid range 0x%08X-0x%08X", address, end);
|
||||
}
|
||||
|
||||
const u32 maxChars = g_disassemblyManager.getMaxParamChars();
|
||||
|
||||
std::string currentLine;
|
||||
@@ -802,7 +807,7 @@ void DisassemblyData::createLines()
|
||||
bool inString = false;
|
||||
while (pos < end)
|
||||
{
|
||||
u8 b = Memory::Read_U8(pos++);
|
||||
u8 b = Memory::ReadUnchecked_U8(pos++);
|
||||
if (b >= 0x20 && b <= 0x7F)
|
||||
{
|
||||
if (currentLine.size()+1 >= maxChars)
|
||||
@@ -879,18 +884,18 @@ void DisassemblyData::createLines()
|
||||
switch (type)
|
||||
{
|
||||
case DATATYPE_BYTE:
|
||||
value = Memory::Read_U8(pos);
|
||||
value = Memory::ReadUnchecked_U8(pos);
|
||||
snprintf(buffer, sizeof(buffer), "0x%02X", value);
|
||||
pos++;
|
||||
break;
|
||||
case DATATYPE_HALFWORD:
|
||||
value = Memory::Read_U16(pos);
|
||||
value = Memory::ReadUnchecked_U16(pos);
|
||||
snprintf(buffer, sizeof(buffer), "0x%04X", value);
|
||||
pos += 2;
|
||||
break;
|
||||
case DATATYPE_WORD:
|
||||
{
|
||||
value = Memory::Read_U32(pos);
|
||||
value = Memory::ReadUnchecked_U32(pos);
|
||||
const std::string label = g_symbolMap->GetLabelString(value);
|
||||
if (!label.empty())
|
||||
snprintf(buffer, sizeof(buffer), "%s", label.c_str());
|
||||
|
||||
@@ -182,7 +182,7 @@ void WebSocketMemoryReadU32(DebuggerRequest &req) {
|
||||
Core_RunOnCPUThread([&] {
|
||||
AutoDisabledReplacements memLock = LockMemory(true);
|
||||
JsonWriter &json = req.Respond();
|
||||
json.writeUint("value", Memory::Read_U32(addr));
|
||||
json.writeUint("value", Memory::ReadUnchecked_U32(addr));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ void WebSocketMemoryWriteU8(DebuggerRequest &req) {
|
||||
// Write two bytes to memory (memory.write_u16)
|
||||
//
|
||||
// Parameters:
|
||||
// - address: unsigned integer
|
||||
// - address: unsigned integer (can be unaligned! But not recommended. Should maybe disallow).
|
||||
// - value: unsigned integer
|
||||
//
|
||||
// Response (same event name):
|
||||
@@ -352,7 +352,7 @@ void WebSocketMemoryWriteU16(DebuggerRequest &req) {
|
||||
return req.Fail("CPU not started");
|
||||
// This only depends on addr, not on anything CPU-thread-owned, so fail fast here rather than
|
||||
// making a round trip through the queue for a request we already know is invalid.
|
||||
if (!Memory::IsValidAddress(addr))
|
||||
if (!Memory::IsValidRange(addr, 2))
|
||||
return req.Fail("Invalid address");
|
||||
|
||||
// Route the actual memory write to the CPU thread instead of poking at it directly
|
||||
@@ -360,7 +360,7 @@ void WebSocketMemoryWriteU16(DebuggerRequest &req) {
|
||||
Core_RunOnCPUThread([&] {
|
||||
AutoDisabledReplacements memLock = LockMemory(true);
|
||||
currentMIPS->InvalidateICache(addr, 2);
|
||||
Memory::Write_U16(val, addr);
|
||||
Memory::WriteUnchecked_U16(val, addr);
|
||||
Reporting::NotifyDebugger();
|
||||
|
||||
JsonWriter &json = req.Respond();
|
||||
@@ -371,7 +371,7 @@ void WebSocketMemoryWriteU16(DebuggerRequest &req) {
|
||||
// Write four bytes to memory (memory.write_u32)
|
||||
//
|
||||
// Parameters:
|
||||
// - address: unsigned integer
|
||||
// - address: unsigned integer (can be unaligned! But not recommended. Should maybe disallow).
|
||||
// - value: unsigned integer
|
||||
//
|
||||
// Response (same event name):
|
||||
@@ -389,7 +389,7 @@ void WebSocketMemoryWriteU32(DebuggerRequest &req) {
|
||||
return req.Fail("CPU not started");
|
||||
// This only depends on addr, not on anything CPU-thread-owned, so fail fast here rather than
|
||||
// making a round trip through the queue for a request we already know is invalid.
|
||||
if (!Memory::IsValidAddress(addr))
|
||||
if (!Memory::IsValidRange(addr, 4))
|
||||
return req.Fail("Invalid address");
|
||||
|
||||
// Route the actual memory write to the CPU thread instead of poking at it directly
|
||||
@@ -397,11 +397,11 @@ void WebSocketMemoryWriteU32(DebuggerRequest &req) {
|
||||
Core_RunOnCPUThread([&] {
|
||||
AutoDisabledReplacements memLock = LockMemory(true);
|
||||
currentMIPS->InvalidateICache(addr, 4);
|
||||
Memory::Write_U32(val, addr);
|
||||
Memory::WriteUnchecked_U32(val, addr);
|
||||
Reporting::NotifyDebugger();
|
||||
|
||||
JsonWriter &json = req.Respond();
|
||||
json.writeUint("value", Memory::Read_U32(addr));
|
||||
json.writeUint("value", Memory::ReadUnchecked_U32(addr));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -43,25 +43,16 @@ const u32 PSP_UTILITY_GAMEDATA_MODE_SHOW_PROGRESS = 1;
|
||||
|
||||
static const std::string SFO_FILENAME = "PARAM.SFO";
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<std::string> GetPSPFileList (const std::string &dirpath) {
|
||||
std::vector<std::string> FileList;
|
||||
auto Fileinfos = pspFileSystem.GetDirListing(dirpath);
|
||||
FileList.reserve(Fileinfos.size());
|
||||
static std::vector<std::string> GetPSPFileList(std::string_view dirpath) {
|
||||
std::vector<std::string> FileList;
|
||||
auto Fileinfos = pspFileSystem.GetDirListing(dirpath);
|
||||
FileList.reserve(Fileinfos.size());
|
||||
|
||||
for (auto it = Fileinfos.begin(); it != Fileinfos.end(); ++it) {
|
||||
std::string info = (*it).name;
|
||||
FileList.push_back(info);
|
||||
}
|
||||
return FileList;
|
||||
for (auto it = Fileinfos.begin(); it != Fileinfos.end(); ++it) {
|
||||
std::string info = (*it).name;
|
||||
FileList.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
PSPGamedataInstallDialog::PSPGamedataInstallDialog(UtilityDialogType type) : PSPDialog(type) {
|
||||
}
|
||||
|
||||
PSPGamedataInstallDialog::~PSPGamedataInstallDialog() {
|
||||
return FileList;
|
||||
}
|
||||
|
||||
int PSPGamedataInstallDialog::Init(u32 paramAddr) {
|
||||
@@ -70,6 +61,12 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) {
|
||||
return SCE_ERROR_UTILITY_INVALID_STATUS;
|
||||
}
|
||||
|
||||
if (!Memory::IsValidRange(paramAddr, sizeof(SceUtilityGamedataInstallParam))) {
|
||||
// This should probably crash
|
||||
ERROR_LOG(Log::sceUtility, "sceGamedataInstallInitStart: invalid param address 0x%08X", paramAddr);
|
||||
return SCE_KERNEL_ERROR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
param.ptr = paramAddr;
|
||||
inFileNames = GetPSPFileList("disc0:/PSP_GAME/INSDIR");
|
||||
numFiles = (int)inFileNames.size();
|
||||
@@ -90,7 +87,7 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int size = Memory::Read_U32(paramAddr);
|
||||
const int size = Memory::ReadUnchecked_U32(paramAddr);
|
||||
if (size != 1424 && size != 1432) {
|
||||
ERROR_LOG_REPORT(Log::sceUtility, "sceGamedataInstallInitStart: invalid param size %d", size);
|
||||
return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE;
|
||||
|
||||
@@ -35,8 +35,7 @@ struct SceUtilityGamedataInstallParam {
|
||||
|
||||
class PSPGamedataInstallDialog: public PSPDialog {
|
||||
public:
|
||||
PSPGamedataInstallDialog(UtilityDialogType type);
|
||||
~PSPGamedataInstallDialog();
|
||||
PSPGamedataInstallDialog(UtilityDialogType type) : PSPDialog(type) {}
|
||||
|
||||
int Init(u32 paramAddr);
|
||||
int Update(int animSpeed) override;
|
||||
|
||||
@@ -57,12 +57,14 @@ int PSPMsgDialog::Init(unsigned int paramAddr) {
|
||||
}
|
||||
|
||||
messageDialogAddr = paramAddr;
|
||||
if (!Memory::IsValidAddress(messageDialogAddr))
|
||||
{
|
||||
return 0;
|
||||
|
||||
if (!Memory::IsValid4AlignedAddress(paramAddr)) {
|
||||
// What to do?
|
||||
return SCE_KERNEL_ERROR_BAD_ARGUMENT;
|
||||
}
|
||||
int size = Memory::Read_U32(paramAddr);
|
||||
memset(&messageDialog,0,sizeof(messageDialog));
|
||||
|
||||
int size = Memory::ReadUnchecked_U32(paramAddr);
|
||||
memset(&messageDialog, 0, sizeof(messageDialog));
|
||||
// Only copy the right size to support different request format
|
||||
Memory::Memcpy(&messageDialog,paramAddr,size);
|
||||
|
||||
|
||||
@@ -59,16 +59,21 @@ int PSPNetconfDialog::Init(u32 paramAddr) {
|
||||
if (ReadStatus() != SCE_UTILITY_STATUS_NONE)
|
||||
return SCE_ERROR_UTILITY_INVALID_STATUS;
|
||||
|
||||
if (!Memory::IsValid4AlignedRange(paramAddr, sizeof(request))) {
|
||||
// What to do?
|
||||
return SCE_KERNEL_ERROR_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
NOTICE_LOG(Log::sceUtility, "PSPNetConfDialog Init");
|
||||
jsonReady_ = false;
|
||||
// Kick off a request to the infra-dns.json since we'll need it later.
|
||||
StartInfraJsonDownload();
|
||||
|
||||
requestAddr = paramAddr;
|
||||
int size = Memory::Read_U32(paramAddr);
|
||||
const u32 size = Memory::ReadUnchecked_U32(paramAddr);
|
||||
memset(&request, 0, sizeof(request));
|
||||
// Only copy the right size to support different request format
|
||||
Memory::Memcpy(&request, paramAddr, size);
|
||||
// Only copy the right size (bounded by the struct) to support different request format
|
||||
Memory::Memcpy(&request, paramAddr, std::min(size, (u32)sizeof(request)));
|
||||
|
||||
ChangeStatusInit(NET_INIT_DELAY_US);
|
||||
|
||||
|
||||
+17
-8
@@ -1009,7 +1009,7 @@ void hlePushFuncDesc(std::string_view module, std::string_view funcName) {
|
||||
}
|
||||
|
||||
// TODO: Also add support for argument names.
|
||||
size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) {
|
||||
size_t HLEFormatLogArgs(const MIPSState *mips, char *message, size_t sz, const char *argmask) {
|
||||
char *p = message;
|
||||
size_t used = 0;
|
||||
|
||||
@@ -1026,9 +1026,9 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) {
|
||||
for (size_t i = 0, n = strlen(argmask); i < n; ++i, ++reg) {
|
||||
u32 regval;
|
||||
if (reg < 8) {
|
||||
regval = PARAM(reg);
|
||||
regval = PARAM_MIPS(mips, reg);
|
||||
} else {
|
||||
u32 sp = currentMIPS->r[MIPS_REG_SP];
|
||||
u32 sp = mips->r[MIPS_REG_SP];
|
||||
// Goes upward on stack.
|
||||
// NOTE: Currently we only support > 8 for 32-bit integer args.
|
||||
regval = Memory::Read_U32(sp + (reg - 8) * 4);
|
||||
@@ -1036,16 +1036,16 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) {
|
||||
|
||||
switch (argmask[i]) {
|
||||
case 'p':
|
||||
if (Memory::IsValidAddress(regval)) {
|
||||
APPEND_FMT("%08x[%08x]", regval, Memory::Read_U32(regval));
|
||||
if (Memory::IsValidRange(regval, 4)) {
|
||||
APPEND_FMT("%08x[%08x]", regval, Memory::ReadUnchecked_U32(regval));
|
||||
} else {
|
||||
APPEND_FMT("%08x[invalid]", regval);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
if (Memory::IsValidAddress(regval)) {
|
||||
APPEND_FMT("%08x[%016llx]", regval, Memory::Read_U64(regval));
|
||||
if (Memory::IsValidRange(regval, 8)) {
|
||||
APPEND_FMT("%08x[%016llx]", regval, Memory::ReadUnchecked_U64(regval));
|
||||
} else {
|
||||
APPEND_FMT("%08x[invalid]", regval);
|
||||
}
|
||||
@@ -1088,6 +1088,7 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) {
|
||||
--reg;
|
||||
break;
|
||||
|
||||
|
||||
// TODO: Double? Does it ever happen?
|
||||
|
||||
default:
|
||||
@@ -1118,6 +1119,14 @@ void hleLeave() {
|
||||
} // else warn?
|
||||
}
|
||||
|
||||
const HLEFunction *HLEGetFunctionBeingCalled() {
|
||||
int stackSize = g_stackSize;
|
||||
if (stackSize > 0) {
|
||||
return g_stack[stackSize - 1];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, const char *reason, const char *formatted_reason) {
|
||||
char formatted_args[2048];
|
||||
const char *funcName = "?";
|
||||
@@ -1139,7 +1148,7 @@ void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line
|
||||
// Need to do something smart in hleCall. But it's better than printing function name and args from the wrong function.
|
||||
|
||||
if (stackSize == 1) {
|
||||
hleFormatLogArgs(formatted_args, sizeof(formatted_args), hleFunc->argmask);
|
||||
HLEFormatLogArgs(currentMIPS, formatted_args, sizeof(formatted_args), hleFunc->argmask);
|
||||
} else {
|
||||
truncate_cpy(formatted_args, "...N/A...");
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ struct Syscall {
|
||||
#define RETURN64(n) {u64 RETURN64_tmp = n; currentMIPS->r[MIPS_REG_V0] = RETURN64_tmp & 0xFFFFFFFF; currentMIPS->r[MIPS_REG_V1] = RETURN64_tmp >> 32;}
|
||||
#define RETURNF(fl) currentMIPS->f[0] = fl
|
||||
|
||||
#define PARAM_MIPS(mips, n) mips->r[MIPS_REG_A0 + n]
|
||||
|
||||
struct HLEModuleMeta {
|
||||
// This is the modname (name from the PRX header). Probably, we should really blacklist on the module names of the exported symbol metadata.
|
||||
const char *modname;
|
||||
@@ -174,6 +176,8 @@ inline s64 hleDelayResult(s64 result, const char *reason, int usec) {
|
||||
void HLEInit();
|
||||
void HLEDoState(PointerWrap &p);
|
||||
void HLEShutdown();
|
||||
const HLEFunction *HLEGetFunctionBeingCalled();
|
||||
size_t HLEFormatLogArgs(const MIPSState *mips, char *message, size_t sz, const char *argmask);
|
||||
u32 GetSyscallOp(std::string_view module, u32 nib);
|
||||
bool WriteHLESyscall(std::string_view module, u32 nib, u32 address);
|
||||
void CallSyscall(MIPSOpcode op);
|
||||
|
||||
@@ -728,16 +728,21 @@ static bool GetMIPSGPAddress(u32 &addr, s32 offset) {
|
||||
static int Hook_godseaterburst_blit_texture() {
|
||||
u32 texaddr;
|
||||
// Only if there's no texture.
|
||||
if (!GetMIPSStaticAddress(texaddr, 0x000c, 0x0030)) {
|
||||
return 0;
|
||||
}
|
||||
u32 fb_infoaddr;
|
||||
if (Memory::Read_U32(texaddr) != 0 || !GetMIPSStaticAddress(fb_infoaddr, 0x01d0, 0x01d4)) {
|
||||
if (!GetMIPSStaticAddress(texaddr, 0x000c, 0x0030) || !Memory::IsValid4AlignedAddress(texaddr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 fb_info = Memory::Read_U32(fb_infoaddr);
|
||||
const u32 fb_address = Memory::Read_U32(fb_info);
|
||||
u32 fb_infoaddr;
|
||||
if (Memory::ReadUnchecked_U32(texaddr) != 0 || !GetMIPSStaticAddress(fb_infoaddr, 0x01d0, 0x01d4) || !Memory::IsValid4AlignedAddress(fb_infoaddr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 fb_info = Memory::ReadUnchecked_U32(fb_infoaddr);
|
||||
if (!Memory::IsValid4AlignedAddress(fb_info)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 fb_address = Memory::ReadUnchecked_U32(fb_info);
|
||||
if (Memory::IsVRAMAddress(fb_address)) {
|
||||
gpu->PerformReadbackToMemory(fb_address, 0x00044000);
|
||||
NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00044000, "godseaterburst_blit_texture");
|
||||
|
||||
+83
-69
@@ -18,11 +18,13 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Common/Serialize/SerializeMap.h"
|
||||
#include "Core/MemMapHelpers.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HLE/ErrorCodes.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
@@ -317,9 +319,13 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
|
||||
}
|
||||
|
||||
if (optionsPtr != 0) {
|
||||
u32 size = Memory::Read_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size);
|
||||
if (Memory::IsValid4AlignedAddress(optionsPtr)) {
|
||||
u32 size = Memory::ReadUnchecked_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size);
|
||||
} else {
|
||||
Core_MemoryExceptionHLE(currentMIPS, optionsPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
}
|
||||
}
|
||||
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr);
|
||||
@@ -327,8 +333,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
|
||||
return hleLogDebug(Log::sceKernel, id);
|
||||
}
|
||||
|
||||
int sceKernelDeleteMutex(SceUID id)
|
||||
{
|
||||
int sceKernelDeleteMutex(SceUID id) {
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);
|
||||
if (!mutex) {
|
||||
@@ -365,8 +370,7 @@ static bool __KernelLockMutexCheck(PSPMutex *mutex, int count, u32 &error) {
|
||||
else if (count + mutex->nm.lockLevel < 0)
|
||||
error = SCE_MUTEX_ERROR_LOCK_OVERFLOW;
|
||||
// Only a recursive mutex can re-lock.
|
||||
else if (mutex->nm.lockThread == __KernelGetCurThread())
|
||||
{
|
||||
else if (mutex->nm.lockThread == __KernelGetCurThread()) {
|
||||
if (mutexIsRecursive)
|
||||
return true;
|
||||
|
||||
@@ -422,14 +426,12 @@ static bool __KernelUnlockMutex(PSPMutex *mutex, u32 &error) {
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
void __KernelMutexTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
void __KernelMutexTimeout(u64 userdata, int cyclesLate) {
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
HLEKernel::WaitExecTimeout<PSPMutex, WAITTYPE_MUTEX>(threadID);
|
||||
}
|
||||
|
||||
void __KernelMutexThreadEnd(SceUID threadID)
|
||||
{
|
||||
void __KernelMutexThreadEnd(SceUID threadID) {
|
||||
u32 error;
|
||||
|
||||
// If it was waiting on the mutex, it should finish now.
|
||||
@@ -457,11 +459,14 @@ void __KernelMutexThreadEnd(SceUID threadID)
|
||||
}
|
||||
}
|
||||
|
||||
// The timeoutPtr is assumed to be checked by the caller to either be 0 or valid.
|
||||
static void __KernelWaitMutex(PSPMutex *mutex, u32 timeoutPtr) {
|
||||
_dbg_assert_(mutexWaitTimer != -1); // this could only come from extremely old savestates.
|
||||
|
||||
if (timeoutPtr == 0 || mutexWaitTimer == -1)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
int micro = (int) Memory::ReadUnchecked_U32(timeoutPtr);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 3)
|
||||
@@ -473,8 +478,7 @@ static void __KernelWaitMutex(PSPMutex *mutex, u32 timeoutPtr) {
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
|
||||
{
|
||||
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) {
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(uid, error);
|
||||
if (!mutex) {
|
||||
@@ -520,15 +524,20 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
|
||||
}
|
||||
}
|
||||
|
||||
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
|
||||
{
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) {
|
||||
// Tekken 6 hack: Let's avoid the unnecessary logspam. It does this on hardware too.
|
||||
// This ID is always invalid.
|
||||
if (id == 0x80020001 && timeoutPtr == 0) {
|
||||
return hleNoLog(0);
|
||||
}
|
||||
|
||||
if (timeoutPtr != 0) {
|
||||
if (!Memory::IsValid4AlignedAddress(timeoutPtr)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, timeoutPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLog(0);
|
||||
}
|
||||
}
|
||||
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);
|
||||
|
||||
@@ -554,9 +563,14 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
}
|
||||
|
||||
// int sceKernelLockMutexCB(SceUID id, int count, int *timeout)
|
||||
int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr)
|
||||
{
|
||||
int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) {
|
||||
if (timeoutPtr != 0) {
|
||||
if (!Memory::IsValid4AlignedAddress(timeoutPtr)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, timeoutPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLog(0);
|
||||
}
|
||||
}
|
||||
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);
|
||||
|
||||
@@ -592,7 +606,6 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr)
|
||||
}
|
||||
}
|
||||
|
||||
// int sceKernelTryLockMutex(SceUID id, int count)
|
||||
int sceKernelTryLockMutex(SceUID id, int count) {
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);
|
||||
@@ -605,9 +618,7 @@ int sceKernelTryLockMutex(SceUID id, int count) {
|
||||
return hleLogDebug(Log::sceKernel, SCE_MUTEX_ERROR_TRYLOCK_FAILED);
|
||||
}
|
||||
|
||||
// int sceKernelUnlockMutex(SceUID id, int count)
|
||||
int sceKernelUnlockMutex(SceUID id, int count)
|
||||
{
|
||||
int sceKernelUnlockMutex(SceUID id, int count) {
|
||||
// Tekken 6 hack: Let's avoid the unnecessary logspam. It does this on hardware too.
|
||||
// This ID is always invalid.
|
||||
if (id == 0x80020001) {
|
||||
@@ -698,11 +709,14 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init
|
||||
workarea->attr = attr;
|
||||
workarea->uid = id;
|
||||
|
||||
if (optionsPtr != 0)
|
||||
{
|
||||
u32 size = Memory::Read_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateLwMutex(%s) unsupported options parameter, size = %d", name, size);
|
||||
if (optionsPtr != 0) {
|
||||
if (Memory::IsValid4AlignedAddress(optionsPtr)) {
|
||||
u32 size = Memory::ReadUnchecked_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateLwMutex(%s) unsupported options parameter, size = %d", name, size);
|
||||
} else {
|
||||
Core_MemoryExceptionHLE(currentMIPS, optionsPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
}
|
||||
}
|
||||
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
|
||||
WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateLwMutex(%s) unsupported attr parameter: %08x", name, attr);
|
||||
@@ -711,8 +725,7 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, u32 &error, int result)
|
||||
{
|
||||
bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, u32 &error, int result) {
|
||||
if (!HLEKernel::VerifyWait(threadID, WAITTYPE_LWMUTEX, mutex->GetUID()))
|
||||
return false;
|
||||
|
||||
@@ -723,9 +736,8 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID,
|
||||
workarea->lockThread = threadID;
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && lwMutexWaitTimer != -1)
|
||||
{
|
||||
const u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && lwMutexWaitTimer != -1) {
|
||||
// Remove any event for this thread.
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
@@ -763,8 +775,7 @@ int sceKernelDeleteLwMutex(u32 workareaPtr) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool __KernelLockLwMutex(NativeLwMutexWorkarea *workarea, int count, u32 &error)
|
||||
{
|
||||
static bool __KernelLockLwMutex(NativeLwMutexWorkarea *workarea, int count, u32 &error) {
|
||||
if (!error)
|
||||
{
|
||||
if (count <= 0)
|
||||
@@ -815,11 +826,9 @@ static bool __KernelLockLwMutex(NativeLwMutexWorkarea *workarea, int count, u32
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool __KernelUnlockLwMutex(T workarea, u32 &error)
|
||||
{
|
||||
bool __KernelUnlockLwMutex(T workarea, u32 &error) {
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea->uid, error);
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
workarea->lockThread = 0;
|
||||
return false;
|
||||
}
|
||||
@@ -849,12 +858,12 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate)
|
||||
HLEKernel::WaitExecTimeout<LwMutex, WAITTYPE_LWMUTEX>(threadID);
|
||||
}
|
||||
|
||||
static void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)
|
||||
{
|
||||
// timeoutPtr is assumed to be checked by the caller to either be 0 or valid.
|
||||
static void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0 || lwMutexWaitTimer == -1)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
int micro = (int) Memory::ReadUnchecked_U32(timeoutPtr);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 3)
|
||||
@@ -889,8 +898,7 @@ void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Resuming lock wait for callback");
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex(u32 workareaPtr, int count)
|
||||
{
|
||||
int sceKernelTryLockLwMutex(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
@@ -908,8 +916,7 @@ int sceKernelTryLockLwMutex(u32 workareaPtr, int count)
|
||||
return hleLogDebug(Log::sceKernel, SCE_MUTEX_ERROR_TRYLOCK_FAILED);
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count)
|
||||
{
|
||||
int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
@@ -926,22 +933,27 @@ int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count)
|
||||
return hleLogDebug(Log::sceKernel, SCE_LWMUTEX_ERROR_TRYLOCK_FAILED);
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
{
|
||||
int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
if (timeoutPtr) {
|
||||
if (!Memory::IsValid4AlignedAddress(timeoutPtr)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, timeoutPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLog(0);
|
||||
}
|
||||
}
|
||||
|
||||
auto workarea = PSPPointer<NativeLwMutexWorkarea>::Create(workareaPtr);
|
||||
hleEatCycles(48);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
if (__KernelLockLwMutex(workarea, count, error)) {
|
||||
return hleLogVerbose(Log::sceKernel, 0);
|
||||
else if (error)
|
||||
} else if (error) {
|
||||
return hleLogVerbose(Log::sceKernel, error);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea->uid, error);
|
||||
if (!mutex) {
|
||||
return hleLogError(Log::sceKernel, error);
|
||||
@@ -959,24 +971,27 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
{
|
||||
VERBOSE_LOG(Log::sceKernel, "sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr);
|
||||
|
||||
int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
if (timeoutPtr) {
|
||||
if (!Memory::IsValid4AlignedAddress(timeoutPtr)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, timeoutPtr, 4, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLog(0);
|
||||
}
|
||||
}
|
||||
|
||||
auto workarea = PSPPointer<NativeLwMutexWorkarea>::Create(workareaPtr);
|
||||
hleEatCycles(48);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
if (__KernelLockLwMutex(workarea, count, error)) {
|
||||
return hleLogVerbose(Log::sceKernel, 0);
|
||||
else if (error)
|
||||
} else if (error) {
|
||||
return hleLogVerbose(Log::sceKernel, error);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea->uid, error);
|
||||
if (!mutex) {
|
||||
return hleLogError(Log::sceKernel, error);
|
||||
@@ -994,8 +1009,7 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelUnlockLwMutex(u32 workareaPtr, int count)
|
||||
{
|
||||
int sceKernelUnlockLwMutex(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
@@ -1018,8 +1032,7 @@ int sceKernelUnlockLwMutex(u32 workareaPtr, int count)
|
||||
|
||||
workarea->lockLevel -= count;
|
||||
|
||||
if (workarea->lockLevel == 0)
|
||||
{
|
||||
if (workarea->lockLevel == 0) {
|
||||
u32 error;
|
||||
if (__KernelUnlockLwMutex(workarea, error))
|
||||
hleReSchedule("lwmutex unlocked");
|
||||
@@ -1032,16 +1045,17 @@ int sceKernelUnlockLwMutex(u32 workareaPtr, int count)
|
||||
static int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) {
|
||||
u32 error;
|
||||
LwMutex *m = kernelObjects.Get<LwMutex>(uid, error);
|
||||
if (!m)
|
||||
if (!m) {
|
||||
return hleLogError(Log::sceKernel, error, "invalid id");
|
||||
}
|
||||
|
||||
// Should we crash the thread somehow?
|
||||
auto info = PSPPointer<NativeLwMutex>::Create(infoPtr);
|
||||
if (!info.IsValid())
|
||||
if (!info.IsValid()) {
|
||||
return hleLogError(Log::sceKernel, -1, "invalid pointer");
|
||||
}
|
||||
|
||||
if (info->size != 0)
|
||||
{
|
||||
if (info->size != 0) {
|
||||
auto workarea = m->nm.workarea;
|
||||
|
||||
HLEKernel::CleanupWaitingThreads(WAITTYPE_LWMUTEX, uid, m->waitingThreads);
|
||||
|
||||
+95
-117
@@ -28,6 +28,7 @@
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Common/Serialize/SerializeList.h"
|
||||
#include "Common/Serialize/SerializeMap.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/ErrorCodes.h"
|
||||
#include "Core/HLE/HLETables.h"
|
||||
@@ -357,8 +358,7 @@ bool PSPThread::AllocateStack(u32 &stackSize) {
|
||||
|
||||
bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0;
|
||||
currentStack.start = StackAllocator().Alloc(stackSize, fromTop, StringFromFormat("stack/%s", nt.name).c_str());
|
||||
if (currentStack.start == (u32)-1)
|
||||
{
|
||||
if (currentStack.start == (u32)-1) {
|
||||
currentStack.start = 0;
|
||||
nt.initialStack = 0;
|
||||
ERROR_LOG(Log::sceKernel, "Failed to allocate stack for thread");
|
||||
@@ -561,19 +561,16 @@ static u64 lastSwitchCycles = 0;
|
||||
//STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int __KernelRegisterActionType(ActionCreator creator)
|
||||
{
|
||||
int __KernelRegisterActionType(ActionCreator creator) {
|
||||
return mipsCalls.registerActionType(creator);
|
||||
}
|
||||
|
||||
void __KernelRestoreActionType(int actionType, ActionCreator creator)
|
||||
{
|
||||
void __KernelRestoreActionType(int actionType, ActionCreator creator) {
|
||||
_assert_(actionType >= 0);
|
||||
mipsCalls.restoreActionType(actionType, creator);
|
||||
}
|
||||
|
||||
PSPAction *__KernelCreateAction(int actionType)
|
||||
{
|
||||
PSPAction *__KernelCreateAction(int actionType) {
|
||||
return mipsCalls.createActionByType(actionType);
|
||||
}
|
||||
|
||||
@@ -611,13 +608,11 @@ void MipsCall::DoState(PointerWrap &p)
|
||||
}
|
||||
}
|
||||
|
||||
void MipsCall::setReturnValue(u32 value)
|
||||
{
|
||||
void MipsCall::setReturnValue(u32 value) {
|
||||
savedV0 = value;
|
||||
}
|
||||
|
||||
void MipsCall::setReturnValue(u64 value)
|
||||
{
|
||||
void MipsCall::setReturnValue(u64 value) {
|
||||
savedV0 = value & 0xFFFFFFFF;
|
||||
savedV1 = (value >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
@@ -670,10 +665,9 @@ static void __KernelDelayEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
// TODO: Don't wake up if __KernelCurHasReadyCallbacks()?
|
||||
|
||||
s64 cyclesLeft = delayDeadline - CoreTiming::GetTicks();
|
||||
if (cyclesLeft < 0)
|
||||
if (cyclesLeft < 0) {
|
||||
__KernelResumeThreadFromWait(threadID, 0);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
CoreTiming::ScheduleEvent(cyclesLeft, eventScheduledWakeup, __KernelGetCurThread());
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelDelayThreadCB: Resuming delay after callback");
|
||||
}
|
||||
@@ -703,8 +697,7 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
}
|
||||
}
|
||||
|
||||
static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPThread, WAITTYPE_THREADEND, SceUID>(threadID, prevCallbackId, eventThreadEndTimeout);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Suspending wait for callback");
|
||||
@@ -738,11 +731,9 @@ static void __KernelThreadEndEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Resuming wait from callback");
|
||||
}
|
||||
|
||||
u32 __KernelSetThreadRA(SceUID threadID, u32 nid)
|
||||
{
|
||||
u32 __KernelSetThreadRA(SceUID threadID, u32 nid) {
|
||||
u32 newRA;
|
||||
switch (nid)
|
||||
{
|
||||
switch (nid) {
|
||||
case NID_MODULERETURN:
|
||||
newRA = moduleReturnHackAddr;
|
||||
break;
|
||||
@@ -751,10 +742,9 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (threadID == currentThread)
|
||||
if (threadID == currentThread) {
|
||||
currentMIPS->r[MIPS_REG_RA] = newRA;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
u32 error;
|
||||
PSPThread *thread = kernelObjects.Get<PSPThread>(threadID, error);
|
||||
if (!thread)
|
||||
@@ -769,8 +759,7 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid)
|
||||
void hleScheduledWakeup(u64 userdata, int cyclesLate);
|
||||
void hleThreadEndTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
static void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos)
|
||||
{
|
||||
static void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos) {
|
||||
*ptr = pos;
|
||||
pos += 8;
|
||||
WriteHLESyscall("FakeSysCalls", nid, *ptr);
|
||||
@@ -786,16 +775,14 @@ u32 HLEMipsCallReturnAddress() {
|
||||
return hleReturnHackAddr;
|
||||
}
|
||||
|
||||
void __KernelThreadingInit()
|
||||
{
|
||||
struct ThreadHack
|
||||
{
|
||||
void __KernelThreadingInit() {
|
||||
struct ThreadHack {
|
||||
u32 nid;
|
||||
u32 *addr;
|
||||
};
|
||||
|
||||
// Yeah, this is straight out of JPCSP, I should be ashamed.
|
||||
const static u32_le idleThreadCode[] = {
|
||||
static const u32_le idleThreadCode[] = {
|
||||
MIPS_MAKE_LUI(MIPS_REG_RA, 0x0800),
|
||||
MIPS_MAKE_JR_RA(),
|
||||
MIPS_MAKE_SYSCALL("FakeSysCalls", "_sceKernelIdle"),
|
||||
@@ -803,7 +790,7 @@ void __KernelThreadingInit()
|
||||
};
|
||||
|
||||
// If you add another func here, don't forget __KernelThreadingDoState() below.
|
||||
static ThreadHack threadHacks[] = {
|
||||
static const ThreadHack threadHacks[] = {
|
||||
{NID_THREADRETURN, &threadReturnHackAddr},
|
||||
{NID_CALLBACKRETURN, &cbReturnHackAddr},
|
||||
{NID_INTERRUPTRETURN, &intReturnHackAddr},
|
||||
@@ -905,32 +892,26 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
Do(p, pendingDeleteThreads);
|
||||
}
|
||||
|
||||
void __KernelThreadingDoStateLate(PointerWrap &p)
|
||||
{
|
||||
void __KernelThreadingDoStateLate(PointerWrap &p) {
|
||||
// We do this late to give modules time to register actions.
|
||||
mipsCalls.DoState(p);
|
||||
p.DoMarker("sceKernelThread Late");
|
||||
}
|
||||
|
||||
KernelObject *__KernelThreadObject()
|
||||
{
|
||||
return new PSPThread;
|
||||
KernelObject *__KernelThreadObject() {
|
||||
return new PSPThread();
|
||||
}
|
||||
|
||||
KernelObject *__KernelCallbackObject()
|
||||
{
|
||||
return new PSPCallback;
|
||||
KernelObject *__KernelCallbackObject() {
|
||||
return new PSPCallback();
|
||||
}
|
||||
|
||||
void __KernelListenThreadEnd(ThreadCallback callback)
|
||||
{
|
||||
void __KernelListenThreadEnd(ThreadCallback callback) {
|
||||
threadEndListeners.push_back(callback);
|
||||
}
|
||||
|
||||
static void __KernelFireThreadEnd(SceUID threadID)
|
||||
{
|
||||
for (auto iter = threadEndListeners.begin(), end = threadEndListeners.end(); iter != end; ++iter)
|
||||
{
|
||||
static void __KernelFireThreadEnd(SceUID threadID) {
|
||||
for (auto iter = threadEndListeners.begin(), end = threadEndListeners.end(); iter != end; ++iter) {
|
||||
ThreadCallback cb = *iter;
|
||||
cb(threadID);
|
||||
}
|
||||
@@ -957,8 +938,7 @@ static void __KernelChangeReadyState(PSPThread *thread, SceUID threadID, bool re
|
||||
}
|
||||
}
|
||||
|
||||
static void __KernelChangeReadyState(SceUID threadID, bool ready)
|
||||
{
|
||||
static void __KernelChangeReadyState(SceUID threadID, bool ready) {
|
||||
u32 error;
|
||||
PSPThread *thread = kernelObjects.Get<PSPThread>(threadID, error);
|
||||
if (thread)
|
||||
@@ -967,10 +947,8 @@ static void __KernelChangeReadyState(SceUID threadID, bool ready)
|
||||
WARN_LOG(Log::sceKernel, "Trying to change the ready state of an unknown thread?");
|
||||
}
|
||||
|
||||
void __KernelStartIdleThreads(SceUID moduleId)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
void __KernelStartIdleThreads(SceUID moduleId) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
u32 error;
|
||||
PSPThread *t = kernelObjects.Get<PSPThread>(threadIdleID[i], error);
|
||||
t->nt.gpreg = __KernelGetModuleGP(moduleId);
|
||||
@@ -987,8 +965,7 @@ void KernelValidateThreadTarget(uint32_t pc) {
|
||||
}
|
||||
}
|
||||
|
||||
bool __KernelSwitchOffThread(const char *reason)
|
||||
{
|
||||
bool __KernelSwitchOffThread(const char *reason) {
|
||||
if (!reason)
|
||||
reason = "switch off thread";
|
||||
|
||||
@@ -1155,8 +1132,7 @@ SceUID __KernelGetCurrentCallbackID(SceUID threadID, u32 &error) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
|
||||
{
|
||||
u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr) {
|
||||
static const u32 THREADINFO_SIZE = 104;
|
||||
static const u32 THREADINFO_SIZE_AFTER_260 = 108;
|
||||
|
||||
@@ -1171,7 +1147,12 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
|
||||
return hleLogError(Log::sceKernel, error, "bad thread");
|
||||
}
|
||||
|
||||
u32 wantedSize = Memory::Read_U32(statusPtr);
|
||||
if (!Memory::IsValid4AlignedAddress(statusPtr)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, statusPtr, 0, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLog(0);
|
||||
}
|
||||
|
||||
u32 wantedSize = Memory::ReadUnchecked_U32(statusPtr);
|
||||
|
||||
if (sceKernelGetCompiledSdkVersion() > 0x02060010) {
|
||||
if (wantedSize > THREADINFO_SIZE_AFTER_260) {
|
||||
@@ -1199,8 +1180,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
|
||||
}
|
||||
|
||||
// Thanks JPCSP
|
||||
u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr)
|
||||
{
|
||||
u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr) {
|
||||
if (threadID == 0)
|
||||
threadID = __KernelGetCurThread();
|
||||
|
||||
@@ -1210,8 +1190,10 @@ u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr)
|
||||
return hleLogError(Log::sceKernel, error, "bad thread");
|
||||
}
|
||||
|
||||
if (!Memory::IsValidAddress(statusPtr))
|
||||
if (!Memory::IsValidRange(statusPtr, sizeof(SceKernelThreadRunStatus))) {
|
||||
// Raise exception?
|
||||
return hleLogError(Log::sceKernel, -1);
|
||||
}
|
||||
|
||||
auto runStatus = PSPPointer<SceKernelThreadRunStatus>::Create(statusPtr);
|
||||
|
||||
@@ -2574,7 +2556,7 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) {
|
||||
if (t->nt.status != THREADSTATUS_DORMANT)
|
||||
{
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::Read_U32(timeoutPtr));
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::ReadUnchecked_U32(timeoutPtr));
|
||||
if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end())
|
||||
t->waitingThreads.push_back(currentThread);
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, false, "thread wait end");
|
||||
@@ -2601,7 +2583,7 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) {
|
||||
if (t->nt.status != THREADSTATUS_DORMANT)
|
||||
{
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::Read_U32(timeoutPtr));
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::ReadUnchecked_U32(timeoutPtr));
|
||||
if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end())
|
||||
t->waitingThreads.push_back(currentThread);
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, true, "thread wait end");
|
||||
@@ -2724,8 +2706,7 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg)
|
||||
return hleLogInfo(Log::sceKernel, id);
|
||||
}
|
||||
|
||||
int sceKernelDeleteCallback(SceUID cbId)
|
||||
{
|
||||
int sceKernelDeleteCallback(SceUID cbId) {
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(cbId, error);
|
||||
if (cb)
|
||||
@@ -2743,8 +2724,7 @@ int sceKernelDeleteCallback(SceUID cbId)
|
||||
}
|
||||
|
||||
// Generally very rarely used, but Numblast uses it like candy.
|
||||
int sceKernelNotifyCallback(SceUID cbId, int notifyArg)
|
||||
{
|
||||
int sceKernelNotifyCallback(SceUID cbId, int notifyArg) {
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(cbId, error);
|
||||
if (cb) {
|
||||
@@ -2755,8 +2735,7 @@ int sceKernelNotifyCallback(SceUID cbId, int notifyArg)
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelCancelCallback(SceUID cbId)
|
||||
{
|
||||
int sceKernelCancelCallback(SceUID cbId) {
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(cbId, error);
|
||||
if (cb) {
|
||||
@@ -2768,8 +2747,7 @@ int sceKernelCancelCallback(SceUID cbId)
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelGetCallbackCount(SceUID cbId)
|
||||
{
|
||||
int sceKernelGetCallbackCount(SceUID cbId) {
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(cbId, error);
|
||||
if (cb) {
|
||||
@@ -2796,8 +2774,7 @@ int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter)
|
||||
{
|
||||
u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) {
|
||||
if (size < 512) {
|
||||
return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "stack size too small");
|
||||
}
|
||||
@@ -2828,25 +2805,28 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter)
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
}
|
||||
|
||||
void __KernelReturnFromExtendStack()
|
||||
{
|
||||
void __KernelReturnFromExtendStack() {
|
||||
hleSkipDeadbeef();
|
||||
|
||||
PSPThread *thread = __GetCurrentThread();
|
||||
if (!thread)
|
||||
{
|
||||
if (!thread) {
|
||||
ERROR_LOG_REPORT(Log::sceKernel, "__KernelReturnFromExtendStack() - not on a thread?");
|
||||
hleNoLogVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the saved regs at the top of the stack.
|
||||
u32 restoreRA = Memory::Read_U32(thread->currentStack.end - 4);
|
||||
u32 restoreSP = Memory::Read_U32(thread->currentStack.end - 8);
|
||||
u32 restorePC = Memory::Read_U32(thread->currentStack.end - 12);
|
||||
if (!Memory::IsValid4AlignedRange(thread->currentStack.end - 12, 12)) {
|
||||
Core_MemoryExceptionHLE(currentMIPS, thread->currentStack.end, 12, MemoryExceptionType::HLE_READ);
|
||||
hleNoLogVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!thread->PopExtendedStack())
|
||||
{
|
||||
// Grab the saved regs at the top of the stack.
|
||||
u32 restoreRA = Memory::ReadUnchecked_U32(thread->currentStack.end - 4);
|
||||
u32 restoreSP = Memory::ReadUnchecked_U32(thread->currentStack.end - 8);
|
||||
u32 restorePC = Memory::ReadUnchecked_U32(thread->currentStack.end - 12);
|
||||
|
||||
if (!thread->PopExtendedStack()) {
|
||||
ERROR_LOG_REPORT(Log::sceKernel, "__KernelReturnFromExtendStack() - no stack to restore?");
|
||||
return;
|
||||
}
|
||||
@@ -2944,16 +2924,15 @@ void __KernelSwitchContext(PSPThread *target, const char *reason) {
|
||||
__KernelChangeReadyState(cur, oldUID, true);
|
||||
}
|
||||
|
||||
if (target)
|
||||
{
|
||||
if (target) {
|
||||
__SetCurrentThread(target, target->GetUID(), target->nt.name);
|
||||
__KernelChangeReadyState(target, currentThread, false);
|
||||
target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
|
||||
|
||||
__KernelLoadContext(&target->context, (target->nt.attr & PSP_THREAD_ATTR_VFPU) != 0);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
__SetCurrentThread(NULL, 0, NULL);
|
||||
}
|
||||
|
||||
const bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1];
|
||||
const bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1];
|
||||
@@ -3187,14 +3166,21 @@ void __KernelReturnFromMipsCall() {
|
||||
call->doAfter = nullptr;
|
||||
}
|
||||
|
||||
u32 &sp = currentMIPS->r[MIPS_REG_SP];
|
||||
for (int i = MIPS_REG_A0; i <= MIPS_REG_T7; ++i) {
|
||||
currentMIPS->r[i] = Memory::Read_U32(sp + i * 4);
|
||||
u32 sp = currentMIPS->r[MIPS_REG_SP];
|
||||
if (!Memory::IsValid4AlignedRange(sp, 32 * 4)) {
|
||||
// We're really screwed.
|
||||
Core_MemoryExceptionHLE(currentMIPS, sp, 4, MemoryExceptionType::HLE_READ);
|
||||
return hleNoLogVoid();
|
||||
}
|
||||
currentMIPS->r[MIPS_REG_T8] = Memory::Read_U32(sp + MIPS_REG_T8 * 4);
|
||||
currentMIPS->r[MIPS_REG_T9] = Memory::Read_U32(sp + MIPS_REG_T9 * 4);
|
||||
currentMIPS->r[MIPS_REG_RA] = Memory::Read_U32(sp + MIPS_REG_RA * 4);
|
||||
sp += 32 * 4;
|
||||
|
||||
for (int i = MIPS_REG_A0; i <= MIPS_REG_T7; ++i) {
|
||||
currentMIPS->r[i] = Memory::ReadUnchecked_U32(sp + i * 4);
|
||||
}
|
||||
currentMIPS->r[MIPS_REG_T8] = Memory::ReadUnchecked_U32(sp + MIPS_REG_T8 * 4);
|
||||
currentMIPS->r[MIPS_REG_T9] = Memory::ReadUnchecked_U32(sp + MIPS_REG_T9 * 4);
|
||||
currentMIPS->r[MIPS_REG_RA] = Memory::ReadUnchecked_U32(sp + MIPS_REG_RA * 4);
|
||||
// Increment SP.
|
||||
currentMIPS->r[MIPS_REG_SP] += 32 * 4;
|
||||
|
||||
KernelValidateThreadTarget(call->savedPc);
|
||||
|
||||
@@ -3210,15 +3196,11 @@ void __KernelReturnFromMipsCall() {
|
||||
}
|
||||
currentCallbackThreadID = 0;
|
||||
|
||||
if (cur->nt.waitType != WAITTYPE_NONE)
|
||||
{
|
||||
if (call->cbId > 0)
|
||||
{
|
||||
if (waitTypeFuncs[cur->nt.waitType].endFunc != NULL)
|
||||
waitTypeFuncs[cur->nt.waitType].endFunc(cur->GetUID(), cur->currentCallbackId);
|
||||
else
|
||||
ERROR_LOG_REPORT(Log::HLE, "Missing begin/restore funcs for wait type %d", cur->nt.waitType);
|
||||
}
|
||||
if (cur->nt.waitType != WAITTYPE_NONE && call->cbId > 0) {
|
||||
if (waitTypeFuncs[cur->nt.waitType].endFunc != NULL)
|
||||
waitTypeFuncs[cur->nt.waitType].endFunc(cur->GetUID(), cur->currentCallbackId);
|
||||
else
|
||||
ERROR_LOG_REPORT(Log::HLE, "Missing begin/restore funcs for wait type %d", cur->nt.waitType);
|
||||
}
|
||||
|
||||
// yeah! back in the real world, let's keep going. Should we process more callbacks?
|
||||
@@ -3506,12 +3488,10 @@ void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) {
|
||||
__KernelChangeThreadState(t, newStatus);
|
||||
}
|
||||
|
||||
int sceKernelRegisterExitCallback(SceUID cbId)
|
||||
{
|
||||
int sceKernelRegisterExitCallback(SceUID cbId) {
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(cbId, error);
|
||||
if (!cb)
|
||||
{
|
||||
if (!cb) {
|
||||
WARN_LOG(Log::sceKernel, "sceKernelRegisterExitCallback(%i): invalid callback id", cbId);
|
||||
if (sceKernelGetCompiledSdkVersion() >= 0x3090500)
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT);
|
||||
@@ -3568,8 +3548,7 @@ bool __KernelIsExitCallbackPending() {
|
||||
}
|
||||
|
||||
// Update the exit callback status?
|
||||
int LoadExecForUser_362A956B()
|
||||
{
|
||||
int LoadExecForUser_362A956B() {
|
||||
WARN_LOG_REPORT(Log::sceKernel, "LoadExecForUser_362A956B()");
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(registeredExitCbId, error);
|
||||
@@ -3577,24 +3556,23 @@ int LoadExecForUser_362A956B()
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_UNKNOWN_CBID, "registeredExitCbId not found 0x%x", registeredExitCbId);
|
||||
}
|
||||
int cbArg = cb->nc.commonArgument;
|
||||
if (!Memory::IsValidAddress(cbArg)) {
|
||||
if (!Memory::IsValidRange(cbArg - 8, 8)) {
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid address for cbArg (0x%08X)", cbArg);
|
||||
}
|
||||
u32 unknown1 = Memory::Read_U32(cbArg - 8);
|
||||
const u32 unknown1 = Memory::ReadUnchecked_U32(cbArg - 8);
|
||||
if (unknown1 >= 4) {
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid value unknown1 (0x%08X)", unknown1);
|
||||
}
|
||||
u32 parameterArea = Memory::Read_U32(cbArg - 4);
|
||||
if (!Memory::IsValidAddress(parameterArea)) {
|
||||
const u32 parameterArea = Memory::ReadUnchecked_U32(cbArg - 4);
|
||||
if (!Memory::IsValid4AlignedRange(parameterArea, 12)) {
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid address for parameterArea on userMemory (0x%08X)", parameterArea);
|
||||
}
|
||||
|
||||
u32 size = Memory::Read_U32(parameterArea);
|
||||
const u32 size = Memory::ReadUnchecked_U32(parameterArea);
|
||||
if (size < 12) {
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_SIZE, "invalid parameterArea size %d", size);
|
||||
}
|
||||
Memory::Write_U32(0, parameterArea + 4);
|
||||
Memory::Write_U32(-1, parameterArea + 8);
|
||||
Memory::WriteUnchecked_U32(0, parameterArea + 4);
|
||||
Memory::WriteUnchecked_U32(-1, parameterArea + 8);
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
}
|
||||
|
||||
@@ -3630,7 +3608,7 @@ struct ThreadEventHandler : public KernelObject {
|
||||
|
||||
KernelObject *__KernelThreadEventHandlerObject() {
|
||||
// Default object to load from state.
|
||||
return new ThreadEventHandler;
|
||||
return new ThreadEventHandler();
|
||||
}
|
||||
|
||||
bool __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID threadID, ThreadEventType type) {
|
||||
|
||||
@@ -1642,7 +1642,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
avcAu.write(auAddr);
|
||||
|
||||
if (result == 0) {
|
||||
// Jeanne d'Arc return 00000000 as attrAddr here and cause WriteToHardware error
|
||||
// Jeanne d'Arc return 00000000 as attrAddr here and cause WriteMemoryOrRaiseException error
|
||||
if (Memory::IsValidAddress(attrAddr)) {
|
||||
Memory::Write_U32(1, attrAddr);
|
||||
}
|
||||
@@ -1742,7 +1742,7 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
atracAu.write(auAddr);
|
||||
|
||||
if (result == 0) {
|
||||
// 3rd birthday return 00000000 as attrAddr here and cause WriteToHardware error
|
||||
// 3rd birthday return 00000000 as attrAddr here and cause WriteMemoryOrRaiseException error
|
||||
if (Memory::IsValidAddress(attrAddr)) {
|
||||
Memory::Write_U32(0, attrAddr);
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ void Jit::Comp_Jump(MIPSOpcode op) {
|
||||
// Might be a stubbed address or something?
|
||||
if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) {
|
||||
if (js.nextExit == 0) {
|
||||
ERROR_LOG(Log::JIT, "Jump to invalid address: %08x PC %08x LR %08x", targetAddr, GetCompilerPC(), currentMIPS->r[MIPS_REG_RA]);
|
||||
ERROR_LOG(Log::JIT, "Jump to invalid address: %08x PC %08x RA %08x", targetAddr, GetCompilerPC(), currentMIPS->r[MIPS_REG_RA]);
|
||||
} else {
|
||||
js.compiling = false;
|
||||
}
|
||||
@@ -562,8 +562,7 @@ void Jit::Comp_Jump(MIPSOpcode op) {
|
||||
js.compiling = false;
|
||||
}
|
||||
|
||||
void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
{
|
||||
void Jit::Comp_JumpReg(MIPSOpcode op) {
|
||||
CONDITIONAL_LOG;
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(Log::JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart);
|
||||
|
||||
+5
-1
@@ -320,7 +320,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
||||
uint32_t approximatePC = currentMIPS->pc;
|
||||
// TODO: Determine access size from the disassembled native instruction. We have some partial info already,
|
||||
// just need to clean it up.
|
||||
Core_MemoryException(guestAddress, 0, approximatePC, type, infoString, true);
|
||||
Core_MemoryException(guestAddress, 0, approximatePC, type, infoString);
|
||||
|
||||
// There's a small chance we can resume from this type of crash.
|
||||
g_lastCrashAddress = codePtr;
|
||||
@@ -373,6 +373,10 @@ std::vector<MIPSStackWalk::StackFrame> WalkCurrentStack(int threadID) {
|
||||
std::string FormatStackTrace(const std::vector<MIPSStackWalk::StackFrame> &frames) {
|
||||
std::stringstream str;
|
||||
for (const auto &frame : frames) {
|
||||
if (frame.pc == 0xFFFFFFFF) {
|
||||
// Bottom of stack, probably.
|
||||
continue;
|
||||
}
|
||||
std::string desc = g_symbolMap->GetDescription(frame.entry);
|
||||
char moduleDesc[96];
|
||||
if (DescribeKernelModuleAddress(frame.entry, moduleDesc, sizeof(moduleDesc))) {
|
||||
|
||||
+10
-10
@@ -86,7 +86,7 @@ const u8 *GetPointerRange(const u32 address, const u32 size) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void ReadFromHardware(T &var, const u32 address) {
|
||||
inline void ReadMemoryOrRaiseException(T &var, const u32 address) {
|
||||
if ((address & 0x3E000000) == 0x08000000 || // RAM
|
||||
(address & 0xBF800000) == 0x04000000 || // VRAM
|
||||
(address & 0xBFFFC000) == 0x00010000 || // Scratchpad
|
||||
@@ -99,7 +99,7 @@ inline void ReadFromHardware(T &var, const u32 address) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void WriteToHardware(u32 address, const T data) {
|
||||
inline void WriteMemoryOrRaiseException(u32 address, const T data) {
|
||||
if ((address & 0x3E000000) == 0x08000000 || // RAM
|
||||
(address & 0xBF800000) == 0x04000000 || // VRAM
|
||||
(address & 0xBFFFC000) == 0x00010000 || // Scratchpad
|
||||
@@ -126,25 +126,25 @@ bool IsScratchpadAddress(const u32 address) {
|
||||
|
||||
u8 Read_U8(const u32 address) {
|
||||
u8 value = 0;
|
||||
ReadFromHardware<u8>(value, address);
|
||||
ReadMemoryOrRaiseException<u8>(value, address);
|
||||
return (u8)value;
|
||||
}
|
||||
|
||||
u16 Read_U16(const u32 address) {
|
||||
u16_le value = 0;
|
||||
ReadFromHardware<u16_le>(value, address);
|
||||
ReadMemoryOrRaiseException<u16_le>(value, address);
|
||||
return (u16)value;
|
||||
}
|
||||
|
||||
u32 Read_U32(const u32 address) {
|
||||
u32_le value = 0;
|
||||
ReadFromHardware<u32_le>(value, address);
|
||||
ReadMemoryOrRaiseException<u32_le>(value, address);
|
||||
return value;
|
||||
}
|
||||
|
||||
u64 Read_U64(const u32 address) {
|
||||
u64_le value = 0;
|
||||
ReadFromHardware<u64_le>(value, address);
|
||||
ReadMemoryOrRaiseException<u64_le>(value, address);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -157,19 +157,19 @@ u32 Read_U16_ZX(const u32 address) {
|
||||
}
|
||||
|
||||
void Write_U8(const u8 _Data, const u32 address) {
|
||||
WriteToHardware<u8>(address, _Data);
|
||||
WriteMemoryOrRaiseException<u8>(address, _Data);
|
||||
}
|
||||
|
||||
void Write_U16(const u16 _Data, const u32 address) {
|
||||
WriteToHardware<u16_le>(address, _Data);
|
||||
WriteMemoryOrRaiseException<u16_le>(address, _Data);
|
||||
}
|
||||
|
||||
void Write_U32(const u32 _Data, const u32 address) {
|
||||
WriteToHardware<u32_le>(address, _Data);
|
||||
WriteMemoryOrRaiseException<u32_le>(address, _Data);
|
||||
}
|
||||
|
||||
void Write_U64(const u64 _Data, const u32 address) {
|
||||
WriteToHardware<u64_le>(address, _Data);
|
||||
WriteMemoryOrRaiseException<u64_le>(address, _Data);
|
||||
}
|
||||
|
||||
} // namespace Memory
|
||||
|
||||
@@ -628,8 +628,13 @@ void Recorder::NotifyCommand(u32 pc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Memory::IsValid4AlignedAddress(pc)) {
|
||||
ERROR_LOG(Log::G3D, "Bad pc in Recorder: %08x", pc);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckEdramTrans();
|
||||
const u32 op = Memory::Read_U32(pc);
|
||||
const u32 op = Memory::ReadUnchecked_U32(pc);
|
||||
const GECommand cmd = GECommand(op >> 24);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
+6
-1
@@ -1576,7 +1576,12 @@ int GPUCommon::GetCurrentPrim(GEPrimitiveType *prim, GECommand *outCmd) const {
|
||||
DisplayList list;
|
||||
u32 cmdWord;
|
||||
if (GetCurrentDisplayList(list)) {
|
||||
cmdWord = Memory::Read_U32(list.pc);
|
||||
if (Memory::IsValid4AlignedAddress(list.pc)) {
|
||||
cmdWord = Memory::ReadUnchecked_U32(list.pc);
|
||||
} else {
|
||||
// We are screwed.
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Current prim value.
|
||||
cmdWord = gstate.cmdmem[GE_CMD_PRIM];
|
||||
|
||||
@@ -896,21 +896,21 @@ void ImDisasmView::updateStatusBarText() {
|
||||
}
|
||||
|
||||
if (line.info.isDataAccess) {
|
||||
if (!Memory::IsValidAddress(line.info.dataAddress)) {
|
||||
snprintf(text, sizeof(text), "Invalid address %08X", line.info.dataAddress);
|
||||
if (!Memory::IsValidRange(line.info.dataAddress, line.info.dataSize)) {
|
||||
snprintf(text, sizeof(text), "Invalid address range %08X (size %d)", line.info.dataAddress, line.info.dataSize);
|
||||
} else {
|
||||
bool isFloat = MIPSGetInfo(line.info.encodedOpcode) & (IS_FPU | IS_VFPU);
|
||||
switch (line.info.dataSize) {
|
||||
case 1:
|
||||
snprintf(text, sizeof(text), "[%08X] = %02X", line.info.dataAddress, Memory::Read_U8(line.info.dataAddress));
|
||||
snprintf(text, sizeof(text), "[%08X] = %02X", line.info.dataAddress, Memory::ReadUnchecked_U8(line.info.dataAddress));
|
||||
break;
|
||||
case 2:
|
||||
snprintf(text, sizeof(text), "[%08X] = %04X", line.info.dataAddress, Memory::Read_U16(line.info.dataAddress));
|
||||
snprintf(text, sizeof(text), "[%08X] = %04X", line.info.dataAddress, Memory::ReadUnchecked_U16(line.info.dataAddress));
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
u32 dataInt = Memory::Read_U32(line.info.dataAddress);
|
||||
u32 dataFloat = Memory::Read_Float(line.info.dataAddress);
|
||||
u32 dataInt = Memory::ReadUnchecked_U32(line.info.dataAddress);
|
||||
u32 dataFloat = Memory::ReadUnchecked_Float(line.info.dataAddress);
|
||||
std::string dataString;
|
||||
if (isFloat)
|
||||
dataString = StringFromFormat("%08X / %f", dataInt, dataFloat);
|
||||
@@ -930,8 +930,8 @@ void ImDisasmView::updateStatusBarText() {
|
||||
uint32_t dataInt[4];
|
||||
float dataFloat[4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
dataInt[i] = Memory::Read_U32(line.info.dataAddress + i * 4);
|
||||
dataFloat[i] = Memory::Read_Float(line.info.dataAddress + i * 4);
|
||||
dataInt[i] = Memory::ReadUnchecked_U32(line.info.dataAddress + i * 4);
|
||||
dataFloat[i] = Memory::ReadUnchecked_Float(line.info.dataAddress + i * 4);
|
||||
}
|
||||
std::string dataIntString = StringFromFormat("%08X,%08X,%08X,%08X", dataInt[0], dataInt[1], dataInt[2], dataInt[3]);
|
||||
std::string dataFloatString = StringFromFormat("%f,%f,%f,%f", dataFloat[0], dataFloat[1], dataFloat[2], dataFloat[3]);
|
||||
|
||||
@@ -635,6 +635,10 @@ void ImStructViewer::DrawType(
|
||||
}
|
||||
|
||||
const u32 address = base + offset;
|
||||
if (!Memory::IsValidAddress(address)) {
|
||||
// Bad!
|
||||
return;
|
||||
}
|
||||
ImGui::PushID(static_cast<int>(address));
|
||||
ImGui::PushID(watchId); // We push watch id too as it's possible to have multiple watches on the same address
|
||||
|
||||
|
||||
Reference in New Issue
Block a user