1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Debug helper used to dump the stage-2 pagetables of the system and their 4 * associated permissions. 5 * 6 * Copyright (C) Google, 2024 7 * Author: Sebastian Ene <sebastianene@google.com> 8 */ 9 #include <linux/debugfs.h> 10 #include <linux/kvm_host.h> 11 #include <linux/seq_file.h> 12 13 #include <asm/cpufeature.h> 14 #include <asm/kvm_mmu.h> 15 #include <asm/kvm_pgtable.h> 16 #include <asm/ptdump.h> 17 18 #define MARKERS_LEN 2 19 #define KVM_PGTABLE_MAX_LEVELS (KVM_PGTABLE_LAST_LEVEL + 1) 20 #define S2FNAMESZ sizeof("nested_mmu0000") 21 22 struct kvm_ptdump_guest_state { 23 struct kvm_s2_mmu *mmu; 24 struct ptdump_pg_state parser_state; 25 struct addr_marker ipa_marker[MARKERS_LEN]; 26 struct ptdump_pg_level level[KVM_PGTABLE_MAX_LEVELS]; 27 }; 28 29 static const struct ptdump_prot_bits stage2_pte_bits[] = { 30 { 31 .mask = PTE_VALID, 32 .val = PTE_VALID, 33 .set = " ", 34 .clear = "F", 35 }, 36 { 37 .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R, 38 .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R, 39 .set = "R", 40 .clear = " ", 41 }, 42 { 43 .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W, 44 .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W, 45 .set = "W", 46 .clear = " ", 47 }, 48 { 49 .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN, 50 .val = 0b00UL << __bf_shf(KVM_PTE_LEAF_ATTR_HI_S2_XN), 51 .set = "px ux ", 52 }, 53 { 54 .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN, 55 .val = 0b01UL << __bf_shf(KVM_PTE_LEAF_ATTR_HI_S2_XN), 56 .set = "PXNux ", 57 }, 58 { 59 .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN, 60 .val = 0b10UL << __bf_shf(KVM_PTE_LEAF_ATTR_HI_S2_XN), 61 .set = "PXNUXN", 62 }, 63 { 64 .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN, 65 .val = 0b11UL << __bf_shf(KVM_PTE_LEAF_ATTR_HI_S2_XN), 66 .set = "px UXN", 67 }, 68 { 69 .mask = KVM_PTE_LEAF_ATTR_LO_S2_AF, 70 .val = KVM_PTE_LEAF_ATTR_LO_S2_AF, 71 .set = "AF", 72 .clear = " ", 73 }, 74 { 75 .mask = PMD_TYPE_MASK, 76 .val = PMD_TYPE_SECT, 77 .set = "BLK", 78 .clear = " ", 79 }, 80 }; 81 82 static int kvm_ptdump_visitor(const struct kvm_pgtable_visit_ctx *ctx, 83 enum kvm_pgtable_walk_flags visit) 84 { 85 struct ptdump_pg_state *st = ctx->arg; 86 struct ptdump_state *pt_st = &st->ptdump; 87 88 note_page(pt_st, ctx->addr, ctx->level, ctx->old); 89 90 return 0; 91 } 92 93 static int kvm_ptdump_build_levels(struct ptdump_pg_level *level, u32 start_lvl) 94 { 95 u32 i; 96 u64 mask; 97 98 if (WARN_ON_ONCE(start_lvl >= KVM_PGTABLE_LAST_LEVEL)) 99 return -EINVAL; 100 101 mask = 0; 102 for (i = 0; i < ARRAY_SIZE(stage2_pte_bits); i++) 103 mask |= stage2_pte_bits[i].mask; 104 105 for (i = start_lvl; i < KVM_PGTABLE_MAX_LEVELS; i++) { 106 snprintf(level[i].name, sizeof(level[i].name), "%u", i); 107 108 level[i].num = ARRAY_SIZE(stage2_pte_bits); 109 level[i].bits = stage2_pte_bits; 110 level[i].mask = mask; 111 } 112 113 return 0; 114 } 115 116 static struct kvm_ptdump_guest_state *kvm_ptdump_parser_create(struct kvm_s2_mmu *mmu) 117 { 118 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 119 struct kvm_ptdump_guest_state *st; 120 s8 start_level; 121 int ret; 122 123 /* 124 * We only need the pgt start level to initialize the ptdump, get it 125 * while holding the mmu_lock. It's fine if the pgt gets freed 126 * afterwards, we'll check again when doing the actual dump. 127 */ 128 scoped_guard(read_lock, &kvm->mmu_lock) { 129 if (mmu->pgt) 130 start_level = mmu->pgt->start_level; 131 else 132 return ERR_PTR(-ENOENT); 133 } 134 135 st = kzalloc_obj(struct kvm_ptdump_guest_state, GFP_KERNEL_ACCOUNT); 136 if (!st) 137 return ERR_PTR(-ENOMEM); 138 139 ret = kvm_ptdump_build_levels(&st->level[0], start_level); 140 if (ret) { 141 kfree(st); 142 return ERR_PTR(ret); 143 } 144 145 st->ipa_marker[0].name = "Guest IPA"; 146 st->ipa_marker[1].start_address = ULONG_MAX; 147 148 st->mmu = mmu; 149 return st; 150 } 151 152 static int kvm_ptdump_guest_show(struct seq_file *m, void *unused) 153 { 154 int ret; 155 struct kvm_ptdump_guest_state *st = m->private; 156 struct kvm_s2_mmu *mmu = st->mmu; 157 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 158 struct kvm_pgtable_walker walker = (struct kvm_pgtable_walker) { 159 .cb = kvm_ptdump_visitor, 160 .arg = &st->parser_state, 161 .flags = KVM_PGTABLE_WALK_LEAF, 162 }; 163 164 guard(write_lock)(&kvm->mmu_lock); 165 if (!mmu->pgt) 166 return 0; 167 168 st->parser_state = (struct ptdump_pg_state) { 169 .marker = &st->ipa_marker[0], 170 .end_address = BIT(mmu->pgt->ia_bits), 171 .level = -1, 172 .pg_level = &st->level[0], 173 .seq = m, 174 }; 175 176 if (kvm_is_nested_s2_mmu(kvm, mmu)) { 177 if (kvm_s2_mmu_valid(mmu)) 178 seq_printf(m, "VTCR: 0x%016llx VTTBR: 0x%016llx s2: %s\n", 179 mmu->tlb_vtcr, mmu->tlb_vttbr, 180 mmu->nested_stage2_enabled ? "enabled" : "disabled"); 181 else 182 return 0; 183 } 184 185 ret = kvm_pgtable_walk(mmu->pgt, 0, BIT(mmu->pgt->ia_bits), &walker); 186 if (ret) 187 return ret; 188 note_page_flush(&st->parser_state.ptdump); 189 190 return 0; 191 } 192 193 static int kvm_ptdump_guest_open(struct inode *m, struct file *file) 194 { 195 struct kvm_s2_mmu *mmu = m->i_private; 196 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 197 struct kvm_ptdump_guest_state *st; 198 int ret; 199 200 if (!kvm_get_kvm_safe(kvm)) 201 return -ENOENT; 202 203 st = kvm_ptdump_parser_create(mmu); 204 if (IS_ERR(st)) { 205 ret = PTR_ERR(st); 206 goto err_with_kvm_ref; 207 } 208 209 ret = single_open(file, kvm_ptdump_guest_show, st); 210 if (!ret) 211 return 0; 212 213 kfree(st); 214 err_with_kvm_ref: 215 kvm_put_kvm(kvm); 216 return ret; 217 } 218 219 static int kvm_ptdump_guest_close(struct inode *m, struct file *file) 220 { 221 struct kvm *kvm = kvm_s2_mmu_to_kvm(m->i_private); 222 void *st = ((struct seq_file *)file->private_data)->private; 223 224 kfree(st); 225 kvm_put_kvm(kvm); 226 227 return single_release(m, file); 228 } 229 230 static const struct file_operations kvm_ptdump_guest_fops = { 231 .open = kvm_ptdump_guest_open, 232 .read = seq_read, 233 .llseek = seq_lseek, 234 .release = kvm_ptdump_guest_close, 235 }; 236 237 static int kvm_pgtable_range_show(struct seq_file *m, void *unused) 238 { 239 struct kvm_s2_mmu *mmu = m->private; 240 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 241 242 guard(read_lock)(&kvm->mmu_lock); 243 244 if (mmu->pgt) 245 seq_printf(m, "%2u\n", mmu->pgt->ia_bits); 246 247 return 0; 248 } 249 250 static int kvm_pgtable_levels_show(struct seq_file *m, void *unused) 251 { 252 struct kvm_s2_mmu *mmu = m->private; 253 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 254 255 guard(read_lock)(&kvm->mmu_lock); 256 257 if (mmu->pgt) 258 seq_printf(m, "%1d\n", KVM_PGTABLE_MAX_LEVELS - mmu->pgt->start_level); 259 260 return 0; 261 } 262 263 static int kvm_pgtable_debugfs_open(struct inode *m, struct file *file, 264 int (*show)(struct seq_file *, void *)) 265 { 266 struct kvm_s2_mmu *mmu = m->i_private; 267 struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); 268 int ret; 269 270 if (!kvm_get_kvm_safe(kvm)) 271 return -ENOENT; 272 273 ret = single_open(file, show, mmu); 274 if (ret < 0) 275 kvm_put_kvm(kvm); 276 return ret; 277 } 278 279 static int kvm_pgtable_range_open(struct inode *m, struct file *file) 280 { 281 return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_range_show); 282 } 283 284 static int kvm_pgtable_levels_open(struct inode *m, struct file *file) 285 { 286 return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_levels_show); 287 } 288 289 static int kvm_pgtable_debugfs_close(struct inode *m, struct file *file) 290 { 291 struct kvm *kvm = kvm_s2_mmu_to_kvm(m->i_private); 292 293 kvm_put_kvm(kvm); 294 return single_release(m, file); 295 } 296 297 static const struct file_operations kvm_pgtable_range_fops = { 298 .open = kvm_pgtable_range_open, 299 .read = seq_read, 300 .llseek = seq_lseek, 301 .release = kvm_pgtable_debugfs_close, 302 }; 303 304 static const struct file_operations kvm_pgtable_levels_fops = { 305 .open = kvm_pgtable_levels_open, 306 .read = seq_read, 307 .llseek = seq_lseek, 308 .release = kvm_pgtable_debugfs_close, 309 }; 310 311 void kvm_nested_s2_ptdump_create_debugfs(struct kvm_s2_mmu *mmu, int idx) 312 { 313 char file_name[S2FNAMESZ]; 314 315 snprintf(file_name, sizeof(file_name), "nested_mmu%d", idx); 316 317 debugfs_create_file(file_name, 0400, 318 mmu->arch->debugfs_nv_dentry, mmu, 319 &kvm_ptdump_guest_fops); 320 } 321 322 void kvm_s2_ptdump_create_debugfs(struct kvm *kvm) 323 { 324 /* pKVM handles the page-tables in the hypervisor */ 325 if (is_protected_kvm_enabled()) 326 return; 327 328 debugfs_create_file("stage2_page_tables", 0400, kvm->debugfs_dentry, 329 &kvm->arch.mmu, &kvm_ptdump_guest_fops); 330 debugfs_create_file("ipa_range", 0400, kvm->debugfs_dentry, 331 &kvm->arch.mmu, &kvm_pgtable_range_fops); 332 debugfs_create_file("stage2_levels", 0400, kvm->debugfs_dentry, 333 &kvm->arch.mmu, &kvm_pgtable_levels_fops); 334 if (cpus_have_final_cap(ARM64_HAS_NESTED_VIRT)) 335 kvm->arch.debugfs_nv_dentry = debugfs_create_dir("nested", kvm->debugfs_dentry); 336 } 337