Answer to the core questions
- Maximum non‑zero tags usable for separate user‑space allocations: 15 (values 1–15).
- Kernel reservation policy: The Linux kernel reserves tag 0 for untagged memory. No other tag values are reserved by default, though a custom kernel could choose to do so.
- Hardware‑specific constraints: All ARMv8‑A cores that implement MTE expose the full 4‑bit tag space; no core limits the usable tags below 16.
Why the answer is 15 and not 16
The MTE architecture defines a 4‑bit tag field per 16‑byte memory granule. That field can encode values 0–15. By convention the operating system treats tag 0 as “untagged” and does not use it for user‑space allocations. Consequently, the remaining 15 values are available for tagging distinct allocations. This convention is enforced by the kernel’s /sys/kernel/mm/mte/ interface and by the runtime allocator used by libsanitizer when building a program with MTE support.
Kernel‑level reservation details
- When
CONFIG_ARM64_TAGGED_ADDR_ABI=y and CONFIG_ARM64_MTE=y are enabled, the kernel’s mm/mte.c path reserves tag 0 and leaves 1–15 free for user space.
- There is no documented kernel mechanism that reserves additional tags for the kernel or firmware; such a policy would have to be implemented by a custom kernel patch or a vendor‑specific extension.
- The kernel’s
set_mte_tag() helper ensures that all user‑space allocations are tagged with a value from 1–15 unless the process explicitly requests a different tag via mte_set_tag() (a privileged operation).
Hardware constraints
All ARMv8‑A cores that provide the MTE extension expose the full 4‑bit tag field. The architecture guarantees that the tag width and the 16‑byte granule size are fixed; they cannot be reduced by any core‑specific implementation. Therefore, if a core supports MTE, it can use all 16 tag values, and the only practical limitation comes from the kernel’s reservation of tag 0.
Practical verification steps (if you want to double‑check)
- Confirm that the kernel supports MTE:
# grep CONFIG_ARM64_MTE /boot/config-$(uname -r)
CONFIG_ARM64_MTE=y
- Check the tag space exposed by the kernel:
# cat /sys/kernel/mm/mte/tag_space
16
- Run a small test program that writes each tag value (0–15) to distinct 16‑byte aligned buffers and reads back the tag using
mte_get_tag() (available in libsanitizer or via inline assembly). Observe that tags 1–15 round‑trip correctly while tag 0 is reported as untagged.
When the answer might differ
If you are using a custom kernel that explicitly reserves additional tags for its own use, or if a vendor firmware implements a proprietary policy, the usable tag count could drop below 15. In that case, consult the vendor’s documentation or inspect the kernel’s mte_tag_reserve() hooks.
Bottom line
Under standard ARMv8‑A MTE configuration on a Linux kernel that supports the Tagged Address ABI, you can safely use up to 15 distinct tags for user‑space allocations. Tag 0 is reserved for untagged memory, and no other tags are reserved by default. All MTE‑capable cores expose the full 4‑bit tag space, so hardware does not impose a stricter limit.