kernel: implement syscall 0x83 FindAddress + unit tests (#93)

This commit is contained in:
Antonio Guastella
2026-03-06 16:55:34 +01:00
committed by GitHub
parent 493522a769
commit 9e4fd794c1
3 changed files with 123 additions and 0 deletions
+3
View File
@@ -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;
+67
View File
@@ -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");
});
});
}