mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
kernel: implement syscall 0x83 FindAddress + unit tests (#93)
This commit is contained in:
committed by
GitHub
parent
493522a769
commit
9e4fd794c1
@@ -286,6 +286,9 @@ namespace ps2_syscalls
|
||||
case static_cast<uint32_t>(-0x78):
|
||||
ps2_stubs::sceSifSetDChain(rdram, ctx, runtime);
|
||||
return true;
|
||||
case 0x83:
|
||||
FindAddress(rdram, ctx, runtime);
|
||||
return true;
|
||||
case 0x85:
|
||||
SetMemoryMode(rdram, ctx, runtime);
|
||||
return true;
|
||||
|
||||
@@ -355,6 +355,59 @@ void GetMemorySize(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
setReturnU32(ctx, PS2_RAM_SIZE);
|
||||
}
|
||||
|
||||
static inline uint32_t normalizeKernelAlias(uint32_t addr)
|
||||
{
|
||||
if (addr >= 0x80000000u && addr < 0xC0000000u)
|
||||
{
|
||||
return addr & 0x1FFFFFFFu;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
// 0x83 FindAddress:
|
||||
// - a0: table start (inclusive)
|
||||
// - a1: table end (exclusive)
|
||||
// - a2: target address to locate inside the table (word entries)
|
||||
// Returns the guest address of the matching word entry, or 0 if not found.
|
||||
void FindAddress(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
{
|
||||
(void)runtime;
|
||||
|
||||
uint32_t start = getRegU32(ctx, 4);
|
||||
uint32_t end = getRegU32(ctx, 5);
|
||||
const uint32_t target = getRegU32(ctx, 6);
|
||||
const uint32_t targetNorm = normalizeKernelAlias(target);
|
||||
|
||||
// Word-scan semantics: align the search window to uint32 boundaries.
|
||||
start = (start + 3u) & ~0x3u;
|
||||
end &= ~0x3u;
|
||||
|
||||
if (start >= end)
|
||||
{
|
||||
setReturnU32(ctx, 0u);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t addr = start; addr < end; addr += sizeof(uint32_t))
|
||||
{
|
||||
const uint8_t *entryPtr = getConstMemPtr(rdram, addr);
|
||||
if (!entryPtr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t entry = 0;
|
||||
std::memcpy(&entry, entryPtr, sizeof(entry));
|
||||
if (entry == target || normalizeKernelAlias(entry) == targetNorm)
|
||||
{
|
||||
setReturnU32(ctx, addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setReturnU32(ctx, 0u);
|
||||
}
|
||||
|
||||
void Deci2Call(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime)
|
||||
{
|
||||
(void)rdram;
|
||||
|
||||
@@ -386,5 +386,72 @@ void register_ps2_runtime_kernel_tests()
|
||||
const uint32_t setupSp = static_cast<uint32_t>(getRegS32(env.ctx, 2));
|
||||
t.Equals(setupSp & 0xFu, 0u, "SetupThread should always return a 16-byte aligned stack pointer");
|
||||
});
|
||||
|
||||
tc.Run("numeric syscall 0x83 finds matching table entry", [](TestCase &t)
|
||||
{
|
||||
TestEnv env;
|
||||
constexpr uint32_t kTableBase = 0x00002000u;
|
||||
constexpr uint32_t kValues[] = {
|
||||
0x11111111u,
|
||||
0x11223344u,
|
||||
0x55555555u,
|
||||
0x89ABCDEFu
|
||||
};
|
||||
|
||||
writeGuestWords(env.rdram.data(), kTableBase, kValues, std::size(kValues));
|
||||
setRegU32(env.ctx, 4, kTableBase);
|
||||
setRegU32(env.ctx, 5, kTableBase + static_cast<uint32_t>(sizeof(kValues)));
|
||||
setRegU32(env.ctx, 6, 0x11223344u);
|
||||
|
||||
t.IsTrue(callSyscall(0x83u, env.rdram.data(), &env.ctx, &env.runtime),
|
||||
"syscall 0x83 should dispatch");
|
||||
t.Equals(static_cast<uint32_t>(getRegS32(env.ctx, 2)),
|
||||
kTableBase + 4u,
|
||||
"FindAddress should return address of first matching word");
|
||||
});
|
||||
|
||||
tc.Run("numeric syscall 0x83 supports KSEG aliases", [](TestCase &t)
|
||||
{
|
||||
TestEnv env;
|
||||
constexpr uint32_t kTableBasePhys = 0x00003000u;
|
||||
constexpr uint32_t kTableBaseKseg = 0x80003000u;
|
||||
constexpr uint32_t kValues[] = {
|
||||
0x00123456u,
|
||||
0x8000AAAAu
|
||||
};
|
||||
|
||||
writeGuestWords(env.rdram.data(), kTableBasePhys, kValues, std::size(kValues));
|
||||
setRegU32(env.ctx, 4, kTableBaseKseg);
|
||||
setRegU32(env.ctx, 5, kTableBaseKseg + static_cast<uint32_t>(sizeof(kValues)));
|
||||
setRegU32(env.ctx, 6, 0x80123456u); // Alias of first table value
|
||||
|
||||
t.IsTrue(callSyscall(0x83u, env.rdram.data(), &env.ctx, &env.runtime),
|
||||
"syscall 0x83 should dispatch");
|
||||
t.Equals(static_cast<uint32_t>(getRegS32(env.ctx, 2)),
|
||||
kTableBaseKseg,
|
||||
"FindAddress should match KSEG aliases and preserve guest segment in return value");
|
||||
});
|
||||
|
||||
tc.Run("numeric syscall 0x83 returns 0 when entry is absent", [](TestCase &t)
|
||||
{
|
||||
TestEnv env;
|
||||
constexpr uint32_t kTableBase = 0x00004000u;
|
||||
constexpr uint32_t kValues[] = {
|
||||
0x00000001u,
|
||||
0x00000002u,
|
||||
0x00000003u
|
||||
};
|
||||
|
||||
writeGuestWords(env.rdram.data(), kTableBase, kValues, std::size(kValues));
|
||||
setRegU32(env.ctx, 4, kTableBase);
|
||||
setRegU32(env.ctx, 5, kTableBase + static_cast<uint32_t>(sizeof(kValues)));
|
||||
setRegU32(env.ctx, 6, 0xDEADBEEFu);
|
||||
|
||||
t.IsTrue(callSyscall(0x83u, env.rdram.data(), &env.ctx, &env.runtime),
|
||||
"syscall 0x83 should dispatch");
|
||||
t.Equals(static_cast<uint32_t>(getRegS32(env.ctx, 2)),
|
||||
0u,
|
||||
"FindAddress should return 0 when no matching word exists");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user