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