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/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/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 5e56c3d2b6..b609955fb4 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; } @@ -1489,9 +1512,12 @@ static int Hook_starocean_clear_framebuf_after() { } 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; + } + u32 fb_address = Memory::ReadUnchecked_U32(currentMIPS->r[MIPS_REG_A0] + 0x18); + u32 fb_height = Memory::ReadUnchecked_U16(currentMIPS->r[MIPS_REG_A0] + 0x26); + 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; @@ -1529,8 +1555,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 +1798,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 +1837,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 +1849,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 +1861,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; } } 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/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/sceIo.cpp b/Core/HLE/sceIo.cpp index 3641881906..2f6bc89547 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. @@ -1785,8 +1785,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 +1813,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 +1836,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 +1897,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 +1924,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 +1946,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"); @@ -1974,8 +1974,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 +1987,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; @@ -2503,6 +2503,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()) { @@ -2515,7 +2519,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) { @@ -2530,17 +2534,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)); } } } @@ -2715,9 +2719,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); @@ -2746,10 +2750,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); diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 18581860f0..1129d228ed 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -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; 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..d9670519fb 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -61,8 +61,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 +92,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 +150,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; } @@ -276,11 +272,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 +311,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 +351,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 +378,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); + if (wokeThreads) { Memory::Write_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 +428,88 @@ 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) { + if (!Memory::IsValid4AlignedAddress(packetAddrPtr)) { + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR); + } + if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR); + } + 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) { + if (!Memory::IsValid4AlignedAddress(packetAddrPtr)) { + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR); + } + if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR); + } + 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; @@ -557,8 +534,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..aff2d78aa9 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -629,58 +629,62 @@ 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) { + if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid timeout ptr"); + } + 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::WriteUnchecked_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) { + if (timeoutPtr && !Memory::IsValid4AlignedAddress(timeoutPtr)) { + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid timeout ptr"); + } + 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::WriteUnchecked_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 +692,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::Write_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); } } @@ -1355,11 +1359,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); @@ -1593,8 +1598,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 +1633,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) { @@ -1709,8 +1714,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 +1899,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 3b0212eb64..af9ca91efe 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -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; diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index 9860d11372..0f4967af97 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -708,11 +708,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); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index f2610be215..165e1b96bc 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -2014,7 +2014,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 +2031,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); } diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 7544876ab9..4c6a440ed5 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -320,9 +320,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/sceNet.cpp b/Core/HLE/sceNet.cpp index d54520b499..b3ee54fda4 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -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"); diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 2cb4264d06..457480f8b1 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -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"); } @@ -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,9 +6209,10 @@ 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) @@ -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::Read_U32(netAdhocDiscoverBufAddr + 0x80) > 0 && (Memory::Read_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::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); + 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::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; 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::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; // 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/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/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..82db90b86f 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -729,12 +729,11 @@ static int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks) static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) { - if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) - { + 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{}; @@ -766,7 +765,7 @@ static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) static int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears) { - if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) { + if (!Memory::IsValid4AlignedRange(destTickPtr, 8) || !Memory::IsValid4AlignedRange(srcTickPtr, 8)) { return hleLogWarning(Log::sceRtc, -1, "invalid address"); } @@ -973,9 +972,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 +1002,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 +1036,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 +1049,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 +1073,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 +1086,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/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/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..021d1f7f7b 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); 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/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..29bca2d6d6 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -140,7 +140,6 @@ Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = u8 Read_U8(const u32 _Address); u16 Read_U16(const u32 _Address); u32 Read_U32(const u32 _Address); -u64 Read_U64(const u32 _Address); inline u8* GetPointerWriteUnchecked(const u32 address) { #ifdef MASKED_PSP_MEMORY @@ -238,10 +237,6 @@ 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); @@ -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..c2ef321593 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -148,14 +148,6 @@ 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) { WriteMemoryOrRaiseException(address, _Data); } 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/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;