mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Tests: stop the DXSTG write-back check skipping on 16K-page hosts
MapAt's candidate addresses are 4K-aligned and none is 16K-aligned, so on a 16K-page kernel -- Asahi, Apple Silicon, some Android, and one of our own CI jobs -- the kernel rejects every one of them and the mapping fails. The write-back check treated that as a precondition and skipped outright, which took its guest-side assertions with it: the ones that actually pin where a DXSTG-steered eviction lands, none of which need anything from the host. The mapping is only the negative control, there to show the write-back did not ALSO reach the host page carrying the same number. Make it optional. The guest-side half now runs everywhere and only the control drops out. DxstgDirtyStaysInsideGuestMemory still skips, and should: it is entirely about the host page. That leaves one skip here on a 16K-page host instead of two, and none at all on a 4K one.
This commit is contained in:
@@ -145,10 +145,14 @@ u32 Obs(int id, const char* name)
|
|||||||
// process. Elsewhere the two callers skip.
|
// process. Elsewhere the two callers skip.
|
||||||
//
|
//
|
||||||
// The candidates are 4K-aligned but none is 16K-aligned, so on a 16K-page
|
// The candidates are 4K-aligned but none is 16K-aligned, so on a 16K-page
|
||||||
// kernel — Asahi, Apple Silicon, some Android — every one is rejected outright
|
// kernel — Asahi, Apple Silicon, some Android — every one is rejected outright.
|
||||||
// and the two callers always skip. Re-picking them 16K-aligned would need the
|
// Re-picking them 16K-aligned would need the tag/index constraints re-derived
|
||||||
// tag/index constraints re-derived against the console capture, so it is left
|
// against the console capture, so it is left to whoever holds that data.
|
||||||
// to whoever holds that data.
|
//
|
||||||
|
// A null return is therefore routine, not exceptional, and callers should treat
|
||||||
|
// the mapping as an optional negative control rather than a precondition. Only
|
||||||
|
// DxstgDirtyStaysInsideGuestMemory is wholly about the host page and has to
|
||||||
|
// skip; the write-back check keeps its guest-side half running everywhere.
|
||||||
void* MapAt(u32* chosen)
|
void* MapAt(u32* chosen)
|
||||||
{
|
{
|
||||||
#if defined(MAP_FIXED_NOREPLACE)
|
#if defined(MAP_FIXED_NOREPLACE)
|
||||||
@@ -439,14 +443,22 @@ TEST(EeCache2Console, DxstgWriteBackTargetsTheTaggedGuestPage)
|
|||||||
constexpr u32 kTargetPage = 0x00129000;
|
constexpr u32 kTargetPage = 0x00129000;
|
||||||
constexpr u32 kTarget = kTargetPage + kSetIndex * 64;
|
constexpr u32 kTarget = kTargetPage + kSetIndex * 64;
|
||||||
|
|
||||||
|
// The host mapping is only the negative control: proof that the write-back
|
||||||
|
// did not ALSO reach the host page that happens to carry the same number.
|
||||||
|
// Everything else here is guest-side and needs nothing from the host, so it
|
||||||
|
// runs unconditionally. On a 16K-page kernel -- Asahi, Apple Silicon, some
|
||||||
|
// Android -- MapAt cannot honour a 4K-aligned request and returns null;
|
||||||
|
// only the control is skipped then, not the whole test.
|
||||||
u32 page = 0;
|
u32 page = 0;
|
||||||
void* p = MapAt(&page);
|
void* p = MapAt(&page);
|
||||||
if (!p)
|
const u32* host = nullptr;
|
||||||
GTEST_SKIP() << "could not map a page at any candidate host address";
|
if (p)
|
||||||
ASSERT_EQ(page, kTargetPage) << "the control page moved; re-point kTargetPage";
|
{
|
||||||
std::memset(p, 0xEE, 0x1000);
|
ASSERT_EQ(page, kTargetPage) << "the control page moved; re-point kTargetPage";
|
||||||
const u32* host = reinterpret_cast<const u32*>(
|
std::memset(p, 0xEE, 0x1000);
|
||||||
static_cast<uptr>(page) + kSetIndex * 64);
|
host = reinterpret_cast<const u32*>(
|
||||||
|
static_cast<uptr>(page) + kSetIndex * 64);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
EeRecTestHarness h;
|
EeRecTestHarness h;
|
||||||
@@ -463,7 +475,8 @@ TEST(EeCache2Console, DxstgWriteBackTargetsTheTaggedGuestPage)
|
|||||||
// 64 bytes of guest cache line, at the guest physical page the tag names.
|
// 64 bytes of guest cache line, at the guest physical page the tag names.
|
||||||
EXPECT_EQ(memRead32(kTarget), 0x5A5A0009u);
|
EXPECT_EQ(memRead32(kTarget), 0x5A5A0009u);
|
||||||
EXPECT_EQ(memRead32(kTarget + 4), 0xDEADBEEFu);
|
EXPECT_EQ(memRead32(kTarget + 4), 0xDEADBEEFu);
|
||||||
EXPECT_EQ(host[0], 0xEEEEEEEEu) << "the write-back still reaches a host address";
|
if (host)
|
||||||
|
EXPECT_EQ(host[0], 0xEEEEEEEEu) << "the write-back still reaches a host address";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never filled, and filled-then-invalidated. Both used to be declined
|
// Never filled, and filled-then-invalidated. Both used to be declined
|
||||||
@@ -471,7 +484,8 @@ TEST(EeCache2Console, DxstgWriteBackTargetsTheTaggedGuestPage)
|
|||||||
for (const bool invalidate_first : {false, true})
|
for (const bool invalidate_first : {false, true})
|
||||||
{
|
{
|
||||||
SCOPED_TRACE(invalidate_first ? "filled then invalidated" : "never filled");
|
SCOPED_TRACE(invalidate_first ? "filled then invalidated" : "never filled");
|
||||||
std::memset(p, 0xEE, 0x1000);
|
if (p)
|
||||||
|
std::memset(p, 0xEE, 0x1000);
|
||||||
EeRecTestHarness h;
|
EeRecTestHarness h;
|
||||||
resetCache();
|
resetCache();
|
||||||
memWrite32(kTarget, 0xA5A5A5A5u);
|
memWrite32(kTarget, 0xA5A5A5A5u);
|
||||||
@@ -489,10 +503,12 @@ TEST(EeCache2Console, DxstgWriteBackTargetsTheTaggedGuestPage)
|
|||||||
RunCacheOp(0x12, kProbeLine);
|
RunCacheOp(0x12, kProbeLine);
|
||||||
RunCacheOp(0x14, kProbeLine);
|
RunCacheOp(0x14, kProbeLine);
|
||||||
EXPECT_EQ(memRead32(kTarget), 0u) << "the cleared line did not write back";
|
EXPECT_EQ(memRead32(kTarget), 0u) << "the cleared line did not write back";
|
||||||
EXPECT_EQ(host[0], 0xEEEEEEEEu) << "the write-back still reaches a host address";
|
if (host)
|
||||||
|
EXPECT_EQ(host[0], 0xEEEEEEEEu) << "the write-back still reaches a host address";
|
||||||
}
|
}
|
||||||
|
|
||||||
munmap(p, 0x1000);
|
if (p)
|
||||||
|
munmap(p, 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A DXSTG naming a page that does not resolve to plain guest memory leaves the
|
// A DXSTG naming a page that does not resolve to plain guest memory leaves the
|
||||||
|
|||||||
Reference in New Issue
Block a user