diff --git a/Common/Data/Format/RIFF.cpp b/Common/Data/Format/RIFF.cpp index 77a24438f8..bfdce68368 100644 --- a/Common/Data/Format/RIFF.cpp +++ b/Common/Data/Format/RIFF.cpp @@ -47,6 +47,7 @@ bool RIFFReader::Descend(uint32_t intoId) { int startLocation = pos_; if (pos_ + length > fileSize_) { + // This should already catch the case where the file is truncated, but we also check for it in ReadData just in case. ERROR_LOG(Log::IO, "Block extends outside of RIFF file - failing descend"); pos_ = stack[depth_].parentStartLocation; return false; @@ -89,7 +90,8 @@ void RIFFReader::Ascend() { eof_ = stack[depth_].parentEOF; } -void RIFFReader::ReadData(void *what, int count) { +bool RIFFReader::ReadData(void *what, int count) { + bool success = true; if (count > 0) { int available = pos_ < fileSize_ ? fileSize_ - pos_ : 0; int toRead = count < available ? count : available; @@ -98,9 +100,11 @@ void RIFFReader::ReadData(void *what, int count) { } if (toRead < count) { // Truncated/corrupt file - don't read past the buffer. Zero the rest so - // callers don't read uninitialized data. + // callers don't read uninitialized data, but also return false. + // However, reaching this is probably impossible due to the check in Descend. ERROR_LOG(Log::IO, "RIFFReader::ReadData: wanted %d bytes but only %d available", count, toRead); memset((uint8_t *)what + toRead, 0, count - toRead); + success = false; } } pos_ += count; @@ -109,6 +113,7 @@ void RIFFReader::ReadData(void *what, int count) { count = 4 - count; pos_ += count; } + return success; } int RIFFReader::GetCurrentChunkSize() { diff --git a/Common/Data/Format/RIFF.h b/Common/Data/Format/RIFF.h index 79d1c567a6..7d85d5141f 100644 --- a/Common/Data/Format/RIFF.h +++ b/Common/Data/Format/RIFF.h @@ -20,7 +20,7 @@ public: void Ascend(); int ReadInt(); - void ReadData(void *data, int count); + bool ReadData(void *data, int count); // Read count bytes into data, return false if hits EOF during read. int GetCurrentChunkSize(); diff --git a/Common/Net/HTTPHeaders.cpp b/Common/Net/HTTPHeaders.cpp index 5ebc2e5781..410ed63060 100644 --- a/Common/Net/HTTPHeaders.cpp +++ b/Common/Net/HTTPHeaders.cpp @@ -49,8 +49,6 @@ bool RequestHeader::GetOther(const char *name, std::string *value) const { return false; } -// Intended to be a mad fast parser. It's not THAT fast currently, there's still -// things to optimize, but meh. int RequestHeader::ParseHttpHeader(const char *buffer) { if (first_header_) { // Step 1: Method @@ -101,7 +99,7 @@ int RequestHeader::ParseHttpHeader(const char *buffer) { resource[resource_name_len] = '\0'; if (q_ptr) { int param_length = (int)(endptr - q_ptr - 1); - if (param_length < 0) + if (param_length < 0) // This is likely just paranoia. param_length = 0; params = new char[param_length + 1]; memcpy(params, q_ptr + 1, param_length); diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 1968f23d57..8fa4ca2c32 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -751,6 +751,8 @@ void CWCheatEngine::ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper Memory::WriteUnchecked_U16((u16)oper(Memory::ReadUnchecked_U16(op.addr), op.val),op. addr); else if (op.sz == 4) Memory::WriteUnchecked_U32((u32)oper(Memory::ReadUnchecked_U32(op.addr), op.val), op.addr); + } else { + // Report memory error } } @@ -1046,10 +1048,10 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, const CheatLine &line = cheat.lines[i++]; switch (line.part1 >> 28) { case 0x1: // type copy byte - { + if (Memory::IsValidRange(op.addr, 4) && Memory::IsValidRange(op.addr + op.pointerCommands.baseOffset, 4)) { InvalidateICache(op.addr, 4); // See note at top of file - u32 srcAddr = Memory::Read_U32(op.addr) + op.pointerCommands.offset; - u32 dstAddr = Memory::Read_U32(op.addr + op.pointerCommands.baseOffset) + (line.part1 & 0x0FFFFFFF); + u32 srcAddr = Memory::ReadUnchecked_U32(op.addr) + op.pointerCommands.offset; + u32 dstAddr = Memory::ReadUnchecked_U32(op.addr + op.pointerCommands.baseOffset) + (line.part1 & 0x0FFFFFFF); if (Memory::IsValidRange(dstAddr, val) && Memory::IsValidRange(srcAddr, val)) { InvalidateICache(dstAddr, val); InvalidateICache(srcAddr, val); // See note at top of file @@ -1067,23 +1069,27 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, if ((line.part1 >> 28) == 0x3) { walkOffset = -walkOffset; } - // TODO: I've seen crashes here. Presumably an unaligned pointer just off the edge of memory. - // We should probably check pointer validity and invalidate the cheat if this happens. - base = Memory::Read_U32(base + walkOffset); - switch (line.part2 >> 28) { - case 0x2: - case 0x3: // type pointer walk - walkOffset = line.part2 & 0x0FFFFFFF; - if ((line.part2 >> 28) == 0x3) { - walkOffset = -walkOffset; - } - InvalidateICache(base + walkOffset, 4); // See note at top of file - base = Memory::Read_U32(base + walkOffset); - break; + if (Memory::IsValidRange(base + walkOffset, 4)) { + // TODO: I've seen crashes here. Presumably an unaligned pointer just off the edge of memory. + // We should probably check pointer validity and invalidate the cheat if this happens. + base = Memory::ReadUnchecked_U32(base + walkOffset); + switch (line.part2 >> 28) { + case 0x2: + case 0x3: // type pointer walk + walkOffset = line.part2 & 0x0FFFFFFF; + if ((line.part2 >> 28) == 0x3) { + walkOffset = -walkOffset; + } + if (Memory::IsValidRange(base + walkOffset, 4)) { + InvalidateICache(base + walkOffset, 4); // See note at top of file + base = Memory::ReadUnchecked_U32(base + walkOffset); + } + break; - default: - // Unexpected value in cheat line? - break; + default: + // Unexpected value in cheat line? + break; + } } } break; diff --git a/Core/Debugger/WebSocket/MemorySubscriber.cpp b/Core/Debugger/WebSocket/MemorySubscriber.cpp index f3cd3ac2bf..f4da5bec95 100644 --- a/Core/Debugger/WebSocket/MemorySubscriber.cpp +++ b/Core/Debugger/WebSocket/MemorySubscriber.cpp @@ -323,11 +323,11 @@ void WebSocketMemoryWriteU8(DebuggerRequest &req) { Core_RunOnCPUThread([&] { AutoDisabledReplacements memLock = LockMemory(true); currentMIPS->InvalidateICache(addr, 1); - Memory::Write_U8(val, addr); + Memory::WriteUnchecked_U8(val, addr); Reporting::NotifyDebugger(); JsonWriter &json = req.Respond(); - json.writeUint("value", Memory::Read_U8(addr)); + json.writeUint("value", Memory::ReadUnchecked_U8(addr)); }); } @@ -364,7 +364,7 @@ void WebSocketMemoryWriteU16(DebuggerRequest &req) { Reporting::NotifyDebugger(); JsonWriter &json = req.Respond(); - json.writeUint("value", Memory::Read_U16(addr)); + json.writeUint("value", Memory::ReadUnchecked_U16(addr)); }); } diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 848daf3f3d..fecb99e5de 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -245,33 +245,29 @@ int PSPNetconfDialog::Update(int animSpeed) { if (Memory::IsValidAddress(scanInfosAddr)) userMemory.Free(scanInfosAddr); scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo"); - // TOOD: What if scanInfosAddr is not valid? - if (Memory::IsValid4AlignedAddress(scanInfosAddr)) { - Memory::WriteUnchecked_U32(sizeof(SceNetAdhocctlScanInfoEmu), scanInfosAddr); - } + // TODO: What if scanInfosAddr is not valid? + Memory::WriteOrException_U32(sizeof(SceNetAdhocctlScanInfoEmu), scanInfosAddr); scanStep = 1; } } else if (scanStep == 1) { - s32 sz = Memory::ReadUnchecked_U32(scanInfosAddr); + s32 sz = Memory::ReadOrException_U32(scanInfosAddr); // Get required buffer size if (hleCall(sceNetAdhocctl, int, sceNetAdhocctlGetScanInfo, scanInfosAddr, 0) >= 0) { - s32 reqsz = Memory::ReadUnchecked_U32(scanInfosAddr); + s32 reqsz = Memory::ReadOrException_U32(scanInfosAddr); if (reqsz > sz) { sz = reqsz; userMemory.Free(scanInfosAddr); u32 structsz = sz + sizeof(s32); scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo"); - // TOOD: What if scanInfosAddr is not valid? - if (Memory::IsValid4AlignedAddress(scanInfosAddr)) { - Memory::WriteUnchecked_U32(sz, scanInfosAddr); - } + // TODO: What if scanInfosAddr is not valid? + Memory::WriteOrException_U32(sz, scanInfosAddr); } if (reqsz > 0) { if (hleCall(sceNetAdhocctl, int, sceNetAdhocctlGetScanInfo, scanInfosAddr, scanInfosAddr + (u32)sizeof(s32)) >= 0) { ScanInfos* scanInfos = (ScanInfos*)Memory::GetPointer(scanInfosAddr); int n = scanInfos->sz / sizeof(SceNetAdhocctlScanInfoEmu); - // Assuming returned SceNetAdhocctlScanInfoEmu(s) are contagious where next is pointing to current addr + sizeof(SceNetAdhocctlScanInfoEmu) + // Assuming returned SceNetAdhocctlScanInfoEmu(s) are contiguous where next is pointing to current addr + sizeof(SceNetAdhocctlScanInfoEmu) while (n > 0) { SceNetAdhocctlScanInfoEmu* si = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfosAddr + sizeof(s32) + sizeof(SceNetAdhocctlScanInfoEmu) * (n - 1LL)); if (memcmp(si->group_name.data, request.NetconfData->groupName, ADHOCCTL_GROUPNAME_LEN) == 0) { @@ -299,7 +295,7 @@ int PSPNetconfDialog::Update(int animSpeed) { connResult = hleCall(sceNetAdhocctl, int, sceNetAdhocctlJoin, scanInfosAddr + (u32)sizeof(s32)); if (connResult >= 0) { // We are done! - if (Memory::IsValid4AlignedAddress(scanInfosAddr)) + if (Memory::IsValidAddress(scanInfosAddr)) userMemory.Free(scanInfosAddr); scanInfosAddr = 0; } @@ -325,7 +321,7 @@ int PSPNetconfDialog::Update(int animSpeed) { } // Let's not leaks any memory - if (Memory::IsValid4AlignedAddress(scanInfosAddr)) + if (Memory::IsValidAddress(scanInfosAddr)) userMemory.Free(scanInfosAddr); scanInfosAddr = 0; } @@ -335,7 +331,7 @@ int PSPNetconfDialog::Update(int animSpeed) { ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US); request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; // Let's not leaks any memory - if (Memory::IsValid4AlignedAddress(scanInfosAddr)) + if (Memory::IsValidAddress(scanInfosAddr)) userMemory.Free(scanInfosAddr); scanInfosAddr = 0; } diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 6bdb048bd5..4f56dd89b9 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -395,7 +395,7 @@ void ElfReader::LoadRelocations2(int rel_seg) break; } - Memory::Write_U32(op, rel_offset); + Memory::WriteUnchecked_U32(op, rel_offset); NotifyMemInfo(MemBlockFlags::WRITE, rel_offset, 4, "Relocation2"); rcount += 1; } diff --git a/Core/Font/PGF.cpp b/Core/Font/PGF.cpp index b36864bdba..ef1900b232 100644 --- a/Core/Font/PGF.cpp +++ b/Core/Font/PGF.cpp @@ -784,7 +784,7 @@ void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, in const int newPix = std::min((int)((oldColor >> (i * 8)) & 0xFF) + pixelColor, 255); pix32 |= (u32)newPix << (i * 8); } - Memory::Write_U32(pix32, framebufferAddr); + Memory::WriteUnchecked_U32(pix32, framebufferAddr); break; } } diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index d898e29deb..78fc5032df 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -429,36 +429,41 @@ u32 GetSyscallOp(std::string_view moduleName, u32 nib) { } } -void WriteFuncStub(u32 stubAddr, u32 symAddr) -{ +// It's assumed that stubAddr and symAddr are valid. +void WriteFuncStub(u32 stubAddr, u32 symAddr) { + _dbg_assert_(Memory::IsValid4AlignedAddress(stubAddr)); + _dbg_assert_(Memory::IsValid4AlignedAddress(symAddr)); + // Note that this should be J not JAL, as otherwise control will return to the stub.. - Memory::Write_U32(MIPS_MAKE_J(symAddr), stubAddr); + Memory::WriteUnchecked_U32(MIPS_MAKE_J(symAddr), stubAddr); // Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently // Perhaps a syscall here (and verify support in jit), marking the module by uid (debugIdentifier)? - Memory::Write_U32(MIPS_MAKE_NOP(), stubAddr + 4); + Memory::WriteUnchecked_U32(MIPS_MAKE_NOP(), stubAddr + 4); } -void WriteFuncMissingStub(u32 stubAddr, u32 nid) -{ +// It's assumed that stubAddr is valid. +void WriteFuncMissingStub(u32 stubAddr, u32 nid) { + _dbg_assert_(Memory::IsValid4AlignedAddress(stubAddr)); // Write a trap so we notice this func if it's called before resolving. - Memory::Write_U32(MIPS_MAKE_JR_RA(), stubAddr); // jr ra - Memory::Write_U32(GetSyscallOp("", nid), stubAddr + 4); + Memory::WriteUnchecked_U32(MIPS_MAKE_JR_RA(), stubAddr); // jr ra + Memory::WriteUnchecked_U32(GetSyscallOp("", nid), stubAddr + 4); } -bool WriteHLESyscall(std::string_view moduleName, u32 nib, u32 address) -{ +// It's assumed that address is valid. +bool WriteHLESyscall(std::string_view moduleName, u32 nib, u32 address) { + _dbg_assert_(Memory::IsValid4AlignedAddress(address)); if (nib == 0) { WARN_LOG_REPORT(Log::HLE, "Wrote patched out nid=0 syscall (%.*s)", (int)moduleName.size(), moduleName.data()); - Memory::Write_U32(MIPS_MAKE_JR_RA(), address); //patched out? - Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out? + Memory::WriteUnchecked_U32(MIPS_MAKE_JR_RA(), address); //patched out? + Memory::WriteUnchecked_U32(MIPS_MAKE_NOP(), address+4); //patched out? return true; } int modindex = GetHLEModuleIndex(moduleName); if (modindex != -1) { - Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra - Memory::Write_U32(GetSyscallOp(moduleName, nib), address + 4); + Memory::WriteUnchecked_U32(MIPS_MAKE_JR_RA(), address); // jr ra + Memory::WriteUnchecked_U32(GetSyscallOp(moduleName, nib), address + 4); return true; } else @@ -640,7 +645,7 @@ void hleFlushCalls() { } stackData->argc = (int)info.args.size(); for (int j = 0; j < (int)info.args.size(); ++j) { - Memory::Write_U32(info.args[j], sp + sizeof(HLEMipsCallStack) + j * sizeof(u32)); + Memory::WriteUnchecked_U32(info.args[j], sp + sizeof(HLEMipsCallStack) + j * sizeof(u32)); } } enqueuedMipsCalls.clear(); diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index d90208d75a..7b78215a8c 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -26,18 +26,18 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPSCodeUtils.h" -HLEHelperThread::HLEHelperThread() : id_(0), entry_(0) { -} +HLEHelperThread::HLEHelperThread() : id_(0), entry_(0) {} HLEHelperThread::HLEHelperThread(const char *threadName, const u32 instructions[], u32 instrCount, u32 prio, int stacksize) { u32 instrBytes = instrCount * sizeof(u32); u32 totalBytes = instrBytes + sizeof(u32) * 2; AllocEntry(totalBytes); + _dbg_assert_(Memory::IsValid4AlignedAddress(entry_)); // after AllocEntry. Memory::Memcpy(entry_, instructions, instrBytes, "HelperMIPS"); // Just to simplify things, we add the return here. - Memory::Write_U32(MIPS_MAKE_JR_RA(), entry_ + instrBytes + 0); - Memory::Write_U32(MIPS_MAKE_NOP(), entry_ + instrBytes + 4); + Memory::WriteUnchecked_U32(MIPS_MAKE_JR_RA(), entry_ + instrBytes + 0); + Memory::WriteUnchecked_U32(MIPS_MAKE_NOP(), entry_ + instrBytes + 4); Create(threadName, prio, stacksize); } @@ -45,8 +45,9 @@ HLEHelperThread::HLEHelperThread(const char *threadName, const u32 instructions[ HLEHelperThread::HLEHelperThread(const char *threadName, const char *module, const char *func, u32 prio, int stacksize) { const u32 bytes = sizeof(u32) * 2; AllocEntry(bytes); - Memory::Write_U32(MIPS_MAKE_JR_RA(), entry_ + 0); - Memory::Write_U32(MIPS_MAKE_SYSCALL(module, func), entry_ + 4); + _dbg_assert_(Memory::IsValid4AlignedAddress(entry_)); // after AllocEntry. + Memory::WriteUnchecked_U32(MIPS_MAKE_JR_RA(), entry_ + 0); + Memory::WriteUnchecked_U32(MIPS_MAKE_SYSCALL(module, func), entry_ + 4); Create(threadName, prio, stacksize); } @@ -60,6 +61,7 @@ HLEHelperThread::~HLEHelperThread() { void HLEHelperThread::AllocEntry(u32 size) { entry_ = kernelMemory.Alloc(size, false, "HLEHelper"); + _dbg_assert_(Memory::IsValid4AlignedAddress(entry_)); // after AllocEntry. Memory::Memset(entry_, 0, size, "HLEHelperClear"); currentMIPS->InvalidateICache(entry_, size); } diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index 735b7875d9..027ede75b8 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -39,7 +39,7 @@ inline void WaitExecTimeout(SceUID threadID) { if (ko) { if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); + Memory::WriteOrException_U32(0, timeoutPtr); // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. // The reason is, if it times out, but what it was waiting on is DELETED prior to it @@ -196,7 +196,7 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI // TODO: Since it was deleted, we don't know how long was actually left. // For now, we just say the full time was taken. if (timeoutPtr != 0 && waitTimer != -1) { - Memory::Write_U32(0, timeoutPtr); + Memory::WriteOrException_U32(0, timeoutPtr); } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); @@ -217,7 +217,7 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI s64 cyclesLeft = waitDeadline - CoreTiming::GetTicks(); if (cyclesLeft < 0 && waitDeadline != 0) { if (timeoutPtr != 0 && waitTimer != -1) { - Memory::Write_U32(0, timeoutPtr); + Memory::WriteOrException_U32(0, timeoutPtr); } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); @@ -247,7 +247,7 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI // TODO: Since it was deleted, we don't know how long was actually left. // For now, we just say the full time was taken. if (timeoutPtr != 0 && waitTimer != -1) { - Memory::Write_U32(0, timeoutPtr); + Memory::WriteOrException_U32(0, timeoutPtr); } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 5e56c3d2b6..c98d878190 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -784,8 +784,10 @@ static int Hook_hexyzforce_monoclome_thread() { if (!GetMIPSStaticAddress(fb_info, -4, 0)) { return 0; } - - const u32 fb_address = Memory::Read_U32(fb_info); + 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, 0x00088000); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00088000, "hexyzforce_monoclome_thread"); @@ -834,13 +836,16 @@ static int Hook_brandish_download_frame() { if (!GetMIPSStaticAddress(fb_infoaddr, 0x2c, 0x30)) { return 0; } - const u32 fb_info = Memory::Read_U32(fb_infoaddr); + if (!Memory::IsValid4AlignedRange(fb_infoaddr, 256)) { // TODO: Figure out the right range to check. + return 0; + } + const u32 fb_info = Memory::ReadUnchecked_U32(fb_infoaddr); const MIPSOpcode fb_index_load = Memory::Read_Instruction(currentMIPS->pc + 0x38, true); if (fb_index_load != MIPS_MAKE_LW(MIPS_GET_RT(fb_index_load), MIPS_GET_RS(fb_index_load), fb_index_load & 0xffff)) { return 0; } const int fb_index_offset = (s16)(fb_index_load & 0xffff); - const u32 fb_index = (Memory::Read_U32(fb_info + fb_index_offset) + 1) & 1; + const u32 fb_index = (Memory::ReadUnchecked_U32(fb_info + fb_index_offset) + 1) & 1; const u32 fb_address = 0x4000000 + (0x44000 * fb_index); const u32 dest_address = currentMIPS->r[MIPS_REG_A1]; if (Memory::IsRAMAddress(dest_address)) { @@ -851,8 +856,8 @@ static int Hook_brandish_download_frame() { } static int Hook_growlanser_create_saveicon() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 4); - const u32 fmt = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP]); + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 4); + const u32 fmt = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP]); const u32 sz = fmt == GE_FORMAT_8888 ? 0x00088000 : 0x00044000; if (Memory::IsVRAMAddress(fb_address) && fmt <= 3) { gpu->PerformMemoryCopy(fb_address, fb_address, sz, GPUCopyFlag::FORCE_DST_MATCH_MEM | GPUCopyFlag::DISALLOW_CREATE_VFB); @@ -862,8 +867,8 @@ static int Hook_growlanser_create_saveicon() { } static int Hook_sd_gundam_g_generation_download_frame() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 8); - const u32 fmt = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 4); + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 8); + const u32 fmt = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 4); const u32 sz = fmt == GE_FORMAT_8888 ? 0x00088000 : 0x00044000; if (Memory::IsVRAMAddress(fb_address) && fmt <= 3) { gpu->PerformReadbackToMemory(fb_address, sz); @@ -927,8 +932,8 @@ static int Hook_suikoden1_and_2_download_frame_2() { } static int Hook_rezel_cross_download_frame() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 0x1C); - const u32 fmt = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 0x14); + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 0x1C); + const u32 fmt = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 0x14); const u32 sz = fmt == GE_FORMAT_8888 ? 0x00088000 : 0x00044000; if (Memory::IsVRAMAddress(fb_address) && fmt <= 3) { gpu->PerformReadbackToMemory(fb_address, sz); @@ -960,13 +965,17 @@ static int Hook_soranokiseki_sc_download_frame() { if (!GetMIPSStaticAddress(fb_infoaddr, 0x28, 0x2C)) { return 0; } - const u32 fb_info = Memory::Read_U32(fb_infoaddr); + if (!Memory::IsValid4AlignedAddress(fb_infoaddr)) { + return 0; + } + + const u32 fb_info = Memory::ReadUnchecked_U32(fb_infoaddr); const MIPSOpcode fb_index_load = Memory::Read_Instruction(currentMIPS->pc + 0x34, true); if (fb_index_load != MIPS_MAKE_LW(MIPS_GET_RT(fb_index_load), MIPS_GET_RS(fb_index_load), fb_index_load & 0xffff)) { return 0; } const int fb_index_offset = (s16)(fb_index_load & 0xffff); - const u32 fb_index = (Memory::Read_U32(fb_info + fb_index_offset) + 1) & 1; + const u32 fb_index = (Memory::ReadUnchecked_U32(fb_info + fb_index_offset) + 1) & 1; const u32 fb_address = 0x4000000 + (0x44000 * fb_index); const u32 dest_address = currentMIPS->r[MIPS_REG_A1]; if (Memory::IsRAMAddress(dest_address)) { @@ -1135,7 +1144,10 @@ static int Hook_flowers_download_frame() { } static int Hook_motorstorm_download_frame() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_A1] + 0x18); + if (!Memory::IsValid4AlignedAddress(currentMIPS->r[MIPS_REG_A1] + 0x18)) { + return 0; + } + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_A1] + 0x18); if (Memory::IsVRAMAddress(fb_address)) { gpu->PerformReadbackToMemory(fb_address, 0x00088000); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00088000, "motorstorm_download_frame"); @@ -1194,7 +1206,7 @@ static int Hook_zettai_hero_update_minimap_tex() { const uint32_t texSize = 64 * 64 * 1; const uint32_t writeAddr = currentMIPS->r[MIPS_REG_V1] + SignExtend16ToS32(storeOffset); if (Memory::IsValidRange(texAddr, texSize) && writeAddr >= texAddr && writeAddr < texAddr + texSize) { - const uint8_t currentValue = Memory::Read_U8(writeAddr); + const uint8_t currentValue = Memory::ReadUnchecked_U8(writeAddr); if (currentValue != currentMIPS->r[MIPS_REG_A3]) { gpu->InvalidateCache(texAddr, texSize, GPU_INVALIDATE_FORCE); } @@ -1277,7 +1289,7 @@ static int Hook_unendingbloodycall_download_frame() { } static int Hook_omertachinmokunookitethelegacy_download_frame() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_SP] + 4); + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_SP] + 4); if (Memory::IsVRAMAddress(fb_address)) { gpu->PerformReadbackToMemory(fb_address, 0x00044000); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00044000, "omertachinmokunookitethelegacy_download_frame"); @@ -1304,7 +1316,10 @@ static int Hook_steinsgate_download_frame() { if (!GetMIPSStaticAddress(fb_offset_addr, 0x1C, 0x20)) { return 0; } - const u32 fb_address = 0x04000000 + Memory::Read_U32(fb_offset_addr); + if (!Memory::IsValid4AlignedAddress(fb_offset_addr)) { + return 0; + } + const u32 fb_address = 0x04000000 + Memory::ReadUnchecked_U32(fb_offset_addr); if (Memory::IsVRAMAddress(fb_address)) { gpu->PerformReadbackToMemory(fb_address, 0x00088000); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00088000, "steinsgate_download_frame"); @@ -1320,9 +1335,11 @@ static int Hook_infinity_download_frame() { if (!GetMIPSStaticAddress(magic_value_addr, 0x08, 0x1C)) { return 0; } - + if (!Memory::IsValid4AlignedAddress(magic_value_addr)) { + return 0; + } // Not sure why it was done like this, but that's what the actual function does. - const u32 fb_address = (Memory::Read_U32(magic_value_addr) & 1) ? 0x04000000 : 0x04088000; + const u32 fb_address = (Memory::ReadUnchecked_U32(magic_value_addr) & 1) ? 0x04000000 : 0x04088000; gpu->PerformReadbackToMemory(fb_address, 0x00088000); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00088000, "infinity_download_frame"); @@ -1352,7 +1369,7 @@ static int Hook_kingdomhearts_download_frame() { return 0; } - const u32 fb_offset_index = Memory::Read_U32(fb_offset_index_addr); // 0x08821E90-0x08821E98 + const u32 fb_offset_index = Memory::ReadUnchecked_U32(fb_offset_index_addr); // 0x08821E90-0x08821E98 if (fb_offset_index > 2) { return 0; } @@ -1369,16 +1386,16 @@ static int Hook_kingdomhearts_download_frame() { if (!Memory::IsValidRange(fb_offset_table, 12)) { return 0; } - const u32 fb_offset = Memory::Read_U32(fb_offset_table + fb_offset_index*4); // 0x08821E98-0x08821EB0 + const u32 fb_offset = Memory::ReadUnchecked_U32(fb_offset_table + fb_offset_index*4); // 0x08821E98-0x08821EB0 u32 magic_ptr_addr; if (!GetMIPSStaticAddress(magic_ptr_addr, 0x08, 0x10)) { return 0; } - const u32 magic_ptr = Memory::Read_U32(magic_ptr_addr); // 0x0881EF70, 0x0881EF78 + const u32 magic_ptr = Memory::ReadUnchecked_U32(magic_ptr_addr); // 0x0881EF70, 0x0881EF78 // Function of the variable guessed. - const u8 bytes_per_pixel = Memory::Read_U8(magic_ptr+0x50); // 0x0881EFE0 + const u8 bytes_per_pixel = Memory::ReadUnchecked_U8(magic_ptr+0x50); // 0x0881EFE0 const u32 fb_address = fb_base + fb_offset; const u32 fb_size = (bytes_per_pixel == 2) ? 0x044000 : 0x088000; // Branch at 0x0881EFE8, s3 set at 0x0881EFB8 @@ -1390,21 +1407,27 @@ static int Hook_kingdomhearts_download_frame() { } static int Hook_katamari_render_check() { - const u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_A0] + 0x3C); - const u32 fbInfoPtr = Memory::Read_U32(currentMIPS->r[MIPS_REG_A0] + 0x40); - if (Memory::IsVRAMAddress(fb_address) && fbInfoPtr != 0) { - const u32 sizeInfoPtr = Memory::Read_U32(fbInfoPtr + 0x0C); - // These are the values it uses to control the loop. - // Width in memory appears to be stride / 8. - const u32 width = Memory::Read_U16(sizeInfoPtr + 0x08) * 8; - // Height in memory is also divided by 8 (but this one isn't hardcoded.) - const u32 heightBlocks = Memory::Read_U16(sizeInfoPtr + 0x0A); - // For some reason this is the number of heightBlocks less 1. - const u32 heightBlockCount = Memory::Read_U8(fbInfoPtr + 0x08) + 1; + if (!Memory::IsValidRange(currentMIPS->r[MIPS_REG_A0] + 0x3C, 8)) { + return 0; + } - const u32 totalBytes = width * heightBlocks * heightBlockCount; - gpu->PerformReadbackToMemory(fb_address, totalBytes); - NotifyMemInfo(MemBlockFlags::WRITE, fb_address, totalBytes, "katamari_render_check"); + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_A0] + 0x3C); + const u32 fbInfoPtr = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_A0] + 0x40); + if (Memory::IsVRAMAddress(fb_address) && fbInfoPtr != 0 && Memory::IsValid4AlignedRange(fbInfoPtr, 0x10)) { + const u32 sizeInfoPtr = Memory::ReadUnchecked_U32(fbInfoPtr + 0x0C); + if (Memory::IsValidRange(sizeInfoPtr, 0x10)) { + // These are the values it uses to control the loop. + // Width in memory appears to be stride / 8. + const u32 width = Memory::ReadUnchecked_U16(sizeInfoPtr + 0x08) * 8; + // Height in memory is also divided by 8 (but this one isn't hardcoded.) + const u32 heightBlocks = Memory::ReadUnchecked_U16(sizeInfoPtr + 0x0A); + // For some reason this is the number of heightBlocks less 1. + const u32 heightBlockCount = Memory::ReadUnchecked_U8(fbInfoPtr + 0x08) + 1; + + const u32 totalBytes = width * heightBlocks * heightBlockCount; + gpu->PerformReadbackToMemory(fb_address, totalBytes); + NotifyMemInfo(MemBlockFlags::WRITE, fb_address, totalBytes, "katamari_render_check"); + } } return 0; } @@ -1478,20 +1501,24 @@ static int Hook_starocean_clear_framebuf_after() { u32 y_address, h_address; if (GetMIPSGPAddress(y_address, -204) && GetMIPSGPAddress(h_address, -200)) { - int y = (s16)Memory::Read_U16(y_address); - int h = (s16)Memory::Read_U16(h_address); - - DEBUG_LOG(Log::HLE, "starocean_clear_framebuf() - %08x y=%d-%d", framebuf, y, h); - // TODO: This is always clearing to 0, actually, which could be faster than an upload. - gpu->PerformWriteColorFromMemory(framebuf + 512 * y * 4, 512 * h * 4); + if (Memory::IsValid2AlignedAddress(y_address) && Memory::IsValid2AlignedAddress(h_address)) { + int y = (s16)Memory::ReadUnchecked_U16(y_address); + int h = (s16)Memory::ReadUnchecked_U16(h_address); + DEBUG_LOG(Log::HLE, "starocean_clear_framebuf() - %08x y=%d-%d", framebuf, y, h); + // TODO: This is always clearing to 0, actually, which could be faster than an upload. + gpu->PerformWriteColorFromMemory(framebuf + 512 * y * 4, 512 * h * 4); + } } return 0; } static int Hook_motorstorm_pixel_read() { - u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_A0] + 0x18); - u32 fb_height = Memory::Read_U16(currentMIPS->r[MIPS_REG_A0] + 0x26); - u32 fb_stride = Memory::Read_U16(currentMIPS->r[MIPS_REG_A0] + 0x28); + if (!Memory::IsValidRange(currentMIPS->r[MIPS_REG_A0] + 0x18, 0x20)) { + return 0; + } + const u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_A0] + 0x18); + const u32 fb_height = Memory::ReadUnchecked_U16(currentMIPS->r[MIPS_REG_A0] + 0x26); + const u32 fb_stride = Memory::ReadUnchecked_U16(currentMIPS->r[MIPS_REG_A0] + 0x28); gpu->PerformReadbackToMemory(fb_address, fb_height * fb_stride); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, fb_height * fb_stride, "motorstorm_pixel_read"); return 0; @@ -1499,8 +1526,8 @@ static int Hook_motorstorm_pixel_read() { static int Hook_worms_copy_normalize_alpha() { // At this point in the function (0x0CC), s1 is the framebuf and a2 is the size. - u32 fb_address = currentMIPS->r[MIPS_REG_S1]; - u32 fb_size = currentMIPS->r[MIPS_REG_A2]; + const u32 fb_address = currentMIPS->r[MIPS_REG_S1]; + const u32 fb_size = currentMIPS->r[MIPS_REG_A2]; if (Memory::IsVRAMAddress(fb_address) && Memory::IsValidRange(fb_address, fb_size)) { gpu->PerformReadbackToMemory(fb_address, fb_size); NotifyMemInfo(MemBlockFlags::WRITE, fb_address, fb_size, "worms_copy_normalize_alpha"); @@ -1529,8 +1556,8 @@ static int Hook_soltrigger_render_ucschar() { u32 targetInfoPtrPtr = currentMIPS->r[MIPS_REG_A2]; u32 targetInfoPtr = Memory::IsValidRange(targetInfoPtrPtr, 4) ? Memory::ReadUnchecked_U32(targetInfoPtrPtr) : 0; if (Memory::IsValidRange(targetInfoPtr, 32)) { - u32 targetPtr = Memory::Read_U32(targetInfoPtr + 8); - u32 targetByteStride = Memory::Read_U32(targetInfoPtr + 16); + u32 targetPtr = Memory::ReadUnchecked_U32(targetInfoPtr + 8); + u32 targetByteStride = Memory::ReadUnchecked_U32(targetInfoPtr + 16); // We don't know the height specifically. gpu->InvalidateCache(targetPtr, targetByteStride * 512, GPU_INVALIDATE_HINT); @@ -1772,11 +1799,11 @@ static bool WriteReplaceInstruction(u32 address, int index) { prevInstr = replacedInstructions[address]; } - if (MIPS_IS_RUNBLOCK(Memory::Read_U32(address))) { + if (MIPS_IS_RUNBLOCK(Memory::ReadUnchecked_U32(address))) { WARN_LOG(Log::HLE, "Replacing jitted func address %08x", address); } replacedInstructions[address] = prevInstr; - Memory::Write_U32(MIPS_EMUHACK_CALL_REPLACEMENT | index, address); + Memory::WriteUnchecked_U32(MIPS_EMUHACK_CALL_REPLACEMENT | index, address); return true; } @@ -1811,10 +1838,11 @@ void WriteReplaceInstructions(u32 address, u64 hash, int size) { } } +// address is valid here. void RestoreReplacedInstruction(u32 address) { - const u32 curInstr = Memory::Read_U32(address); + const u32 curInstr = Memory::ReadUnchecked_U32(address); if (MIPS_IS_REPLACEMENT(curInstr)) { - Memory::Write_U32(replacedInstructions[address], address); + Memory::WriteUnchecked_U32(replacedInstructions[address], address); NOTICE_LOG(Log::HLE, "Restored replaced func at %08x", address); } else { NOTICE_LOG(Log::HLE, "Replaced func changed at %08x", address); @@ -1822,6 +1850,7 @@ void RestoreReplacedInstruction(u32 address) { replacedInstructions.erase(address); } +// startaddr and endaddr are valid here. void RestoreReplacedInstructions(u32 startAddr, u32 endAddr) { if (endAddr == startAddr) return; @@ -1833,9 +1862,9 @@ void RestoreReplacedInstructions(u32 startAddr, u32 endAddr) { int restored = 0; for (auto it = start; it != end; ++it) { const u32 addr = it->first; - const u32 curInstr = Memory::Read_U32(addr); + const u32 curInstr = Memory::ReadUnchecked_U32(addr); if (MIPS_IS_REPLACEMENT(curInstr)) { - Memory::Write_U32(it->second, addr); + Memory::WriteUnchecked_U32(it->second, addr); ++restored; } } @@ -1853,7 +1882,7 @@ std::map SaveAndClearReplacements() { const u32 curInstr = Memory::Read_Opcode_JIT(addr).encoding; if (MIPS_IS_REPLACEMENT(curInstr)) { saved[addr] = curInstr; - Memory::Write_U32(instr, addr); + Memory::WriteUnchecked_U32(instr, addr); } } @@ -1864,7 +1893,11 @@ std::map SaveAndClearReplacements() { void RestoreSavedReplacements(const std::map &saved) { for (const auto &[addr, instr] : saved) { // Just put the replacements back. - Memory::Write_U32(instr, addr); + if (Memory::IsValid4AlignedAddress(addr)) { + Memory::WriteUnchecked_U32(instr, addr); + } else { + ERROR_LOG(Log::HLE, "RestoreSavedReplacements: Invalid address %08x", addr); + } } } diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index e01fa66068..e13b99d804 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -273,10 +273,12 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { } } else if (chan.format == PSP_AUDIO_FORMAT_MONO) { // Rare, so unoptimized. Expands to stereo. - for (u32 i = 0; i < chan.sampleCount; i++) { - s16 sample = (s16)Memory::Read_U16(chan.sampleAddress + 2 * i); - chanSampleQueues[chanNum].push(ApplySampleVolume(sample, leftVol)); - chanSampleQueues[chanNum].push(ApplySampleVolume(sample, rightVol)); + if (Memory::IsValidRange(chan.sampleAddress, chan.sampleCount * sizeof(s16))) { + for (u32 i = 0; i < chan.sampleCount; i++) { + s16 sample = (s16)Memory::ReadUnchecked_U16(chan.sampleAddress + 2 * i); + chanSampleQueues[chanNum].push(ApplySampleVolume(sample, leftVol)); + chanSampleQueues[chanNum].push(ApplySampleVolume(sample, rightVol)); + } } } } diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index e6657bb670..d9b53ebaff 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -482,15 +482,15 @@ static int sceCtrlSetIdleCancelThreshold(int idleReset, int idleBack) static int sceCtrlGetIdleCancelThreshold(u32 idleResetPtr, u32 idleBackPtr) { - if (idleResetPtr && !Memory::IsValidAddress(idleResetPtr)) + if (idleResetPtr && !Memory::IsValid4AlignedAddress(idleResetPtr)) return hleLogError(Log::sceCtrl, SCE_KERNEL_ERROR_PRIV_REQUIRED); - if (idleBackPtr && !Memory::IsValidAddress(idleBackPtr)) + if (idleBackPtr && !Memory::IsValid4AlignedAddress(idleBackPtr)) return hleLogError(Log::sceCtrl, SCE_KERNEL_ERROR_PRIV_REQUIRED); if (idleResetPtr) - Memory::Write_U32(ctrlIdleReset, idleResetPtr); + Memory::WriteUnchecked_U32(ctrlIdleReset, idleResetPtr); if (idleBackPtr) - Memory::Write_U32(ctrlIdleBack, idleBackPtr); + Memory::WriteUnchecked_U32(ctrlIdleBack, idleBackPtr); return hleLogDebug(Log::sceCtrl, 0); } diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b81a848fb8..ef01c2276a 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -357,7 +357,7 @@ void __DisplaySetWasPaused() { wasPaused = true; } -// TOOD: Should return 59.997? +// TODO: Should return 59.997? static int FrameTimingLimit() { if (!NetworkAllowSpeedControl()) { return 60; @@ -955,12 +955,12 @@ bool __DisplayGetFramebuf(PSPPointer *topaddr, u32 *linesize, GEBufferFormat static u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, int latchedMode) { const FrameBufferState &fbState = latchedMode == PSP_DISPLAY_SETBUF_NEXTFRAME ? latchedFramebuf : framebuf; - if (Memory::IsValidAddress(topaddrPtr)) - Memory::Write_U32(fbState.topaddr, topaddrPtr); - if (Memory::IsValidAddress(linesizePtr)) - Memory::Write_U32(fbState.stride, linesizePtr); - if (Memory::IsValidAddress(pixelFormatPtr)) - Memory::Write_U32(fbState.fmt, pixelFormatPtr); + if (Memory::IsValid4AlignedAddress(topaddrPtr)) + Memory::WriteUnchecked_U32(fbState.topaddr, topaddrPtr); + if (Memory::IsValid4AlignedAddress(linesizePtr)) + Memory::WriteUnchecked_U32(fbState.stride, linesizePtr); + if (Memory::IsValid4AlignedAddress(pixelFormatPtr)) + Memory::WriteUnchecked_U32(fbState.fmt, pixelFormatPtr); return hleLogDebug(Log::sceDisplay, 0); } @@ -1068,12 +1068,12 @@ static u32 sceDisplayIsForeground() { } static u32 sceDisplayGetMode(u32 modeAddr, u32 widthAddr, u32 heightAddr) { - if (Memory::IsValidAddress(modeAddr)) - Memory::Write_U32(mode, modeAddr); - if (Memory::IsValidAddress(widthAddr)) - Memory::Write_U32(width, widthAddr); - if (Memory::IsValidAddress(heightAddr)) - Memory::Write_U32(height, heightAddr); + if (Memory::IsValid4AlignedAddress(modeAddr)) + Memory::WriteUnchecked_U32(mode, modeAddr); + if (Memory::IsValid4AlignedAddress(widthAddr)) + Memory::WriteUnchecked_U32(width, widthAddr); + if (Memory::IsValid4AlignedAddress(heightAddr)) + Memory::WriteUnchecked_U32(height, heightAddr); return hleLogDebug(Log::sceDisplay, 0); } @@ -1086,8 +1086,8 @@ static u32 sceDisplayIsVsync() { } static u32 sceDisplayGetResumeMode(u32 resumeModeAddr) { - if (Memory::IsValidAddress(resumeModeAddr)) - Memory::Write_U32(resumeMode, resumeModeAddr); + if (Memory::IsValid4AlignedAddress(resumeModeAddr)) + Memory::WriteUnchecked_U32(resumeMode, resumeModeAddr); return hleLogDebug(Log::sceDisplay, 0); } @@ -1100,12 +1100,12 @@ static u32 sceDisplaySetResumeMode(u32 rMode) { static u32 sceDisplayGetBrightness(u32 levelAddr, u32 otherAddr) { // Standard levels on a PSP: 44, 60, 72, 84 (AC only) - if (Memory::IsValidAddress(levelAddr)) { - Memory::Write_U32(brightnessLevel, levelAddr); + if (Memory::IsValid4AlignedAddress(levelAddr)) { + Memory::WriteUnchecked_U32(brightnessLevel, levelAddr); } // Always seems to write zero? - if (Memory::IsValidAddress(otherAddr)) { - Memory::Write_U32(0, otherAddr); + if (Memory::IsValid4AlignedAddress(otherAddr)) { + Memory::WriteUnchecked_U32(0, otherAddr); } return hleLogWarning(Log::sceDisplay, 0); } diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 2856a5232a..51c023423a 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -785,7 +785,7 @@ void PostAllocCallback::run(MipsCall &call) { if (v0 == 0) { // TODO: Who deletes fontLib? if (errorCodePtr_) - Memory::Write_U32(SCE_FONT_ERROR_OUT_OF_MEMORY, errorCodePtr_); + Memory::WriteOrException_U32(SCE_FONT_ERROR_OUT_OF_MEMORY, errorCodePtr_); call.setReturnValue(0); } else { _dbg_assert_(fontLibID_ >= 0); diff --git a/Core/HLE/sceHeap.cpp b/Core/HLE/sceHeap.cpp index bd880f3b9d..9a77099316 100644 --- a/Core/HLE/sceHeap.cpp +++ b/Core/HLE/sceHeap.cpp @@ -122,14 +122,16 @@ static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 param u32 grain = 4; // 0 is ignored. if (paramsPtr != 0) { - u32 size = Memory::Read_U32(paramsPtr); - if (size < 8) { - return hleLogError(Log::HLE, 0, "invalid param size"); + if (Memory::IsValid4AlignedRange(paramsPtr, 8)) { + u32 size = Memory::ReadUnchecked_U32(paramsPtr); + if (size < 8) { + return hleLogError(Log::HLE, 0, "invalid param size"); + } + if (size > 8) { + WARN_LOG_REPORT(Log::HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size); + } + grain = Memory::ReadUnchecked_U32(paramsPtr + 4); } - if (size > 8) { - WARN_LOG_REPORT(Log::HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size); - } - grain = Memory::Read_U32(paramsPtr + 4); } // There's 8 bytes at the end of every block, reserved. @@ -178,8 +180,12 @@ static int sceHeapDeleteHeap(u32 heapAddr) { static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 paramsPtr) { if (paramsPtr != 0) { - u32 size = Memory::Read_U32(paramsPtr); - WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size); + if (Memory::IsValid4AlignedAddress(paramsPtr)) { + u32 size = Memory::ReadUnchecked_U32(paramsPtr); + if (size > 4) { + WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size); + } + } } if (!name) { WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): name is NULL"); diff --git a/Core/HLE/sceHprm.cpp b/Core/HLE/sceHprm.cpp index 688ccf3087..3581fc5646 100644 --- a/Core/HLE/sceHprm.cpp +++ b/Core/HLE/sceHprm.cpp @@ -22,7 +22,7 @@ #include "Core/MIPS/MIPS.h" static u32 sceHprmPeekCurrentKey(u32 keyAddress) { - Memory::Write_U32(0, keyAddress); + Memory::WriteOrException_U32(0, keyAddress); return hleLogDebug(Log::HLE, 0); } diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index e54165c6fe..8c83ee6cca 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -468,8 +468,8 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) { // Someone woke up, so it's no longer got one. f->hasAsyncResult = false; - if (Memory::IsValidAddress(address)) { - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedAddress(address)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); } // If this was a sceIoCloseAsync, we should close it at this point. @@ -560,7 +560,9 @@ static bool __IoCheckAsyncWait(FileNode *f, SceUID threadID, u32 &error, int res } u32 address = __KernelGetWaitValue(threadID, error); - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedRange(address, 8)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); + } f->hasAsyncResult = false; if (f->closePending) { @@ -1675,8 +1677,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o switch (cmd) { case 0x01F20001: // Get UMD disc type - if (Memory::IsValidAddress(outPtr) && outLen >= 8) { - Memory::Write_U32(0x10, outPtr + 4); // Always return game disc (if present) + if (Memory::IsValid4AlignedRange(outPtr, 8) && outLen >= 8) { + Memory::WriteUnchecked_U32(0x10, outPtr + 4); // Always return game disc (if present) return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); @@ -1684,17 +1686,17 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x01F20002: // Get UMD current LBA - if (Memory::IsValidAddress(outPtr) && outLen >= 4) { - Memory::Write_U32(0x10, outPtr); // Assume first sector + if (Memory::IsValid4AlignedRange(outPtr, 4) && outLen >= 4) { + Memory::WriteUnchecked_U32(0x10, outPtr); // Assume first sector return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } break; case 0x01F20003: - if (Memory::IsValidAddress(argAddr) && argLen >= 4) { + if (Memory::IsValid4AlignedRange(argAddr, 4) && argLen >= 4) { PSPFileInfo info = pspFileSystem.GetFileInfo("umd1:"); - Memory::Write_U32((u32) (info.size) - 1, outPtr); + Memory::WriteUnchecked_U32((u32) (info.size) - 1, outPtr); return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); @@ -1719,7 +1721,11 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o case 0x01F300A5: // Prepare UMD data into cache and get status if (Memory::IsValidAddress(argAddr) && argLen >= 4) { - Memory::Write_U32(1, outPtr); // Status (unitary index of the requested read, greater or equal to 1) + if (Memory::IsValid4AlignedAddress(outPtr)) { + Memory::WriteUnchecked_U32(1, outPtr); // Status (unitary index of the requested read, greater or equal to 1) + } else { + return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS, "bad outptr"); + } return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); @@ -1771,12 +1777,12 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o switch (cmd) { case 0x02025801: // Check the MemoryStick's driver status (mscmhc0: only.) - if (Memory::IsValidAddress(outPtr) && outLen >= 4) { + if (Memory::IsValidRange(outPtr, 4) && outLen >= 4) { if (MemoryStick_State() == PSP_MEMORYSTICK_STATE_INSERTED) { // 1 = not inserted (ready), 4 = inserted - Memory::Write_U32(PSP_MEMORYSTICK_STATE_DEVICE_INSERTED, outPtr); + Memory::WriteUnchecked_U32(PSP_MEMORYSTICK_STATE_DEVICE_INSERTED, outPtr); } else { - Memory::Write_U32(PSP_MEMORYSTICK_STATE_DRIVER_READY, outPtr); + Memory::WriteUnchecked_U32(PSP_MEMORYSTICK_STATE_DRIVER_READY, outPtr); } return hleLogDebug(Log::sceIo, 0); } else { @@ -1785,8 +1791,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02015804: // Register MemoryStick's insert/eject callback (mscmhc0) - if (Memory::IsValidAddress(argAddr) && outPtr == 0 && argLen >= 4) { - u32 cbId = Memory::Read_U32(argAddr); + if (Memory::IsValid4AlignedAddress(argAddr) && outPtr == 0 && argLen >= 4) { + u32 cbId = Memory::ReadUnchecked_U32(argAddr); int type = -1; kernelObjects.GetIDType(cbId, &type); @@ -1813,8 +1819,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02015805: // Unregister MemoryStick's insert/eject callback (mscmhc0) - if (Memory::IsValidAddress(argAddr) && argLen >= 4) { - SceUID cbId = Memory::Read_U32(argAddr); + if (Memory::IsValid4AlignedAddress(argAddr) && argLen >= 4) { + SceUID cbId = Memory::ReadUnchecked_U32(argAddr); size_t slot = (size_t)-1; // We want to only remove one at a time. for (size_t i = 0; i < memStickCallbacks.size(); ++i) { @@ -1836,10 +1842,10 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02025806: // Check if the device is inserted (mscmhc0) - if (Memory::IsValidAddress(outPtr) && outLen >= 4) { + if (Memory::IsValid4AlignedAddress(outPtr) && outLen >= 4) { // 1 = Inserted. // 2 = Not inserted. - Memory::Write_U32(MemoryStick_State(), outPtr); + Memory::WriteUnchecked_U32(MemoryStick_State(), outPtr); return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); @@ -1897,8 +1903,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02415821: // MScmRegisterMSInsertEjectCallback - if (Memory::IsValidAddress(argAddr) && argLen >= 4) { - u32 cbId = Memory::Read_U32(argAddr); + if (Memory::IsValidRange(argAddr, argLen) && argLen >= 4) { + u32 cbId = Memory::ReadUnchecked_U32(argAddr); int type = -1; kernelObjects.GetIDType(cbId, &type); @@ -1924,8 +1930,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02415822: // MScmUnregisterMSInsertEjectCallback - if (Memory::IsValidAddress(argAddr) && argLen >= 4) { - SceUID cbId = Memory::Read_U32(argAddr); + if (Memory::IsValidRange(argAddr,4 ) && argLen >= 4) { + SceUID cbId = Memory::ReadUnchecked_U32(argAddr); size_t slot = (size_t)-1; // We want to only remove one at a time. for (size_t i = 0; i < memStickFatCallbacks.size(); ++i) { @@ -1946,8 +1952,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o break; case 0x02415823: // Set FAT as enabled - if (Memory::IsValidAddress(argAddr) && argLen == 4) { - MemoryStick_SetFatState((MemStickFatState)Memory::Read_U32(argAddr)); + if (Memory::IsValidRange(argAddr, 4) && argLen == 4) { + MemoryStick_SetFatState((MemStickFatState)Memory::ReadUnchecked_U32(argAddr)); return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, -1, "Failed 0x02415823 fat"); @@ -1958,14 +1964,14 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o // If the values added together are >= 0x80000000, or less than outPtr, invalid address. if (((int)outPtr + outLen) < (int)outPtr) { return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "sceIoDevctl: fatms0: 0x02425823 command, bad address"); - } else if (!Memory::IsValidAddress(outPtr)) { + } else if (!Memory::IsValidRange(outPtr, 4)) { // Technically, only checks for NULL, crashes for many bad addresses. ERROR_LOG(Log::sceIo, "sceIoDevctl: "); return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "fatms0: 0x02425823 command, no output address"); } else { // Does not care about outLen, even if it's 0. // Note: writes 1 when inserted, 0 when not inserted. - Memory::Write_U32(MemoryStick_FatState(), outPtr); + Memory::WriteUnchecked_U32(MemoryStick_FatState(), outPtr); return hleDelayResult(hleLogDebug(Log::sceIo, 0), "check fat state", cyclesToUs(23500)); } break; @@ -1974,8 +1980,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o if (MemoryStick_State() != PSP_MEMORYSTICK_STATE_INSERTED) { return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_DEVICE_NOT_FOUND); } - if (Memory::IsValidAddress(outPtr) && outLen == 4) { - Memory::Write_U32(0, outPtr); + if (Memory::IsValidRange(outPtr, 4) && outLen == 4) { + Memory::WriteUnchecked_U32(0, outPtr); return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, -1, "Failed 0x02425824 fat"); @@ -1987,8 +1993,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_DEVICE_NOT_FOUND); } // TODO: Pretend we have a 2GB memory stick? Should we check MemoryStick_FreeSpace? - if (Memory::IsValidAddress(argAddr) && argLen >= 4) { // NOTE: not outPtr - u32 pointer = Memory::Read_U32(argAddr); + if (Memory::IsValidRange(argAddr, 4) && argLen >= 4) { // NOTE: not outPtr + u32 pointer = Memory::ReadUnchecked_U32(argAddr); u32 sectorSize = 0x200; u32 memStickSectorSize = 32 * 1024; u32 sectorCount = memStickSectorSize / sectorSize; @@ -2274,7 +2280,9 @@ static u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) { } DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x)", f->asyncResult, id, poll, address); - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedRange(address, 8)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); + } f->hasAsyncResult = false; if (f->closePending) { @@ -2312,7 +2320,9 @@ static int sceIoWaitAsync(int id, u32 address) { if (!__KernelIsDispatchEnabled()) { return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedRange(address, 8)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); + } f->hasAsyncResult = false; if (f->closePending) { @@ -2346,7 +2356,9 @@ static int sceIoWaitAsyncCB(int id, u32 address) { __KernelWaitCurThread(WAITTYPE_ASYNCIO, f->GetUID(), address, 0, true, "io waited"); return hleLogDebug(Log::sceIo, 0, "waiting"); } else if (f->hasAsyncResult) { - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedRange(address, 8)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); + } f->hasAsyncResult = false; if (f->closePending) { @@ -2369,7 +2381,9 @@ static u32 sceIoPollAsync(int id, u32 address) { if (f->pendingAsyncResult) { return hleLogVerbose(Log::sceIo, 1, "not ready"); } else if (f->hasAsyncResult) { - Memory::Write_U64((u64) f->asyncResult, address); + if (Memory::IsValid4AlignedRange(address, 8)) { + Memory::WriteUnchecked_U64((u64)f->asyncResult, address); + } f->hasAsyncResult = false; if (f->closePending) { @@ -2504,6 +2518,10 @@ static u32 sceIoDread(int id, u32 dirent_addr) { u32 error; DirListing *dir = kernelObjects.Get(id, error); if (dir) { + if (!Memory::IsValidRange(dirent_addr, sizeof(SceIoDirEnt))) { + Core_MemoryException(dirent_addr, sizeof(SceIoDirEnt), currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK, "sceIoDread"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid address"); + } SceIoDirEnt *entry = (SceIoDirEnt*) Memory::GetPointer(dirent_addr); if (dir->index == (int) dir->listing.size()) { @@ -2516,7 +2534,7 @@ static u32 sceIoDread(int id, u32 dirent_addr) { strncpy(entry->d_name, info.name.c_str(), 256); entry->d_name[255] = '\0'; - + bool isFAT = pspFileSystem.FlagsFromFilename(dir->name) & FileSystemFlags::SIMULATE_FAT32; // Only write d_private for memory stick if (isFAT) { @@ -2531,17 +2549,17 @@ static u32 sceIoDread(int id, u32 dirent_addr) { // - [13..???] long file name (null-terminated) // Hm, so currently we don't write the short name at all to d_private? TODO - strcpy_limit((char*)Memory::GetPointer(entry->d_private + 13), (const char*)entry->d_name, ARRAY_SIZE(entry->d_name)); + strcpy_limit((char*)Memory::GetPointerUnchecked(entry->d_private + 13), (const char*)entry->d_name, ARRAY_SIZE(entry->d_name)); } else { // d_private is pointing to an area of total size 1044 // - [0..3] size of area // - [4..19] "8.3" file name (null-terminated), could be empty. // - [20..???] long file name (null-terminated) - auto size = Memory::Read_U32(entry->d_private); + auto size = Memory::ReadUnchecked_U32(entry->d_private); // Hm, so currently we don't write the short name at all to d_private? TODO if (size >= 1044) { - strcpy_limit((char*)Memory::GetPointer(entry->d_private + 20), (const char*)entry->d_name, ARRAY_SIZE(entry->d_name)); + strcpy_limit((char*)Memory::GetPointerUnchecked(entry->d_private + 20), (const char*)entry->d_name, ARRAY_SIZE(entry->d_name)); } } } @@ -2642,9 +2660,9 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for sector size of file %i", id); - if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { + if (Memory::IsValidRange(outdataPtr, 4) && outlen >= 4) { // ISOs always use 2048 sized sectors. - Memory::Write_U32(2048, outdataPtr); + Memory::WriteUnchecked_U32(2048, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2655,25 +2673,26 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. DEBUG_LOG(Log::sceIo, "sceIoIoctl: Asked for file offset of file %d", id); - if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { + if (Memory::IsValidRange(outdataPtr, 4) && outlen >= 4) { u32 offset = (u32)pspFileSystem.GetSeekPos(f->handle); - Memory::Write_U32(offset, outdataPtr); + Memory::WriteUnchecked_U32(offset, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } break; case 0x01010005: + { // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Seek for file %i", id); // Even if the size is 4, it still actually reads a 16 byte struct, it seems. - if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { - struct SeekInfo { - u64_le offset; - u32_le unk; - u32_le whence; - }; + struct SeekInfo { + u64_le offset; + u32_le unk; + u32_le whence; + }; + if (Memory::IsValidRange(indataPtr, sizeof(SeekInfo)) && inlen >= 4) { const auto seekInfo = PSPPointer::Create(indataPtr); FileMove seek; s64 newPos = __IoLseekDest(f, seekInfo->offset, seekInfo->whence, seek); @@ -2686,14 +2705,15 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } break; + } // Get UMD file start sector. case 0x01020006: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for start sector of file %i", id); - if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { - Memory::Write_U32(f->FileInfo().startSector, outdataPtr); + if (Memory::IsValidRange(outdataPtr, 4) && outlen >= 4) { + Memory::WriteUnchecked_U32(f->FileInfo().startSector, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2704,8 +2724,8 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for size of file %i", id); - if (Memory::IsValidAddress(outdataPtr) && outlen >= 8) { - Memory::Write_U64(f->FileInfo().size, outdataPtr); + if (Memory::IsValid4AlignedRange(outdataPtr, 8)) { + Memory::WriteUnchecked_U64(f->FileInfo().size, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2716,9 +2736,9 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Read from file %i", id); - if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { - u32 size = Memory::Read_U32(indataPtr); - if (Memory::IsValidAddress(outdataPtr) && size <= outlen) { + if (Memory::IsValidRange(indataPtr, 4) && inlen >= 4) { + u32 size = Memory::ReadUnchecked_U32(indataPtr); + if (Memory::IsValidRange(outdataPtr, size) && size <= outlen) { // sceIoRead does its own delaying (and deferring.) usec = 0; return hleCall(IoFileMgrForUser, u32, sceIoRead, id, outdataPtr, size); @@ -2735,8 +2755,8 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should work only for umd0:/, etc. not for ms0:/ or disc0:/. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Sector tell from file %i", id); - if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { - Memory::Write_U32((u32)pspFileSystem.GetSeekPos(f->handle), outdataPtr); + if (Memory::IsValidRange(outdataPtr, 4) && outlen >= 4) { + Memory::WriteUnchecked_U32((u32)pspFileSystem.GetSeekPos(f->handle), outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2747,10 +2767,10 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // TODO: Should work only for umd0:/, etc. not for ms0:/ or disc0:/. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(Log::sceIo, "sceIoIoctl: Sector read from file %i", id); - if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { - u32 size = Memory::Read_U32(indataPtr); + if (Memory::IsValidRange(indataPtr, 4) && inlen >= 4) { + u32 size = Memory::ReadUnchecked_U32(indataPtr); // Note that size is specified in sectors, not bytes. - if (size > 0 && Memory::IsValidAddress(outdataPtr) && size <= outlen) { + if (size > 0 && Memory::IsValidRange(outdataPtr, size) && size <= outlen) { // sceIoRead does its own delaying (and deferring.) usec = 0; return hleCall(IoFileMgrForUser, u32, sceIoRead, id, outdataPtr, size); @@ -2866,8 +2886,8 @@ static u32 sceIoGetFdList(u32 outAddr, int outSize, u32 fdNumAddr) { ++count; } - if (Memory::IsValidAddress(fdNumAddr)) - Memory::Write_U32(count, fdNumAddr); + if (Memory::IsValidRange(fdNumAddr, 4)) + Memory::WriteUnchecked_U32(count, fdNumAddr); if (count >= outSize) { return outSize; } else { diff --git a/Core/HLE/sceJpeg.cpp b/Core/HLE/sceJpeg.cpp index 366499d3ba..3ea7f3b89b 100644 --- a/Core/HLE/sceJpeg.cpp +++ b/Core/HLE/sceJpeg.cpp @@ -389,9 +389,9 @@ static int JpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr) { // - Bits 16 to 24 (Color mode): 0x00 (Unknown), 0x01 (Greyscale) or 0x02 (YCbCr) // - Bits 8 to 16 (Vertical chroma subsampling value): 0x00, 0x01 or 0x02 // - Bits 0 to 8 (Horizontal chroma subsampling value): 0x00, 0x01 or 0x02 - if (Memory::IsValidAddress(colourInfoAddr)) { + if (Memory::IsValid4AlignedAddress(colourInfoAddr)) { // Note: can't actually seem to get any other subsampling values or color modes to work on a PSP. - Memory::Write_U32(0x00020202, colourInfoAddr); + Memory::WriteUnchecked_U32(0x00020202, colourInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, colourInfoAddr, 4, "JpegGetOutputInfo"); } diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 18581860f0..a3a6dee106 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -144,8 +144,8 @@ static bool __KernelCheckEventFlagMatches(u32 pattern, u32 bits, u8 wait) { static bool __KernelApplyEventFlagMatch(u32_le *pattern, u32 bits, u8 wait, u32 outAddr) { if (__KernelCheckEventFlagMatches(*pattern, bits, wait)) { - if (Memory::IsValidAddress(outAddr)) - Memory::Write_U32(*pattern, outAddr); + if (Memory::IsValid4AlignedAddress(outAddr)) + Memory::WriteUnchecked_U32(*pattern, outAddr); if (wait & PSP_EVENT_WAITCLEAR) *pattern &= ~bits; @@ -167,14 +167,14 @@ static bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 } else { // Otherwise, we set the current result since we're bailing. if (Memory::IsValidAddress(th.outAddr)) - Memory::Write_U32(e->nef.currentPattern, th.outAddr); + Memory::WriteOrException_U32(e->nef.currentPattern, th.outAddr); } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error); if (timeoutPtr != 0 && eventFlagWaitTimer != -1) { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, th.threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(th.threadID, result); @@ -231,9 +231,11 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte e->nef.numWaitThreads = 0; if (optPtr != 0) { - u32 size = Memory::Read_U32(optPtr); - if (size > 4) - WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size); + if (Memory::IsValid4AlignedAddress(optPtr)) { + u32 size = Memory::ReadUnchecked_U32(optPtr); + if (size > 4) + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size); + } } if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0) WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr); @@ -246,8 +248,8 @@ u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr) { EventFlag *e = kernelObjects.Get(uid, error); if (e) { e->nef.numWaitThreads = (int) e->waitingThreads.size(); - if (Memory::IsValidAddress(numWaitThreadsPtr)) - Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr); + if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr)) + Memory::WriteUnchecked_U32(e->nef.numWaitThreads, numWaitThreadsPtr); e->nef.currentPattern = pattern; @@ -325,7 +327,7 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate) { EventFlag *e = kernelObjects.Get(flagID, error); if (e) { if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); + Memory::WriteOrException_U32(0, timeoutPtr); for (size_t i = 0; i < e->waitingThreads.size(); i++) { EventFlagTh *t = &e->waitingThreads[i]; @@ -347,7 +349,7 @@ static void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) { if (timeoutPtr == 0 || eventFlagWaitTimer == -1) return; - int micro = (int) Memory::Read_U32(timeoutPtr); + int micro = (int) Memory::ReadOrException_U32(timeoutPtr); // This seems like the actual timing of timeouts on hardware. if (micro <= 1) @@ -383,7 +385,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) - timeout = Memory::Read_U32(timeoutPtr); + timeout = Memory::ReadOrException_U32(timeoutPtr); // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { @@ -446,7 +448,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) - timeout = Memory::Read_U32(timeoutPtr); + timeout = Memory::ReadOrException_U32(timeoutPtr); // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { @@ -500,8 +502,9 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr) { EventFlag *e = kernelObjects.Get(id, error); if (e) { if (!__KernelApplyEventFlagMatch(&e->nef.currentPattern, bits, wait, outBitsPtr)) { - if (Memory::IsValidAddress(outBitsPtr)) - Memory::Write_U32(e->nef.currentPattern, outBitsPtr); + if (Memory::IsValid4AlignedAddress(outBitsPtr)) { + Memory::WriteUnchecked_U32(e->nef.currentPattern, outBitsPtr); + } if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_MULTI); diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 7ea0071d45..284a70564d 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -144,12 +144,14 @@ static int sceKernelAllocHeapMemoryWithOption(int heapId, u32 memSize, u32 param u32 grain = 4; // 0 is ignored. if (paramsPtr != 0) { - u32 size = Memory::Read_U32(paramsPtr); + if (!Memory::IsValid4AlignedRange(paramsPtr, 8)) + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid paramsPtr"); + u32 size = Memory::ReadUnchecked_U32(paramsPtr); // size of the params struct if (size < 8) return hleLogError(Log::sceKernel, 0, "invalid param size"); if (size > 8) WARN_LOG(Log::HLE, "sceKernelAllocHeapMemoryWithOption(): unexpected param size %d", size); - grain = Memory::Read_U32(paramsPtr + 4); + grain = Memory::ReadUnchecked_U32(paramsPtr + 4); } INFO_LOG(Log::HLE, "sceKernelAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapId, memSize, paramsPtr); // There's 8 bytes at the end of every block, reserved. diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 6069eefe05..e9f0e3191e 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -778,11 +778,11 @@ static int sysclib_sprintf_impl(u32 dst, int limit, u32 fmt, int paramOffset) { int stack_idx = arg_idx - 6; u32 stack_cur = currentMIPS->r[MIPS_REG_SP] + stack_idx * 4; - if (!Memory::IsValidAddress(stack_cur)) { + if (!Memory::IsValid4AlignedAddress(stack_cur)) { ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad stack pointer %08x", stack_cur); return 0; } - val = Memory::Read_U32(stack_cur); + val = Memory::ReadUnchecked_U32(stack_cur); VERBOSE_LOG(Log::sceKernel, "sysclib_sprintf fetching %08x from sp + %u", val, stack_idx * 4); } arg_idx++; @@ -825,11 +825,11 @@ static int sysclib_sprintf_impl(u32 dst, int limit, u32 fmt, int paramOffset) { int stack_idx = arg_idx - 6; u32 stack_cur = currentMIPS->r[MIPS_REG_SP] + stack_idx * 4; - if (!Memory::IsValidAddress(stack_cur)) { + if (!Memory::IsValid4AlignedAddress(stack_cur)) { ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad stack pointer %08x", stack_cur); return 0; } - val_from_arg = Memory::Read_U32(stack_cur); + val_from_arg = Memory::ReadUnchecked_U32(stack_cur); DEBUG_LOG(Log::sceKernel, "sysclib_sprintf fetching %08x from sp + %u", val_from_arg, stack_idx * 4); } arg_idx++; diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index d4dea65c37..b8da518a3f 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -36,14 +36,12 @@ const int PSP_MBX_ERROR_DUPLICATE_MSG = 0x800201C9; -struct MbxWaitingThread -{ +struct MbxWaitingThread { SceUID threadID; u32 packetAddr; u64 pausedTimeout; - bool operator ==(const SceUID &otherThreadID) const - { + bool operator ==(const SceUID &otherThreadID) const { return threadID == otherThreadID; } }; @@ -51,8 +49,7 @@ void __KernelMbxTimeout(u64 userdata, int cyclesLate); static int mbxWaitTimer = -1; -struct NativeMbx -{ +struct NativeMbx { SceSize_le size; char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; SceUInt_le attr; @@ -61,8 +58,7 @@ struct NativeMbx u32_le packetListHead; }; -struct Mbx : public KernelObject -{ +struct Mbx : public KernelObject { const char *GetName() override { return nmb.name; } const char *GetTypeName() override { return GetStaticTypeName(); } static const char *GetStaticTypeName() { return "Mbx"; } @@ -93,51 +89,48 @@ struct Mbx : public KernelObject } } - inline void AddInitialMessage(u32 ptr) - { + inline void AddInitialMessage(u32 ptr) { nmb.numMessages++; - Memory::Write_U32(ptr, ptr); + Memory::WriteUnchecked_U32(ptr, ptr); nmb.packetListHead = ptr; } - inline void AddFirstMessage(u32 endPtr, u32 ptr) - { + inline void AddFirstMessage(u32 endPtr, u32 ptr) { nmb.numMessages++; - Memory::Write_U32(nmb.packetListHead, ptr); - Memory::Write_U32(ptr, endPtr); + Memory::WriteUnchecked_U32(nmb.packetListHead, ptr); + Memory::WriteUnchecked_U32(ptr, endPtr); nmb.packetListHead = ptr; } - inline void AddLastMessage(u32 endPtr, u32 ptr) - { + inline void AddLastMessage(u32 endPtr, u32 ptr) { nmb.numMessages++; - Memory::Write_U32(ptr, endPtr); - Memory::Write_U32(nmb.packetListHead, ptr); + Memory::WriteUnchecked_U32(ptr, endPtr); + Memory::WriteUnchecked_U32(nmb.packetListHead, ptr); } - inline void AddMessage(u32 beforePtr, u32 afterPtr, u32 ptr) - { + inline void AddMessage(u32 beforePtr, u32 afterPtr, u32 ptr) { nmb.numMessages++; - Memory::Write_U32(afterPtr, ptr); - Memory::Write_U32(ptr, beforePtr); + Memory::WriteUnchecked_U32(afterPtr, ptr); + Memory::WriteUnchecked_U32(ptr, beforePtr); } + // receivePtr must be valid. int ReceiveMessage(u32 receivePtr) { u32 ptr = nmb.packetListHead; - if (!Memory::IsValidAddress(nmb.packetListHead)) { + if (!Memory::IsValid4AlignedAddress(nmb.packetListHead)) { return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } // Check over the linked list and reset the head. int c = 0; while (true) { - u32 next = Memory::Read_U32(nmb.packetListHead); - if (!Memory::IsValidAddress(next)) + u32 next = Memory::ReadUnchecked_U32(nmb.packetListHead); + if (!Memory::IsValid4AlignedAddress(next)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; if (next == ptr) { if (nmb.packetListHead != ptr) { - next = Memory::Read_U32(next); - Memory::Write_U32(next, nmb.packetListHead); + next = Memory::ReadUnchecked_U32(next); + Memory::WriteUnchecked_U32(next, nmb.packetListHead); nmb.packetListHead = next; break; } else { @@ -154,7 +147,7 @@ struct Mbx : public KernelObject } // Tell the receiver about the message. - Memory::Write_U32(ptr, receivePtr); + Memory::WriteUnchecked_U32(ptr, receivePtr); nmb.numMessages--; return 0; } @@ -211,7 +204,7 @@ static bool __KernelUnlockMbxForThread(Mbx *m, MbxWaitingThread &th, u32 &error, { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(mbxWaitTimer, th.threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(th.threadID, result); @@ -258,7 +251,7 @@ static void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) if (timeoutPtr == 0 || mbxWaitTimer == -1) return; - int micro = (int) Memory::Read_U32(timeoutPtr); + int micro = (int) Memory::ReadOrException_U32(timeoutPtr); // This seems to match the actual timing. if (micro <= 2) @@ -276,11 +269,9 @@ static std::vector::iterator __KernelMbxFindPriority(std::vect std::vector::iterator iter, end, best = waiting.end(); u32 best_prio = 0xFFFFFFFF; - for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter) - { + for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter) { u32 iter_prio = __KernelGetThreadPrio(iter->threadID); - if (iter_prio < best_prio) - { + if (iter_prio < best_prio) { best = iter; best_prio = iter_prio; } @@ -317,11 +308,12 @@ SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr) DEBUG_LOG(Log::sceKernel, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr); - if (optAddr != 0) - { - u32 size = Memory::Read_U32(optAddr); - if (size > 4) - WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size); + if (optAddr != 0) { + if (Memory::IsValidRange(optAddr, 4)) { + u32 size = Memory::ReadUnchecked_U32(optAddr); + if (size > 4) + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size); + } } if ((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) != 0) WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMbx(%s) unsupported attr parameter: %08x", name, attr); @@ -356,19 +348,16 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) { u32 error; Mbx *m = kernelObjects.Get(id, error); - if (!m) - { - ERROR_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr); - return error; + if (!m) { + return hleLogError(Log::sceKernel, error, "invalid mbx id"); } - NativeMbxPacket *addPacket = (NativeMbxPacket*)Memory::GetPointer(packetAddr); - if (addPacket == 0) - { - ERROR_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr); - return -1; + if (!Memory::IsValidRange(packetAddr, sizeof(NativeMbxPacket))) { + return hleLogError(Log::sceKernel, -1, "invalid packet address"); } + NativeMbxPacket *addPacket = (NativeMbxPacket *)Memory::GetPointerUnchecked(packetAddr); + // If the queue is empty, maybe someone is waiting. // We have to check them first, they might've timed out. if (m->nmb.numMessages == 0) @@ -386,34 +375,30 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) __KernelUnlockMbxForThread(m, t, error, 0, wokeThreads); m->waitingThreads.erase(iter); - if (wokeThreads) - { - DEBUG_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, t.threadID); - Memory::Write_U32(packetAddr, t.packetAddr); + if (wokeThreads) { + Memory::WriteOrException_U32(packetAddr, t.packetAddr); hleReSchedule("mbx sent"); // We don't need to do anything else, finish here. - return 0; + return hleLogDebug(Log::sceKernel, 0, "threads waiting, resuming %d", t.threadID); } } } DEBUG_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr); - if (m->nmb.numMessages == 0) + if (m->nmb.numMessages == 0) { m->AddInitialMessage(packetAddr); - else - { + } else { u32 next = m->nmb.packetListHead, prev = 0; - for (int i = 0, n = m->nmb.numMessages; i < n; i++) - { + for (int i = 0, n = m->nmb.numMessages; i < n; i++) { if (next == packetAddr) return PSP_MBX_ERROR_DUPLICATE_MSG; - if (!Memory::IsValidAddress(next)) + if (!Memory::IsValid4AlignedAddress(next)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; prev = next; - next = Memory::Read_U32(next); + next = Memory::ReadUnchecked_U32(next); } bool inserted = false; @@ -440,99 +425,74 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) m->AddLastMessage(prev, packetAddr); } - return 0; + return hleNoLog(0); } -int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) -{ +int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) { u32 error; Mbx *m = kernelObjects.Get(id, error); - - if (!m) - { - ERROR_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); - return error; + if (!m) { + return hleLogError(Log::sceKernel, error, "invalid mbx id"); } - if (m->nmb.numMessages > 0) - { - DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); - return m->ReceiveMessage(packetAddrPtr); - } - else - { - DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + if (m->nmb.numMessages > 0) { + return hleLogDebug(Log::sceKernel, m->ReceiveMessage(packetAddrPtr), "sending first queue message"); + } else { HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited"); - return 0; + return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting"); } } -int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) -{ +int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) { u32 error; Mbx *m = kernelObjects.Get(id, error); - - if (!m) - { - ERROR_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); - return error; + if (!m) { + return hleLogError(Log::sceKernel, error, "invalid mbx id"); } - if (m->nmb.numMessages > 0) - { - DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); + if (m->nmb.numMessages > 0) { hleCheckCurrentCallbacks(); - return m->ReceiveMessage(packetAddrPtr); - } - else - { - DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + return hleLogDebug(Log::sceKernel, m->ReceiveMessage(packetAddrPtr), "sending first queue message"); + } else { HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited"); - return 0; + return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting"); } } -int sceKernelPollMbx(SceUID id, u32 packetAddrPtr) -{ +int sceKernelPollMbx(SceUID id, u32 packetAddrPtr) { u32 error; Mbx *m = kernelObjects.Get(id, error); - if (!m) - { + if (!m) { ERROR_LOG(Log::sceKernel, "sceKernelPollMbx(%i, %08x): invalid mbx id", id, packetAddrPtr); return error; } - if (m->nmb.numMessages > 0) - { + if (m->nmb.numMessages > 0) { DEBUG_LOG(Log::sceKernel, "sceKernelPollMbx(%i, %08x): sending first queue message", id, packetAddrPtr); return m->ReceiveMessage(packetAddrPtr); - } - else - { + } else { DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_MBOX_NOMSG=sceKernelPollMbx(%i, %08x): no message in queue", id, packetAddrPtr); return SCE_KERNEL_ERROR_MBOX_NOMSG; } } -int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) -{ +int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) { u32 error; Mbx *m = kernelObjects.Get(id, error); - if (!m) - { + if (!m) { ERROR_LOG(Log::sceKernel, "sceKernelCancelReceiveMbx(%i, %08x): invalid mbx id", id, numWaitingThreadsAddr); return error; } - u32 count = (u32) m->waitingThreads.size(); + const u32 count = (u32)m->waitingThreads.size(); DEBUG_LOG(Log::sceKernel, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count); bool wokeThreads = false; @@ -544,7 +504,7 @@ int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) hleReSchedule("mbx canceled"); if (numWaitingThreadsAddr) - Memory::Write_U32(count, numWaitingThreadsAddr); + Memory::WriteOrException_U32(count, numWaitingThreadsAddr); return 0; } @@ -557,8 +517,9 @@ int sceKernelReferMbxStatus(SceUID id, u32 infoAddr) { // Should we crash the thread somehow? auto info = PSPPointer::Create(infoAddr); - if (!info.IsValid()) + if (!info.IsValid()) { return hleLogError(Log::sceKernel, -1, "invalid pointer"); + } // The PSP's ReferMbxStatus doesn't just read packetListHead — it traverses // the linked list and *updates* firstMessage to handle test programs that diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 77f039119a..79948fc32a 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -457,7 +457,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u int blockNum = fpl->AllocateBlock(); if (blockNum >= 0) { u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; - Memory::Write_U32(blockPtr, threadInfo.addrPtr); + Memory::WriteOrException_U32(blockPtr, threadInfo.addrPtr); NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); } else { return false; @@ -468,7 +468,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u if (timeoutPtr != 0 && fplWaitTimer != -1) { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(fplWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, result); @@ -543,10 +543,10 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid blockSize/count"); int alignment = 4; - if (Memory::IsValidRange(optPtr, 4)) { + if (Memory::IsValidRange(optPtr, 8)) { u32 size = Memory::ReadUnchecked_U32(optPtr); if (size >= 4) - alignment = Memory::Read_U32(optPtr + 4); + alignment = Memory::ReadUnchecked_U32(optPtr + 4); // Must be a power of 2 to be valid. if ((alignment & (alignment - 1)) != 0) return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid alignment %d", alignment); @@ -614,7 +614,7 @@ static void __KernelSetFplTimeout(u32 timeoutPtr) if (timeoutPtr == 0 || fplWaitTimer == -1) return; - int micro = (int) Memory::Read_U32(timeoutPtr); + int micro = (int) Memory::ReadOrException_U32(timeoutPtr); // TODO: test for fpls. // This happens to be how the hardware seems to time things. @@ -629,58 +629,54 @@ static void __KernelSetFplTimeout(u32 timeoutPtr) CoreTiming::ScheduleEvent(usToCycles(micro), fplWaitTimer, __KernelGetCurThread()); } -int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) -{ +int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) { u32 error; FPL *fpl = kernelObjects.Get(uid, error); if (!fpl) { return hleLogDebug(Log::sceKernel, error, "invalid fpl"); - } else { - int blockNum = fpl->AllocateBlock(); - if (blockNum >= 0) { - u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; - Memory::Write_U32(blockPtr, blockPtrAddr); - NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); - } else { - SceUID threadID = __KernelGetCurThread(); - HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); - FplWaitingThread waiting = {threadID, blockPtrAddr}; - fpl->waitingThreads.push_back(waiting); - - __KernelSetFplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited"); - } - - return hleLogDebug(Log::sceKernel, 0); } + + int blockNum = fpl->AllocateBlock(); + if (blockNum >= 0) { + u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; + Memory::WriteOrException_U32(blockPtr, blockPtrAddr); + NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); + } else { + SceUID threadID = __KernelGetCurThread(); + HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); + FplWaitingThread waiting = {threadID, blockPtrAddr}; + fpl->waitingThreads.push_back(waiting); + + __KernelSetFplTimeout(timeoutPtr); + __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited"); + } + + return hleLogDebug(Log::sceKernel, 0); } -int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) -{ +int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) { u32 error; FPL *fpl = kernelObjects.Get(uid, error); if (!fpl) { return hleLogError(Log::sceKernel, error, "invalid fpl"); - } else { - DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr); - - int blockNum = fpl->AllocateBlock(); - if (blockNum >= 0) { - u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; - Memory::Write_U32(blockPtr, blockPtrAddr); - NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); - } else { - SceUID threadID = __KernelGetCurThread(); - HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); - FplWaitingThread waiting = {threadID, blockPtrAddr}; - fpl->waitingThreads.push_back(waiting); - - __KernelSetFplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited"); - } - - return 0; } + + int blockNum = fpl->AllocateBlock(); + if (blockNum >= 0) { + u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; + Memory::WriteOrException_U32(blockPtr, blockPtrAddr); + NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); + } else { + SceUID threadID = __KernelGetCurThread(); + HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); + FplWaitingThread waiting = {threadID, blockPtrAddr}; + fpl->waitingThreads.push_back(waiting); + + __KernelSetFplTimeout(timeoutPtr); + __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited"); + } + + return hleLogDebug(Log::sceKernel, 0); } int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr) { @@ -688,16 +684,16 @@ int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr) { FPL *fpl = kernelObjects.Get(uid, error); if (!fpl) { return hleLogError(Log::sceKernel, error, "invalid fpl"); + } + + int blockNum = fpl->AllocateBlock(); + if (blockNum >= 0) { + u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; + Memory::WriteOrException_U32(blockPtr, blockPtrAddr); + NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); + return hleLogDebug(Log::sceKernel, 0); } else { - int blockNum = fpl->AllocateBlock(); - if (blockNum >= 0) { - u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; - Memory::Write_U32(blockPtr, blockPtrAddr); - NotifyMemInfo(MemBlockFlags::SUB_ALLOC, blockPtr, fpl->alignedSize, "FplAllocate"); - return hleLogDebug(Log::sceKernel, 0); - } else { - return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY); - } + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY); } } @@ -753,8 +749,9 @@ int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr) { } fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size(); - if (Memory::IsValidAddress(numWaitThreadsPtr)) - Memory::Write_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr); + if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr)) { + Memory::WriteUnchecked_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr); + } bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_CANCEL); if (wokeThreads) hleReSchedule("fpl canceled"); @@ -1243,7 +1240,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u addr = vpl->alloc.Alloc(allocSize, true); } if (addr != (u32) -1) { - Memory::Write_U32(addr, threadInfo.addrPtr); + Memory::WriteOrException_U32(addr, threadInfo.addrPtr); } else { return false; } @@ -1253,7 +1250,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u if (timeoutPtr != 0 && vplWaitTimer != -1) { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(vplWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, result); @@ -1355,11 +1352,12 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize DEBUG_LOG(Log::sceKernel, "%x=sceKernelCreateVpl(\"%s\", block=%i, attr=%i, size=%i)", id, name, partition, vpl->nv.attr, vpl->nv.poolSize); - if (optPtr != 0) - { - u32 size = Memory::Read_U32(optPtr); - if (size > 4) - WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size); + if (optPtr != 0) { + if (Memory::IsValid4AlignedAddress(optPtr)) { + u32 size = Memory::ReadUnchecked_U32(optPtr); + if (size > 4) + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size); + } } return hleNoLog(id); @@ -1423,7 +1421,7 @@ static bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, b addr = vpl->alloc.Alloc(allocSize, true, "VplAllocate"); } if (addr != (u32) -1) { - Memory::Write_U32(addr, addrPtr); + Memory::WriteOrException_U32(addr, addrPtr); error = 0; } else { error = SCE_KERNEL_ERROR_NO_MEMORY; @@ -1460,7 +1458,7 @@ static void __KernelSetVplTimeout(u32 timeoutPtr) if (timeoutPtr == 0 || vplWaitTimer == -1) return; - int micro = (int) Memory::Read_U32(timeoutPtr); + int micro = (int) Memory::ReadOrException_U32(timeoutPtr); // This happens to be how the hardware seems to time things. if (micro <= 5) @@ -1482,7 +1480,7 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) VPL *vpl = kernelObjects.Get(uid, ignore); if (error == SCE_KERNEL_ERROR_NO_MEMORY) { - if (timeoutPtr != 0 && Memory::Read_U32(timeoutPtr) == 0) + if (timeoutPtr != 0 && Memory::ReadOrException_U32(timeoutPtr) == 0) return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT); if (vpl) { @@ -1512,7 +1510,7 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) VPL *vpl = kernelObjects.Get(uid, ignore); if (error == SCE_KERNEL_ERROR_NO_MEMORY) { - if (timeoutPtr != 0 && Memory::Read_U32(timeoutPtr) == 0) + if (timeoutPtr != 0 && Memory::ReadOrException_U32(timeoutPtr) == 0) return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT); if (vpl) @@ -1593,8 +1591,8 @@ int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr) return hleLogError(Log::sceKernel, error, "invalid vpl"); } else { vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size(); - if (Memory::IsValidAddress(numWaitThreadsPtr)) - Memory::Write_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr); + if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr)) + Memory::WriteUnchecked_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr); bool wokeThreads = __KernelClearVplThreads(vpl, SCE_KERNEL_ERROR_WAIT_CANCEL); if (wokeThreads) @@ -1628,8 +1626,8 @@ int sceKernelReferVplStatus(SceUID uid, u32 infoPtr) { static u32 sceKernelAllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAddr) { - if (Memory::IsValidAddress(paramsAddr) && Memory::Read_U32(paramsAddr) != 4) { - ERROR_LOG_REPORT(Log::sceKernel, "sceKernelAllocMemoryBlock(%s): unsupported params size %d", pname, Memory::Read_U32(paramsAddr)); + if (Memory::IsValid4AlignedAddress(paramsAddr) && Memory::ReadUnchecked_U32(paramsAddr) != 4) { + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelAllocMemoryBlock(%s): unsupported params size %d", pname, Memory::ReadUnchecked_U32(paramsAddr)); return hleNoLog(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT); } if (type != PSP_SMEM_High && type != PSP_SMEM_Low) { @@ -1664,7 +1662,7 @@ static u32 sceKernelGetMemoryBlockAddr(u32 uid, u32 addr) { u32 error; PartitionMemoryBlock *block = kernelObjects.Get(uid, error); if (block) { - Memory::Write_U32(block->address, addr); + Memory::WriteOrException_U32(block->address, addr); return hleLogInfo(Log::sceKernel, 0, "block address: %08x", block->address); } else { return hleLogError(Log::sceKernel, 0, "failed"); @@ -1709,8 +1707,7 @@ struct NativeTlspl u32_le numWaitThreads; }; -struct TLSPL : public KernelObject -{ +struct TLSPL : public KernelObject { const char *GetName() override { return ntls.name; } const char *GetTypeName() override { return GetStaticTypeName(); } static const char *GetStaticTypeName() { return "TLS"; } @@ -1895,10 +1892,10 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block // Unless otherwise specified, we align to 4 bytes (a mips word.) u32 alignment = 4; - if (Memory::IsValidRange(optionsPtr, 4)) { + if (Memory::IsValidRange(optionsPtr, 8)) { u32 size = Memory::ReadUnchecked_U32(optionsPtr); if (size >= 8) - alignment = Memory::Read_U32(optionsPtr + 4); + alignment = Memory::ReadUnchecked_U32(optionsPtr + 4); // Note that 0 intentionally is allowed. if ((alignment & (alignment - 1)) != 0) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 06488ec44d..5a3a12a6c7 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -395,7 +395,7 @@ public: }; void AfterModuleEntryCall::run(MipsCall &call) { - Memory::Write_U32(retValAddr, currentMIPS->r[MIPS_REG_V0]); + Memory::WriteOrException_U32(retValAddr, currentMIPS->r[MIPS_REG_V0]); } ////////////////////////////////////////////////////////////////////////// @@ -571,7 +571,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re // The low instruction will be a signed add, which means (full & 0x8000) will subtract. // We add 1 in that case so that it ends up the right value. u16 high = (full >> 16) + ((full & 0x8000) ? 1 : 0); - Memory::Write_U32((reloc.data & ~0xFFFF) | high, reloc.addr); + Memory::WriteUnchecked_U32((reloc.data & ~0xFFFF) | high, reloc.addr); currentMIPS->InvalidateICache(reloc.addr, 4); } state.lastHI16Processed = true; @@ -586,7 +586,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re WARN_LOG_REPORT(Log::Loader, "Unsupported var relocation type %d - %08x => %08x", type, exportAddress, relocAddress); } - Memory::Write_U32(relocData, relocAddress); + Memory::WriteUnchecked_U32(relocData, relocAddress); currentMIPS->InvalidateICache(relocAddress, 4); } @@ -901,8 +901,8 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; for (int i = 0; i < entry->numVars; ++i) { - u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8); - u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4); + u32 varRefsPtr = Memory::ReadUnchecked_U32(entry->varData + i * 8); + u32 nid = Memory::ReadUnchecked_U32(entry->varData + i * 8 + 4); if (!Memory::IsValidAddress(varRefsPtr)) { WARN_LOG_REPORT(Log::Loader, "Bad relocation list address for nid %08x in %s", nid, modulename); continue; @@ -1538,44 +1538,49 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load const u32 nid = residentPtr[ent->fcount + j]; const u32 exportAddr = exportPtr[ent->fcount + j]; // These can be unaligned (small varables or char arrays). + if (!Memory::IsValidAddress(exportAddr)) { + WARN_LOG(Log::Loader, "Invalid var %d, nid %08x, export address %08x", j, nid, exportAddr); + continue; + } + int size; switch (nid) { case NID_MODULE_INFO: // Points to a PspModuleInfo, often the exact one .rodata.sceModuleInfo points to. break; case NID_MODULE_START_THREAD_PARAMETER: - size = Memory::Read_U32(exportAddr); + size = Memory::ReadUnchecked_U32(exportAddr); if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(Log::Loader, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); - module->nm.module_start_thread_priority = Memory::Read_U32(exportAddr + 4); - module->nm.module_start_thread_stacksize = Memory::Read_U32(exportAddr + 8); - module->nm.module_start_thread_attr = Memory::Read_U32(exportAddr + 12); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_start_thread_parameter export: %08x", Memory::ReadUnchecked_U32(exportAddr)); + module->nm.module_start_thread_priority = Memory::ReadUnchecked_U32(exportAddr + 4); + module->nm.module_start_thread_stacksize = Memory::ReadUnchecked_U32(exportAddr + 8); + module->nm.module_start_thread_attr = Memory::ReadUnchecked_U32(exportAddr + 12); break; case NID_MODULE_STOP_THREAD_PARAMETER: - size = Memory::Read_U32(exportAddr); + size = Memory::ReadUnchecked_U32(exportAddr); if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(Log::Loader, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); - module->nm.module_stop_thread_priority = Memory::Read_U32(exportAddr + 4); - module->nm.module_stop_thread_stacksize = Memory::Read_U32(exportAddr + 8); - module->nm.module_stop_thread_attr = Memory::Read_U32(exportAddr + 12); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_stop_thread_parameter export: %08x", Memory::ReadUnchecked_U32(exportAddr)); + module->nm.module_stop_thread_priority = Memory::ReadUnchecked_U32(exportAddr + 4); + module->nm.module_stop_thread_stacksize = Memory::ReadUnchecked_U32(exportAddr + 8); + module->nm.module_stop_thread_attr = Memory::ReadUnchecked_U32(exportAddr + 12); break; case NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER: - size = Memory::Read_U32(exportAddr); + size = Memory::ReadUnchecked_U32(exportAddr); if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(Log::Loader, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); - module->nm.module_reboot_before_thread_priority = Memory::Read_U32(exportAddr + 4); - module->nm.module_reboot_before_thread_stacksize = Memory::Read_U32(exportAddr + 8); - module->nm.module_reboot_before_thread_attr = Memory::Read_U32(exportAddr + 12); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::ReadUnchecked_U32(exportAddr)); + module->nm.module_reboot_before_thread_priority = Memory::ReadUnchecked_U32(exportAddr + 4); + module->nm.module_reboot_before_thread_stacksize = Memory::ReadUnchecked_U32(exportAddr + 8); + module->nm.module_reboot_before_thread_attr = Memory::ReadUnchecked_U32(exportAddr + 12); break; case NID_MODULE_SDK_VERSION: - DEBUG_LOG(Log::Loader, "Module SDK: %08x", Memory::Read_U32(exportAddr)); - devkitVersion = Memory::Read_U32(exportAddr); + devkitVersion = Memory::ReadUnchecked_U32(exportAddr); + DEBUG_LOG(Log::Loader, "Module SDK: %08x", devkitVersion); break; default: var.nid = nid; @@ -2135,7 +2140,7 @@ u32 sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValue return hleLogWarning(Log::sceModule, error, "error %08x", error); } else if (module->isFake) { if (returnValueAddr) - Memory::Write_U32(0, returnValueAddr); + Memory::WriteOrException_U32(0, returnValueAddr); return hleLogInfo(Log::sceModule, moduleId, "Faked module"); } else if (module->nm.status == MODULE_STATUS_STARTED) { // TODO: Maybe should be SCE_KERNEL_ERROR_ALREADY_STARTED, but I get SCE_KERNEL_ERROR_ERROR. @@ -2173,7 +2178,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur if (module->isFake) { if (returnValueAddr) - Memory::Write_U32(0, returnValueAddr); + Memory::WriteOrException_U32(0, returnValueAddr); return hleLogInfo(Log::sceModule, 0, "faking"); } if (module->nm.status != MODULE_STATUS_STARTED) { @@ -2189,8 +2194,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur attr = module->nm.module_stop_thread_attr; // TODO: Need to test how this really works. Let's assume it's an override. - if (Memory::IsValidAddress(optionAddr)) - { + if (Memory::IsValidRange(optionAddr, sizeof(SceKernelSMOption))) { auto options = PSPPointer::Create(optionAddr); // TODO: Check how size handling actually works. if (options->size != 0 && options->priority != 0) @@ -2204,11 +2208,10 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur WARN_LOG_REPORT(Log::sceModule, "Stopping module with attr=%x, but options specify 0", attr); } - if (Memory::IsValidAddress(stopFunc)) - { + if (Memory::IsValid4AlignedAddress(stopFunc)) { SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, stopFunc, priority, stacksize, attr, 0, (module->nm.attribute & 0x1000) != 0); _dbg_assert_(threadID > 0); - // TOOD: Check the return value and bail? + // TODO: Check the return value and bail? __KernelStartThreadValidate(threadID, argSize, argAddr); __KernelSetThreadRA(threadID, NID_MODULERETURN); __KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "stopped module"); @@ -2216,14 +2219,10 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur const ModuleWaitingThread mwt = {__KernelGetCurThread(), returnValueAddr}; module->nm.status = MODULE_STATUS_STOPPING; module->waitingThreads.push_back(mwt); - } - else if (stopFunc == 0) - { + } else if (stopFunc == 0) { module->nm.status = MODULE_STATUS_STOPPED; return hleLogInfo(Log::sceModule, 0, "no stop func, skipping"); - } - else - { + } else { module->nm.status = MODULE_STATUS_STOPPED; return hleLogError(Log::sceModule, 0, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address", moduleId, argSize, argAddr, returnValueAddr, optionAddr); } @@ -2292,7 +2291,7 @@ u32 __KernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u if (Memory::IsValidAddress(stopFunc)) { SceUID threadID = __KernelCreateThread(module->nm.name, moduleID, stopFunc, priority, stacksize, attr, 0, (module->nm.attribute & 0x1000) != 0); _dbg_assert_(threadID > 0); - // TOOD: Check the return value and bail? + // TODO: Check the return value and bail? __KernelStartThreadValidate(threadID, argSize, argp); __KernelSetThreadRA(threadID, NID_MODULERETURN); __KernelWaitCurThread(WAITTYPE_MODULE, moduleID, 1, 0, false, "unloadstopped module"); @@ -2375,7 +2374,7 @@ void __KernelReturnFromModuleFunc() { hleCall(ThreadManForKernel, int, sceKernelTerminateDeleteThread, it->threadID); } else { if (it->statusPtr != 0) - Memory::Write_U32(exitStatus, it->statusPtr); + Memory::WriteOrException_U32(exitStatus, it->statusPtr); __KernelResumeThreadFromWait(it->threadID, module->nm.status == MODULE_STATUS_STARTED ? leftModuleID : 0); } } @@ -2641,14 +2640,14 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 PSPModule *module = kernelObjects.Get(moduleId, error); if (!module->isFake || liedAboutThisModule(module)) { if (resultBufferOffset < resultBufferSize) { - Memory::Write_U32(module->GetUID(), resultBuffer + resultBufferOffset); + Memory::WriteOrException_U32(module->GetUID(), resultBuffer + resultBufferOffset); resultBufferOffset += 4; } idCount++; } // Actually, should we return fake modules too? They wouldn't be fake on the real hardware. Not like any games use this function though. } - Memory::Write_U32(idCount, idCountAddr); + Memory::WriteOrException_U32(idCount, idCountAddr); return hleNoLog(0); } diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index 9860d11372..c78f4fa341 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -85,7 +85,7 @@ struct MsgPipeWaitingThread { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(waitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } } } @@ -315,12 +315,11 @@ static void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate) HLEKernel::WaitExecTimeout(threadID); } -// Assumes timeout is valid or 0. static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) { if (timeoutPtr == 0 || waitTimer == -1) return true; - int micro = (int)Memory::ReadUnchecked_U32(timeoutPtr); + int micro = (int)Memory::ReadOrException_U32(timeoutPtr); if (micro <= 2) { // Don't wait or reschedule, just timeout immediately. return false; @@ -369,8 +368,8 @@ static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int wa if (poll) { // Generally, result is not updated in this case. But for a 0 size buffer in ASAP mode, it is. - if (Memory::IsValidAddress(resultAddr) && waitMode == SCE_KERNEL_MPW_ASAP) - Memory::Write_U32(curSendAddr - sendBufAddr, resultAddr); + if (Memory::IsValid4AlignedAddress(resultAddr) && waitMode == SCE_KERNEL_MPW_ASAP) + Memory::WriteUnchecked_U32(curSendAddr - sendBufAddr, resultAddr); return SCE_KERNEL_ERROR_MPP_FULL; } else @@ -424,8 +423,8 @@ static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int wa } // We didn't wait, so update the number of bytes transferred now. - if (Memory::IsValidAddress(resultAddr)) - Memory::Write_U32(curSendAddr - sendBufAddr, resultAddr); + if (Memory::IsValid4AlignedAddress(resultAddr)) + Memory::WriteUnchecked_U32(curSendAddr - sendBufAddr, resultAddr); return 0; } @@ -469,8 +468,8 @@ static int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSiz if (poll) { // Generally, result is not updated in this case. But for a 0 size buffer in ASAP mode, it is. - if (Memory::IsValidAddress(resultAddr) && waitMode == SCE_KERNEL_MPW_ASAP) - Memory::Write_U32(curReceiveAddr - receiveBufAddr, resultAddr); + if (Memory::IsValid4AlignedAddress(resultAddr) && waitMode == SCE_KERNEL_MPW_ASAP) + Memory::WriteUnchecked_U32(curReceiveAddr - receiveBufAddr, resultAddr); return SCE_KERNEL_ERROR_MPP_EMPTY; } else @@ -520,8 +519,8 @@ static int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSiz } } - if (Memory::IsValidAddress(resultAddr)) - Memory::Write_U32(curReceiveAddr - receiveBufAddr, resultAddr); + if (Memory::IsValid4AlignedAddress(resultAddr)) + Memory::WriteUnchecked_U32(curReceiveAddr - receiveBufAddr, resultAddr); return 0; } @@ -708,11 +707,12 @@ int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, DEBUG_LOG(Log::sceKernel, "%d=sceKernelCreateMsgPipe(%s, part=%d, attr=%08x, size=%d, opt=%08x)", id, name, partition, attr, size, optionsPtr); - if (optionsPtr != 0) - { - u32 optionsSize = Memory::Read_U32(optionsPtr); - if (optionsSize > 4) - WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMsgPipe(%s) unsupported options parameter, size = %d", name, optionsSize); + if (optionsPtr != 0) { + if (Memory::IsValid4AlignedAddress(optionsPtr)) { + u32 optionsSize = Memory::ReadUnchecked_U32(optionsPtr); + if (optionsSize > 4) + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMsgPipe(%s) unsupported options parameter, size = %d", name, optionsSize); + } } return hleNoLog(id); @@ -778,7 +778,6 @@ static int __KernelValidateSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize return 0; } -// Assumes timeoutPtr is valid or 0. static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll) { hleEatCycles(2400); @@ -808,9 +807,6 @@ int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode if (!m) { return hleLogError(Log::sceKernel, error, "bad msgpipe id"); } - if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { - return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad timeout address"); - } int result = __KernelSendMsgPipe(m, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr, false, false); return hleLogDebug(Log::sceKernel, result); @@ -825,9 +821,6 @@ int sceKernelSendMsgPipeCB(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMo if (!m) { return hleLogError(Log::sceKernel, error, "bad msgpipe id"); } - if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { - return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad timeout address"); - } // TODO: Verify callback behavior. hleCheckCurrentCallbacks(); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 92b986d545..b61306e454 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -263,7 +263,7 @@ static bool __KernelUnlockMutexForThread(PSPMutex *mutex, SceUID threadID, u32 & { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, result); @@ -498,8 +498,8 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) { // Remove threads no longer waiting on this first (so the numWaitThreads value is correct.) HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, uid, mutex->waitingThreads); - if (Memory::IsValidAddress(numWaitThreadsPtr)) - Memory::Write_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr); + if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr)) + Memory::WriteUnchecked_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr); bool wokeThreads = false; for (auto iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) @@ -531,13 +531,6 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) { 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(id, error); @@ -564,13 +557,6 @@ int sceKernelLockMutex(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(id, error); @@ -730,8 +716,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, return false; // If result is an error code, we're just letting it go. - if (result == 0) - { + if (result == 0) { workarea->lockLevel = (int) __KernelGetWaitValue(threadID, error); workarea->lockThread = threadID; } @@ -740,7 +725,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, if (timeoutPtr != 0 && lwMutexWaitTimer != -1) { // Remove any event for this thread. s64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, result); @@ -938,13 +923,6 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) { 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::Create(workareaPtr); hleEatCycles(48); @@ -976,13 +954,6 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { 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::Create(workareaPtr); hleEatCycles(48); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 47fc250360..a04740f11d 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -132,7 +132,7 @@ static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &e s64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID); if (cyclesLeft < 0) cyclesLeft = 0; - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, result); @@ -184,7 +184,7 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) s->ns.numWaitThreads = (int) s->waitingThreads.size(); if (Memory::IsValidAddress(numWaitThreadsPtr)) - Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr); + Memory::WriteOrException_U32(s->ns.numWaitThreads, numWaitThreadsPtr); if (newCount < 0) s->ns.currentCount = s->ns.initCount; @@ -329,12 +329,11 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) { } } -// Assumes timeoutPtr is zero or valid. static void __KernelSetSemaTimeout(PSPSemaphore *s, u32 timeoutPtr) { if (timeoutPtr == 0 || semaWaitTimer == -1) return; - int micro = (int) Memory::ReadUnchecked_U32(timeoutPtr); + int micro = (int)Memory::ReadOrException_U32(timeoutPtr); // This happens to be how the hardware seems to time things. if (micro <= 3) @@ -346,7 +345,6 @@ static void __KernelSetSemaTimeout(PSPSemaphore *s, u32 timeoutPtr) { CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); } -// Assumes timeoutPtr is zero or valid. static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCallbacks) { hleEatCycles(900); @@ -381,10 +379,6 @@ static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool pro } int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { - if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { - return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_BAD_ARGUMENT, "invalid timeout pointer"); // untested - } - int result = __KernelWaitSema(id, wantedCount, timeoutPtr, false); if (id == 0 && result == SCE_KERNEL_ERROR_UNKNOWN_SEMID) { @@ -396,10 +390,6 @@ int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { } int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { - if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { - return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_BAD_ARGUMENT, "invalid timeout pointer"); // untested - } - int result = __KernelWaitSema(id, wantedCount, timeoutPtr, true); if (id == 0 && result == SCE_KERNEL_ERROR_UNKNOWN_SEMID) { diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 451201401c..eb02c25878 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -382,13 +382,13 @@ bool PSPThread::FillStack() { context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; u32 k0 = context.r[MIPS_REG_K0]; Memory::Memset(k0, 0, 0x100, "ThreadK0"); - Memory::Write_U32(GetUID(), k0 + 0xc0); - Memory::Write_U32(nt.initialStack, k0 + 0xc8); - Memory::Write_U32(0xffffffff, k0 + 0xf8); - Memory::Write_U32(0xffffffff, k0 + 0xfc); + Memory::WriteOrException_U32(GetUID(), k0 + 0xc0); + Memory::WriteOrException_U32(nt.initialStack, k0 + 0xc8); + Memory::WriteOrException_U32(0xffffffff, k0 + 0xf8); + Memory::WriteOrException_U32(0xffffffff, k0 + 0xfc); // After k0 comes the arguments, which is done by sceKernelStartThread(). - Memory::Write_U32(GetUID(), nt.initialStack); + Memory::WriteOrException_U32(GetUID(), nt.initialStack); return true; } @@ -418,7 +418,7 @@ bool PSPThread::PushExtendedStack(u32 size) { // We still drop the threadID at the bottom and fill it, but there's no k0. Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack"); - Memory::Write_U32(GetUID(), nt.initialStack); + Memory::WriteOrException_U32(GetUID(), nt.initialStack); return true; } @@ -715,7 +715,7 @@ static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error); s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThreadID); if (timeoutPtr != 0) - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); s32 exitStatus = t->nt.exitStatus; __KernelResumeThreadFromWait(waitingThreadID, exitStatus); return true; @@ -1327,7 +1327,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i } if (Memory::IsValidAddress(idCountPtr)) { - Memory::Write_U32(total, idCountPtr); + Memory::WriteOrException_U32(total, idCountPtr); } return total > readBufSize ? readBufSize : total; } @@ -1420,8 +1420,9 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time thread->waitInfo.waitValue = waitValue; thread->waitInfo.timeoutPtr = timeoutPtr; - if (!reason) + if (!reason) { reason = "started wait"; + } hleReSchedule(processCallbacks, reason); } @@ -1513,7 +1514,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) { s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThread); if (timeoutPtr != 0) - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); HLEKernel::ResumeFromWait(waitingThread, WAITTYPE_THREADEND, threadID, exitStatus); } @@ -1956,8 +1957,8 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo // At the bottom of those 64 bytes, the return syscall and ra is written. // Test Drive Unlimited actually depends on it being in the correct place. WriteHLESyscall("FakeSysCalls", NID_THREADRETURN, sp); - Memory::Write_U32(MIPS_MAKE_B(-1), sp + 8); - Memory::Write_U32(MIPS_MAKE_NOP(), sp + 12); + Memory::WriteOrException_U32(MIPS_MAKE_B(-1), sp + 8); + Memory::WriteOrException_U32(MIPS_MAKE_NOP(), sp + 12); // Point ra at our return stub, and start fp off matching sp. startThread->context.r[MIPS_REG_RA] = sp; @@ -2014,7 +2015,6 @@ int __KernelStartThreadValidate(SceUID threadToStartID, int argSize, u32 argBloc return __KernelStartThread(threadToStartID, argSize, argBlockPtr, forceArgs); } -// int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock) int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr) { int retval = __KernelStartThreadValidate(threadToStartID, argSize, argBlockPtr); return hleLogDebugOrError(Log::sceKernel, retval); @@ -2032,13 +2032,17 @@ int sceKernelGetThreadStackFreeSize(SceUID threadID) { // Scan the stack for 0xFF, starting after 0x10 (the thread id is written there.) // Obviously this doesn't work great if PSP_THREAD_ATTR_NO_FILLSTACK is used. - int sz = 0; - for (u32 offset = 0x10; offset < thread->nt.stackSize; ++offset) { - if (Memory::Read_U8(thread->currentStack.start + offset) != 0xFF) - break; - sz++; - } + int sz = 0; + if (Memory::IsValidRange(thread->currentStack.start + 0x10, thread->nt.stackSize - 0x10)) { + for (u32 offset = 0x10; offset < thread->nt.stackSize; ++offset) { + if (Memory::ReadUnchecked_U8(thread->currentStack.start + offset) != 0xFF) + break; + sz++; + } + } else { + // Probably should do something here. + } return hleLogDebug(Log::sceKernel, sz & ~3); } @@ -2608,7 +2612,7 @@ int sceKernelReleaseWaitThread(SceUID threadID) { return hleLogError(Log::sceKernel, error, "bad thread ID"); } else { if (!t->isWaiting()) { - return hleLogInfo(Log::sceKernel, SCE_KERNEL_ERROR_NOT_WAIT); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_NOT_WAIT); } if (t->nt.waitType == WAITTYPE_HLEDELAY) { WARN_LOG_REPORT_ONCE(rwt_delay, Log::sceKernel, "sceKernelReleaseWaitThread(): Refusing to wake HLE-delayed thread, right thing to do?"); @@ -2789,9 +2793,9 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) { // The stack has been changed now, so it's do or die time. // Push the old SP, RA, and PC onto the stack (so we can restore them later.) - Memory::Write_U32(currentMIPS->r[MIPS_REG_RA], thread->currentStack.end - 4); - Memory::Write_U32(currentMIPS->r[MIPS_REG_SP], thread->currentStack.end - 8); - Memory::Write_U32(currentMIPS->pc, thread->currentStack.end - 12); + Memory::WriteOrException_U32(currentMIPS->r[MIPS_REG_RA], thread->currentStack.end - 4); + Memory::WriteOrException_U32(currentMIPS->r[MIPS_REG_SP], thread->currentStack.end - 8); + Memory::WriteOrException_U32(currentMIPS->pc, thread->currentStack.end - 12); KernelValidateThreadTarget(entryAddr); @@ -3113,11 +3117,11 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter) // Let's just save regs generously. Better to be safe. sp -= 32 * 4; for (int i = MIPS_REG_A0; i <= MIPS_REG_T7; ++i) { - Memory::Write_U32(currentMIPS->r[i], sp + i * 4); + Memory::WriteOrException_U32(currentMIPS->r[i], sp + i * 4); } - Memory::Write_U32(currentMIPS->r[MIPS_REG_T8], sp + MIPS_REG_T8 * 4); - Memory::Write_U32(currentMIPS->r[MIPS_REG_T9], sp + MIPS_REG_T9 * 4); - Memory::Write_U32(currentMIPS->r[MIPS_REG_RA], sp + MIPS_REG_RA * 4); + Memory::WriteOrException_U32(currentMIPS->r[MIPS_REG_T8], sp + MIPS_REG_T8 * 4); + Memory::WriteOrException_U32(currentMIPS->r[MIPS_REG_T9], sp + MIPS_REG_T9 * 4); + Memory::WriteOrException_U32(currentMIPS->r[MIPS_REG_RA], sp + MIPS_REG_RA * 4); // Save the few regs that need saving call->savedPc = currentMIPS->pc; diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index fb801eb0dc..4e344f63d8 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -69,8 +69,9 @@ void __KernelTimeDoState(PointerWrap &p) int sceKernelGetSystemTime(u32 sysclockPtr) { u64 t = CoreTiming::GetGlobalTimeUs(); - if (Memory::IsValidAddress(sysclockPtr)) - Memory::Write_U64(t, sysclockPtr); + if (Memory::IsValid4AlignedRange(sysclockPtr, 8)) { + Memory::WriteUnchecked_U64(t, sysclockPtr); + } VERBOSE_LOG(Log::sceKernel, "sceKernelGetSystemTime(out:%16llx)", t); hleEatCycles(265); hleReSchedule("system time"); @@ -83,8 +84,9 @@ u32 sceKernelGetSystemTimeLow() u64 t = CoreTiming::GetGlobalTimeUs(); VERBOSE_LOG(Log::sceKernel,"%08x=sceKernelGetSystemTimeLow()",(u32)t); hleEatCycles(165); - if (PSP_CoreParameter().compat.flags().KernelGetSystemTimeLowEatMoreCycles) + if (PSP_CoreParameter().compat.flags().KernelGetSystemTimeLowEatMoreCycles) { hleEatCycles(70000); + } hleReSchedule("system time"); return hleNoLog((u32)t); } @@ -101,8 +103,9 @@ u64 sceKernelGetSystemTimeWide() int sceKernelUSec2SysClock(u32 usec, u32 clockPtr) { VERBOSE_LOG(Log::sceKernel, "sceKernelUSec2SysClock(%i, %08x)", usec, clockPtr); - if (Memory::IsValidAddress(clockPtr)) - Memory::Write_U64((usec & 0xFFFFFFFFL), clockPtr); + if (Memory::IsValid4AlignedRange(clockPtr, 8)) { + Memory::WriteUnchecked_U64((usec & 0xFFFFFFFFL), clockPtr); + } hleEatCycles(165); return hleNoLog(0); } diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 7544876ab9..1651182bd0 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -148,9 +148,10 @@ public: // Reserve some stack space for arguments. u32 argArea = currentMIPS->r[MIPS_REG_SP]; currentMIPS->r[MIPS_REG_SP] -= HANDLER_STACK_SPACE; - - Memory::Write_U64(vtimer->nvt.schedule, argArea - 16); - Memory::Write_U64(__getVTimerCurrentTime(vtimer), argArea - 8); + if (Memory::IsValidRange(argArea - HANDLER_STACK_SPACE, HANDLER_STACK_SPACE)) { + Memory::WriteUnchecked_U64(vtimer->nvt.schedule, argArea - 16); + Memory::WriteUnchecked_U64(__getVTimerCurrentTime(vtimer), argArea - 8); + } currentMIPS->pc = vtimer->nvt.handlerAddr; currentMIPS->r[MIPS_REG_A0] = vtimer->GetUID(); @@ -228,8 +229,8 @@ u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { strncpy(vtimer->nvt.name, name, KERNELOBJECT_MAX_NAME_LENGTH); vtimer->nvt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - if (optParamAddr != 0 && Memory::IsValid4AlignedAddress(optParamAddr)) { - u32 size = Memory::ReadUnchecked_U32(optParamAddr); + if (optParamAddr != 0) { + u32 size = Memory::ReadOrException_U32(optParamAddr); if (size > 4) WARN_LOG_REPORT_ONCE(vtimeropt, Log::sceKernel, "sceKernelCreateVTimer(%s) unsupported options parameter, size = %d", name, size); } @@ -261,8 +262,9 @@ u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) { return hleLogError(Log::sceKernel, error, "bad timer ID"); } - if (Memory::IsValidAddress(baseClockAddr)) - Memory::Write_U64(vt->nvt.base, baseClockAddr); + if (Memory::IsValid4AlignedRange(baseClockAddr, 8)) { + Memory::WriteUnchecked_U64(vt->nvt.base, baseClockAddr); + } return hleLogDebug(Log::sceKernel, 0); } @@ -285,9 +287,9 @@ u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr) { } u64 time = __getVTimerCurrentTime(vt); - if (Memory::IsValidAddress(timeClockAddr)) - Memory::Write_U64(time, timeClockAddr); - + if (Memory::IsValid4AlignedRange(timeClockAddr, 8)) { + Memory::WriteUnchecked_U64(time, timeClockAddr); + } return hleLogDebug(Log::sceKernel, 0); } @@ -320,9 +322,9 @@ u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) { return hleLogError(Log::sceKernel, error, "bad timer ID"); } - if (Memory::IsValidAddress(timeClockAddr)) { - u64 time = Memory::Read_U64(timeClockAddr); - Memory::Write_U64(__KernelSetVTimer(vt, time), timeClockAddr); + if (Memory::IsValid4AlignedRange(timeClockAddr, 8)) { + u64 time = Memory::ReadUnchecked_U64(timeClockAddr); + Memory::WriteUnchecked_U64(__KernelSetVTimer(vt, time), timeClockAddr); } else { _dbg_assert_(false); } diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index e23d987b0b..7f6195b240 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -739,8 +739,8 @@ static u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumed int outBytes = outSamples * sizeof(int16_t) * 2; NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outBytes, "Mp3LowLevelDecode"); - Memory::Write_U32(inbytesConsumed, sourceBytesConsumedAddr); - Memory::Write_U32(outBytes, sampleBytesAddr); + Memory::WriteOrException_U32(inbytesConsumed, sourceBytesConsumedAddr); + Memory::WriteOrException_U32(outBytes, sampleBytesAddr); return hleLogDebug(Log::ME, 0); } diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index cfe367ddbb..fc45897771 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -509,15 +509,15 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr // Generate, and write mpeg handle into mpeg data, for some reason int mpegHandle = dataPtr + 0x30; - Memory::Write_U32(mpegHandle, mpegAddr); + Memory::WriteUnchecked_U32(mpegHandle, mpegAddr); // Initialize fake mpeg struct. Memory::Memcpy(mpegHandle, "LIBMPEG\0", 8, "Mpeg"); Memory::Memcpy(mpegHandle + 8, "001\0", 4, "Mpeg"); - Memory::Write_U32(-1, mpegHandle + 12); + Memory::WriteUnchecked_U32(-1, mpegHandle + 12); if (ringbuffer.IsValid()) { - Memory::Write_U32(ringbufferAddr, mpegHandle + 16); - Memory::Write_U32(ringbuffer->dataUpperBound, mpegHandle + 20); + Memory::WriteUnchecked_U32(ringbufferAddr, mpegHandle + 16); + Memory::WriteUnchecked_U32(ringbuffer->dataUpperBound, mpegHandle + 20); } MpegContext *ctx = new MpegContext(); if (g_mpegCtxs.find(mpegHandle) != g_mpegCtxs.end()) { @@ -1158,11 +1158,11 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr if (mpegLibVersion >= 0x0105 && mpegLibVersion < 0x010a) { //Killzone - Liberation expect , issue #16727 - Memory::Write_U32(1, initAddr); + Memory::WriteOrException_U32(1, initAddr); } else { // Save the current frame's status to initAddr - Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr); + Memory::WriteOrException_U32(ctx->avc.avcFrameStatus, initAddr); } ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; @@ -1186,7 +1186,7 @@ static u32 sceMpegAvcDecodeStop(u32 mpeg, u32 frameWidth, u32 bufferAddr, u32 st } // No last frame generated - Memory::Write_U32(0, statusAddr); + Memory::WriteOrException_U32(0, statusAddr); return hleLogDebug(Log::Mpeg, 0); } @@ -1225,7 +1225,7 @@ static u32 sceMpegUnRegistStream(u32 mpeg, int streamUid) { } static int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr) { - if (!Memory::IsValidAddress(detailAddr)) { + if (!Memory::IsValidRange(detailAddr, 36)) { return hleLogError(Log::Mpeg, -1, "invalid addresses"); } @@ -1234,15 +1234,15 @@ static int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr) { return hleLogWarning(Log::Mpeg, -1, "bad mpeg handle"); } - Memory::Write_U32(ctx->avc.avcDecodeResult, detailAddr + 0); - Memory::Write_U32(ctx->videoFrameCount, detailAddr + 4); - Memory::Write_U32(ctx->avc.avcDetailFrameWidth, detailAddr + 8); - Memory::Write_U32(ctx->avc.avcDetailFrameHeight, detailAddr + 12); - Memory::Write_U32(0, detailAddr + 16); - Memory::Write_U32(0, detailAddr + 20); - Memory::Write_U32(0, detailAddr + 24); - Memory::Write_U32(0, detailAddr + 28); - Memory::Write_U32(ctx->avc.avcFrameStatus, detailAddr + 32); + Memory::WriteUnchecked_U32(ctx->avc.avcDecodeResult, detailAddr + 0); + Memory::WriteUnchecked_U32(ctx->videoFrameCount, detailAddr + 4); + Memory::WriteUnchecked_U32(ctx->avc.avcDetailFrameWidth, detailAddr + 8); + Memory::WriteUnchecked_U32(ctx->avc.avcDetailFrameHeight, detailAddr + 12); + Memory::WriteUnchecked_U32(0, detailAddr + 16); + Memory::WriteUnchecked_U32(0, detailAddr + 20); + Memory::WriteUnchecked_U32(0, detailAddr + 24); + Memory::WriteUnchecked_U32(0, detailAddr + 28); + Memory::WriteUnchecked_U32(ctx->avc.avcFrameStatus, detailAddr + 32); return hleLogDebug(Log::Mpeg, 0); } @@ -1378,7 +1378,7 @@ static int sceMpegInitAu(u32 mpeg, u32 bufferAddr, u32 auPointer) { } static int sceMpegQueryAtracEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { - if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) { + if (!Memory::IsValid4AlignedAddress(esSizeAddr) || !Memory::IsValid4AlignedAddress(outSizeAddr)) { return hleLogError(Log::Mpeg, -1, "invalid addresses"); } @@ -1387,8 +1387,8 @@ static int sceMpegQueryAtracEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { return hleLogWarning(Log::Mpeg, -1, "bad mpeg handle"); } - Memory::Write_U32(MPEG_ATRAC_ES_SIZE, esSizeAddr); - Memory::Write_U32(MPEG_ATRAC_ES_OUTPUT_SIZE, outSizeAddr); + Memory::WriteUnchecked_U32(MPEG_ATRAC_ES_SIZE, esSizeAddr); + Memory::WriteUnchecked_U32(MPEG_ATRAC_ES_OUTPUT_SIZE, outSizeAddr); return hleLogDebug(Log::Mpeg, 0); } @@ -1611,8 +1611,8 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) avcAu.dts = avcAu.pts - videoTimestampStep; avcAu.esBuffer = streamInfo->second.num; avcAu.write(auAddr); - if (Memory::IsValidAddress(attrAddr)) { - Memory::Write_U32(1, attrAddr); + if (Memory::IsValid4AlignedAddress(attrAddr)) { + Memory::WriteUnchecked_U32(1, attrAddr); } return hleDelayResult(hleLogDebug(Log::Mpeg, 0), "mpeg get avc ignore", 100); } @@ -1651,7 +1651,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) if (result == 0) { // Jeanne d'Arc return 00000000 as attrAddr here and cause WriteMemoryOrRaiseException error if (Memory::IsValidAddress(attrAddr)) { - Memory::Write_U32(1, attrAddr); + Memory::WriteOrException_U32(1, attrAddr); } } @@ -1710,8 +1710,8 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) atracAu.dts = atracAu.pts; atracAu.esBuffer = streamInfo->second.num; atracAu.write(auAddr); - if (Memory::IsValidAddress(attrAddr)) { - Memory::Write_U32(0, attrAddr); + if (Memory::IsValid4AlignedAddress(attrAddr)) { + Memory::WriteUnchecked_U32(0, attrAddr); } return hleDelayResult(hleLogDebug(Log::Mpeg, 0), "mpeg get atrac ignore", 100); } @@ -1750,8 +1750,8 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) if (result == 0) { // 3rd birthday return 00000000 as attrAddr here and cause WriteMemoryOrRaiseException error - if (Memory::IsValidAddress(attrAddr)) { - Memory::Write_U32(0, attrAddr); + if (Memory::IsValid4AlignedAddress(attrAddr)) { + Memory::WriteUnchecked_U32(0, attrAddr); } } @@ -1761,7 +1761,7 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) static int sceMpegQueryPcmEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { - if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) { + if (!Memory::IsValid4AlignedAddress(esSizeAddr) || !Memory::IsValid4AlignedAddress(outSizeAddr)) { return hleLogError(Log::Mpeg, -1, "invalid addresses"); } @@ -1770,8 +1770,8 @@ static int sceMpegQueryPcmEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) return hleLogWarning(Log::Mpeg, -1, "bad mpeg handle"); } - Memory::Write_U32(MPEG_PCM_ES_SIZE, esSizeAddr); - Memory::Write_U32(MPEG_PCM_ES_OUTPUT_SIZE, outSizeAddr); + Memory::WriteUnchecked_U32(MPEG_PCM_ES_SIZE, esSizeAddr); + Memory::WriteUnchecked_U32(MPEG_PCM_ES_OUTPUT_SIZE, outSizeAddr); return hleLogError(Log::Mpeg, 0, "UNIMPL"); } diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index d54520b499..11b9ed20af 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -1521,7 +1521,7 @@ static int sceNetApctlGetState(u32 pStateAddr) { // Valid Arguments if (Memory::IsValidAddress(pStateAddr)) { // Return Thread Status - Memory::Write_U32(NetApctl_GetState(), pStateAddr); + Memory::WriteOrException_U32(NetApctl_GetState(), pStateAddr); // Return Success return hleLogDebug(Log::sceNet, 0); } @@ -1557,7 +1557,7 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { int size = Memory::ReadUnchecked_U32(sizeAddr); // Return size required - Memory::Write_U32(entries * userInfoSize, sizeAddr); + Memory::WriteUnchecked_U32(entries * userInfoSize, sizeAddr); if (bufAddr != 0 && Memory::IsValidAddress(sizeAddr)) { int offset = 0; @@ -1570,16 +1570,16 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { DEBUG_LOG(Log::sceNet, "%s writing ID#%d to %08x", __FUNCTION__, i, bufAddr + offset); // Pointer to next Network structure in list - Memory::Write_U32((i + 1) * userInfoSize + bufAddr, bufAddr + offset); + Memory::WriteUnchecked_U32((i + 1) * userInfoSize + bufAddr, bufAddr + offset); offset += 4; // Entry ID - Memory::Write_U32(i, bufAddr + offset); + Memory::WriteUnchecked_U32(i, bufAddr + offset); offset += 4; } // Fix the last Pointer if (offset > 0) - Memory::Write_U32(0, bufAddr + offset - userInfoSize); + Memory::WriteUnchecked_U32(0, bufAddr + offset - userInfoSize); } return hleLogInfo(Log::sceNet, 0); @@ -1621,33 +1621,33 @@ int NetApctl_GetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) { case PSP_NET_APCTL_DESC_SSID_NAME_LENGTH: // Return one 32-bit value if (entryId == 0) - Memory::Write_U32(netApctlInfo.ssidLength, resultAddr); + Memory::WriteUnchecked_U32(netApctlInfo.ssidLength, resultAddr); else { // Calculate the SSID length - Memory::Write_U32((u32)strlen(dummySSID), resultAddr); + Memory::WriteUnchecked_U32((u32)strlen(dummySSID), resultAddr); } break; case PSP_NET_APCTL_DESC_CHANNEL: // FIXME: Return one 1 byte value or may be 32-bit if this is not a channel? if (entryId == 0) - Memory::Write_U8(netApctlInfo.channel, resultAddr); + Memory::WriteUnchecked_U8(netApctlInfo.channel, resultAddr); else { // Generate channel for testing purposes, not even sure whether this is channel or not, MGS:PW seems to treat the data as u8 - Memory::Write_U8(entryId, resultAddr); + Memory::WriteUnchecked_U8(entryId, resultAddr); } break; case PSP_NET_APCTL_DESC_SIGNAL_STRENGTH: // Return 1 byte if (entryId == 0) - Memory::Write_U8(netApctlInfo.strength, resultAddr); + Memory::WriteUnchecked_U8(netApctlInfo.strength, resultAddr); else { // Randomize signal strength between 1%~99% since games like MGS:PW are using signal strength to determine the strength of the recruit - Memory::Write_U8((int)(((float)rand() / (float)RAND_MAX) * 99.0 + 1.0), resultAddr); + Memory::WriteUnchecked_U8((int)(((float)rand() / (float)RAND_MAX) * 99.0 + 1.0), resultAddr); } break; case PSP_NET_APCTL_DESC_SECURITY: // Return one 32-bit value - Memory::Write_U32(netApctlInfo.securityType, resultAddr); + Memory::WriteUnchecked_U32(netApctlInfo.securityType, resultAddr); break; default: return hleLogError(Log::sceNet, SCE_NET_APCTL_ERROR_INVALID_CODE, "unknown info id"); @@ -1762,8 +1762,8 @@ static int sceNetUpnpGetNatInfo() { } static int sceNetGetDropRate(u32 dropRateAddr, u32 dropDurationAddr) { - Memory::Write_U32(netDropRate, dropRateAddr); - Memory::Write_U32(netDropDuration, dropDurationAddr); + Memory::WriteOrException_U32(netDropRate, dropRateAddr); + Memory::WriteOrException_U32(netDropDuration, dropDurationAddr); return hleLogInfo(Log::sceNet, 0); } diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 2cb4264d06..ddef583492 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -2023,7 +2023,7 @@ int sceNetAdhocctlGetState(u32 ptrToStatus) { int state = NetAdhocctl_GetState(); // Output Adhocctl State - Memory::Write_U32(state, ptrToStatus); + Memory::WriteOrException_U32(state, ptrToStatus); // Return Success return hleLogVerbose(Log::sceNet, 0, "state = %d", state); @@ -3208,7 +3208,7 @@ int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { buf = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointer(bufAddr); } - INFO_LOG(Log::sceNet, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, Memory::ReadUnchecked_U32(sizeAddr), bufAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return hleLogWarning(Log::sceNet, 0, "WLAN off"); } @@ -5788,7 +5788,7 @@ int sceNetAdhocGetSocketAlert(int id, u32 flagPtr) { return hleLogDebug(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID, "invalid socket id"); s32_le flg = adhocSockets[id - 1]->flags; - Memory::Write_U32(flg, flagPtr); + Memory::WriteOrException_U32(flg, flagPtr); return hleLogDebug(Log::sceNet, 0, "flags = %08x", flg); } @@ -5960,11 +5960,15 @@ static int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) { static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { s32_le *buflen = NULL; - if (Memory::IsValidAddress(sizeAddr)) buflen = (s32_le *)Memory::GetPointer(sizeAddr); + if (Memory::IsValidAddress(sizeAddr)) { + buflen = (s32_le *)Memory::GetPointer(sizeAddr); + } SceNetAdhocctlPeerInfoEmu *buf = NULL; - if (Memory::IsValidAddress(bufAddr)) buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointer(bufAddr); + if (Memory::IsValidAddress(bufAddr)) { + buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointer(bufAddr); + } - DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, /*buflen ? *buflen : -1*/Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, /*buflen ? *buflen : -1*/Memory::ReadUnchecked_U32(sizeAddr), bufAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return hleLogError(Log::sceNet, -1, "WLAN off"); } @@ -6205,13 +6209,14 @@ int sceNetAdhocDiscoverInitStart(u32 paramAddr) { // TODO: Allocate internal buffer/struct (on the stack?) to be returned on sceNetAdhocDiscoverUpdate (the struct may contains WLAN channel from sceUtilityGetSystemParamInt at offset 0xA0 ?), setup adhocctl state callback handler to detects state change (using sceNetAdhocctl_lib_F8BABD85(stateCallbackFunction=0x09F436F8, adhocctlStateCallbackArg=0x0) on JPCSP+prx) u32 bufSize = 256; // dummy size, not sure how large it supposed to be, may be at least 0x3c bytes like in param->unknown2 ? if (netAdhocDiscoverBufAddr == 0) { - netAdhocDiscoverBufAddr = userMemory.Alloc(bufSize, true, "AdhocDiscover"); // The address returned on DiscoverUpdate seems to be much higher than the param address, closer to the internal stateCallbackFunction address - if (!Memory::IsValidAddress(netAdhocDiscoverBufAddr)) + u32 addr = userMemory.Alloc(bufSize, true, "AdhocDiscover"); // The address returned on DiscoverUpdate seems to be much higher than the param address, closer to the internal stateCallbackFunction address + if (!Memory::IsValidAddress(addr)) return 0x80410005; + netAdhocDiscoverBufAddr = addr; Memory::Memset(netAdhocDiscoverBufAddr, 0, bufSize); } // FIME: Not sure what is this address 0x000010B0 used for (current Step may be?), but return 0x80411301 if (*((int *) 0x000010B0) != 0) - //if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) != 0) //if (*((int*)Memory::GetPointer(0x000010B0)) != 0) + //if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) != 0) //if (*((int*)Memory::GetPointer(0x000010B0)) != 0) // return 0x80411301; // Already Initialized/Started? // TODO: Need to findout whether using invalid params or param address will return an error code or not netAdhocDiscoverParam = (SceNetAdhocDiscoverParam*)Memory::GetPointer(paramAddr); @@ -6231,20 +6236,20 @@ int sceNetAdhocDiscoverInitStart(u32 paramAddr) { // Offset 0xA4: Seems to be at 0x000010D4 and related to RequestSuspend // Offset 0xA8: paramAddr // This seems to be a fixed address at 0x000010D8 (ie. *((int *) 0x000010D8) = paramAddr) // The rest are zeroed - Memory::Write_U32(0x06060010, netAdhocDiscoverBufAddr + 0x60); - Memory::Write_U32(0xffffffff, netAdhocDiscoverBufAddr + 0x70); + Memory::WriteUnchecked_U32(0x06060010, netAdhocDiscoverBufAddr + 0x60); + Memory::WriteUnchecked_U32(0xffffffff, netAdhocDiscoverBufAddr + 0x70); if (netAdhocDiscoverParam->unknown1 == 0) { - Memory::Write_U32(0x0B, netAdhocDiscoverBufAddr + 0x80); - Memory::Write_U32(0x03, netAdhocDiscoverBufAddr + 0x84); + Memory::WriteUnchecked_U32(0x0B, netAdhocDiscoverBufAddr + 0x80); + Memory::WriteUnchecked_U32(0x03, netAdhocDiscoverBufAddr + 0x84); } else if (netAdhocDiscoverParam->unknown1 == 1) { - Memory::Write_U32(0x0F, netAdhocDiscoverBufAddr + 0x80); - Memory::Write_U32(0x04, netAdhocDiscoverBufAddr + 0x84); + Memory::WriteUnchecked_U32(0x0F, netAdhocDiscoverBufAddr + 0x80); + Memory::WriteUnchecked_U32(0x04, netAdhocDiscoverBufAddr + 0x84); } - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0x98); - Memory::Write_U32(g_Config.iWlanAdhocChannel, netAdhocDiscoverBufAddr + 0xA0); - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0xA4); - Memory::Write_U32(paramAddr, netAdhocDiscoverBufAddr + 0xA8); + Memory::WriteUnchecked_U32(0, netAdhocDiscoverBufAddr + 0x98); + Memory::WriteUnchecked_U32(g_Config.iWlanAdhocChannel, netAdhocDiscoverBufAddr + 0xA0); + Memory::WriteUnchecked_U32(0, netAdhocDiscoverBufAddr + 0xA4); + Memory::WriteUnchecked_U32(paramAddr, netAdhocDiscoverBufAddr + 0xA8); char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; memcpy(grpName, netAdhocDiscoverParam->groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated @@ -6268,9 +6273,11 @@ int sceNetAdhocDiscoverStop() { if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) > 0 && (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80)^0x13) > 0) { - Memory::Write_U32(Memory::Read_U32(netAdhocDiscoverBufAddr + 0x98) | 0x20, netAdhocDiscoverBufAddr + 0x98); - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0xA4); + if (Memory::IsValid4AlignedRange(netAdhocDiscoverBufAddr, 256)) { + if (Memory::ReadUnchecked_U32(netAdhocDiscoverBufAddr + 0x80) > 0 && (Memory::ReadUnchecked_U32(netAdhocDiscoverBufAddr + 0x80) ^ 0x13) > 0) { + Memory::WriteUnchecked_U32(Memory::ReadUnchecked_U32(netAdhocDiscoverBufAddr + 0x98) | 0x20, netAdhocDiscoverBufAddr + 0x98); + Memory::WriteUnchecked_U32(0, netAdhocDiscoverBufAddr + 0xA4); + } } // FIXME: Doesn't seems to be immediately changed the status, may be waiting until Disconnected from Adhocctl before changing the status to Completed? netAdhocDiscoverIsStopping = true; @@ -6281,21 +6288,21 @@ int sceNetAdhocDiscoverStop() { int sceNetAdhocDiscoverTerm() { WARN_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverTerm() at %08x", currentMIPS->pc); - /* - if (sceKernelCheckThreadStack() < 0x00000FF0) - return 0x80410005; - - if (!(Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) > 0 && (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) ^ 0x13) > 0)) - return 0x80411301; // Not Initialized/Started yet? - */ + + // if (sceKernelCheckThreadStack() < 0x00000FF0) + // return 0x80410005; + // + // if (!(Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) > 0 && (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) ^ 0x13) > 0)) + // return 0x80411301; // Not Initialized/Started yet? + // TODO: Use sceNetAdhocctl_lib_1C679240 to remove adhocctl state callback handler setup in sceNetAdhocDiscoverInitStart - /*if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x70) >= 0) { - LinkDiscoverSkip(Memory::Read_U32(netAdhocDiscoverBufAddr + 0x70)); //sceNetAdhocctl_lib_1C679240 - Memory::Write_U32(0xffffffff, netAdhocDiscoverBufAddr + 0x70); - } - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0x80); - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0xA8); - */ + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x70) >= 0) { + // LinkDiscoverSkip(Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x70)); //sceNetAdhocctl_lib_1C679240 + // Memory::WriteOrException_U32(0xffffffff, netAdhocDiscoverBufAddr + 0x70); + // } + // Memory::WriteOrException_U32(0, netAdhocDiscoverBufAddr + 0x80); + // Memory::WriteOrException_U32(0, netAdhocDiscoverBufAddr + 0xA8); + netAdhocDiscoverStatus = NET_ADHOC_DISCOVER_STATUS_NONE; //if (netAdhocDiscoverParam) netAdhocDiscoverParam->result = NET_ADHOC_DISCOVER_RESULT_NO_PEER_FOUND; // Test: Using result = NET_ADHOC_DISCOVER_RESULT_NO_PEER_FOUND will trigger Legend Of The Dragon to call sceNetAdhocctlGetPeerList after DiscoverTerm if (Memory::IsValidAddress(netAdhocDiscoverBufAddr)) { @@ -6310,14 +6317,12 @@ int sceNetAdhocDiscoverGetStatus() { DEBUG_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverGetStatus() at %08x", currentMIPS->pc); if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; - /* - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) <= 0) - return 0; - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) <= 0x13) - return 1; - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) == 0x13) - return 2; - */ + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) <= 0) + // return 0; + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) <= 0x13) + // return 1; + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) == 0x13) + // return 2; return hleLogDebug(Log::sceNet, netAdhocDiscoverStatus); // Returning 2 will trigger Legend Of The Dragon to call sceNetAdhocctlGetPeerList (only happened if it was the first sceNetAdhocDiscoverGetStatus after sceNetAdhocDiscoverInitStart) } @@ -6327,16 +6332,14 @@ int sceNetAdhocDiscoverRequestSuspend() // FIXME: Not sure what is this syscall used for, may be related to Sleep Mode and can be triggered by using Power/Hold Switch? (based on what's written on Dissidia 012) if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; - /* - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0xA4) == 0) - return 0x80411303; // Already Suspended? - if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) != 0) - return 0x80411303; // Already Suspended? - int ret = sceNetAdhocctl_lib_1572422C(); - if (ret >= 0) - Memory::Write_U32(0, netAdhocDiscoverBufAddr + 0xA4); - return ret; - */ + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0xA4) == 0) + // return 0x80411303; // Already Suspended? + // if (Memory::ReadOrException_U32(netAdhocDiscoverBufAddr + 0x80) != 0) + // return 0x80411303; // Already Suspended? + // int ret = sceNetAdhocctl_lib_1572422C(); + // if (ret >= 0) + // Memory::WriteOrException_U32(0, netAdhocDiscoverBufAddr + 0xA4); + // return ret; // Since we don't know what this supposed to do, and we currently don't have a working AdhocDiscover yet, may be we should cancel the progress for now? netAdhocDiscoverIsStopping = true; return hleLogError(Log::sceNet, 0); diff --git a/Core/HLE/sceNetAdhocMatching.cpp b/Core/HLE/sceNetAdhocMatching.cpp index 14ee4c73fc..287edf7f94 100644 --- a/Core/HLE/sceNetAdhocMatching.cpp +++ b/Core/HLE/sceNetAdhocMatching.cpp @@ -2262,7 +2262,6 @@ int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAd } static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) { - DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingGetMembers(%i, [%08x]=%i, %08x) at %08x", matchingId, sizeAddr, Memory::Read_U32(sizeAddr), buf, currentMIPS->pc); if (!g_Config.bEnableWlan) { return hleLogError(Log::sceNet, -1, "WLAN off"); } @@ -2293,10 +2292,10 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) if (!Memory::IsValidAddress(sizeAddr)) return hleLogError(Log::sceNet, SCE_NET_ADHOC_MATCHING_ERROR_INVALID_ARG, "adhocmatching invalid arg"); - int* buflen = (int*)Memory::GetPointer(sizeAddr); + int *buflen = (int*)Memory::GetPointerUnchecked(sizeAddr); SceNetAdhocMatchingMemberInfoEmu* buf2 = NULL; if (Memory::IsValidAddress(buf)) { - buf2 = (SceNetAdhocMatchingMemberInfoEmu*)Memory::GetPointer(buf); + buf2 = (SceNetAdhocMatchingMemberInfoEmu*)Memory::GetPointerUnchecked(buf); } // Number of Connected Peers, should we exclude timeout members? diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index b4547b9289..7eaf796df5 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -112,7 +112,7 @@ static int NetResolver_StartNtoA(NetResolver *resolver, u32 hostnamePtr, u32 inA } } net::DNSResolveFree(resolved); - Memory::Write_U32(addr.in.sin_addr.s_addr, inAddrPtr); + Memory::WriteOrException_U32(addr.in.sin_addr.s_addr, inAddrPtr); INFO_LOG(Log::sceNet, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), ip2str(addr.in.sin_addr, false).c_str()); } diff --git a/Core/HLE/sceNet_lib.cpp b/Core/HLE/sceNet_lib.cpp index 7ca6209001..80de698a9d 100644 --- a/Core/HLE/sceNet_lib.cpp +++ b/Core/HLE/sceNet_lib.cpp @@ -26,6 +26,8 @@ // This is one of the firmware modules (pspnet.prx), the official PSP games can't call these funcs +// Fortunately, because this is badly implemented currently. Need to go through all this and make +// it safe. // Ugh, this is ugly. u32 sceNetStrtoul(const char *str, u32 strEndAddrPtr, int base) { diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index 2db1d98efc..80e931b2dc 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -173,8 +173,8 @@ static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) INFO_LOG(Log::sceNet, "%s - Parental Control: %d", __FUNCTION__, npParentalControl); INFO_LOG(Log::sceNet, "%s - User Age: %d", __FUNCTION__, npUserAge); - Memory::Write_U32(npParentalControl, parentalControlAddr); - Memory::Write_U32(npUserAge, userAgeAddr); + Memory::WriteOrException_U32(npParentalControl, parentalControlAddr); + Memory::WriteOrException_U32(npUserAge, userAgeAddr); return hleLogWarning(Log::sceNet, 0, "UNTESTED"); } @@ -184,7 +184,7 @@ static int sceNpGetChatRestrictionFlag(u32 flagAddr) if (!Memory::IsValidAddress(flagAddr)) return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - Memory::Write_U32(npChatRestriction, flagAddr); + Memory::WriteOrException_U32(npChatRestriction, flagAddr); return hleLogWarning(Log::sceNet, 0, "Chat restriction: %d", npChatRestriction); } diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp index eca61133e7..e88b8abb40 100644 --- a/Core/HLE/sceNp2.cpp +++ b/Core/HLE/sceNp2.cpp @@ -106,13 +106,11 @@ static int sceNpMatching2Term() return 0; } -static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) -{ - ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%hu], %i) at %08x", __FUNCTION__, communicationIdPtr, safe_string(Memory::GetCharPointer(communicationIdPtr)), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); +static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) { if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidAddress(ctxIdPtr)) + if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidRange(ctxIdPtr, 2)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context @@ -139,8 +137,8 @@ static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr // Returning dummy Id, a 16-bit variable according to JPCSP // FIXME: It seems ctxId need to be in the range of 1 to 7 to be valid ? - Memory::Write_U16(1, ctxIdPtr); - return 0; + Memory::WriteUnchecked_U16(1, ctxIdPtr); + return hleLogError(Log::sceNet, 0, "UNIMPL"); } static int sceNpMatching2ContextStart(int ctxId) @@ -369,12 +367,13 @@ static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int m if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(serverIdsPtr)) + if (!Memory::IsValidRange(serverIdsPtr, maxServerIds * sizeof(u16))) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); - // Returning dummy Id, a 16-bit variable according to JPCSP - for (int i = 0; i < maxServerIds; i++) - Memory::Write_U16(1234+i, serverIdsPtr+(i*2)); + // Returning dummy ids, 16-bit variables according to JPCSP + for (int i = 0; i < maxServerIds; i++) { + Memory::WriteUnchecked_U16(1234 + i, serverIdsPtr + (i * 2)); + } return maxServerIds; // dummy value } @@ -382,15 +381,14 @@ static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int m // Unknown1 = optParam, unknown2 = assignedReqId according to https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.cpp ? static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1Ptr, u32 unknown2Ptr) { - ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(serverIdPtr) || !Memory::IsValidAddress(unknown2Ptr)) + if (!Memory::IsValidRange(serverIdPtr, 2) || !Memory::IsValid4AlignedRange(unknown2Ptr, 8)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? // Server ID is a 16-bit variable according to JPCSP - int serverId = Memory::Read_U16(serverIdPtr); + int serverId = Memory::ReadUnchecked_U16(serverIdPtr); if (serverId == 0) return hleLogError(Log::sceNet, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? @@ -404,8 +402,8 @@ static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1P // 0008 32-bit set to 0 // 000a 16-bit set to 0 // - u32 cbFunc = Memory::Read_U32(unknown1Ptr); - u32 cbArg = Memory::Read_U32(unknown1Ptr + 0x04); + u32 cbFunc = Memory::ReadUnchecked_U32(unknown1Ptr); + u32 cbArg = Memory::ReadUnchecked_U32(unknown1Ptr + 0x04); // Notify callback handler if (Memory::IsValidAddress(cbFunc)) { @@ -435,24 +433,23 @@ static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1P notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 0, 1); - Memory::Write_U32(args.data[1], unknown2Ptr); // server status or flags? + Memory::WriteUnchecked_U32(args.data[1], unknown2Ptr); // server status or flags? } // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; + return hleLogError(Log::sceNet, 0, "UNIMPL"); } static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + if (!Memory::IsValidRange(reqParamPtr, 8) || !Memory::IsValid4AlignedRange(assignedReqIdPtr, 4)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + u32 cbFunc = Memory::ReadUnchecked_U32(reqParamPtr); + u32 cbArg = Memory::ReadUnchecked_U32(reqParamPtr + 0x04); // Notify callback handler if (Memory::IsValidAddress(cbFunc)) { @@ -469,30 +466,29 @@ static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x0c); - Memory::Write_U32(args.data[1], assignedReqIdPtr); + Memory::WriteUnchecked_U32(args.data[1], assignedReqIdPtr); } // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; + return hleLogError(Log::sceNet, 0, "UNIMPL"); } static int sceNpMatching2CreateJoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 unknown1, u32 unknown2, u32 assignedReqIdPtr) { - ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + if (!Memory::IsValidRange(reqParamPtr, 8) || !Memory::IsValid4AlignedRange(assignedReqIdPtr, 4)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? // Server ID is a 16-bit variable according to JPCSP - int serverId = Memory::Read_U16(reqParamPtr + 0x06); + int serverId = Memory::ReadUnchecked_U16(reqParamPtr + 0x06); if (serverId == 0) return hleLogError(Log::sceNet, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + u32 cbFunc = Memory::ReadUnchecked_U32(reqParamPtr); + u32 cbArg = Memory::ReadUnchecked_U32(reqParamPtr + 0x04); // Notify callback handler if (Memory::IsValidAddress(cbFunc)) { @@ -512,24 +508,23 @@ static int sceNpMatching2CreateJoinRoom(int ctxId, u32 reqParamPtr, u32 optParam notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 1, 0x0a); - Memory::Write_U32(args.data[1], assignedReqIdPtr); + Memory::WriteUnchecked_U32(args.data[1], assignedReqIdPtr); } // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; + return hleLogError(Log::sceNet, 0, "UNIMPL"); } static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + if (!Memory::IsValidRange(reqParamPtr, 8) || !Memory::IsValid4AlignedRange(assignedReqIdPtr, 4)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + u32 cbFunc = Memory::ReadUnchecked_U32(reqParamPtr); + u32 cbArg = Memory::ReadUnchecked_U32(reqParamPtr + 0x04); // Notify callback handler if (Memory::IsValidAddress(cbFunc)) { @@ -537,23 +532,22 @@ static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, NpMatching2Args args = {}; // TODO: Set the correct callback args - Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + Memory::WriteUnchecked_U32(args.data[1], assignedReqIdPtr); // server status or flags? } - return 0; + return hleLogError(Log::sceNet, 0, "UNIMPL"); } static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + if (!Memory::IsValidRange(reqParamPtr, 8) || !Memory::IsValid4AlignedRange(assignedReqIdPtr, 4)) return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + u32 cbFunc = Memory::ReadUnchecked_U32(reqParamPtr); + u32 cbArg = Memory::ReadUnchecked_U32(reqParamPtr + 0x04); // Notify callback handler if (Memory::IsValidAddress(cbFunc)) { @@ -570,11 +564,11 @@ static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 opt notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x10); - Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + Memory::WriteUnchecked_U32(args.data[1], assignedReqIdPtr); // server status or flags? } // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; + return hleLogError(Log::sceNet, 0, "UNIMPL"); } const HLEFunction sceNpMatching2[] = { diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index a00194a093..d2c263ea14 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -409,24 +409,16 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { case SCE_KERNEL_ERROR_CAN_NOT_WAIT: { WARN_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled", type, paddr, psize); - if (Memory::IsValid4AlignedAddress(paddr)) { - Memory::WriteUnchecked_U32(0x08400000, paddr); - } - if (Memory::IsValid4AlignedAddress(psize)) { - Memory::WriteUnchecked_U32(0x00400000, psize); - } + Memory::WriteOrException_U32(0x08400000, paddr); + Memory::WriteOrException_U32(0x00400000, psize); } break; case SCE_KERNEL_ERROR_ILLEGAL_CONTEXT: { WARN_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt", type, paddr, psize); - if (Memory::IsValid4AlignedAddress(paddr)) { - Memory::WriteUnchecked_U32(0x08400000, paddr); - } - if (Memory::IsValid4AlignedAddress(psize)) { - Memory::WriteUnchecked_U32(0x00400000, psize); - } + Memory::WriteOrException_U32(0x08400000, paddr); + Memory::WriteOrException_U32(0x00400000, psize); } break; diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index fcb57013b9..1c9f7fb2f1 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -670,9 +670,9 @@ static Psmf *getPsmf(u32 psmf) { } } -static PsmfPlayer *getPsmfPlayer(u32 psmfplayer) -{ - auto iter = psmfPlayerMap.find(Memory::Read_U32(psmfplayer)); +// This can assume that psmfPlayer is a valid pointer. +static PsmfPlayer *getPsmfPlayer(u32 psmfplayer) { + auto iter = psmfPlayerMap.find(Memory::ReadUnchecked_U32(psmfplayer)); if (iter != psmfPlayerMap.end()) return iter->second; else @@ -883,8 +883,8 @@ static u32 scePsmfGetVideoInfo(u32 psmfStruct, u32 videoInfoAddr) { if (info->videoWidth_ == PsmfStream::INVALID) { return hleLogError(Log::ME, SCE_PSMF_ERROR_INVALID_ID, "not a video stream"); } - Memory::Write_U32(info->videoWidth_ == PsmfStream::USE_PSMF ? psmf->videoWidth : info->videoWidth_, videoInfoAddr); - Memory::Write_U32(info->videoHeight_ == PsmfStream::USE_PSMF ? psmf->videoHeight : info->videoHeight_, videoInfoAddr + 4); + Memory::WriteUnchecked_U32(info->videoWidth_ == PsmfStream::USE_PSMF ? psmf->videoWidth : info->videoWidth_, videoInfoAddr); + Memory::WriteUnchecked_U32(info->videoHeight_ == PsmfStream::USE_PSMF ? psmf->videoHeight : info->videoHeight_, videoInfoAddr + 4); return hleLogDebug(Log::ME, 0); } @@ -903,8 +903,8 @@ static u32 scePsmfGetAudioInfo(u32 psmfStruct, u32 audioInfoAddr) { if (info->audioChannels_ == PsmfStream::INVALID) { return hleLogError(Log::ME, SCE_PSMF_ERROR_INVALID_ID, "not an audio stream"); } - Memory::Write_U32(info->audioChannels_ == PsmfStream::USE_PSMF ? psmf->audioChannels : info->audioChannels_, audioInfoAddr); - Memory::Write_U32(info->audioFrequency_ == PsmfStream::USE_PSMF ? psmf->audioFrequency : info->audioFrequency_, audioInfoAddr + 4); + Memory::WriteUnchecked_U32(info->audioChannels_ == PsmfStream::USE_PSMF ? psmf->audioChannels : info->audioChannels_, audioInfoAddr); + Memory::WriteUnchecked_U32(info->audioFrequency_ == PsmfStream::USE_PSMF ? psmf->audioFrequency : info->audioFrequency_, audioInfoAddr + 4); return hleLogDebug(Log::ME, 0); } @@ -940,20 +940,18 @@ static u32 scePsmfGetStreamSize(u32 psmfStruct, u32 sizeAddr) static u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr) { - WARN_LOG(Log::ME, "scePsmfQueryStreamOffset(%08x, %08x)", bufferAddr, offsetAddr); - if (Memory::IsValidAddress(offsetAddr)) { - Memory::WriteUnchecked_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr); + if (Memory::IsValidAddress(offsetAddr) && Memory::IsValidRange(bufferAddr, 12)) { + Memory::WriteUnchecked_U32(bswap32(Memory::ReadUnchecked_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr); } - return 0; + return hleLogWarning(Log::ME, 0); } static u32 scePsmfQueryStreamSize(u32 bufferAddr, u32 sizeAddr) { - WARN_LOG(Log::ME, "scePsmfQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr); - if (Memory::IsValidAddress(sizeAddr)) { - Memory::WriteUnchecked_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_SIZE_OFFSET)), sizeAddr); + if (Memory::IsValidAddress(sizeAddr) && Memory::IsValidRange(bufferAddr, 12)) { + Memory::WriteUnchecked_U32(bswap32(Memory::ReadUnchecked_U32(bufferAddr + PSMF_STREAM_SIZE_OFFSET)), sizeAddr); } - return 0; + return hleLogWarning(Log::ME, 0); } static u32 scePsmfGetHeaderSize(u32 psmfStruct, u32 sizeAddr) @@ -979,11 +977,14 @@ static u32 scePsmfGetPsmfVersion(u32 psmfStruct) static u32 scePsmfVerifyPsmf(u32 psmfAddr) { - u32 magic = Memory::Read_U32(psmfAddr); + if (!Memory::IsValid4AlignedRange(psmfAddr, 12)) { + return hleLogError(Log::ME, SCE_PSMF_ERROR_NOT_FOUND, "bad address"); + } + const u32 magic = Memory::ReadUnchecked_U32(psmfAddr); if (magic != PSMF_MAGIC) { return hleLogError(Log::ME, SCE_PSMF_ERROR_NOT_FOUND, "bad magic %08x", magic); } - int version = Memory::Read_U32(psmfAddr + PSMF_STREAM_VERSION_OFFSET); + const int version = Memory::ReadUnchecked_U32(psmfAddr + PSMF_STREAM_VERSION_OFFSET); if (version < 0) { return hleLogError(Log::ME, SCE_PSMF_ERROR_NOT_FOUND, "bad version at %08x: %d", psmfAddr + PSMF_STREAM_VERSION_OFFSET, version); } @@ -1008,8 +1009,8 @@ static u32 scePsmfGetPresentationStartTime(u32 psmfStruct, u32 startTimeAddr) if (!psmf) { return hleLogError(Log::ME, SCE_PSMF_ERROR_NOT_FOUND, "invalid psmf"); } - if (Memory::IsValidAddress(startTimeAddr)) { - Memory::Write_U32(psmf->presentationStartTime, startTimeAddr); + if (Memory::IsValid4AlignedAddress(startTimeAddr)) { + Memory::WriteUnchecked_U32(psmf->presentationStartTime, startTimeAddr); } return hleLogDebug(Log::ME, 0); } @@ -1022,7 +1023,7 @@ static u32 scePsmfGetPresentationEndTime(u32 psmfStruct, u32 endTimeAddr) return SCE_PSMF_ERROR_NOT_FOUND; } DEBUG_LOG(Log::ME, "scePsmfGetPresentationEndTime(%08x, %08x)", psmfStruct, endTimeAddr); - if (Memory::IsValidAddress(endTimeAddr)) { + if (Memory::IsValid4AlignedAddress(endTimeAddr)) { Memory::WriteUnchecked_U32(psmf->presentationEndTime, endTimeAddr); } return 0; @@ -1484,8 +1485,8 @@ static int scePsmfPlayerDelete(u32 psmfPlayer) delete psmfplayer; - psmfPlayerMap.erase(Memory::Read_U32(psmfPlayer)); - Memory::Write_U32(0, psmfPlayer); + psmfPlayerMap.erase(Memory::ReadUnchecked_U32(psmfPlayer)); + Memory::WriteUnchecked_U32(0, psmfPlayer); return hleDelayResult(hleLogDebug(Log::ME, 0), "psmfplayer deleted", 20000); } diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 00920acafb..8a4111a411 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -280,8 +280,9 @@ static u32 sceRtcGetCurrentTick(u32 tickPtr) VERBOSE_LOG(Log::sceRtc, "sceRtcGetCurrentTick(%08x)", tickPtr); u64 curTick = __RtcGetCurrentTick(); - if (Memory::IsValidAddress(tickPtr)) - Memory::Write_U64(curTick, tickPtr); + if (Memory::IsValid4AlignedRange(tickPtr, 8)) { + Memory::WriteUnchecked_U64(curTick, tickPtr); + } hleEatCycles(300); hleReSchedule("rtc current tick"); return hleNoLog(0); @@ -448,7 +449,7 @@ static int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr) tm *time = localtime(&timezone); srcTick -= time->tm_gmtoff*1000000ULL; #endif - Memory::Write_U64(srcTick, tickUTCPtr); + Memory::WriteUnchecked_U64(srcTick, tickUTCPtr); } else { @@ -589,8 +590,7 @@ static int sceRtcGetDosTime(u32 datePtr, u32 dosTime) { return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcSetWin32FileTime(u32 datePtr, u64 win32Time) -{ +static int sceRtcSetWin32FileTime(u32 datePtr, u64 win32Time) { if (!Memory::IsValidAddress(datePtr)) { ERROR_LOG_REPORT(Log::sceRtc, "sceRtcSetWin32FileTime(%08x, %lld): invalid address", datePtr, win32Time); @@ -605,35 +605,32 @@ static int sceRtcSetWin32FileTime(u32 datePtr, u64 win32Time) return 0; } -static int sceRtcGetWin32FileTime(u32 datePtr, u32 win32TimePtr) -{ - if (!Memory::IsValidAddress(datePtr)) - { +static int sceRtcGetWin32FileTime(u32 datePtr, u32 win32TimePtr) { + if (!Memory::IsValidAddress(datePtr)) { ERROR_LOG_REPORT(Log::sceRtc, "sceRtcGetWin32FileTime(%08x, %08x): invalid address", datePtr, win32TimePtr); return -1; } DEBUG_LOG(Log::sceRtc, "sceRtcGetWin32FileTime(%08x, %08x)", datePtr, win32TimePtr); - if (!Memory::IsValidAddress(win32TimePtr)) + if (!Memory::IsValid4AlignedRange(win32TimePtr, 8)) { return SCE_KERNEL_ERROR_INVALID_VALUE; + } auto pspTime = PSPPointer::Create(datePtr); u64 result = __RtcPspTimeToTicks(*pspTime); - if (!__RtcValidatePspTime(*pspTime) || result < rtcFiletimeOffset) - { - Memory::Write_U64(0, win32TimePtr); + if (!__RtcValidatePspTime(*pspTime) || result < rtcFiletimeOffset) { + Memory::WriteUnchecked_U64(0, win32TimePtr); return SCE_KERNEL_ERROR_INVALID_VALUE; } - Memory::Write_U64((result - rtcFiletimeOffset) * 10, win32TimePtr); + Memory::WriteUnchecked_U64((result - rtcFiletimeOffset) * 10, win32TimePtr); return 0; } -static int sceRtcCompareTick(u32 tick1Ptr, u32 tick2Ptr) -{ +static int sceRtcCompareTick(u32 tick1Ptr, u32 tick2Ptr) { DEBUG_LOG(Log::sceRtc, "sceRtcCompareTick(%d,%d)", tick1Ptr, tick2Ptr); - if (Memory::IsValid4AlignedAddress(tick1Ptr) && Memory::IsValid4AlignedAddress(tick2Ptr)) { + if (Memory::IsValid4AlignedRange(tick1Ptr, 8) && Memory::IsValid4AlignedRange(tick2Ptr, 8)) { u64 tick1 = Memory::ReadUnchecked_U64(tick1Ptr); u64 tick2 = Memory::ReadUnchecked_U64(tick2Ptr); if (tick1 > tick2) @@ -644,10 +641,8 @@ static int sceRtcCompareTick(u32 tick1Ptr, u32 tick2Ptr) return hleNoLog(0); } -static int sceRtcTickAddTicks(u32 destTickPtr, u32 srcTickPtr, u64 numTicks) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddTicks(u32 destTickPtr, u32 srcTickPtr, u64 numTicks) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { u64 srcTick = Memory::ReadUnchecked_U64(srcTickPtr); srcTick += numTicks; @@ -656,10 +651,8 @@ static int sceRtcTickAddTicks(u32 destTickPtr, u32 srcTickPtr, u64 numTicks) return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddMicroseconds(u32 destTickPtr,u32 srcTickPtr, u64 numMS) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddMicroseconds(u32 destTickPtr,u32 srcTickPtr, u64 numMS) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); srcTick += numMS; @@ -668,10 +661,8 @@ static int sceRtcTickAddMicroseconds(u32 destTickPtr,u32 srcTickPtr, u64 numMS) return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddSeconds(u32 destTickPtr, u32 srcTickPtr, u64 numSecs) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddSeconds(u32 destTickPtr, u32 srcTickPtr, u64 numSecs) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); srcTick += numSecs * 1000000UL; @@ -680,10 +671,8 @@ static int sceRtcTickAddSeconds(u32 destTickPtr, u32 srcTickPtr, u64 numSecs) return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddMinutes(u32 destTickPtr, u32 srcTickPtr, u64 numMins) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddMinutes(u32 destTickPtr, u32 srcTickPtr, u64 numMins) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); srcTick += numMins*60000000UL; @@ -692,10 +681,8 @@ static int sceRtcTickAddMinutes(u32 destTickPtr, u32 srcTickPtr, u64 numMins) return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddHours(u32 destTickPtr, u32 srcTickPtr, int numHours) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddHours(u32 destTickPtr, u32 srcTickPtr, int numHours) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); srcTick += numHours * 3600ULL * 1000000ULL; Memory::WriteUnchecked_U64(srcTick, destTickPtr); @@ -703,38 +690,30 @@ static int sceRtcTickAddHours(u32 destTickPtr, u32 srcTickPtr, int numHours) return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddDays(u32 destTickPtr, u32 srcTickPtr, int numDays) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddDays(u32 destTickPtr, u32 srcTickPtr, int numDays) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); - srcTick += numDays * 86400ULL * 1000000ULL; Memory::WriteUnchecked_U64(srcTick, destTickPtr); } return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks) -{ - if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks) { + if (Memory::IsValid4AlignedRange(destTickPtr, 8) && Memory::IsValid4AlignedRange(srcTickPtr, 8)) { s64 srcTick = (s64)Memory::ReadUnchecked_U64(srcTickPtr); - srcTick += numWeeks * 7ULL * 86400ULL * 1000000ULL; Memory::WriteUnchecked_U64(srcTick, destTickPtr); } return hleLogDebug(Log::sceRtc, 0); } -static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) -{ - if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) - { +static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) { + if (!Memory::IsValid4AlignedRange(destTickPtr, 8) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { return hleLogWarning(Log::sceRtc, -1, "invalid address"); } - u64 srcTick = Memory::Read_U64(srcTickPtr); + u64 srcTick = Memory::ReadUnchecked_U64(srcTickPtr); ScePspDateTime pt{}; @@ -742,13 +721,11 @@ static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) pt.year += numMonths / 12; pt.month += numMonths % 12; - if (pt.month < 1) - { + if (pt.month < 1) { pt.month += 12; pt.year--; } - if (pt.month > 12) - { + if (pt.month > 12) { pt.month -= 12; pt.year++; } @@ -764,9 +741,8 @@ static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) return hleNoLog(0); } -static int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears) -{ - if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) { +static int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears) { + if (!Memory::IsValid4AlignedRange(destTickPtr, 8) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { return hleLogWarning(Log::sceRtc, -1, "invalid address"); } @@ -926,10 +902,10 @@ static bool rtcParseRFC2822(const char *s, RtcParseResult &r) { static int sceRtcParseDateTime(u32 destTickPtr, u32 dateStringPtr) { - if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(dateStringPtr)) + if (!Memory::IsValid4AlignedRange(destTickPtr, 8) || !Memory::IsValidAddress(dateStringPtr)) return hleLogError(Log::sceRtc, -1, "bad address"); - const char *s = (const char *)Memory::GetPointer(dateStringPtr); + const char *s = Memory::GetCharPointer(dateStringPtr); if (!s) { return hleLogError(Log::sceRtc, -1, "null string"); } @@ -941,7 +917,7 @@ static int sceRtcParseDateTime(u32 destTickPtr, u32 dateStringPtr) u64 ticks = __RtcPspTimeToTicks(r.date); s64 offsetUs = (s64)r.tzOffsetMinutes * 60 * 1000000; ticks -= offsetUs; - Memory::Write_U64(ticks, destTickPtr); + Memory::WriteUnchecked_U64(ticks, destTickPtr); return hleLogDebug(Log::sceRtc, 0); } @@ -951,16 +927,16 @@ static int sceRtcParseDateTime(u32 destTickPtr, u32 dateStringPtr) static int sceRtcGetLastAdjustedTime(u32 tickPtr) { - if (Memory::IsValidAddress(tickPtr)) - Memory::Write_U64(rtcLastAdjustedTicks, tickPtr); + if (Memory::IsValid4AlignedRange(tickPtr, 8)) + Memory::WriteUnchecked_U64(rtcLastAdjustedTicks, tickPtr); DEBUG_LOG(Log::sceRtc, "sceRtcGetLastAdjustedTime(%d)", tickPtr); return 0; } static int sceRtcGetLastReincarnatedTime(u32 tickPtr) { - if (Memory::IsValidAddress(tickPtr)) - Memory::Write_U64(rtcLastReincarnatedTicks, tickPtr); + if (Memory::IsValid4AlignedRange(tickPtr, 8)) + Memory::WriteUnchecked_U64(rtcLastReincarnatedTicks, tickPtr); DEBUG_LOG(Log::sceRtc, "sceRtcGetLastReincarnatedTime(%d)", tickPtr); return 0; } @@ -973,9 +949,8 @@ static int sceRtcSetAlarmTick(u32 unknown1, u32 unknown2) } // Caller must check outPtr and srcTickPtr. -static int __RtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) -{ - u64 srcTick = Memory::Read_U64(srcTickPtr); +static int __RtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) { + u64 srcTick = Memory::ReadUnchecked_U64(srcTickPtr); ScePspDateTime pt; memset(&pt, 0, sizeof(pt)); @@ -1004,9 +979,9 @@ static int __RtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) return 0; } -static int __RtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) -{ - u64 srcTick = Memory::Read_U64(srcTickPtr); +// Caller must check outPtr and srcTickPtr. +static int __RtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) { + u64 srcTick = Memory::ReadUnchecked_U64(srcTickPtr); ScePspDateTime pt; memset(&pt, 0, sizeof(pt)); @@ -1038,7 +1013,7 @@ static int __RtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) static int sceRtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) { - if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) + if (!Memory::IsValidAddress(outPtr) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { // TODO: Not well tested. ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC2822(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); @@ -1051,7 +1026,7 @@ static int sceRtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) static int sceRtcFormatRFC2822LocalTime(u32 outPtr, u32 srcTickPtr) { - if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) + if (!Memory::IsValidAddress(outPtr) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { // TODO: Not well tested. ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC2822LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); @@ -1075,7 +1050,7 @@ static int sceRtcFormatRFC2822LocalTime(u32 outPtr, u32 srcTickPtr) static int sceRtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) { - if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) + if (!Memory::IsValidAddress(outPtr) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { // TODO: Not well tested. ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC3339(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); @@ -1088,7 +1063,7 @@ static int sceRtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) static int sceRtcFormatRFC3339LocalTime(u32 outPtr, u32 srcTickPtr) { - if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) + if (!Memory::IsValidAddress(outPtr) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { // TODO: Not well tested. ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC3339LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 95515570e0..cf78967e13 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -665,7 +665,7 @@ static u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { __SasDrain(); for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { int voiceHeight = sas->voices[i].envelope.GetHeight(); - Memory::Write_U32(voiceHeight, heightsAddr + i * 4); + Memory::WriteOrException_U32(voiceHeight, heightsAddr + i * 4); } return hleLogDebug(Log::sceSas, 0); @@ -735,7 +735,7 @@ static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { v.on = false; // This unpauses. Some games, like Sol Trigger, depend on this. v.paused = false; - Memory::Write_U32(0, core + 56 * voiceNum + 20); + Memory::WriteOrException_U32(0, core + 56 * voiceNum + 20); return hleLogDebug(Log::sceSas, 0); } diff --git a/Core/HLE/sceSsl.cpp b/Core/HLE/sceSsl.cpp index f1c668c995..e20ae2d388 100644 --- a/Core/HLE/sceSsl.cpp +++ b/Core/HLE/sceSsl.cpp @@ -23,19 +23,17 @@ #include "Core/MemMap.h" #include "Core/HLE/sceSsl.h" -bool isSslInit; -u32 maxMemSize; -u32 currentMemSize; +static bool isSslInit; +static u32 maxMemSize; +static u32 currentMemSize; -void __SslInit() -{ +void __SslInit() { isSslInit = 0; maxMemSize = 0; currentMemSize = 0; } -void __SslDoState(PointerWrap &p) -{ +void __SslDoState(PointerWrap &p) { auto s = p.Section("sceSsl", 1); if (!s) return; @@ -45,67 +43,52 @@ void __SslDoState(PointerWrap &p) Do(p, currentMemSize); } -static int sceSslInit(int heapSize) -{ - DEBUG_LOG(Log::HLE, "sceSslInit %d", heapSize); - if (isSslInit) - { +static int sceSslInit(int heapSize) { + if (isSslInit) { return SCE_SSL_ERROR_ALREADY_INIT; } - if (heapSize <= 0) - { + if (heapSize <= 0) { return SCE_SSL_ERROR_INVALID_PARAMETER; } maxMemSize = heapSize; currentMemSize = heapSize / 2; // As per jpcsp isSslInit = true; - return 0; + return hleLogDebug(Log::HLE, 0); } -static int sceSslEnd() -{ +static int sceSslEnd() { DEBUG_LOG(Log::HLE, "sceSslEnd"); - if (!isSslInit) - { + if (!isSslInit) { return SCE_SSL_ERROR_NOT_INIT; } isSslInit = false; - return 0; + return hleLogDebug(Log::HLE, 0); } -static int sceSslGetUsedMemoryMax(u32 maxMemPtr) -{ - DEBUG_LOG(Log::HLE, "sceSslGetUsedMemoryMax %d", maxMemPtr); - if (!isSslInit) - { +static int sceSslGetUsedMemoryMax(u32 maxMemPtr) { + if (!isSslInit) { return SCE_SSL_ERROR_NOT_INIT; } - if (Memory::IsValidAddress(maxMemPtr)) - { - Memory::Write_U32(maxMemSize, maxMemPtr); + if (Memory::IsValid4AlignedAddress(maxMemPtr)) { + Memory::WriteUnchecked_U32(maxMemSize, maxMemPtr); } - return 0; + return hleLogDebug(Log::HLE, 0); } -static int sceSslGetUsedMemoryCurrent(u32 currentMemPtr) -{ - DEBUG_LOG(Log::HLE, "sceSslGetUsedMemoryCurrent %d", currentMemPtr); - if (!isSslInit) - { +static int sceSslGetUsedMemoryCurrent(u32 currentMemPtr) { + if (!isSslInit) { return SCE_SSL_ERROR_NOT_INIT; } - if (Memory::IsValidAddress(currentMemPtr)) - { - Memory::Write_U32(currentMemSize, currentMemPtr); + if (Memory::IsValid4AlignedAddress(currentMemPtr)) { + Memory::WriteUnchecked_U32(currentMemSize, currentMemPtr); } - return 0; + return hleLogDebug(Log::HLE, 0); } -const HLEFunction sceSsl[] = -{ +const HLEFunction sceSsl[] = { {0X957ECBE2, &WrapI_I, "sceSslInit", 'i', "i"}, {0X191CDEFF, &WrapI_V, "sceSslEnd", 'i', "" }, {0X5BFB6B61, nullptr, "sceSslGetNotAfter", '?', "" }, @@ -120,7 +103,6 @@ const HLEFunction sceSsl[] = {0XF57765D3, nullptr, "sceSslGetKeyUsage", '?', "" }, }; -void Register_sceSsl() -{ +void Register_sceSsl() { RegisterHLEModule("sceSsl", ARRAY_SIZE(sceSsl), sceSsl); } diff --git a/Core/HLE/sceUsbMic.cpp b/Core/HLE/sceUsbMic.cpp index afcacd0bea..4ff841e620 100644 --- a/Core/HLE/sceUsbMic.cpp +++ b/Core/HLE/sceUsbMic.cpp @@ -82,7 +82,7 @@ static void __MicBlockingResume(u64 userdata, int cyclesLate) { } else { for (int i = 0; i < iter->needSize; i++) { if (Memory::IsValidAddress(iter->addr + i)) { - Memory::Write_U8(i & 0xFF, iter->addr + i); + Memory::WriteUnchecked_U8(i & 0xFF, iter->addr + i); } } u32 ret = __KernelGetWaitValue(threadID, error); diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 864bfb0496..34eb6a169b 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -1090,7 +1090,7 @@ static int sceUtilityGetNetParam(int id, int param, u32 dataAddr) { static int sceUtilityGetNetParamLatestID(u32 idAddr) { DEBUG_LOG(Log::sceUtility, "sceUtilityGetNetParamLatestID(%08x)", idAddr); // This function is saving the last net param ID (non-zero ID?) and not the number of net configurations. - Memory::Write_U32(netParamLatestId, idAddr); + Memory::WriteOrException_U32(netParamLatestId, idAddr); return 0; } @@ -1269,7 +1269,7 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) { // FIXME: Outputted channel (might be unchanged?) either 0 when not connected to a group yet (ie. adhocctlState == ADHOCCTL_STATE_DISCONNECTED), // or -1 (0xFFFFFFFF) when a scan is in progress (ie. adhocctlState == ADHOCCTL_STATE_SCANNING), // or 0x60 early when in connected state (ie. adhocctlState == ADHOCCTL_STATE_CONNECTED) right after Creating a group, regardless the channel settings. - Memory::Write_U32(param, destaddr); + Memory::WriteOrException_U32(param, destaddr); return 0x800ADF4; } break; @@ -1309,7 +1309,7 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) { return hleLogError(Log::sceUtility, SCE_ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID); } - Memory::Write_U32(param, destaddr); + Memory::WriteOrException_U32(param, destaddr); return hleLogInfo(Log::sceUtility, 0, "(%s): %08x", SystemParamToString(id), param); } diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index a5d46c8e5e..56d017e6c2 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -496,7 +496,7 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { int outpcmbufsize = 0; if (pcmAddr) - Memory::Write_U32(outptr, pcmAddr); + Memory::WriteOrException_U32(outptr, pcmAddr); // Decode a single frame in sourcebuff and output into PCMBuf. if (!sourcebuff.empty()) { diff --git a/Core/Loaders.h b/Core/Loaders.h index a0e84e02bc..6804abbdf2 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -63,7 +63,7 @@ enum class IdentifiedFileType { const char *IdentifiedFileTypeToString(IdentifiedFileType type); // NB: It is a REQUIREMENT that implementations of this class are entirely thread safe! -// TOOD: actually, is it really? +// TODO: actually, is it really? class FileLoader { public: enum class Flags { diff --git a/Core/LuaContext.cpp b/Core/LuaContext.cpp index 973cf9ea60..193c06275e 100644 --- a/Core/LuaContext.cpp +++ b/Core/LuaContext.cpp @@ -55,7 +55,7 @@ static int r32(int address) { static void w32(int address, int value) { if (Memory::IsValid4AlignedAddress(address)) { - Memory::Write_U32(value, address); // NOTE: These are backwards for historical reasons. + Memory::WriteUnchecked_U32(value, address); // NOTE: These are backwards for historical reasons. } else { g_lua.Print(LogLineType::Error, StringFromFormat("w32: bad address %08x trying to write %08x", address, value)); } diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 112bae8679..00bc4a7eb1 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -98,12 +98,10 @@ void ArmJit::Comp_FPULS(MIPSOpcode op) s32 offset = SignExtend16ToS32(op & 0xFFFF); int ft = _FT; MIPSGPReg rs = _RS; - // u32 addr = R(rs) + offset; - // logBlocks = 1; bool doCheck = false; switch(op >> 26) { - case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 + case 49: //lwc1 if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { gpr.MapRegAsPointer(rs); fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY); @@ -147,7 +145,7 @@ void ArmJit::Comp_FPULS(MIPSOpcode op) fpr.ReleaseSpillLocksAndDiscardTemps(); break; - case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 + case 57: //swc1 if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { gpr.MapRegAsPointer(rs); fpr.MapReg(ft, 0); diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 8139bca632..05ddf8464d 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -236,7 +236,7 @@ namespace MIPSComp bool doCheck = false; switch (op >> 26) { - case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); + case 50: //lv.s { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { gpr.MapRegAsPointer(rs); @@ -281,7 +281,7 @@ namespace MIPSComp } break; - case 58: //sv.s // Memory::Write_U32(VI(vt), addr); + case 58: //sv.s { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { gpr.MapRegAsPointer(rs); diff --git a/Core/MIPS/ARM64/Arm64CompFPU.cpp b/Core/MIPS/ARM64/Arm64CompFPU.cpp index c279d5f862..fc0060adf3 100644 --- a/Core/MIPS/ARM64/Arm64CompFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompFPU.cpp @@ -86,10 +86,9 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op) s32 offset = SignExtend16ToS32(op & 0xFFFF); int ft = _FT; MIPSGPReg rs = _RS; - // u32 addr = R(rs) + offset; std::vector skips; switch (op >> 26) { - case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 + case 49: // lwc1 if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset <= 16380 && offset >= 0) { gpr.MapRegAsPointer(rs); fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY); @@ -121,7 +120,7 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op) fpr.ReleaseSpillLocksAndDiscardTemps(); break; - case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 + case 57: // swc1 if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset <= 16380 && offset >= 0) { gpr.MapRegAsPointer(rs); fpr.MapReg(ft, 0); diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 9fbd2dc43d..48f4868372 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -212,7 +212,7 @@ namespace MIPSComp { std::vector skips; switch (op >> 26) { - case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); + case 50: // lv.s { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset >= 0 && offset < 16384) { gpr.MapRegAsPointer(rs); @@ -245,7 +245,7 @@ namespace MIPSComp { } break; - case 58: //sv.s // Memory::Write_U32(VI(vt), addr); + case 58: // sv.s { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset >= 0 && offset < 16384) { gpr.MapRegAsPointer(rs); diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index ca603199ea..cedf708745 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -82,11 +82,11 @@ void IRFrontend::Comp_FPULS(MIPSOpcode op) { CheckMemoryBreakpoint(rs, offset); switch (op >> 26) { - case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 + case 49: // lwc1 ir.Write(IROp::LoadFloat, ft, rs, ir.AddConstant(offset)); break; - case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 + case 57: // swc1 ir.Write(IROp::StoreFloat, ft, rs, ir.AddConstant(offset)); break; diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index e8b751b776..d4e9a7afe8 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -255,10 +255,10 @@ MIPSOpcode JitBlockCache::GetEmuHackOpForBlock(int blockNum) const { } int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) const { - if (!blocks_ || !Memory::IsValidAddress(addr)) + if (!blocks_ || !Memory::IsValid4AlignedAddress(addr)) return -1; - MIPSOpcode inst = MIPSOpcode(Memory::Read_U32(addr)); + MIPSOpcode inst = MIPSOpcode(Memory::ReadUnchecked_U32(addr)); int bl = GetBlockNumberFromEmuHackOp(inst); if (bl < 0) { return -1; diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index a77d836bb7..2bce1ecf3f 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -635,6 +635,10 @@ namespace MIPSAnalyst { } bool OpWouldChangeMemory(u32 pc, u32 addr, u32 size) { + if (!Memory::IsValidRange(addr, 4)) { + return false; + } + const auto op = Memory::Read_Instruction(pc, true); // TODO: Trap sc/ll, svl.q, svr.q? @@ -658,30 +662,32 @@ namespace MIPSAnalyst { u32 writeVal = 0xFFFFFFFF; u32 prevVal = 0x00000000; - if (gprMask != 0) - { + if (gprMask != 0) { MIPSGPReg rt = MIPS_GET_RT(op); writeVal = currentMIPS->r[rt] & gprMask; - prevVal = Memory::Read_U32(addr) & gprMask; + prevVal = Memory::ReadUnchecked_U32(addr) & gprMask; } if (IsSWC1Instr(op)) { int ft = MIPS_GET_FT(op); writeVal = currentMIPS->fi[ft]; - prevVal = Memory::Read_U32(addr); + prevVal = Memory::ReadUnchecked_U32(addr); } if (IsSVSInstr(op)) { int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); writeVal = currentMIPS->vi[voffset[vt]]; - prevVal = Memory::Read_U32(addr); + prevVal = Memory::ReadUnchecked_U32(addr); } if (IsSVQInstr(op)) { + if (!Memory::IsValidRange(addr, 16)) { + return false; + } int vt = (((op >> 16) & 0x1f)) | ((op & 1) << 5); float rd[4]; ReadVector(rd, V_Quad, vt); - return memcmp(rd, Memory::GetPointerRange(addr, 16), sizeof(float) * 4) != 0; + return memcmp(rd, Memory::GetPointerUnchecked(addr), 16) != 0; // sizeof(float) * 4 } return writeVal != prevVal; diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 9ca2a1be4b..98f20874c3 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -361,7 +361,7 @@ namespace MIPSInt Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "ll"); return; } - R(rt) = Memory::Read_U32(addr); + R(rt) = Memory::ReadUnchecked_U32(addr); } currentMIPS->llBit = 1; break; @@ -371,7 +371,7 @@ namespace MIPSInt Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sc"); return; } - Memory::Write_U32(R(rt), addr); + Memory::WriteUnchecked_U32(R(rt), addr); if (rt != 0) { R(rt) = 1; } @@ -460,35 +460,35 @@ namespace MIPSInt Core_MemoryException(addr, 1, PC, MemoryExceptionType::READ_WORD, "lbu"); return; } - R(rt) = Memory::Read_U8 (addr); + R(rt) = Memory::ReadUnchecked_U8(addr); break; //lbu case 37: if (!Memory::IsValid2AlignedAddress(addr)) { Core_MemoryException(addr, 2, PC, MemoryExceptionType::READ_WORD, "lhu"); return; } - R(rt) = Memory::Read_U16(addr); + R(rt) = Memory::ReadUnchecked_U16(addr); break; //lhu case 40: if (!Memory::IsValidAddress(addr)) { Core_MemoryException(addr, 1, PC, MemoryExceptionType::WRITE_WORD, "sb"); return; } - Memory::Write_U8(R(rt), addr); + Memory::WriteUnchecked_U8(R(rt), addr); break; //sb case 41: if (!Memory::IsValid2AlignedAddress(addr)) { Core_MemoryException(addr, 2, PC, MemoryExceptionType::WRITE_WORD, "sh"); return; } - Memory::Write_U16(R(rt), addr); + Memory::WriteUnchecked_U16(R(rt), addr); break; //sh case 43: if (!Memory::IsValid4AlignedAddress(addr)) { Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sw"); return; } - Memory::Write_U32(R(rt), addr); + Memory::WriteUnchecked_U32(R(rt), addr); break; //sw // When there's an LWL and an LWR together, we should be able to peephole optimize that @@ -569,14 +569,14 @@ namespace MIPSInt Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lwc1"); return; } - FI(ft) = Memory::Read_U32(addr); + FI(ft) = Memory::ReadUnchecked_U32(addr); break; //lwc1 case 57: if (!Memory::IsValid4AlignedAddress(addr)) { Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "swc1"); return; } - Memory::Write_U32(FI(ft), addr); + Memory::WriteUnchecked_U32(FI(ft), addr); break; //swc1 default: _dbg_assert_msg_(false,"Trying to interpret FPULS instruction that can't be interpreted"); diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 69cd0bfcd2..ca32f9f436 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -1754,10 +1754,18 @@ namespace MIPSInt switch (op >> 26) { case 50: //lv.s - VI(vt) = Memory::Read_U32(addr); + if (!Memory::IsValid4AlignedAddress(addr)) { + Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lv.s"); + return; + } + VI(vt) = Memory::ReadUnchecked_U32(addr); break; case 58: //sv.s - Memory::Write_U32(VI(vt), addr); + if (!Memory::IsValid4AlignedAddress(addr)) { + Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sv.s"); + return; + } + Memory::WriteUnchecked_U32(VI(vt), addr); break; default: _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); diff --git a/Core/MIPS/MIPSStackWalk.cpp b/Core/MIPS/MIPSStackWalk.cpp index dc6019b717..3b312b441b 100644 --- a/Core/MIPS/MIPSStackWalk.cpp +++ b/Core/MIPS/MIPSStackWalk.cpp @@ -133,8 +133,8 @@ namespace MIPSStackWalk { frame.entry = pc; frame.stackSize = -_IMM16; - if (ra_offset != -1 && Memory::IsValidAddress(frame.sp + ra_offset)) { - ra = Memory::Read_U32(frame.sp + ra_offset); + if (ra_offset != -1 && Memory::IsValid4AlignedAddress(frame.sp + ra_offset)) { + ra = Memory::ReadUnchecked_U32(frame.sp + ra_offset); } return true; } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 83ce6ab4bd..fa797d3be6 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -973,8 +973,11 @@ static inline void RunUntilFast() { // NEVER stop in a delay slot! while (curMips->downcount >= 0 && coreState == CORE_RUNNING_CPU) { do { - // Replacements and similar are processed here, intentionally. - MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + if (!Memory::IsValid4AlignedAddress(curMips->pc)) { + Core_ExecException(curMips->pc, curMips->pc, ExecExceptionType::JUMP); + return; + } + MIPSOpcode op = MIPSOpcode(Memory::ReadUnchecked_U32(curMips->pc)); bool wasInDelaySlot = curMips->inDelaySlot; const MIPSInstruction *instr = MIPSGetInstruction(op); @@ -997,8 +1000,12 @@ static void RunUntilWithChecks(u64 globalTicks) { bool hasMCs = g_breakpoints.HasMemChecks(); while (curMips->downcount >= 0 && coreState == CORE_RUNNING_CPU) { do { + if (!Memory::IsValid4AlignedAddress(curMips->pc)) { + Core_ExecException(curMips->pc, curMips->pc, ExecExceptionType::JUMP); + return; + } + MIPSOpcode op = MIPSOpcode(Memory::ReadUnchecked_U32(curMips->pc)); // Replacements and similar are processed here, intentionally. - MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); const MIPSInstruction *instr = MIPSGetInstruction(op); // Check for breakpoint diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 57831a3cc5..4927975f02 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -130,7 +130,7 @@ void Jit::Comp_FPULS(MIPSOpcode op) { CheckMemoryBreakpoint(0, rs, offset); switch (op >> 26) { - case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 + case 49: // lwc1 { gpr.Lock(rs); fpr.SpillLock(ft); @@ -148,7 +148,7 @@ void Jit::Comp_FPULS(MIPSOpcode op) { fpr.ReleaseSpillLocks(); } break; - case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 + case 57: // swc1 { gpr.Lock(rs); fpr.SpillLock(ft); diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index d4d8129252..e5bf9232f2 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -247,7 +247,7 @@ void Jit::Comp_SV(MIPSOpcode op) { CheckMemoryBreakpoint(0, rs, imm); switch (op >> 26) { - case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); + case 50: // lv.s { gpr.Lock(rs); fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT); @@ -267,7 +267,7 @@ void Jit::Comp_SV(MIPSOpcode op) { } break; - case 58: //sv.s // Memory::Write_U32(VI(vt), addr); + case 58: // sv.s { gpr.Lock(rs); diff --git a/Core/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index c0644eb535..91ef1200b4 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -346,7 +346,7 @@ void JitSafeMem::IndirectCALL(const void *safeFunc) { void JitSafeMem::Finish() { - // Memory::Read_U32/etc. may have tripped coreState. + // Memory::ReadOrException_U32/etc. may have tripped coreState. if (needsCheck_ && !g_Config.bIgnoreBadMemAccess) jit_->js.afterOp |= JitState::AFTER_CORE_STATE; if (needsSkip_) @@ -365,18 +365,18 @@ void JitSafeMemFuncs::Init(ThunkManager *thunks) { BeginWrite(1024); readU32 = GetCodePtr(); - CreateReadFunc(32, (const void *)&Memory::Read_U32); + CreateReadFunc(32, (const void *)&Memory::ReadOrException_U32); readU16 = GetCodePtr(); - CreateReadFunc(16, (const void *)&Memory::Read_U16); + CreateReadFunc(16, (const void *)&Memory::ReadOrException_U16); readU8 = GetCodePtr(); - CreateReadFunc(8, (const void *)&Memory::Read_U8); + CreateReadFunc(8, (const void *)&Memory::ReadOrException_U8); writeU32 = GetCodePtr(); - CreateWriteFunc(32, (const void *)&Memory::Write_U32); + CreateWriteFunc(32, (const void *)&Memory::WriteOrException_U32); writeU16 = GetCodePtr(); - CreateWriteFunc(16, (const void *)&Memory::Write_U16); + CreateWriteFunc(16, (const void *)&Memory::WriteOrException_U16); writeU8 = GetCodePtr(); - CreateWriteFunc(8, (const void *)&Memory::Write_U8); + CreateWriteFunc(8, (const void *)&Memory::WriteOrException_U8); EndWrite(); } diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index a518e957c1..3cac1f45d8 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -519,10 +519,10 @@ void Memset(const u32 addr, const u8 value, const u32 size, const char *tag) { memset(ptr, value, size); } else { // TODO: This mainly seems to be produced by GPUCommon::PerformMemorySet, called from - // Replace_memset_jak(). Strangely, this managed to crash in Write_U8(). - for (size_t i = 0; i < size; i++) { - if (Memory::IsValidAddress(addr + (u32)i)) { - WriteUnchecked_U8(value, (u32)(addr + i)); + // Replace_memset_jak(). + if (Memory::IsValidRange(addr, size)) { + for (size_t i = 0; i < size; i++) { + Memory::WriteUnchecked_U8(value, (u32)(addr + i)); } } } diff --git a/Core/MemMap.h b/Core/MemMap.h index d0364a4acb..76c421f659 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -137,10 +137,9 @@ void Write_Opcode_JIT(const u32 _Address, const Opcode& _Value); Opcode Read_Instruction(const u32 _Address, bool resolveReplacements = false); Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = false); -u8 Read_U8(const u32 _Address); -u16 Read_U16(const u32 _Address); -u32 Read_U32(const u32 _Address); -u64 Read_U64(const u32 _Address); +u8 ReadOrException_U8(const u32 _Address); +u16 ReadOrException_U16(const u32 _Address); +u32 ReadOrException_U32(const u32 _Address); inline u8* GetPointerWriteUnchecked(const u32 address) { #ifdef MASKED_PSP_MEMORY @@ -238,14 +237,10 @@ inline void WriteUnchecked_U8(u8 data, u32 address) { #endif } -// used by JIT. Return zero-extended 32bit values -u32 Read_U8_ZX(const u32 address); -u32 Read_U16_ZX(const u32 address); - -void Write_U8(const u8 data, const u32 address); -void Write_U16(const u16 data, const u32 address); -void Write_U32(const u32 data, const u32 address); -void Write_U64(const u64 data, const u32 address); +void WriteOrException_U8(const u8 data, const u32 address); +void WriteOrException_U16(const u16 data, const u32 address); +void WriteOrException_U32(const u32 data, const u32 address); +void WriteOrException_U64(const u64 data, const u32 address); u8* GetPointerWrite(const u32 address); const u8* GetPointer(const u32 address); @@ -296,6 +291,9 @@ inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const MemcpyUnchecked(GetPointerWriteUnchecked(to_address), from_address, len); } +// Without a length, IsValidAddress is generally semi-meaningless, unless it's about a single byte access. For larger accesses, use IsValid4AlignedAddress +// etc when appropriate, or for longer sizes, use IsValidRange or IsValid4AlignedRange for example. Checking aligned-ness helps avoid the problem +// of reading past the last byte, say reading 4 bytes at offset 5 of a memory sized 8. inline bool IsValidAddress(const u32 address) { if ((address & 0x3E000000) == 0x08000000) { return true; @@ -338,7 +336,7 @@ inline bool IsValid4AlignedAddress(const u32 address) { } } -inline u32 MaxSizeAtAddress(const u32 address){ +inline u32 MaxSizeAtAddress(const u32 address) { if ((address & 0x3E000000) == 0x08000000) { return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF); } else if ((address & 0x3F800000) == 0x04000000) { diff --git a/Core/MemMapFunctions.cpp b/Core/MemMapFunctions.cpp index 756f4957c3..363a997f6d 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -124,19 +124,19 @@ bool IsScratchpadAddress(const u32 address) { return (address & 0xBFFFC000) == 0x00010000; } -u8 Read_U8(const u32 address) { +u8 ReadOrException_U8(const u32 address) { u8 value = 0; ReadMemoryOrRaiseException(value, address); return (u8)value; } -u16 Read_U16(const u32 address) { +u16 ReadOrException_U16(const u32 address) { u16_le value = 0; ReadMemoryOrRaiseException(value, address); return (u16)value; } -u32 Read_U32(const u32 address) { +u32 ReadOrException_U32(const u32 address) { u32_le value = 0; ReadMemoryOrRaiseException(value, address); return value; @@ -148,27 +148,19 @@ u64 Read_U64(const u32 address) { return value; } -u32 Read_U8_ZX(const u32 address) { - return (u32)Read_U8(address); -} - -u32 Read_U16_ZX(const u32 address) { - return (u32)Read_U16(address); -} - -void Write_U8(const u8 _Data, const u32 address) { +void WriteOrException_U8(const u8 _Data, const u32 address) { WriteMemoryOrRaiseException(address, _Data); } -void Write_U16(const u16 _Data, const u32 address) { +void WriteOrException_U16(const u16 _Data, const u32 address) { WriteMemoryOrRaiseException(address, _Data); } -void Write_U32(const u32 _Data, const u32 address) { +void WriteOrException_U32(const u32 _Data, const u32 address) { WriteMemoryOrRaiseException(address, _Data); } -void Write_U64(const u64 _Data, const u32 address) { +void WriteOrException_U64(const u64 _Data, const u32 address) { WriteMemoryOrRaiseException(address, _Data); } diff --git a/Core/Util/AtracTrack.cpp b/Core/Util/AtracTrack.cpp index 5ebf3f6170..e263c8d307 100644 --- a/Core/Util/AtracTrack.cpp +++ b/Core/Util/AtracTrack.cpp @@ -201,20 +201,11 @@ int AnalyzeAtracTrack(const u8 *buffer, u32 size, Track *track, std::string *err *error = StringFromFormat("smpl chunk too small for loop (%d, %d)", checkNumLoops, chunkSize); return SCE_ERROR_ATRAC_UNKNOWN_FORMAT; } - if (checkNumLoops < 0) { + u32 maxLoops = chunkSize >= 36 ? (chunkSize - 36) / 24 : 0; + if (checkNumLoops < 0 || checkNumLoops > maxLoops) { *error = StringFromFormat("bad checkNumLoops (%d)", checkNumLoops); return SCE_ERROR_ATRAC_UNKNOWN_FORMAT; } - // checkNumLoops is otherwise just an unvalidated field from the file - left - // unclamped, it could both drive an unbounded (up to ~2 billion entry) - // allocation here, and (since the loop below compares the loop counter `i` - // against chunkSize, rather than the byte offset actually being advanced by - // 24 per iteration) let reads run well past the end of this chunk. Clamp it - // to how many 24-byte loop entries could actually fit. - u32 maxLoops = chunkSize >= 36 ? (chunkSize - 36) / 24 : 0; - if ((u32)checkNumLoops > maxLoops) { - checkNumLoops = (int)maxLoops; - } track->loopinfo.resize(checkNumLoops); u32 loopinfoOffset = offset + 36; diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 13b61290b0..93adfe1e62 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -459,11 +459,11 @@ void BlockAllocator::DoState(PointerWrap &p) // A corrupt/malicious savestate could claim an enormous block count. Each // block needs at least sizeof(start)+sizeof(size)+sizeof(taken)+sizeof(tag) - // bytes in the stream, so clamp to what could plausibly still be there - // instead of always trying to allocate `count` Blocks up front. + // bytes in the stream. Reject totally outlandish values, and also if count is now sub-zero. size_t maxRemainingBlocks = p.Remaining() / (sizeof(u32) + sizeof(u32) + 1 + 32); if (count < 0) { count = 0; + p.SetError(PointerWrap::ERROR_FAILURE); } else if ((size_t)count > maxRemainingBlocks) { count = (int)maxRemainingBlocks; p.SetError(PointerWrap::ERROR_FAILURE); diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index e3d28df4a8..6fb7dd7e0a 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -156,7 +156,7 @@ void PPGeSetTexture(u32 dataAddr, int width, int height); //only 0xFFFFFF of data is used static void WriteCmd(u8 cmd, u32 data) { - Memory::Write_U32((cmd << 24) | (data & 0xFFFFFF), dlWritePtr); + Memory::WriteUnchecked_U32((cmd << 24) | (data & 0xFFFFFF), dlWritePtr); dlWritePtr += 4; _dbg_assert_(dlWritePtr <= dlPtr + dlSize); } diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 6b0d0ed57b..4b55d21ba3 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -159,7 +159,7 @@ uint32_t PackDepalBits(bool pixelMapped) { uint32_t val = BytesToUint32(indexMask, indexShift, indexOffset, format); // NOTE: This must follow similar logic to TextureCacheCommon::GetSamplingParams - // maybe we can share it somehow. - // TOOD: Handle replaced textures. + // TODO: Handle replaced textures. bool bilinear = gstate.isMagnifyFilteringEnabled() && !pixelMapped; switch (g_Config.iTexFiltering) { case TEX_FILTER_FORCE_NEAREST: diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 017102ca04..b954703332 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -434,7 +434,7 @@ void DumpExecute::Registers(u32 ptr, u32 sz) { } execListPos = execListBuf; - Memory::Write_U32(GE_CMD_NOP << 24, execListPos); + Memory::WriteUnchecked_U32(GE_CMD_NOP << 24, execListPos); execListPos += 4; // TODO: Why do we disable interrupts here? @@ -447,8 +447,8 @@ void DumpExecute::Registers(u32 ptr, u32 sz) { // Validate space for jump. u32 allocSize = pendingSize + sz + 8; if (execListPos + allocSize >= execListBuf + LIST_BUF_SIZE) { - Memory::Write_U32((GE_CMD_BASE << 24) | ((execListBuf >> 8) & 0x00FF0000), execListPos); - Memory::Write_U32((GE_CMD_JUMP << 24) | (execListBuf & 0x00FFFFFF), execListPos + 4); + Memory::WriteUnchecked_U32((GE_CMD_BASE << 24) | ((execListBuf >> 8) & 0x00FF0000), execListPos); + Memory::WriteUnchecked_U32((GE_CMD_JUMP << 24) | (execListBuf & 0x00FFFFFF), execListPos + 4); execListPos = execListBuf; lastBase_ = execListBuf & 0xFF000000; @@ -506,8 +506,8 @@ void DumpExecute::SubmitListEnd() { } // There's always space for the end, same size as a jump. - Memory::Write_U32(GE_CMD_FINISH << 24, execListPos); - Memory::Write_U32(GE_CMD_END << 24, execListPos + 4); + Memory::WriteUnchecked_U32(GE_CMD_FINISH << 24, execListPos); + Memory::WriteUnchecked_U32(GE_CMD_END << 24, execListPos + 4); execListPos += 8; for (int i = 0; i < 8; ++i) diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index 9046c29602..2cca5599ef 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -161,7 +161,12 @@ bool WavData::Read(RIFFReader &file_) { raw_data_size = numBytes; if (num_channels == 1 || num_channels == 2) { - file_.ReadData(raw_data, numBytes); + if (!file_.ReadData(raw_data, numBytes)) { + ERROR_LOG(Log::Audio, "Error - data chunk truncated"); + free(raw_data); + raw_data = nullptr; + return false; + } } else { ERROR_LOG(Log::Audio, "Error - bad blockalign or channels"); free(raw_data); @@ -187,15 +192,16 @@ bool WavData::Read(RIFFReader &file_) { // Turns out that AT3 files used for this are modified WAVE files so fairly easy to parse. class AT3PlusReader { public: - explicit AT3PlusReader(const std::string &data) - : file_((const uint8_t *)&data[0], (int32_t)data.size()) { + explicit AT3PlusReader(const std::string &data) : file_((const uint8_t *)&data[0], (int32_t)data.size()) { + if (!wave_.Read(file_)) { + ERROR_LOG(Log::Audio, "Error - could not read wave data"); + return; + } + // Normally 8k but let's be safe. buffer_ = new short[32 * 1024]; - skip_next_samples_ = 0; - wave_.Read(file_); - uint8_t *extraData = nullptr; size_t extraDataSize = 0; size_t blockSize = 0; diff --git a/UI/ImDebugger/ImDisasmView.cpp b/UI/ImDebugger/ImDisasmView.cpp index b4aaac9fbe..2e2e9d58d8 100644 --- a/UI/ImDebugger/ImDisasmView.cpp +++ b/UI/ImDebugger/ImDisasmView.cpp @@ -782,8 +782,10 @@ void ImDisasmView::PopupMenu(ImControl &control) { assembleOpcode(curAddress_, ""); } if (ImGui::MenuItem("NOP instructions (destructive)")) { - for (u32 addr = selectRangeStart_; addr < selectRangeEnd_; addr += 4) { - Memory::Write_U32(0, addr); + if (Memory::IsValid4AlignedRange(selectRangeStart_, selectRangeEnd_ - selectRangeStart_)) { + for (u32 addr = selectRangeStart_; addr < selectRangeEnd_; addr += 4) { + Memory::WriteUnchecked_U32(0, addr); + } } if (currentMIPS) { currentMIPS->InvalidateICache(selectRangeStart_, selectRangeEnd_ - selectRangeStart_); diff --git a/UI/ImDebugger/ImStructViewer.cpp b/UI/ImDebugger/ImStructViewer.cpp index 94d69ffc8c..4416c14dd6 100644 --- a/UI/ImDebugger/ImStructViewer.cpp +++ b/UI/ImDebugger/ImStructViewer.cpp @@ -718,7 +718,7 @@ void ImStructViewer::DrawType( } case POINTER: { const bool nodeOpen = ImGui::TreeNodeEx("Pointer", extraTreeNodeFlags, "%s", name); - const u32 pointer = Memory::Read_U32(address); + const u32 pointer = Memory::ReadUnchecked_U32(address); const u64 pointer64 = pointer; DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchId, &pointer64); DrawTypeColumn("%s", typeDisplayName, base, offset); diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 214f64cd88..2fcde81d91 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -954,8 +954,10 @@ void CtrlDisAsmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) { // Route the memory writes to the CPU thread instead of poking at it directly from this GUI // thread - see Core_RunOnCPUThread() in Core.h. Core_RunOnCPUThread([&] { - for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) { - Memory::Write_U32(0, addr); + if (Memory::IsValidRange(selectRangeStart, selectRangeEnd - selectRangeStart)) { + for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) { + Memory::WriteUnchecked_U32(0, addr); + } } if (currentMIPS) { diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index f467d198ed..b0fd096ccd 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -338,11 +338,12 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) char *temp = new char[space]; char *p = temp, *end = temp + space; - for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize) - { - u32 opcode = Memory::Read_U32(pos); - GPUDebugOp op = gpu->DisassembleOp(pos, opcode); - p += snprintf(p, end - p, "%s\r\n", op.desc.c_str()); + if (Memory::IsValid4AlignedRange(selectRangeStart, selectRangeEnd - selectRangeStart)) { + for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize) { + u32 opcode = Memory::ReadUnchecked_U32(pos); + GPUDebugOp op = gpu->DisassembleOp(pos, opcode); + p += snprintf(p, end - p, "%s\r\n", op.desc.c_str()); + } } W32Util::CopyTextToClipboard(wnd, temp); diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 9c3481c50f..6cac289170 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -77,10 +77,12 @@ static void BindPreviewProgram(GLSLProgram *&prog) { u32 CGEDebugger::PrimPreviewOp() { DisplayList list; if (gpu != nullptr && gpu->GetCurrentDisplayList(list)) { - const u32 op = Memory::Read_U32(list.pc); - const u32 cmd = op >> 24; - if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { - return op; + if (Memory::IsValid4AlignedAddress(list.pc)) { + const u32 op = Memory::ReadUnchecked_U32(list.pc); + const u32 cmd = op >> 24; + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { + return op; + } } } return 0;