#define SYS_PMCCFILTR_EL0              sys_reg(3, 3, 14, 15, 7)
 
+#define SYS_VPIDR_EL2                  sys_reg(3, 4, 0, 0, 0)
+#define SYS_VMPIDR_EL2                 sys_reg(3, 4, 0, 0, 5)
+
 #define SYS_SCTLR_EL2                  sys_reg(3, 4, 1, 0, 0)
+#define SYS_ACTLR_EL2                  sys_reg(3, 4, 1, 0, 1)
+#define SYS_HCR_EL2                    sys_reg(3, 4, 1, 1, 0)
+#define SYS_MDCR_EL2                   sys_reg(3, 4, 1, 1, 1)
+#define SYS_CPTR_EL2                   sys_reg(3, 4, 1, 1, 2)
+#define SYS_HSTR_EL2                   sys_reg(3, 4, 1, 1, 3)
 #define SYS_HFGRTR_EL2                 sys_reg(3, 4, 1, 1, 4)
 #define SYS_HFGWTR_EL2                 sys_reg(3, 4, 1, 1, 5)
 #define SYS_HFGITR_EL2                 sys_reg(3, 4, 1, 1, 6)
+#define SYS_HACR_EL2                   sys_reg(3, 4, 1, 1, 7)
+
+#define SYS_TTBR0_EL2                  sys_reg(3, 4, 2, 0, 0)
+#define SYS_TTBR1_EL2                  sys_reg(3, 4, 2, 0, 1)
+#define SYS_TCR_EL2                    sys_reg(3, 4, 2, 0, 2)
+#define SYS_VTTBR_EL2                  sys_reg(3, 4, 2, 1, 0)
+#define SYS_VTCR_EL2                   sys_reg(3, 4, 2, 1, 2)
+
 #define SYS_TRFCR_EL2                  sys_reg(3, 4, 1, 2, 1)
 #define SYS_HDFGRTR_EL2                        sys_reg(3, 4, 3, 1, 4)
 #define SYS_HDFGWTR_EL2                        sys_reg(3, 4, 3, 1, 5)
 #define SYS_HAFGRTR_EL2                        sys_reg(3, 4, 3, 1, 6)
 #define SYS_SPSR_EL2                   sys_reg(3, 4, 4, 0, 0)
 #define SYS_ELR_EL2                    sys_reg(3, 4, 4, 0, 1)
+#define SYS_SP_EL1                     sys_reg(3, 4, 4, 1, 0)
 #define SYS_IFSR32_EL2                 sys_reg(3, 4, 5, 0, 1)
+#define SYS_AFSR0_EL2                  sys_reg(3, 4, 5, 1, 0)
+#define SYS_AFSR1_EL2                  sys_reg(3, 4, 5, 1, 1)
 #define SYS_ESR_EL2                    sys_reg(3, 4, 5, 2, 0)
 #define SYS_VSESR_EL2                  sys_reg(3, 4, 5, 2, 3)
 #define SYS_FPEXC32_EL2                        sys_reg(3, 4, 5, 3, 0)
 #define SYS_TFSR_EL2                   sys_reg(3, 4, 5, 6, 0)
 
-#define SYS_VDISR_EL2                  sys_reg(3, 4, 12, 1,  1)
+#define SYS_FAR_EL2                    sys_reg(3, 4, 6, 0, 0)
+#define SYS_HPFAR_EL2                  sys_reg(3, 4, 6, 0, 4)
+
+#define SYS_MAIR_EL2                   sys_reg(3, 4, 10, 2, 0)
+#define SYS_AMAIR_EL2                  sys_reg(3, 4, 10, 3, 0)
+
+#define SYS_VBAR_EL2                   sys_reg(3, 4, 12, 0, 0)
+#define SYS_RVBAR_EL2                  sys_reg(3, 4, 12, 0, 1)
+#define SYS_RMR_EL2                    sys_reg(3, 4, 12, 0, 2)
+#define SYS_VDISR_EL2                  sys_reg(3, 4, 12, 1, 1)
 #define __SYS__AP0Rx_EL2(x)            sys_reg(3, 4, 12, 8, x)
 #define SYS_ICH_AP0R0_EL2              __SYS__AP0Rx_EL2(0)
 #define SYS_ICH_AP0R1_EL2              __SYS__AP0Rx_EL2(1)
 #define SYS_ICH_LR14_EL2               __SYS__LR8_EL2(6)
 #define SYS_ICH_LR15_EL2               __SYS__LR8_EL2(7)
 
+#define SYS_CONTEXTIDR_EL2             sys_reg(3, 4, 13, 0, 1)
+#define SYS_TPIDR_EL2                  sys_reg(3, 4, 13, 0, 2)
+
+#define SYS_CNTVOFF_EL2                        sys_reg(3, 4, 14, 0, 3)
+#define SYS_CNTHCTL_EL2                        sys_reg(3, 4, 14, 1, 0)
+
 /* VHE encodings for architectural EL0/1 system registers */
 #define SYS_SCTLR_EL12                 sys_reg(3, 5, 1, 0, 0)
 #define SYS_TTBR0_EL12                 sys_reg(3, 5, 2, 0, 0)
 #define SYS_CNTV_CTL_EL02              sys_reg(3, 5, 14, 3, 1)
 #define SYS_CNTV_CVAL_EL02             sys_reg(3, 5, 14, 3, 2)
 
+#define SYS_SP_EL2                     sys_reg(3, 6,  4, 1, 0)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_ENTP2        (BIT(60))
 #define SCTLR_ELx_DSSBS        (BIT(44))
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_nested.h>
 #include <asm/perf_event.h>
 #include <asm/sysreg.h>
 
        return ccsidr;
 }
 
+static bool access_rw(struct kvm_vcpu *vcpu,
+                     struct sys_reg_params *p,
+                     const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               vcpu_write_sys_reg(vcpu, p->regval, r->reg);
+       else
+               p->regval = vcpu_read_sys_reg(vcpu, r->reg);
+
+       return true;
+}
+
 /*
  * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
  */
                return read_zero(vcpu, p);
 }
 
+static bool trap_undef(struct kvm_vcpu *vcpu,
+                      struct sys_reg_params *p,
+                      const struct sys_reg_desc *r)
+{
+       kvm_inject_undefined(vcpu);
+       return false;
+}
+
 /*
  * ARMv8.1 mandates at least a trivial LORegion implementation, where all the
  * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0
                            struct sys_reg_params *p,
                            const struct sys_reg_desc *r)
 {
-       if (p->is_write) {
-               vcpu_write_sys_reg(vcpu, p->regval, r->reg);
+       access_rw(vcpu, p, r);
+       if (p->is_write)
                vcpu_set_flag(vcpu, DEBUG_DIRTY);
-       } else {
-               p->regval = vcpu_read_sys_reg(vcpu, r->reg);
-       }
 
        trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
 
        .visibility = mte_visibility,           \
 }
 
+static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *rd)
+{
+       if (vcpu_has_nv(vcpu))
+               return 0;
+
+       return REG_HIDDEN;
+}
+
+#define EL2_REG(name, acc, rst, v) {           \
+       SYS_DESC(SYS_##name),                   \
+       .access = acc,                          \
+       .reset = rst,                           \
+       .reg = name,                            \
+       .visibility = el2_visibility,           \
+       .val = v,                               \
+}
+
 /* sys_reg_desc initialiser for known cpufeature ID registers */
 #define ID_SANITISED(name) {                   \
        SYS_DESC(SYS_##name),                   \
        .visibility = raz_visibility,           \
 }
 
+static bool access_sp_el1(struct kvm_vcpu *vcpu,
+                         struct sys_reg_params *p,
+                         const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               __vcpu_sys_reg(vcpu, SP_EL1) = p->regval;
+       else
+               p->regval = __vcpu_sys_reg(vcpu, SP_EL1);
+
+       return true;
+}
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
        { PMU_SYS_REG(SYS_PMCCFILTR_EL0), .access = access_pmu_evtyper,
          .reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 },
 
+       EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0),
+       EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0),
+       EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
+       EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
+       EL2_REG(HCR_EL2, access_rw, reset_val, 0),
+       EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
+       EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_EL2_DEFAULT ),
+       EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
+       EL2_REG(HACR_EL2, access_rw, reset_val, 0),
+
+       EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
+       EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
+       EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),
+       EL2_REG(VTTBR_EL2, access_rw, reset_val, 0),
+       EL2_REG(VTCR_EL2, access_rw, reset_val, 0),
+
        { SYS_DESC(SYS_DACR32_EL2), NULL, reset_unknown, DACR32_EL2 },
+       EL2_REG(SPSR_EL2, access_rw, reset_val, 0),
+       EL2_REG(ELR_EL2, access_rw, reset_val, 0),
+       { SYS_DESC(SYS_SP_EL1), access_sp_el1},
+
        { SYS_DESC(SYS_IFSR32_EL2), NULL, reset_unknown, IFSR32_EL2 },
+       EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
+       EL2_REG(AFSR1_EL2, access_rw, reset_val, 0),
+       EL2_REG(ESR_EL2, access_rw, reset_val, 0),
        { SYS_DESC(SYS_FPEXC32_EL2), NULL, reset_val, FPEXC32_EL2, 0x700 },
+
+       EL2_REG(FAR_EL2, access_rw, reset_val, 0),
+       EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
+
+       EL2_REG(MAIR_EL2, access_rw, reset_val, 0),
+       EL2_REG(AMAIR_EL2, access_rw, reset_val, 0),
+
+       EL2_REG(VBAR_EL2, access_rw, reset_val, 0),
+       EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
+       { SYS_DESC(SYS_RMR_EL2), trap_undef },
+
+       EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
+       EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
+
+       EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0),
+       EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0),
+
+       EL2_REG(SP_EL2, NULL, reset_unknown, 0),
 };
 
 static bool trap_dbgdidr(struct kvm_vcpu *vcpu,