linux/arch/arm64/kvm/vgic/vgic-debug.c
<<
>>
Prefs
   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 = (struct 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 = (struct 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 = (struct 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 = (struct kvm *)s->private;
 233        struct vgic_state_iter *iter = (struct vgic_state_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}
 281