vgic-debug.c (6260B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2016 Linaro 4 * Author: Christoffer Dall <christoffer.dall@linaro.org> 5 */ 6 7#include <linux/cpu.h> 8#include <linux/debugfs.h> 9#include <linux/interrupt.h> 10#include <linux/kvm_host.h> 11#include <linux/seq_file.h> 12#include <kvm/arm_vgic.h> 13#include <asm/kvm_mmu.h> 14#include "vgic.h" 15 16/* 17 * Structure to control looping through the entire vgic state. We start at 18 * zero for each field and move upwards. So, if dist_id is 0 we print the 19 * distributor info. When dist_id is 1, we have already printed it and move 20 * on. 21 * 22 * When vcpu_id < nr_cpus we print the vcpu info until vcpu_id == nr_cpus and 23 * so on. 24 */ 25struct vgic_state_iter { 26 int nr_cpus; 27 int nr_spis; 28 int nr_lpis; 29 int dist_id; 30 int vcpu_id; 31 int intid; 32 int lpi_idx; 33 u32 *lpi_array; 34}; 35 36static void iter_next(struct vgic_state_iter *iter) 37{ 38 if (iter->dist_id == 0) { 39 iter->dist_id++; 40 return; 41 } 42 43 iter->intid++; 44 if (iter->intid == VGIC_NR_PRIVATE_IRQS && 45 ++iter->vcpu_id < iter->nr_cpus) 46 iter->intid = 0; 47 48 if (iter->intid >= (iter->nr_spis + VGIC_NR_PRIVATE_IRQS)) { 49 if (iter->lpi_idx < iter->nr_lpis) 50 iter->intid = iter->lpi_array[iter->lpi_idx]; 51 iter->lpi_idx++; 52 } 53} 54 55static void iter_init(struct kvm *kvm, struct vgic_state_iter *iter, 56 loff_t pos) 57{ 58 int nr_cpus = atomic_read(&kvm->online_vcpus); 59 60 memset(iter, 0, sizeof(*iter)); 61 62 iter->nr_cpus = nr_cpus; 63 iter->nr_spis = kvm->arch.vgic.nr_spis; 64 if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { 65 iter->nr_lpis = vgic_copy_lpi_list(kvm, NULL, &iter->lpi_array); 66 if (iter->nr_lpis < 0) 67 iter->nr_lpis = 0; 68 } 69 70 /* Fast forward to the right position if needed */ 71 while (pos--) 72 iter_next(iter); 73} 74 75static bool end_of_vgic(struct vgic_state_iter *iter) 76{ 77 return iter->dist_id > 0 && 78 iter->vcpu_id == iter->nr_cpus && 79 iter->intid >= (iter->nr_spis + VGIC_NR_PRIVATE_IRQS) && 80 iter->lpi_idx > iter->nr_lpis; 81} 82 83static void *vgic_debug_start(struct seq_file *s, loff_t *pos) 84{ 85 struct kvm *kvm = s->private; 86 struct vgic_state_iter *iter; 87 88 mutex_lock(&kvm->lock); 89 iter = kvm->arch.vgic.iter; 90 if (iter) { 91 iter = ERR_PTR(-EBUSY); 92 goto out; 93 } 94 95 iter = kmalloc(sizeof(*iter), GFP_KERNEL); 96 if (!iter) { 97 iter = ERR_PTR(-ENOMEM); 98 goto out; 99 } 100 101 iter_init(kvm, iter, *pos); 102 kvm->arch.vgic.iter = iter; 103 104 if (end_of_vgic(iter)) 105 iter = NULL; 106out: 107 mutex_unlock(&kvm->lock); 108 return iter; 109} 110 111static void *vgic_debug_next(struct seq_file *s, void *v, loff_t *pos) 112{ 113 struct kvm *kvm = s->private; 114 struct vgic_state_iter *iter = kvm->arch.vgic.iter; 115 116 ++*pos; 117 iter_next(iter); 118 if (end_of_vgic(iter)) 119 iter = NULL; 120 return iter; 121} 122 123static void vgic_debug_stop(struct seq_file *s, void *v) 124{ 125 struct kvm *kvm = s->private; 126 struct vgic_state_iter *iter; 127 128 /* 129 * If the seq file wasn't properly opened, there's nothing to clearn 130 * up. 131 */ 132 if (IS_ERR(v)) 133 return; 134 135 mutex_lock(&kvm->lock); 136 iter = kvm->arch.vgic.iter; 137 kfree(iter->lpi_array); 138 kfree(iter); 139 kvm->arch.vgic.iter = NULL; 140 mutex_unlock(&kvm->lock); 141} 142 143static void print_dist_state(struct seq_file *s, struct vgic_dist *dist) 144{ 145 bool v3 = dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3; 146 147 seq_printf(s, "Distributor\n"); 148 seq_printf(s, "===========\n"); 149 seq_printf(s, "vgic_model:\t%s\n", v3 ? "GICv3" : "GICv2"); 150 seq_printf(s, "nr_spis:\t%d\n", dist->nr_spis); 151 if (v3) 152 seq_printf(s, "nr_lpis:\t%d\n", dist->lpi_list_count); 153 seq_printf(s, "enabled:\t%d\n", dist->enabled); 154 seq_printf(s, "\n"); 155 156 seq_printf(s, "P=pending_latch, L=line_level, A=active\n"); 157 seq_printf(s, "E=enabled, H=hw, C=config (level=1, edge=0)\n"); 158 seq_printf(s, "G=group\n"); 159} 160 161static void print_header(struct seq_file *s, struct vgic_irq *irq, 162 struct kvm_vcpu *vcpu) 163{ 164 int id = 0; 165 char *hdr = "SPI "; 166 167 if (vcpu) { 168 hdr = "VCPU"; 169 id = vcpu->vcpu_id; 170 } 171 172 seq_printf(s, "\n"); 173 seq_printf(s, "%s%2d TYP ID TGT_ID PLAEHCG HWID TARGET SRC PRI VCPU_ID\n", hdr, id); 174 seq_printf(s, "----------------------------------------------------------------\n"); 175} 176 177static void print_irq_state(struct seq_file *s, struct vgic_irq *irq, 178 struct kvm_vcpu *vcpu) 179{ 180 char *type; 181 bool pending; 182 183 if (irq->intid < VGIC_NR_SGIS) 184 type = "SGI"; 185 else if (irq->intid < VGIC_NR_PRIVATE_IRQS) 186 type = "PPI"; 187 else if (irq->intid < VGIC_MAX_SPI) 188 type = "SPI"; 189 else 190 type = "LPI"; 191 192 if (irq->intid ==0 || irq->intid == VGIC_NR_PRIVATE_IRQS) 193 print_header(s, irq, vcpu); 194 195 pending = irq->pending_latch; 196 if (irq->hw && vgic_irq_is_sgi(irq->intid)) { 197 int err; 198 199 err = irq_get_irqchip_state(irq->host_irq, 200 IRQCHIP_STATE_PENDING, 201 &pending); 202 WARN_ON_ONCE(err); 203 } 204 205 seq_printf(s, " %s %4d " 206 " %2d " 207 "%d%d%d%d%d%d%d " 208 "%8d " 209 "%8x " 210 " %2x " 211 "%3d " 212 " %2d " 213 "\n", 214 type, irq->intid, 215 (irq->target_vcpu) ? irq->target_vcpu->vcpu_id : -1, 216 pending, 217 irq->line_level, 218 irq->active, 219 irq->enabled, 220 irq->hw, 221 irq->config == VGIC_CONFIG_LEVEL, 222 irq->group, 223 irq->hwintid, 224 irq->mpidr, 225 irq->source, 226 irq->priority, 227 (irq->vcpu) ? irq->vcpu->vcpu_id : -1); 228} 229 230static int vgic_debug_show(struct seq_file *s, void *v) 231{ 232 struct kvm *kvm = s->private; 233 struct vgic_state_iter *iter = v; 234 struct vgic_irq *irq; 235 struct kvm_vcpu *vcpu = NULL; 236 unsigned long flags; 237 238 if (iter->dist_id == 0) { 239 print_dist_state(s, &kvm->arch.vgic); 240 return 0; 241 } 242 243 if (!kvm->arch.vgic.initialized) 244 return 0; 245 246 if (iter->vcpu_id < iter->nr_cpus) 247 vcpu = kvm_get_vcpu(kvm, iter->vcpu_id); 248 249 irq = vgic_get_irq(kvm, vcpu, iter->intid); 250 if (!irq) { 251 seq_printf(s, " LPI %4d freed\n", iter->intid); 252 return 0; 253 } 254 255 raw_spin_lock_irqsave(&irq->irq_lock, flags); 256 print_irq_state(s, irq, vcpu); 257 raw_spin_unlock_irqrestore(&irq->irq_lock, flags); 258 259 vgic_put_irq(kvm, irq); 260 return 0; 261} 262 263static const struct seq_operations vgic_debug_sops = { 264 .start = vgic_debug_start, 265 .next = vgic_debug_next, 266 .stop = vgic_debug_stop, 267 .show = vgic_debug_show 268}; 269 270DEFINE_SEQ_ATTRIBUTE(vgic_debug); 271 272void vgic_debug_init(struct kvm *kvm) 273{ 274 debugfs_create_file("vgic-state", 0444, kvm->debugfs_dentry, kvm, 275 &vgic_debug_fops); 276} 277 278void vgic_debug_destroy(struct kvm *kvm) 279{ 280}