[PATCH v9 06/12] iommu/arm-smmu-v3-kexec: Add a CD table parse helper
Nicolin Chen <[email protected]>
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <dc0d53df95a890ce95399a0e799160da41fa1551.1784663184.git.nicolinc@nvidia.com> |
An S1 STE points to a CD table that both of the kexec flavors decode: the kdump adoption scans the CD table to reserve all the in-use ASIDs, and the live-update restoration claims the CD table via the KHO restore API. Add another read-only helper to the arm-smmu-v3-kexec.c: - arm_smmu_kexec_check_ste_cdtab() It validates the CD table geometry in an S1 STE against this kernel's own ssid_bits and the 2-level HW capability. And it accepts a linear CD table on the 2-level capable HW too, since a previous kernel might have used one, like the linear stream table. Assisted-by: Claude:claude-fable-5 Signed-off-by: Nicolin Chen <[email protected]> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 ++ .../iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c | 42 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 6ef307335d80c..183c617ecb273 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -1249,6 +1249,9 @@ int arm_smmu_kexec_parse_strtab_linear(struct arm_smmu_device *smmu, int arm_smmu_kexec_check_strtab_l1_desc(struct arm_smmu_device *smmu, u64 l1_desc, u32 idx, phys_addr_t *l2_base); +int arm_smmu_kexec_check_ste_cdtab(struct arm_smmu_device *smmu, u64 ste0, + phys_addr_t *cdtab, u32 *s1fmt, + u32 *max_contexts); #endif /* CONFIG_ARM_SMMU_V3_KEXEC */ #ifdef CONFIG_CRASH_DUMP diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c index 5346132529427..5ad1fe1922eec 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c @@ -157,3 +157,45 @@ int arm_smmu_kexec_check_strtab_l1_desc(struct arm_smmu_device *smmu, *l2_base = base; return 0; } + +/** + * arm_smmu_kexec_check_ste_cdtab() - Decode the CD table geometry of an STE + * @smmu: SMMU device of this kernel + * @ste0: first 64 bits of the previous kernel's S1 STE + * @cdtab: pointer to return the CD table's physical address + * @s1fmt: pointer to return the CD table format + * @max_contexts: pointer to return the number of CDs + * + * Note that a linear CD table on the 2-level capable hardware is accepted, as a + * previous kernel might have used one, like the linear stream table. + * + * Also, as the CD tables are supposed to be read-only, @cdtab is not validated + * against the table size, but only carries the field's own 64-byte alignment. + * + * Return: 0 on success with the three outputs set, or -EINVAL on a bad geometry + */ +int arm_smmu_kexec_check_ste_cdtab(struct arm_smmu_device *smmu, u64 ste0, + phys_addr_t *cdtab, u32 *s1fmt, + u32 *max_contexts) +{ + phys_addr_t base = ste0 & STRTAB_STE_0_S1CTXPTR_MASK; + u32 s1cdmax = FIELD_GET(STRTAB_STE_0_S1CDMAX, ste0); + u32 fmt = FIELD_GET(STRTAB_STE_0_S1FMT, ste0); + + if (!base || s1cdmax > smmu->ssid_bits) + return -EINVAL; + + if (fmt != STRTAB_STE_0_S1FMT_LINEAR && + fmt != STRTAB_STE_0_S1FMT_64K_L2) + return -EINVAL; + + /* Both kernels run on the same HW, so a genuine STE never has this */ + if (fmt == STRTAB_STE_0_S1FMT_64K_L2 && + !(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB)) + return -EINVAL; + + *cdtab = base; + *s1fmt = fmt; + *max_contexts = 1U << s1cdmax; + return 0; +} -- 2.43.0