|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH v1 23/26] xen/arm/cca: handle Realm RIPAS and GIC sysreg exits
Handle RIPAS changes and selected GICv3 sysreg exits. RIPAS work runs
before the next REC entry, and sysreg transfers use ESR_EL2.ISS.Rt.
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
xen/arch/arm/cca/rec.c | 209 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 206 insertions(+), 3 deletions(-)
diff --git a/xen/arch/arm/cca/rec.c b/xen/arch/arm/cca/rec.c
index efff7fa48745..7959fb767e11 100644
--- a/xen/arch/arm/cca/rec.c
+++ b/xen/arch/arm/cca/rec.c
@@ -399,6 +399,66 @@ static void arm_cca_set_mmio_result(unsigned long
*entry_flags,
entry_gprs[0] = value;
}
+static register_t
+arm_cca_rec_exit_gpr(const struct arm_cca_rmi_rec_exit *exit,
+ unsigned int reg)
+{
+ return reg < ARM_CCA_RMI_REC_NR_GPRS ? exit->gprs[reg] : 0;
+}
+
+static void arm_cca_rec_enter_set_gpr(register_t *entry_gprs,
+ unsigned int reg,
+ register_t value)
+{
+ if ( reg < ARM_CCA_RMI_REC_NR_GPRS )
+ entry_gprs[reg] = value;
+}
+
+static bool arm_cca_vgic_emulate_sgi1r(struct vcpu *v, register_t sgir)
+{
+ return vgic_v3_to_sgi(v, sgir);
+}
+
+static bool arm_cca_vgic_emulate_dir(struct vcpu *v, register_t dir)
+{
+ unsigned int virq = dir & GICC_IAR_INTID_MASK;
+ struct gic_lr lr;
+ unsigned int i;
+
+ /*
+ * RMM may exit to Xen for Realm ICC_DIR_EL1 accesses. Handle the
+ * deactivation locally when Xen can find a matching software LR.
+ * DEN0137 2.0-bet1 - A6.1 Realm interrupts.
+ */
+ if ( virq >= vgic_num_irqs(v->domain) )
+ return true;
+
+ for ( i = 0; i < gic_get_nr_lrs(); i++ )
+ {
+ gic_hw_ops->read_lr(i, &lr);
+
+ if ( lr.virq != virq || !lr.active )
+ continue;
+
+ if ( lr.hw_status )
+ {
+ gprintk(XENLOG_ERR,
+ "ARM CCA: ICC_DIR_EL1 on hw-backed vIRQ %u is
unsupported\n",
+ virq);
+ return false;
+ }
+
+ lr.active = false;
+ gic_hw_ops->write_lr(i, &lr);
+ isb();
+ vgic_sync_from_lrs(v);
+
+ return true;
+ }
+
+ return true;
+}
+
static void arm_cca_request_sea(unsigned long *entry_flags,
register_t *entry_gprs)
{
@@ -560,6 +620,87 @@ static void arm_cca_handle_psci_exit(struct vcpu *v,
}
}
+/*
+ * DEN0137 2.0-bet1 - D1.5.3 RIPAS change flow.
+ * RIPAS_EMPTY and RIPAS_RAM changes are applied with RMI_RTT_SET_RIPAS.
+ * RIPAS_DEV requires VDEV mapping validation support, while RIPAS_DESTROYED
+ * is not a Realm-requested target state.
+ */
+static void
+arm_cca_handle_ripas_change(struct vcpu *v,
+ const struct arm_cca_rmi_rec_exit *exit,
+ unsigned long *entry_flags)
+{
+ struct arm_smccc_res res;
+ paddr_t base = exit->ripas_base;
+ paddr_t top = exit->ripas_top;
+ int rc;
+
+ if ( v->domain->arch.cca.rd == INVALID_PADDR )
+ {
+ gprintk(XENLOG_ERR,
+ "ARM CCA: missing RD for RIPAS completion\n");
+ arm_cca_domain_crash(v);
+ }
+
+ switch ( exit->ripas_value )
+ {
+ case ARM_CCA_RMI_RIPAS_EMPTY:
+ case ARM_CCA_RMI_RIPAS_RAM:
+ break;
+
+ default:
+ gprintk(XENLOG_ERR,
+ "ARM CCA: unsupported RIPAS change value=%u "
+ "range=%#lx-%#lx\n",
+ (unsigned int)exit->ripas_value,
+ (unsigned long)base, (unsigned long)top);
+ arm_cca_domain_crash(v);
+ }
+
+ /*
+ * Note that RMI_RTT_SET_RIPAS uses the pending request recorded in the
+ * REC, so the Host does not pass the target RIPAS value explicitly here.
+ *
+ * Xen accepts the request while progress is possible. If a RIPAS_RAM
+ * request reaches a point the RMM cannot change, report Host rejection on
+ * the next REC_ENTER so the Realm sees the normal RSI response.
+ */
+ while ( base < top )
+ {
+ rc = arm_cca_rmi_rtt_set_ripas(v->domain->arch.cca.rd,
+ v->arch.cca.rec,
+ base, top, &res);
+ if ( rc != 0 )
+ {
+ if ( exit->ripas_value == ARM_CCA_RMI_RIPAS_RAM &&
+ arm_cca_rmi_status_is(arm_cca_rmi_result(&res),
+ ARM_CCA_RMI_ERROR_RTT) )
+ {
+ /* The RIPAS response flag value 1 means Host reject. */
+ *entry_flags |= ARM_CCA_RMI_REC_ENTER_FLAG_RIPAS_RESPONSE;
+ return;
+ }
+
+ gprintk(XENLOG_ERR,
+ "ARM CCA: RMI_RTT_SET_RIPAS failed status=%#x data=%#lx\n",
+ arm_cca_rmi_status_code(arm_cca_rmi_result(&res)),
+ (unsigned long)arm_cca_rmi_result_data(
+ arm_cca_rmi_result(&res)));
+ arm_cca_domain_crash(v);
+ }
+
+ if ( res.a1 <= base || res.a1 > top )
+ {
+ gprintk(XENLOG_ERR,
+ "ARM CCA: invalid RIPAS progress %#lx -> %#lx (top
%#lx)\n",
+ (unsigned long)base, res.a1, (unsigned long)top);
+ arm_cca_domain_crash(v);
+ }
+
+ base = res.a1;
+ }
+}
/*
* DEN0137 2.0-bet1 - D1.3.3 REC exit due to Data Abort fault flow.
@@ -573,6 +714,55 @@ static void arm_cca_handle_sync_exit(struct vcpu *v,
switch ( hsr.ec )
{
+ case HSR_EC_SYSREG:
+ {
+ unsigned int rt = hsr.sysreg.reg;
+ register_t val = arm_cca_rec_exit_gpr(exit, rt);
+
+ /*
+ * Realm guests use the GICv3 sysreg CPU interface:
+ * - Linux expects ICC_SRE_EL1.SRE to read as enabled.
+ * - SGI generation and explicit deactivate stay in Xen's vGIC path.
+ *
+ * DEN0137 2.0-bet1 A6.1 makes ICC_* traps System register exits,
+ * but A4.3.4.4 only guarantees ESR. Use the Rt encoded in ESR_EL2.ISS
+ * for the transfer GPR. Current TF-RMM clears Rt for these exits,
+ * making this equivalent to its gprs[0] convention.
+ */
+ switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
+ {
+ case HSR_SYSREG_ICC_SRE_EL1:
+ arm_cca_rec_enter_set_gpr(entry_gprs, rt,
+ ARM_CCA_ICC_SRE_EL1_VALUE);
+ break;
+ case HSR_SYSREG_ICC_DIR_EL1:
+ if ( hsr.sysreg.read ||
+ !arm_cca_vgic_emulate_dir(v, val) )
+ {
+ gprintk(XENLOG_ERR,
+ "ARM CCA: unsupported ICC_DIR_EL1 access read=%u
val=%#lx\n",
+ hsr.sysreg.read, val);
+ arm_cca_domain_crash(v);
+ }
+ break;
+ case HSR_SYSREG_ICC_SGI1R_EL1:
+ if ( hsr.sysreg.read ||
+ !arm_cca_vgic_emulate_sgi1r(v, val) )
+ {
+ gprintk(XENLOG_ERR,
+ "ARM CCA: unsupported ICC_SGI1R_EL1 access read=%u
val=%#lx\n",
+ hsr.sysreg.read, val);
+ arm_cca_domain_crash(v);
+ }
+ break;
+ default:
+ gprintk(XENLOG_ERR,
+ "ARM CCA: unsupported SYSREG ec=%#x sysreg=%#lx\n",
+ hsr.ec, (unsigned long)(hsr.bits & HSR_SYSREG_REGS_MASK));
+ arm_cca_domain_crash(v);
+ }
+ break;
+ }
case HSR_EC_WFI_WFE:
/*
* DEN0137 2.0-bet1 - A4.3.4.1 REC exit due to WFI or WFE.
@@ -619,6 +809,7 @@ void noreturn arm_cca_vcpu_run(struct vcpu *v)
struct arm_smccc_res res;
unsigned long entry_flags;
register_t entry_gprs[ARM_CCA_RMI_REC_NR_GPRS];
+ bool pending_ripas = false;
int rc;
ASSERT(v == current);
@@ -663,6 +854,19 @@ void noreturn arm_cca_vcpu_run(struct vcpu *v)
arm_cca_check_for_vcpu_work(v);
arm_cca_service_host_events();
+ /*
+ * RMI_RTT_SET_RIPAS can cover a large range. The REC exit buffer
+ * remains valid until the next REC_ENTER, so complete the request
+ * here with IRQs enabled rather than in the exit dispatch path.
+ */
+ if ( pending_ripas )
+ {
+ local_irq_enable();
+ arm_cca_handle_ripas_change(v, &run->exit, &entry_flags);
+ local_irq_disable();
+ pending_ripas = false;
+ }
+
arm_cca_prepare_rec_enter(run, entry_flags, entry_gprs);
entry_flags = ARM_CCA_RMI_REC_ENTER_FLAG_TRAP_WFI |
ARM_CCA_RMI_REC_ENTER_FLAG_TRAP_WFE;
@@ -700,9 +904,8 @@ void noreturn arm_cca_vcpu_run(struct vcpu *v)
break;
case ARM_CCA_RMI_EXIT_RIPAS_CHANGE:
- gprintk(XENLOG_ERR,
- "ARM CCA: RIPAS change exits are unsupported\n");
- arm_cca_domain_crash(v);
+ pending_ripas = true;
+ break;
case ARM_CCA_RMI_EXIT_SYNC:
arm_cca_handle_sync_exit(v, &run->exit, &entry_flags,
--
2.51.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |