| 1 | /* |
| 2 | * QOS SMMUv3 Module |
| 3 | * |
| 4 | * This module provides SMMUv3-specific helper functions for libqos tests, |
| 5 | * encapsulating SMMUv3 setup, and assertions. |
| 6 | * |
| 7 | * Copyright (c) 2026 Phytium Technology |
| 8 | * |
| 9 | * Author: |
| 10 | * Tao Tang <tangtao1634@phytium.com.cn> |
| 11 | * |
| 12 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 13 | */ |
| 14 | |
| 15 | #ifndef QTEST_LIBQOS_SMMUV3_H |
| 16 | #define QTEST_LIBQOS_SMMUV3_H |
| 17 | |
| 18 | #include "hw/misc/iommu-testdev.h" |
| 19 | |
| 20 | /* |
| 21 | * SMMU MMIO register base for virt machine-wide SMMU. This does not |
| 22 | * apply to user-creatable device such as -device arm-smmuv3. |
| 23 | */ |
| 24 | #define VIRT_SMMU_BASE 0x0000000009050000ull |
| 25 | |
| 26 | /* SMMU queue and table base addresses */ |
| 27 | #define QSMMU_CMDQ_BASE_ADDR 0x000000000e16b000ull |
| 28 | #define QSMMU_EVENTQ_BASE_ADDR 0x000000000e170000ull |
| 29 | |
| 30 | /* |
| 31 | * Translation tables and descriptors for a mapping of |
| 32 | * - IOVA (Stage 1 only or nested translation stage) |
| 33 | * - IPA (Stage 2 only) |
| 34 | * to GPA. |
| 35 | * |
| 36 | * The translation is based on the Arm architecture with the following |
| 37 | * prerequisites: |
| 38 | * - Granule size: 4KB pages. |
| 39 | * - Page table levels: 4 levels (L0, L1, L2, L3), starting at level 0. |
| 40 | * - IOVA size: The walk resolves a IOVA: 0x8080604567 |
| 41 | * - Address space: The 4-level lookup with 4KB granules supports up to a |
| 42 | * 48-bit (256TB) virtual address space. Each level uses a 9-bit index |
| 43 | * (512 entries per table). The breakdown is: |
| 44 | * - L0 index: IOVA bits [47:39] |
| 45 | * - L1 index: IOVA bits [38:30] |
| 46 | * - L2 index: IOVA bits [29:21] |
| 47 | * - L3 index: IOVA bits [20:12] |
| 48 | * - Page offset: IOVA bits [11:0] |
| 49 | * |
| 50 | * NOTE: All physical addresses defined here (QSMMU_VTTB, table addresses, etc.) |
| 51 | * appear to be within a secure RAM region. In practice, an offset is added |
| 52 | * to these values to place them in non-secure RAM. For example, when running |
| 53 | * in a virt machine type, the RAM base address (e.g., 0x40000000) is added to |
| 54 | * these constants. |
| 55 | */ |
| 56 | #define QSMMU_IOVA 0x0000008080604567ull |
| 57 | #define QSMMU_VTTB 0x000000000e4d0000ull |
| 58 | #define QSMMU_STR_TAB_BASE 0x000000000e179000ull |
| 59 | #define QSMMU_CD_GPA (QSMMU_STR_TAB_BASE - 0x40ull) |
| 60 | |
| 61 | |
| 62 | #define QSMMU_L0_PTE_VAL 0x000000000e4d1000ull |
| 63 | #define QSMMU_L1_PTE_VAL 0x000000000e4d2000ull |
| 64 | #define QSMMU_L2_PTE_VAL 0x000000000e4d3000ull |
| 65 | #define QSMMU_L3_PTE_VAL 0x000000000ecba000ull |
| 66 | |
| 67 | #define QSMMU_NON_LEAF_PTE_MASK 0x8000000000000003ull |
| 68 | #define QSMMU_LEAF_PTE_RO_MASK 0x04000000000007e3ull |
| 69 | #define QSMMU_LEAF_PTE_RW_MASK 0x0400000000000763ull |
| 70 | #define QSMMU_PTE_MASK 0x0000fffffffff000ull |
| 71 | |
| 72 | /* |
| 73 | * Address-space base offsets for test tables. |
| 74 | * - Non-Secure uses a fixed offset, keeping internal layout identical. |
| 75 | * |
| 76 | * Note: Future spaces (e.g. Secure/Realm/Root) are not implemented here. |
| 77 | * When needed, introduce new offsets and reuse the helpers below so relative |
| 78 | * layout stays identical across spaces. |
| 79 | */ |
| 80 | #define QSMMU_SPACE_OFFS_NS 0x0000000040000000ull |
| 81 | |
| 82 | typedef enum QSMMUSecSID { |
| 83 | QSMMU_SEC_SID_NONSECURE = 0, |
| 84 | } QSMMUSecSID; |
| 85 | |
| 86 | typedef enum QSMMUSpace { |
| 87 | QSMMU_SPACE_NONSECURE = 1, |
| 88 | } QSMMUSpace; |
| 89 | |
| 90 | typedef enum QSMMUTransMode { |
| 91 | QSMMU_TM_S1_ONLY = 0, |
| 92 | QSMMU_TM_S2_ONLY = 1, |
| 93 | QSMMU_TM_NESTED = 2, |
| 94 | } QSMMUTransMode; |
| 95 | |
| 96 | typedef struct QSMMUTestConfig { |
| 97 | QSMMUTransMode trans_mode; /* Translation mode (S1, S2, Nested) */ |
| 98 | QSMMUSecSID sec_sid; /* SEC_SID of test device */ |
| 99 | uint64_t dma_gpa; /* GPA for readback validation */ |
| 100 | uint32_t dma_len; /* DMA length for testing */ |
| 101 | uint32_t expected_result; /* Expected DMA result for validation */ |
| 102 | } QSMMUTestConfig; |
| 103 | |
| 104 | typedef struct QSMMUTestContext { |
| 105 | QTestState *qts; /* QTest state handle */ |
| 106 | QPCIDevice *dev; /* PCI device handle */ |
| 107 | QPCIBar bar; /* PCI BAR for MMIO access */ |
| 108 | QSMMUTestConfig config; /* Test configuration */ |
| 109 | uint64_t smmu_base; /* SMMU base address */ |
| 110 | uint32_t trans_status; /* Translation configuration status */ |
| 111 | uint32_t dma_result; /* DMA operation result */ |
| 112 | uint32_t sid; /* Stream ID for the test */ |
| 113 | QSMMUSpace tx_space; /* Cached transaction space */ |
| 114 | } QSMMUTestContext; |
| 115 | |
| 116 | /* Convert SEC_SID to corresponding Security Space */ |
| 117 | QSMMUSpace qsmmu_sec_sid_to_space(QSMMUSecSID sec_sid); |
| 118 | |
| 119 | /* Get base offset of the specific Security space */ |
| 120 | uint64_t qsmmu_space_offset(QSMMUSpace sp); |
| 121 | |
| 122 | uint32_t qsmmu_build_dma_attrs(QSMMUSpace space); |
| 123 | |
| 124 | /* |
| 125 | * qsmmu_setup_and_enable_translation - Complete translation setup and enable |
| 126 | * |
| 127 | * @ctx: Test context containing configuration and device handles |
| 128 | * |
| 129 | * Returns: Translation status (0 = success, non-zero = error) |
| 130 | * |
| 131 | * This function performs the complete translation setup sequence: |
| 132 | * 1. Builds all required SMMU structures (STE, CD, page tables) |
| 133 | * 2. Programs SMMU registers for the appropriate security space |
| 134 | * 3. Returns configuration status |
| 135 | */ |
| 136 | uint32_t qsmmu_setup_and_enable_translation(QSMMUTestContext *ctx); |
| 137 | |
| 138 | /* |
| 139 | * qsmmu_build_translation - Build SMMU translation structures |
| 140 | * |
| 141 | * @qts: QTest state handle |
| 142 | * @mode: Translation mode (S1_ONLY, S2_ONLY, NESTED) |
| 143 | * @tx_space: Transaction security space |
| 144 | * @sid: Stream ID |
| 145 | * |
| 146 | * Returns: Build status (0 = success, non-zero = error) |
| 147 | * |
| 148 | * Constructs all necessary SMMU translation structures in guest memory |
| 149 | * using the fixed QSMMU_IOVA constant: |
| 150 | * - Stream Table Entry (STE) for the given SID |
| 151 | * - Context Descriptor (CD) if Stage 1 translation is involved |
| 152 | * - Complete page table hierarchy based on translation mode |
| 153 | * |
| 154 | * The structures are written to security-space-specific memory regions. |
| 155 | */ |
| 156 | uint32_t qsmmu_build_translation(QTestState *qts, QSMMUTransMode mode, |
| 157 | QSMMUSpace tx_space, uint32_t sid); |
| 158 | |
| 159 | /* |
| 160 | * qsmmu_bank_base - Get SMMU control bank base address |
| 161 | * |
| 162 | * @base: SMMU base address |
| 163 | * @sp: Security space |
| 164 | * |
| 165 | * Returns: Bank base address for the given security space |
| 166 | * |
| 167 | * Maps security space to the corresponding SMMU control register bank. |
| 168 | * Currently only Non-Secure bank is supported. |
| 169 | */ |
| 170 | uint64_t qsmmu_bank_base(uint64_t base, QSMMUSpace sp); |
| 171 | |
| 172 | /* |
| 173 | * qsmmu_program_bank - Program SMMU control bank registers |
| 174 | * |
| 175 | * @qts: QTest state handle |
| 176 | * @bank_base: SMMU bank base address |
| 177 | * @sp: Security space |
| 178 | * |
| 179 | * Programs a specific SMMU control bank with minimal configuration: |
| 180 | * - Global Bypass Attribute (GBPA) |
| 181 | * - Control registers (CR0, CR1) |
| 182 | * - Command queue (base, producer, consumer) |
| 183 | * - Event queue (base, producer, consumer) |
| 184 | * - Stream table configuration (base, format) |
| 185 | * |
| 186 | * Addresses are adjusted based on security space offset. |
| 187 | */ |
| 188 | void qsmmu_program_bank(QTestState *qts, uint64_t bank_base, QSMMUSpace sp); |
| 189 | |
| 190 | /* |
| 191 | * qsmmu_program_regs - Program all required SMMU register banks |
| 192 | * |
| 193 | * @qts: QTest state handle |
| 194 | * @smmu_base: SMMU base address |
| 195 | * @space: Target security space |
| 196 | * |
| 197 | * Programs SMMU registers for the requested security space which is called in |
| 198 | * qsmmu_setup_and_enable_translation. Always programs Non-Secure bank first, |
| 199 | * then the target space if different. |
| 200 | */ |
| 201 | void qsmmu_program_regs(QTestState *qts, uint64_t smmu_base, QSMMUSpace space); |
| 202 | |
| 203 | /* qsmmu_expected_dma_result - Calculate expected DMA result */ |
| 204 | uint32_t qsmmu_expected_dma_result(QSMMUTestContext *ctx); |
| 205 | |
| 206 | /* |
| 207 | * qsmmu_setup_translation_tables - Setup complete SMMU page table hierarchy |
| 208 | * |
| 209 | * @qts: QTest state handle |
| 210 | * @iova: Input Virtual Address or IPA to translate |
| 211 | * @space: Security space (NONSECURE, SECURE, REALM, ROOT) |
| 212 | * @is_cd: Whether translating CD address (vs regular IOVA) |
| 213 | * @mode: Translation mode (S1_ONLY, S2_ONLY, NESTED) |
| 214 | * |
| 215 | * This function builds the complete page table structure for translating |
| 216 | * the given IOVA through the SMMU. The structure varies based on mode: |
| 217 | * |
| 218 | * - S1_ONLY: Single Stage 1 walk (IOVA -> PA) |
| 219 | * - S2_ONLY: Single Stage 2 walk (IPA -> PA) |
| 220 | * - NESTED: Stage 1 walk (IOVA -> IPA) with nested S2 walks for each |
| 221 | * S1 table access, plus final S2 walk for the result IPA |
| 222 | * |
| 223 | * For nested mode, this creates a complex hierarchy: |
| 224 | * - 4 Stage 1 levels (L0-L3), each requiring a 4-level Stage 2 walk |
| 225 | * - 1 final Stage 2 walk for the resulting IPA |
| 226 | * |
| 227 | * The function writes all necessary Page Table Entries (PTEs) to guest |
| 228 | * memory using qtest_writeq(), setting up the complete translation path |
| 229 | * that the SMMU hardware will traverse during DMA operations. |
| 230 | */ |
| 231 | void qsmmu_setup_translation_tables(QTestState *qts, |
| 232 | uint64_t iova, |
| 233 | QSMMUSpace space, |
| 234 | bool is_cd, |
| 235 | QSMMUTransMode mode); |
| 236 | |
| 237 | /* High-level test execution helpers */ |
| 238 | void qsmmu_run_translation_case(QTestState *qts, QPCIDevice *dev, |
| 239 | QPCIBar bar, uint64_t smmu_base, |
| 240 | const QSMMUTestConfig *cfg); |
| 241 | |
| 242 | #endif /* QTEST_LIBQOS_SMMUV3_H */ |