]> Git Repo - linux.git/commitdiff
Merge branch kvm-arm64/nv-timer-improvements into kvmarm/next
authorOliver Upton <[email protected]>
Mon, 13 Feb 2023 23:26:21 +0000 (23:26 +0000)
committerOliver Upton <[email protected]>
Mon, 13 Feb 2023 23:26:21 +0000 (23:26 +0000)
* kvm-arm64/nv-timer-improvements:
  : Timer emulation improvements, courtesy of Marc Zyngier.
  :
  :  - Avoid re-arming an hrtimer for a guest timer that is already pending
  :
  :  - Only reload the affected timer context when emulating a sysreg access
  :    instead of both the virtual/physical timers.
  KVM: arm64: timers: Don't BUG() on unhandled timer trap
  KVM: arm64: Reduce overhead of trapped timer sysreg accesses
  KVM: arm64: Don't arm a hrtimer for an already pending timer

Signed-off-by: Oliver Upton <[email protected]>
1  2 
arch/arm64/kvm/arch_timer.c
arch/arm64/kvm/sys_regs.c

index 23346585a29429d8dd1ab92b40d618460b738c1b,1a1d7e258abaa95ee568384c44feff4de28a81e3..00610477ec7bd8da4a7ccbd5a764851145989490
@@@ -428,14 -428,17 +428,17 @@@ static void timer_emulate(struct arch_t
         * scheduled for the future.  If the timer cannot fire at all,
         * then we also don't need a soft timer.
         */
-       if (!kvm_timer_irq_can_fire(ctx)) {
-               soft_timer_cancel(&ctx->hrtimer);
+       if (should_fire || !kvm_timer_irq_can_fire(ctx))
                return;
-       }
  
        soft_timer_start(&ctx->hrtimer, kvm_timer_compute_delta(ctx));
  }
  
+ static void set_cntvoff(u64 cntvoff)
+ {
+       kvm_call_hyp(__kvm_timer_set_cntvoff, cntvoff);
+ }
  static void timer_save_state(struct arch_timer_context *ctx)
  {
        struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
                write_sysreg_el0(0, SYS_CNTV_CTL);
                isb();
  
+               /*
+                * The kernel may decide to run userspace after
+                * calling vcpu_put, so we reset cntvoff to 0 to
+                * ensure a consistent read between user accesses to
+                * the virtual counter and kernel access to the
+                * physical counter of non-VHE case.
+                *
+                * For VHE, the virtual counter uses a fixed virtual
+                * offset of zero, so no need to zero CNTVOFF_EL2
+                * register, but this is actually useful when switching
+                * between EL1/vEL2 with NV.
+                *
+                * Do it unconditionally, as this is either unavoidable
+                * or dirt cheap.
+                */
+               set_cntvoff(0);
                break;
        case TIMER_PTIMER:
                timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTP_CTL));
@@@ -532,6 -551,7 +551,7 @@@ static void timer_restore_state(struct 
  
        switch (index) {
        case TIMER_VTIMER:
+               set_cntvoff(timer_get_offset(ctx));
                write_sysreg_el0(timer_get_cval(ctx), SYS_CNTV_CVAL);
                isb();
                write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTV_CTL);
@@@ -552,11 -572,6 +572,6 @@@ out
        local_irq_restore(flags);
  }
  
- static void set_cntvoff(u64 cntvoff)
- {
-       kvm_call_hyp(__kvm_timer_set_cntvoff, cntvoff);
- }
  static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
  {
        int r;
@@@ -631,8 -646,6 +646,6 @@@ void kvm_timer_vcpu_load(struct kvm_vcp
                kvm_timer_vcpu_load_nogic(vcpu);
        }
  
-       set_cntvoff(timer_get_offset(map.direct_vtimer));
        kvm_timer_unblocking(vcpu);
  
        timer_restore_state(map.direct_vtimer);
@@@ -688,15 -701,6 +701,6 @@@ void kvm_timer_vcpu_put(struct kvm_vcp
  
        if (kvm_vcpu_is_blocking(vcpu))
                kvm_timer_blocking(vcpu);
-       /*
-        * The kernel may decide to run userspace after calling vcpu_put, so
-        * we reset cntvoff to 0 to ensure a consistent read between user
-        * accesses to the virtual counter and kernel access to the physical
-        * counter of non-VHE case. For VHE, the virtual counter uses a fixed
-        * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
-        */
-       set_cntvoff(0);
  }
  
  /*
@@@ -811,18 -815,10 +815,18 @@@ void kvm_timer_vcpu_init(struct kvm_vcp
        ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
  }
  
 -static void kvm_timer_init_interrupt(void *info)
 +void kvm_timer_cpu_up(void)
  {
        enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
 -      enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
 +      if (host_ptimer_irq)
 +              enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
 +}
 +
 +void kvm_timer_cpu_down(void)
 +{
 +      disable_percpu_irq(host_vtimer_irq);
 +      if (host_ptimer_irq)
 +              disable_percpu_irq(host_ptimer_irq);
  }
  
  int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
@@@ -934,14 -930,22 +938,22 @@@ u64 kvm_arm_timer_read_sysreg(struct kv
                              enum kvm_arch_timers tmr,
                              enum kvm_arch_timer_regs treg)
  {
+       struct arch_timer_context *timer;
+       struct timer_map map;
        u64 val;
  
+       get_timer_map(vcpu, &map);
+       timer = vcpu_get_timer(vcpu, tmr);
+       if (timer == map.emul_ptimer)
+               return kvm_arm_timer_read(vcpu, timer, treg);
        preempt_disable();
-       kvm_timer_vcpu_put(vcpu);
+       timer_save_state(timer);
  
-       val = kvm_arm_timer_read(vcpu, vcpu_get_timer(vcpu, tmr), treg);
+       val = kvm_arm_timer_read(vcpu, timer, treg);
  
-       kvm_timer_vcpu_load(vcpu);
+       timer_restore_state(timer);
        preempt_enable();
  
        return val;
@@@ -975,15 -979,36 +987,24 @@@ void kvm_arm_timer_write_sysreg(struct 
                                enum kvm_arch_timer_regs treg,
                                u64 val)
  {
-       preempt_disable();
-       kvm_timer_vcpu_put(vcpu);
-       kvm_arm_timer_write(vcpu, vcpu_get_timer(vcpu, tmr), treg, val);
+       struct arch_timer_context *timer;
+       struct timer_map map;
  
-       kvm_timer_vcpu_load(vcpu);
-       preempt_enable();
+       get_timer_map(vcpu, &map);
+       timer = vcpu_get_timer(vcpu, tmr);
+       if (timer == map.emul_ptimer) {
+               soft_timer_cancel(&timer->hrtimer);
+               kvm_arm_timer_write(vcpu, timer, treg, val);
+               timer_emulate(timer);
+       } else {
+               preempt_disable();
+               timer_save_state(timer);
+               kvm_arm_timer_write(vcpu, timer, treg, val);
+               timer_restore_state(timer);
+               preempt_enable();
+       }
  }
  
 -static int kvm_timer_starting_cpu(unsigned int cpu)
 -{
 -      kvm_timer_init_interrupt(NULL);
 -      return 0;
 -}
 -
 -static int kvm_timer_dying_cpu(unsigned int cpu)
 -{
 -      disable_percpu_irq(host_vtimer_irq);
 -      return 0;
 -}
 -
  static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
  {
        if (vcpu)
@@@ -1113,7 -1138,7 +1134,7 @@@ static int kvm_irq_init(struct arch_tim
        return 0;
  }
  
 -int kvm_timer_hyp_init(bool has_gic)
 +int __init kvm_timer_hyp_init(bool has_gic)
  {
        struct arch_timer_kvm_info *info;
        int err;
                goto out_free_irq;
        }
  
 -      cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
 -                        "kvm/arm/timer:starting", kvm_timer_starting_cpu,
 -                        kvm_timer_dying_cpu);
        return 0;
  out_free_irq:
        free_percpu_irq(host_vtimer_irq, kvm_get_running_vcpus());
index 9f3d6b1f2fbbcdc3d5f34b79c39df8c25a18778a,32f4e424b9a5249ac58eec9fa633650614cc53df..6d2e6e47d009b3f6cba8b6233d7e8b2488a34a92
@@@ -11,7 -11,6 +11,7 @@@
  
  #include <linux/bitfield.h>
  #include <linux/bsearch.h>
 +#include <linux/cacheinfo.h>
  #include <linux/kvm_host.h>
  #include <linux/mm.h>
  #include <linux/printk.h>
@@@ -82,97 -81,25 +82,97 @@@ void vcpu_write_sys_reg(struct kvm_vcp
         __vcpu_sys_reg(vcpu, reg) = val;
  }
  
 -/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
 -static u32 cache_levels;
 -
  /* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
  #define CSSELR_MAX 14
  
 +/*
 + * Returns the minimum line size for the selected cache, expressed as
 + * Log2(bytes).
 + */
 +static u8 get_min_cache_line_size(bool icache)
 +{
 +      u64 ctr = read_sanitised_ftr_reg(SYS_CTR_EL0);
 +      u8 field;
 +
 +      if (icache)
 +              field = SYS_FIELD_GET(CTR_EL0, IminLine, ctr);
 +      else
 +              field = SYS_FIELD_GET(CTR_EL0, DminLine, ctr);
 +
 +      /*
 +       * Cache line size is represented as Log2(words) in CTR_EL0.
 +       * Log2(bytes) can be derived with the following:
 +       *
 +       * Log2(words) + 2 = Log2(bytes / 4) + 2
 +       *                 = Log2(bytes) - 2 + 2
 +       *                 = Log2(bytes)
 +       */
 +      return field + 2;
 +}
 +
  /* Which cache CCSIDR represents depends on CSSELR value. */
 -static u32 get_ccsidr(u32 csselr)
 +static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
 +{
 +      u8 line_size;
 +
 +      if (vcpu->arch.ccsidr)
 +              return vcpu->arch.ccsidr[csselr];
 +
 +      line_size = get_min_cache_line_size(csselr & CSSELR_EL1_InD);
 +
 +      /*
 +       * Fabricate a CCSIDR value as the overriding value does not exist.
 +       * The real CCSIDR value will not be used as it can vary by the
 +       * physical CPU which the vcpu currently resides in.
 +       *
 +       * The line size is determined with get_min_cache_line_size(), which
 +       * should be valid for all CPUs even if they have different cache
 +       * configuration.
 +       *
 +       * The associativity bits are cleared, meaning the geometry of all data
 +       * and unified caches (which are guaranteed to be PIPT and thus
 +       * non-aliasing) are 1 set and 1 way.
 +       * Guests should not be doing cache operations by set/way at all, and
 +       * for this reason, we trap them and attempt to infer the intent, so
 +       * that we can flush the entire guest's address space at the appropriate
 +       * time. The exposed geometry minimizes the number of the traps.
 +       * [If guests should attempt to infer aliasing properties from the
 +       * geometry (which is not permitted by the architecture), they would
 +       * only do so for virtually indexed caches.]
 +       *
 +       * We don't check if the cache level exists as it is allowed to return
 +       * an UNKNOWN value if not.
 +       */
 +      return SYS_FIELD_PREP(CCSIDR_EL1, LineSize, line_size - 4);
 +}
 +
 +static int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val)
  {
 -      u32 ccsidr;
 +      u8 line_size = FIELD_GET(CCSIDR_EL1_LineSize, val) + 4;
 +      u32 *ccsidr = vcpu->arch.ccsidr;
 +      u32 i;
 +
 +      if ((val & CCSIDR_EL1_RES0) ||
 +          line_size < get_min_cache_line_size(csselr & CSSELR_EL1_InD))
 +              return -EINVAL;
 +
 +      if (!ccsidr) {
 +              if (val == get_ccsidr(vcpu, csselr))
 +                      return 0;
  
 -      /* Make sure noone else changes CSSELR during this! */
 -      local_irq_disable();
 -      write_sysreg(csselr, csselr_el1);
 -      isb();
 -      ccsidr = read_sysreg(ccsidr_el1);
 -      local_irq_enable();
 +              ccsidr = kmalloc_array(CSSELR_MAX, sizeof(u32), GFP_KERNEL_ACCOUNT);
 +              if (!ccsidr)
 +                      return -ENOMEM;
  
 -      return ccsidr;
 +              for (i = 0; i < CSSELR_MAX; i++)
 +                      ccsidr[i] = get_ccsidr(vcpu, i);
 +
 +              vcpu->arch.ccsidr = ccsidr;
 +      }
 +
 +      ccsidr[csselr] = val;
 +
 +      return 0;
  }
  
  /*
@@@ -719,7 -646,7 +719,7 @@@ static void reset_pmcr(struct kvm_vcpu 
                return;
  
        /* Only preserve PMCR_EL0.N, and reset the rest to 0 */
 -      pmcr = read_sysreg(pmcr_el0) & ARMV8_PMU_PMCR_N_MASK;
 +      pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT);
        if (!kvm_supports_32bit_el0())
                pmcr |= ARMV8_PMU_PMCR_LC;
  
@@@ -1122,7 -1049,9 +1122,9 @@@ static bool access_arch_timer(struct kv
                treg = TIMER_REG_CVAL;
                break;
        default:
-               BUG();
+               print_sys_reg_msg(p, "%s", "Unhandled trapped timer register");
+               kvm_inject_undefined(vcpu);
+               return false;
        }
  
        if (p->is_write)
@@@ -1228,12 -1157,6 +1230,12 @@@ static u64 read_id_reg(const struct kvm
                val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon),
                                  pmuver_to_perfmon(vcpu_pmuver(vcpu)));
                break;
 +      case SYS_ID_AA64MMFR2_EL1:
 +              val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
 +              break;
 +      case SYS_ID_MMFR4_EL1:
 +              val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX);
 +              break;
        }
  
        return val;
@@@ -1464,78 -1387,10 +1466,78 @@@ static bool access_clidr(struct kvm_vcp
        if (p->is_write)
                return write_to_read_only(vcpu, p, r);
  
 -      p->regval = read_sysreg(clidr_el1);
 +      p->regval = __vcpu_sys_reg(vcpu, r->reg);
        return true;
  }
  
 +/*
 + * Fabricate a CLIDR_EL1 value instead of using the real value, which can vary
 + * by the physical CPU which the vcpu currently resides in.
 + */
 +static void reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 +{
 +      u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
 +      u64 clidr;
 +      u8 loc;
 +
 +      if ((ctr_el0 & CTR_EL0_IDC)) {
 +              /*
 +               * Data cache clean to the PoU is not required so LoUU and LoUIS
 +               * will not be set and a unified cache, which will be marked as
 +               * LoC, will be added.
 +               *
 +               * If not DIC, let the unified cache L2 so that an instruction
 +               * cache can be added as L1 later.
 +               */
 +              loc = (ctr_el0 & CTR_EL0_DIC) ? 1 : 2;
 +              clidr = CACHE_TYPE_UNIFIED << CLIDR_CTYPE_SHIFT(loc);
 +      } else {
 +              /*
 +               * Data cache clean to the PoU is required so let L1 have a data
 +               * cache and mark it as LoUU and LoUIS. As L1 has a data cache,
 +               * it can be marked as LoC too.
 +               */
 +              loc = 1;
 +              clidr = 1 << CLIDR_LOUU_SHIFT;
 +              clidr |= 1 << CLIDR_LOUIS_SHIFT;
 +              clidr |= CACHE_TYPE_DATA << CLIDR_CTYPE_SHIFT(1);
 +      }
 +
 +      /*
 +       * Instruction cache invalidation to the PoU is required so let L1 have
 +       * an instruction cache. If L1 already has a data cache, it will be
 +       * CACHE_TYPE_SEPARATE.
 +       */
 +      if (!(ctr_el0 & CTR_EL0_DIC))
 +              clidr |= CACHE_TYPE_INST << CLIDR_CTYPE_SHIFT(1);
 +
 +      clidr |= loc << CLIDR_LOC_SHIFT;
 +
 +      /*
 +       * Add tag cache unified to data cache. Allocation tags and data are
 +       * unified in a cache line so that it looks valid even if there is only
 +       * one cache line.
 +       */
 +      if (kvm_has_mte(vcpu->kvm))
 +              clidr |= 2 << CLIDR_TTYPE_SHIFT(loc);
 +
 +      __vcpu_sys_reg(vcpu, r->reg) = clidr;
 +}
 +
 +static int set_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 +                    u64 val)
 +{
 +      u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
 +      u64 idc = !CLIDR_LOC(val) || (!CLIDR_LOUIS(val) && !CLIDR_LOUU(val));
 +
 +      if ((val & CLIDR_EL1_RES0) || (!(ctr_el0 & CTR_EL0_IDC) && idc))
 +              return -EINVAL;
 +
 +      __vcpu_sys_reg(vcpu, rd->reg) = val;
 +
 +      return 0;
 +}
 +
  static bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                          const struct sys_reg_desc *r)
  {
@@@ -1557,10 -1412,22 +1559,10 @@@ static bool access_ccsidr(struct kvm_vc
                return write_to_read_only(vcpu, p, r);
  
        csselr = vcpu_read_sys_reg(vcpu, CSSELR_EL1);
 -      p->regval = get_ccsidr(csselr);
 +      csselr &= CSSELR_EL1_Level | CSSELR_EL1_InD;
 +      if (csselr < CSSELR_MAX)
 +              p->regval = get_ccsidr(vcpu, csselr);
  
 -      /*
 -       * Guests should not be doing cache operations by set/way at all, and
 -       * for this reason, we trap them and attempt to infer the intent, so
 -       * that we can flush the entire guest's address space at the appropriate
 -       * time.
 -       * To prevent this trapping from causing performance problems, let's
 -       * expose the geometry of all data and unified caches (which are
 -       * guaranteed to be PIPT and thus non-aliasing) as 1 set and 1 way.
 -       * [If guests should attempt to infer aliasing properties from the
 -       * geometry (which is not permitted by the architecture), they would
 -       * only do so for virtually indexed caches.]
 -       */
 -      if (!(csselr & 1)) // data or unified cache
 -              p->regval &= ~GENMASK(27, 3);
        return true;
  }
  
@@@ -1852,9 -1719,7 +1854,9 @@@ static const struct sys_reg_desc sys_re
        { SYS_DESC(SYS_CNTKCTL_EL1), NULL, reset_val, CNTKCTL_EL1, 0},
  
        { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
 -      { SYS_DESC(SYS_CLIDR_EL1), access_clidr },
 +      { SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
 +        .set_user = set_clidr },
 +      { SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
        { SYS_DESC(SYS_SMIDR_EL1), undef_access },
        { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
        { SYS_DESC(SYS_CTR_EL0), access_ctr },
@@@ -2356,10 -2221,6 +2358,10 @@@ static const struct sys_reg_desc cp15_r
  
        { Op1(1), CRn( 0), CRm( 0), Op2(0), access_ccsidr },
        { Op1(1), CRn( 0), CRm( 0), Op2(1), access_clidr },
 +
 +      /* CCSIDR2 */
 +      { Op1(1), CRn( 0), CRm( 0),  Op2(2), undef_access },
 +
        { Op1(2), CRn( 0), CRm( 0), Op2(0), access_csselr, NULL, CSSELR_EL1 },
  };
  
@@@ -2865,6 -2726,7 +2867,6 @@@ id_to_sys_reg_desc(struct kvm_vcpu *vcp
  
  FUNCTION_INVARIANT(midr_el1)
  FUNCTION_INVARIANT(revidr_el1)
 -FUNCTION_INVARIANT(clidr_el1)
  FUNCTION_INVARIANT(aidr_el1)
  
  static void get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r)
  }
  
  /* ->val is filled in by kvm_sys_reg_table_init() */
 -static struct sys_reg_desc invariant_sys_regs[] = {
 +static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = {
        { SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 },
        { SYS_DESC(SYS_REVIDR_EL1), NULL, get_revidr_el1 },
 -      { SYS_DESC(SYS_CLIDR_EL1), NULL, get_clidr_el1 },
        { SYS_DESC(SYS_AIDR_EL1), NULL, get_aidr_el1 },
        { SYS_DESC(SYS_CTR_EL0), NULL, get_ctr_el0 },
  };
@@@ -2912,7 -2775,33 +2914,7 @@@ static int set_invariant_sys_reg(u64 id
        return 0;
  }
  
 -static bool is_valid_cache(u32 val)
 -{
 -      u32 level, ctype;
 -
 -      if (val >= CSSELR_MAX)
 -              return false;
 -
 -      /* Bottom bit is Instruction or Data bit.  Next 3 bits are level. */
 -      level = (val >> 1);
 -      ctype = (cache_levels >> (level * 3)) & 7;
 -
 -      switch (ctype) {
 -      case 0: /* No cache */
 -              return false;
 -      case 1: /* Instruction cache only */
 -              return (val & 1);
 -      case 2: /* Data cache only */
 -      case 4: /* Unified cache */
 -              return !(val & 1);
 -      case 3: /* Separate instruction and data caches */
 -              return true;
 -      default: /* Reserved: we can't know instruction or data. */
 -              return false;
 -      }
 -}
 -
 -static int demux_c15_get(u64 id, void __user *uaddr)
 +static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
  {
        u32 val;
        u32 __user *uval = uaddr;
                        return -ENOENT;
                val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
                        >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
 -              if (!is_valid_cache(val))
 +              if (val >= CSSELR_MAX)
                        return -ENOENT;
  
 -              return put_user(get_ccsidr(val), uval);
 +              return put_user(get_ccsidr(vcpu, val), uval);
        default:
                return -ENOENT;
        }
  }
  
 -static int demux_c15_set(u64 id, void __user *uaddr)
 +static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
  {
        u32 val, newval;
        u32 __user *uval = uaddr;
                        return -ENOENT;
                val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
                        >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
 -              if (!is_valid_cache(val))
 +              if (val >= CSSELR_MAX)
                        return -ENOENT;
  
                if (get_user(newval, uval))
                        return -EFAULT;
  
 -              /* This is also invariant: you can't change it. */
 -              if (newval != get_ccsidr(val))
 -                      return -EINVAL;
 -              return 0;
 +              return set_ccsidr(vcpu, val, newval);
        default:
                return -ENOENT;
        }
@@@ -2996,7 -2888,7 +2998,7 @@@ int kvm_arm_sys_reg_get_reg(struct kvm_
        int err;
  
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
 -              return demux_c15_get(reg->id, uaddr);
 +              return demux_c15_get(vcpu, reg->id, uaddr);
  
        err = get_invariant_sys_reg(reg->id, uaddr);
        if (err != -ENOENT)
@@@ -3040,7 -2932,7 +3042,7 @@@ int kvm_arm_sys_reg_set_reg(struct kvm_
        int err;
  
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
 -              return demux_c15_set(reg->id, uaddr);
 +              return demux_c15_set(vcpu, reg->id, uaddr);
  
        err = set_invariant_sys_reg(reg->id, uaddr);
        if (err != -ENOENT)
  
  static unsigned int num_demux_regs(void)
  {
 -      unsigned int i, count = 0;
 -
 -      for (i = 0; i < CSSELR_MAX; i++)
 -              if (is_valid_cache(i))
 -                      count++;
 -
 -      return count;
 +      return CSSELR_MAX;
  }
  
  static int write_demux_regids(u64 __user *uindices)
  
        val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
        for (i = 0; i < CSSELR_MAX; i++) {
 -              if (!is_valid_cache(i))
 -                      continue;
                if (put_user(val | i, uindices))
                        return -EFAULT;
                uindices++;
@@@ -3159,10 -3059,11 +3161,10 @@@ int kvm_arm_copy_sys_reg_indices(struc
        return write_demux_regids(uindices);
  }
  
 -int kvm_sys_reg_table_init(void)
 +int __init kvm_sys_reg_table_init(void)
  {
        bool valid = true;
        unsigned int i;
 -      struct sys_reg_desc clidr;
  
        /* Make sure tables are unique and in order. */
        valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);
        for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
                invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
  
 -      /*
 -       * CLIDR format is awkward, so clean it up.  See ARM B4.1.20:
 -       *
 -       *   If software reads the Cache Type fields from Ctype1
 -       *   upwards, once it has seen a value of 0b000, no caches
 -       *   exist at further-out levels of the hierarchy. So, for
 -       *   example, if Ctype3 is the first Cache Type field with a
 -       *   value of 0b000, the values of Ctype4 to Ctype7 must be
 -       *   ignored.
 -       */
 -      get_clidr_el1(NULL, &clidr); /* Ugly... */
 -      cache_levels = clidr.val;
 -      for (i = 0; i < 7; i++)
 -              if (((cache_levels >> (i*3)) & 7) == 0)
 -                      break;
 -      /* Clear all higher bits. */
 -      cache_levels &= (1 << (i*3))-1;
 -
        return 0;
  }
This page took 0.092577 seconds and 4 git commands to generate.