diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 57f10c5..1390a98 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -190,7 +190,9 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
     MachineClass *mc = MACHINE_CLASS(oc);
     NMIClass *nc = NMI_CLASS(oc);
     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 
+    s390mc->ri_allowed = true;
     mc->init = ccw_init;
     mc->reset = s390_machine_reset;
     mc->hot_add_cpu = s390_hot_add_cpu;
@@ -237,6 +239,20 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
     ms->dea_key_wrap = value;
 }
 
+bool ri_allowed(void)
+{
+    if (kvm_enabled()) {
+        MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+        if (object_class_dynamic_cast(OBJECT_CLASS(mc),
+                                      TYPE_S390_CCW_MACHINE)) {
+            S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+            return s390mc->ri_allowed;
+        }
+    }
+    return 0;
+}
+
 static inline void s390_machine_initfn(Object *obj)
 {
     object_property_add_bool(obj, "aes-key-wrap",
@@ -262,6 +278,7 @@ static const TypeInfo ccw_machine_info = {
     .abstract      = true,
     .instance_size = sizeof(S390CcwMachineState),
     .instance_init = s390_machine_initfn,
+    .class_size = sizeof(S390CcwMachineClass),
     .class_init    = ccw_machine_class_init,
     .interfaces = (InterfaceInfo[]) {
         { TYPE_NMI },
@@ -363,6 +380,9 @@ static void ccw_machine_2_6_instance_options(MachineState *machine)
 
 static void ccw_machine_2_6_class_options(MachineClass *mc)
 {
+    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+    s390mc->ri_allowed = false;
     ccw_machine_2_7_class_options(mc);
     SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
 }
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index ab08332..a0c1fc8 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -35,6 +35,10 @@ typedef struct S390CcwMachineClass {
     MachineClass parent_class;
 
     /*< public >*/
+    bool ri_allowed;
 } S390CcwMachineClass;
 
+/* runtime-instrumentation allowed by the machine */
+bool ri_allowed(void);
+
 #endif
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 07f76ad..996b790 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -135,6 +135,8 @@ typedef struct CPUS390XState {
     uint64_t gbea;
     uint64_t pp;
 
+    uint8_t riccb[64];
+
     CPU_COMMON
 
     /* reset does memset(0) up to here */
@@ -1159,6 +1161,7 @@ void kvm_s390_reset_vcpu(S390CPU *cpu);
 int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
 void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
 int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
+int kvm_s390_get_ri(void);
 void kvm_s390_crypto_reset(void);
 #else
 static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
@@ -1209,6 +1212,10 @@ static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
 {
     return 0;
 }
+static inline int kvm_s390_get_ri(void)
+{
+    return 0;
+}
 static inline void kvm_s390_crypto_reset(void)
 {
 }
@@ -1272,11 +1279,22 @@ static inline bool vregs_needed(void *opaque)
     }
     return 0;
 }
+static inline bool riccb_needed(void *opaque)
+{
+    if (kvm_enabled()) {
+        return kvm_s390_get_ri();
+    }
+    return 0;
+}
 #else
 static inline bool vregs_needed(void *opaque)
 {
     return 0;
 }
+static inline bool riccb_needed(void *opaque)
+{
+    return 0;
+}
 #endif
 
 /* machine check interruption code */
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index e1859ca..55ae6d3 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -46,6 +46,7 @@
 #include "hw/s390x/ipl.h"
 #include "hw/s390x/ebcdic.h"
 #include "exec/memattrs.h"
+#include "hw/s390x/s390-virtio-ccw.h"
 
 /* #define DEBUG_KVM */
 
@@ -135,6 +136,7 @@ static int cap_sync_regs;
 static int cap_async_pf;
 static int cap_mem_op;
 static int cap_s390_irq;
+static int cap_ri;
 
 static void *legacy_s390_alloc(size_t size, uint64_t *align);
 
@@ -270,6 +272,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
     kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
+    if (ri_allowed()) {
+        if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
+            cap_ri = 1;
+        }
+    }
 
     return 0;
 }
@@ -386,6 +393,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         kvm_set_one_reg(cs, KVM_REG_S390_PP, &env->pp);
     }
 
+    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
+        memcpy(cs->kvm_run->s.regs.riccb, env->riccb, 64);
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_RICCB;
+    }
+
     /* pfault parameters */
     if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
         cs->kvm_run->s.regs.pft = env->pfault_token;
@@ -528,6 +540,10 @@ int kvm_arch_get_registers(CPUState *cs)
         kvm_get_one_reg(cs, KVM_REG_S390_PP, &env->pp);
     }
 
+    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
+        memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
+    }
+
     /* pfault parameters */
     if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
         env->pfault_token = cs->kvm_run->s.regs.pft;
@@ -2136,6 +2152,11 @@ int kvm_s390_get_memslot_count(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
 }
 
+int kvm_s390_get_ri(void)
+{
+    return cap_ri;
+}
+
 int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
 {
     struct kvm_mp_state mp_state = {};
diff --git a/target-s390x/machine.c b/target-s390x/machine.c
index 6b26090..a30b16f 100644
--- a/target-s390x/machine.c
+++ b/target-s390x/machine.c
@@ -135,6 +135,17 @@ static const VMStateDescription vmstate_vregs = {
     }
 };
 
+const VMStateDescription vmstate_riccb = {
+    .name = "cpu/riccb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = riccb_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(env.riccb, S390CPU, 64),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_s390_cpu = {
     .name = "cpu",
     .post_load = cpu_post_load,
@@ -166,6 +177,7 @@ const VMStateDescription vmstate_s390_cpu = {
     .subsections = (const VMStateDescription*[]) {
         &vmstate_fpu,
         &vmstate_vregs,
+        &vmstate_riccb,
         NULL
     },
 };
