Skip to content

Add tests for TLB overlap cases#36

Open
Brian Cain (androm3da) wants to merge 6 commits into
qualcomm:mainfrom
androm3da:main
Open

Add tests for TLB overlap cases#36
Brian Cain (androm3da) wants to merge 6 commits into
qualcomm:mainfrom
androm3da:main

Conversation

@androm3da

Copy link
Copy Markdown
Member

No description provided.

@androm3da

Copy link
Copy Markdown
Member Author

}

/// Build a TLB hi word for a 4MB page with correct V/G encoding.
fn make_tlb_hi_vg_4m(vpn_1m: u32, asid: u32, global: bool) -> u32 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know rust, but is there a reason to define this function instead of using make_tlb_hi_vg directly?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came to the same conclusion. make_tlb_hi_vg_4m isn't used anywhere and even if it was, it's a wrapper without any additional functionality.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed make_tlb_hi_vg_4m in be3a4f7

hi = in(reg) hi,
lo = in(reg) lo,
idx = in(reg) idx,
res = out(reg) result,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe match the result variable names? Either res or result for both. Not important, but got me confused for a second.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency I applied this more generally hexagon-arch-tests: match inline asm operand names to their bindings.

/// entry. Returns overlapping index, 0x8000_0000 (none), or 0xFFFF_FFFF
/// (multiple overlaps). Does NOT write.
#[inline(always)]
fn tlboc(hi: u32, lo: u32) -> u32 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there intrinsics for those helpers?

@androm3da Brian Cain (androm3da) Jul 20, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No intrinsics for tlboc or ctlbw -- yet.

I lobbied for some new intrinsics recently and the architecture team was on board. So if we want these we could push for 'em.

Rename the named asm! template operands (`res`) to match their Rust
variable names (`result`, `val`) in iassignr, tlb_probe, and
memw_phys_read. This follows the idiom used elsewhere in the Rust
ecosystem (e.g. compiler-builtins' arm_linux atomics) where the
operand name and the bound variable share a name, avoiding a
gratuitous res/result split.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Add 11 new tests to test_tlb_mmu.rs covering overlapping TLB entry
detection via ctlbw and tlboc instructions: no-overlap, single overlap,
multiple overlaps, global-entry semantics, ASID isolation, page-size-aware
range checking, invalid-entry exclusion, and incoming G-bit behavior.

Introduces make_tlb_hi_vg() helper with correct V/G bit placement in the
TLB register pair hi word (existing make_tlb_hi always sets G=1).

All 20 tests pass on hexagon-sim, SDK QEMU, and local QEMU build.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Add 4 tests that assert multi-TLB-match raises NMI with cause 0x44
(IMPRECISE_CAUSE_MULTI_TLB_MATCH). These pass on hexagon-sim and
fail on QEMU, which silently resolves overlaps without raising
the imprecise exception.

The NMI handler in crt0.S now records cause/count and returns via
rte instead of jumping to coredump.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
The page size of a TLB entry is the position of the lowest set bit of
the PPD field, lo[23:0].

tlboc forces the valid bit on for the value it is handed, so probing with
an empty PPD reaches the decoder directly. An empty PPD field is not a
size architecture defines a result for, so this test pins expected/
desired behavior for an undefined case: treat such an entry as covering
one small page at its own VPN rather than the whole address space. The
test installs an unrelated mapping elsewhere and requires the probe not
to collide with it. A wrongly-inflated page overlaps everything and
tlboc reports a multi-hit.

The existing invalid-entry coverage does not reach this. tlb_invalidate()
writes all zeroes, which is easy to special-case; a kernel parking a
bookkeeping word in a spare slot is not.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
…read

test_ctlbw_ignores_invalid_entries clears the slot with tlb_invalidate(),
which writes all zeroes -- a shape an implementation can skip with a
single check for a zero entry, without ever consulting the valid bit.
A kernel that parks a bookkeeping word in a spare TLB slot leaves
something quite different behind: non-zero in both words, V=0.

Park such a value and require an unrelated ctlbw to succeed. The PPD
field is set to encode the largest page size, a perfectly legal encoding,
so an implementation that reads the slot's span before testing its
validity sees an entry covering the whole address space and rejects the
write. That makes the check independent of how out-of-range sizes are
handled.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Bit 27 of the lo word is HSV39, a flag distinct from the cache-attribute
field (CCC). It only takes effect for HSV39 entries, which occupy a
separate range of TLB indices starting at 512; entries below that index
are always legacy 38-bit entries and must be interpreted as such
regardless of what value HSV39 carries.

Every existing entry in this suite is built by make_tlb_lo(), which
never sets bit 27, so nothing covered the case. Write an entry, at a
legacy-range index, that is identical to the ones the other tests use
apart from that bit, and require a probe for its address to find it.
An implementation that treats bit 27 as an addressing-mode selector for
this entry places it at VPN << 20 instead and the probe misses.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
@androm3da

Copy link
Copy Markdown
Member Author

Addressed the comments and added more TLB cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants