{
        trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_guest(vcpu, r)) {
+               kvm_inject_undefined(vcpu);
+               return;
+       }
+
        /*
         * Not having an accessor means that we have configured a trap
         * that we don't know how to handle. This certainly qualifies
        if (!r)
                return get_invariant_sys_reg(reg->id, uaddr);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_user(vcpu, r))
+               return -ENOENT;
+
        if (r->get_user)
                return (r->get_user)(vcpu, r, reg, uaddr);
 
        if (!r)
                return set_invariant_sys_reg(reg->id, uaddr);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_user(vcpu, r))
+               return -ENOENT;
+
        if (r->set_user)
                return (r->set_user)(vcpu, r, reg, uaddr);
 
        return true;
 }
 
-static int walk_one_sys_reg(const struct sys_reg_desc *rd,
+static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
+                           const struct sys_reg_desc *rd,
                            u64 __user **uind,
                            unsigned int *total)
 {
        if (!(rd->reg || rd->get_user))
                return 0;
 
+       if (sysreg_hidden_from_user(vcpu, rd))
+               return 0;
+
        if (!copy_reg_to_user(rd, uind))
                return -EFAULT;
 
                int cmp = cmp_sys_reg(i1, i2);
                /* target-specific overrides generic entry. */
                if (cmp <= 0)
-                       err = walk_one_sys_reg(i1, &uind, &total);
+                       err = walk_one_sys_reg(vcpu, i1, &uind, &total);
                else
-                       err = walk_one_sys_reg(i2, &uind, &total);
+                       err = walk_one_sys_reg(vcpu, i2, &uind, &total);
 
                if (err)
                        return err;
 
                        const struct kvm_one_reg *reg, void __user *uaddr);
        int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                        const struct kvm_one_reg *reg, void __user *uaddr);
+
+       /* Return mask of REG_* runtime visibility overrides */
+       unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *rd);
 };
 
+#define REG_HIDDEN_USER                (1 << 0) /* hidden from userspace ioctls */
+#define REG_HIDDEN_GUEST       (1 << 1) /* hidden from guest */
+
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)
 {
        /* Look, we even formatted it for you to paste into the table! */
        __vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
+static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
+                                           const struct sys_reg_desc *r)
+{
+       if (likely(!r->visibility))
+               return false;
+
+       return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
+}
+
+static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
+                                          const struct sys_reg_desc *r)
+{
+       if (likely(!r->visibility))
+               return false;
+
+       return r->visibility(vcpu, r) & REG_HIDDEN_USER;
+}
+
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
                              const struct sys_reg_desc *i2)
 {