linux/virt/kvm/arm/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        if (irq->intid < VGIC_NR_SGIS)
 182                type = "SGI";
 183        else if (irq->intid < VGIC_NR_PRIVATE_IRQS)
 184                type = "PPI";
 185        else if (irq->intid < VGIC_MAX_SPI)
 186                type = "SPI";
 187        else
 188                type = "LPI";
 189
 190        if (irq->intid ==0 || irq->intid == VGIC_NR_PRIVATE_IRQS)
 191                print_header(s, irq, vcpu);
 192
 193        seq_printf(s, "       %s %4d "
 194                      "    %2d "
 195                      "%d%d%d%d%d%d%d "
 196                      "%8d "
 197                      "%8x "
 198                      " %2x "
 199                      "%3d "
 200                      "     %2d "
 201                      "\n",
 202                        type, irq->intid,
 203                        (irq->target_vcpu) ? irq->target_vcpu->vcpu_id : -1,
 204                        irq->pending_latch,
 205                        irq->line_level,
 206                        irq->active,
 207                        irq->enabled,
 208                        irq->hw,
 209                        irq->config == VGIC_CONFIG_LEVEL,
 210                        irq->group,
 211                        irq->hwintid,
 212                        irq->mpidr,
 213                        irq->source,
 214                        irq->priority,
 215                        (irq->vcpu) ? irq->vcpu->vcpu_id : -1);
 216}
 217
 218static int vgic_debug_show(struct seq_file *s, void *v)
 219{
 220        struct kvm *kvm = (struct kvm *)s->private;
 221        struct vgic_state_iter *iter = (struct vgic_state_iter *)v;
 222        struct vgic_irq *irq;
 223        struct kvm_vcpu *vcpu = NULL;
 224        unsigned long flags;
 225
 226        if (iter->dist_id == 0) {
 227                print_dist_state(s, &kvm->arch.vgic);
 228                return 0;
 229        }
 230
 231        if (!kvm->arch.vgic.initialized)
 232                return 0;
 233
 234        if (iter->vcpu_id < iter->nr_cpus)
 235                vcpu = kvm_get_vcpu(kvm, iter->vcpu_id);
 236
 237        irq = vgic_get_irq(kvm, vcpu, iter->intid);
 238        if (!irq) {
 239                seq_printf(s, "       LPI %4d freed\n", iter->intid);
 240                return 0;
 241        }
 242
 243        raw_spin_lock_irqsave(&irq->irq_lock, flags);
 244        print_irq_state(s, irq, vcpu);
 245        raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
 246
 247        vgic_put_irq(kvm, irq);
 248        return 0;
 249}
 250
 251static const struct seq_operations vgic_debug_seq_ops = {
 252        .start = vgic_debug_start,
 253        .next  = vgic_debug_next,
 254        .stop  = vgic_debug_stop,
 255        .show  = vgic_debug_show
 256};
 257
 258static int debug_open(struct inode *inode, struct file *file)
 259{
 260        int ret;
 261        ret = seq_open(file, &vgic_debug_seq_ops);
 262        if (!ret) {
 263                struct seq_file *seq;
 264                /* seq_open will have modified file->private_data */
 265                seq = file->private_data;
 266                seq->private = inode->i_private;
 267        }
 268
 269        return ret;
 270};
 271
 272static const struct file_operations vgic_debug_fops = {
 273        .owner   = THIS_MODULE,
 274        .open    = debug_open,
 275        .read    = seq_read,
 276        .llseek  = seq_lseek,
 277        .release = seq_release
 278};
 279
 280void vgic_debug_init(struct kvm *kvm)
 281{
 282        debugfs_create_file("vgic-state", 0444, kvm->debugfs_dentry, kvm,
 283                            &vgic_debug_fops);
 284}
 285
 286void vgic_debug_destroy(struct kvm *kvm)
 287{
 288}
 289