From: Corneliu ZUZU <czuzu@bitdefender.com>
To: xen-devel@lists.xen.org
Cc: Julien Grall <julien.grall@arm.com>,
Stefano Stabellini <sstabellini@kernel.org>,
Tamas K Lengyel <tamas@tklengyel.com>,
Razvan Cojocaru <rcojocaru@bitdefender.com>
Subject: [PATCH 7/7] vm-event/arm: implement support for control-register write vm-events
Date: Thu, 16 Jun 2016 17:13:23 +0300 [thread overview]
Message-ID: <1466086403-7749-1-git-send-email-czuzu@bitdefender.com> (raw)
In-Reply-To: <1466085888-7428-1-git-send-email-czuzu@bitdefender.com>
Add ARM support for control-register write monitoring through the vm-events
subsystem.
Chosen ARM system control-registers that can be monitored are:
- VM_EVENT_ARM_SCTLR: AArch32 SCTLR, AArch64 SCTLR_EL1
- VM_EVENT_ARM_TTBR{0,1}: AArch32 TTBR{0,1}, AArch64 TTBR{0,1}_EL1
- VM_EVENT_ARM_TTBCR: AArch32 TTBCR, AArch64 TCR_EL1
Trapping of write operations of these registers was attained by setting the
HCR_EL2.TVM / HCR.TVM bit.
Signed-off-by: Corneliu ZUZU <czuzu@bitdefender.com>
---
MAINTAINERS | 1 +
xen/arch/arm/Makefile | 1 +
xen/arch/arm/traps.c | 126 +++++++++++++++++++-
xen/arch/arm/vm_event.c | 112 ++++++++++++++++++
xen/common/monitor.c | 2 -
xen/common/vm_event.c | 2 -
xen/include/asm-arm/domain.h | 30 +++++
xen/include/asm-arm/traps.h | 253 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/vm_event.h | 22 +++-
xen/include/public/vm_event.h | 8 +-
xen/include/xen/monitor.h | 2 -
xen/include/xen/vm_event.h | 2 -
12 files changed, 543 insertions(+), 18 deletions(-)
create mode 100644 xen/arch/arm/vm_event.c
create mode 100644 xen/include/asm-arm/traps.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 9a224d4..634f359 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -402,6 +402,7 @@ M: Tamas K Lengyel <tamas@tklengyel.com>
S: Supported
F: xen/common/mem_access.c
F: xen/*/vm_event.c
+F: xen/arch/*/vm_event.c
F: xen/*/monitor.c
F: xen/include/*/mem_access.h
F: xen/include/*/monitor.h
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 9e38da3..390df0a 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -40,6 +40,7 @@ obj-y += device.o
obj-y += decode.o
obj-y += processor.o
obj-y += smc.o
+obj-y += vm_event.o
obj-$(CONFIG_LIVEPATCH) += livepatch.o
#obj-bin-y += ....o
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 8c50685..af61ac3 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -43,6 +43,7 @@
#include <asm/mmio.h>
#include <asm/cpufeature.h>
#include <asm/flushtlb.h>
+#include <asm/traps.h>
#include "decode.h"
#include "vtimer.h"
@@ -124,7 +125,12 @@ void init_traps(void)
WRITE_SYSREG((HCPTR_CP_MASK & ~(HCPTR_CP(10) | HCPTR_CP(11))) | HCPTR_TTA,
CPTR_EL2);
- /* Setup hypervisor traps */
+ /* Setup hypervisor traps
+ *
+ * Note: HCR_TVM bit is also set for system-register write monitoring
+ * purposes (see vm_event_monitor_cr), but (for performance reasons) that's
+ * done selectively (see vcpu_enter_adjust_traps).
+ */
WRITE_SYSREG(HCR_PTW|HCR_BSU_INNER|HCR_AMO|HCR_IMO|HCR_FMO|HCR_VM|
HCR_TWE|HCR_TWI|HCR_TSC|HCR_TAC|HCR_SWIO|HCR_TIDCP|HCR_FB,
HCR_EL2);
@@ -1720,6 +1726,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
const struct hsr_cp32 cp32 = hsr.cp32;
int regidx = cp32.reg;
struct vcpu *v = current;
+ register_t r = get_user_reg(regs, regidx);
if ( !check_conditional_instr(regs, hsr) )
{
@@ -1730,6 +1737,61 @@ static void do_cp15_32(struct cpu_user_regs *regs,
switch ( hsr.bits & HSR_CP32_REGS_MASK )
{
/*
+ * HCR_EL2.TVM / HCR.TVM
+ *
+ * ARMv7 (DDI 0406C.b): B1.14.13
+ * ARMv8 (DDI 0487A.e): D1-1569 Table D1-34
+ */
+ case HSR_CPREG32(SCTLR):
+ TVM_EMUL_VMEVT(v, regs, hsr, r, SCTLR);
+ break;
+ case HSR_CPREG32(TTBR0_32):
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TTBR0_32);
+ break;
+ case HSR_CPREG32(TTBR1_32):
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TTBR1_32);
+ break;
+ case HSR_CPREG32(TTBCR):
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TTBCR);
+ break;
+ case HSR_CPREG32(DACR):
+ TVM_EMUL(regs, hsr, r, DACR);
+ break;
+ case HSR_CPREG32(DFSR):
+ TVM_EMUL(regs, hsr, r, DFSR);
+ break;
+ case HSR_CPREG32(IFSR):
+ TVM_EMUL(regs, hsr, r, IFSR);
+ break;
+ case HSR_CPREG32(DFAR):
+ TVM_EMUL(regs, hsr, r, DFAR);
+ break;
+ case HSR_CPREG32(IFAR):
+ TVM_EMUL(regs, hsr, r, IFAR);
+ break;
+ case HSR_CPREG32(ADFSR):
+ TVM_EMUL(regs, hsr, r, ADFSR);
+ break;
+ case HSR_CPREG32(AIFSR):
+ TVM_EMUL(regs, hsr, r, AIFSR);
+ break;
+ case HSR_CPREG32(MAIR0):
+ TVM_EMUL(regs, hsr, r, MAIR0);
+ break;
+ case HSR_CPREG32(MAIR1):
+ TVM_EMUL(regs, hsr, r, MAIR1);
+ break;
+ case HSR_CPREG32(AMAIR0):
+ TVM_EMUL(regs, hsr, r, AMAIR0);
+ break;
+ case HSR_CPREG32(AMAIR1):
+ TVM_EMUL(regs, hsr, r, AMAIR1);
+ break;
+ case HSR_CPREG32(CONTEXTIDR):
+ TVM_EMUL(regs, hsr, r, CONTEXTIDR);
+ break;
+
+ /*
* !CNTHCTL_EL2.EL1PCEN / !CNTHCTL.PL1PCEN
*
* ARMv7 (DDI 0406C.b): B4.1.22
@@ -1853,6 +1915,13 @@ static void do_cp15_32(struct cpu_user_regs *regs,
static void do_cp15_64(struct cpu_user_regs *regs,
const union hsr hsr)
{
+ struct vcpu *v = current;
+ const struct hsr_cp64 cp64 = hsr.cp64;
+ sysreg64_t r = {
+ .low32 = (uint32_t) get_user_reg(regs, cp64.reg1),
+ .high32 = (uint32_t) get_user_reg(regs, cp64.reg2)
+ };
+
if ( !check_conditional_instr(regs, hsr) )
{
advance_pc(regs, hsr);
@@ -1862,6 +1931,19 @@ static void do_cp15_64(struct cpu_user_regs *regs,
switch ( hsr.bits & HSR_CP64_REGS_MASK )
{
/*
+ * HCR_EL2.TVM / HCR.TVM
+ *
+ * ARMv7 (DDI 0406C.b): B1.14.13
+ * ARMv8 (DDI 0487A.e): D1-1569 Table D1-34
+ */
+ case HSR_CPREG64(TTBR0):
+ TVM_EMUL_VMEVT(v, regs, hsr, r.val64, TTBR0_64);
+ break;
+ case HSR_CPREG64(TTBR1):
+ TVM_EMUL_VMEVT(v, regs, hsr, r.val64, TTBR1_64);
+ break;
+
+ /*
* !CNTHCTL_EL2.EL1PCEN / !CNTHCTL.PL1PCEN
*
* ARMv7 (DDI 0406C.b): B4.1.22
@@ -1891,8 +1973,6 @@ static void do_cp15_64(struct cpu_user_regs *regs,
*/
default:
{
- const struct hsr_cp64 cp64 = hsr.cp64;
-
gdprintk(XENLOG_ERR,
"%s p15, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",
cp64.read ? "mrrc" : "mcrr",
@@ -2128,10 +2208,50 @@ static void do_sysreg(struct cpu_user_regs *regs,
{
int regidx = hsr.sysreg.reg;
struct vcpu *v = current;
+ register_t r = get_user_reg(regs, regidx);
switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
{
/*
+ * HCR_EL2.TVM
+ *
+ * ARMv8 (DDI 0487A.e): D1-1569 Table D1-34
+ */
+ case HSR_SYSREG_SCTLR_EL1:
+ TVM_EMUL_VMEVT(v, regs, hsr, r, SCTLR_EL1);
+ break;
+ case HSR_SYSREG_TTBR0_EL1:
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TTBR0_EL1);
+ break;
+ case HSR_SYSREG_TTBR1_EL1:
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TTBR1_EL1);
+ break;
+ case HSR_SYSREG_TCR_EL1:
+ TVM_EMUL_VMEVT(v, regs, hsr, r, TCR_EL1);
+ break;
+ case HSR_SYSREG_ESR_EL1:
+ TVM_EMUL(regs, hsr, r, ESR_EL1);
+ break;
+ case HSR_SYSREG_FAR_EL1:
+ TVM_EMUL(regs, hsr, r, FAR_EL1);
+ break;
+ case HSR_SYSREG_AFSR0_EL1:
+ TVM_EMUL(regs, hsr, r, AFSR0_EL1);
+ break;
+ case HSR_SYSREG_AFSR1_EL1:
+ TVM_EMUL(regs, hsr, r, AFSR1_EL1);
+ break;
+ case HSR_SYSREG_MAIR_EL1:
+ TVM_EMUL(regs, hsr, r, MAIR_EL1);
+ break;
+ case HSR_SYSREG_AMAIR_EL1:
+ TVM_EMUL(regs, hsr, r, AMAIR_EL1);
+ break;
+ case HSR_SYSREG_CONTEXTIDR_EL1:
+ TVM_EMUL(regs, hsr, r, CONTEXTIDR_EL1);
+ break;
+
+ /*
* HCR_EL2.TACR
*
* ARMv8 (DDI 0487A.d): D7.2.1
diff --git a/xen/arch/arm/vm_event.c b/xen/arch/arm/vm_event.c
new file mode 100644
index 0000000..3f23fec
--- /dev/null
+++ b/xen/arch/arm/vm_event.c
@@ -0,0 +1,112 @@
+/*
+ * arch/arm/vm_event.c
+ *
+ * Architecture-specific vm_event handling routines
+ *
+ * Copyright (c) 2016, Bitdefender S.R.L.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/vm_event.h>
+#include <asm/traps.h>
+
+#if CONFIG_ARM_64
+
+#define MWSINF_SCTLR 32,SCTLR_EL1
+#define MWSINF_TTBR0 64,TTBR0_EL1
+#define MWSINF_TTBR1 64,TTBR1_EL1
+#define MWSINF_TTBCR 64,TCR_EL1
+
+#elif CONFIG_ARM_32
+
+#define MWSINF_SCTLR 32,SCTLR
+#define MWSINF_TTBR0 64,TTBR0
+#define MWSINF_TTBR1 64,TTBR1
+#define MWSINF_TTBR0_32 32,TTBR0_32
+#define MWSINF_TTBR1_32 32,TTBR1_32
+#define MWSINF_TTBCR 32,TTBCR
+
+#endif
+
+#define MWS_EMUL_(val, sz, r...) WRITE_SYSREG##sz((uint##sz##_t) (val), r)
+#define MWS_EMUL(r) CALL_MACRO(MWS_EMUL_, w->value, MWSINF_##r)
+
+static inline void vcpu_enter_write_data(struct vcpu *v)
+{
+ struct monitor_write_data *w = &v->arch.vm_event.write_data;
+
+ if ( likely(MWS_NOWRITE == w->status) )
+ return;
+
+ switch ( w->status )
+ {
+ case MWS_SCTLR:
+ MWS_EMUL(SCTLR);
+ break;
+ case MWS_TTBR0:
+ MWS_EMUL(TTBR0);
+ break;
+ case MWS_TTBR1:
+ MWS_EMUL(TTBR1);
+ break;
+#if CONFIG_ARM_32
+ case MWS_TTBR0_32:
+ MWS_EMUL(TTBR0_32);
+ break;
+ case MWS_TTBR1_32:
+ MWS_EMUL(TTBR1_32);
+ break;
+#endif
+ case MWS_TTBCR:
+ MWS_EMUL(TTBCR);
+ break;
+ default:
+ break;
+ }
+
+ w->status = MWS_NOWRITE;
+}
+
+static inline void vcpu_enter_adjust_traps(struct vcpu *v)
+{
+ register_t old_hcr, hcr;
+
+ hcr = (old_hcr = READ_SYSREG(HCR_EL2));
+
+ if ( unlikely(0 != v->domain->arch.monitor.write_ctrlreg_enabled) )
+ hcr |= HCR_TVM;
+ else
+ hcr &= ~HCR_TVM;
+
+ if ( unlikely(hcr != old_hcr) )
+ {
+ WRITE_SYSREG(hcr, HCR_EL2);
+ isb();
+ }
+}
+
+void arch_vm_event_vcpu_enter(struct vcpu *v)
+{
+ vcpu_enter_write_data(v);
+ vcpu_enter_adjust_traps(v);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 2366bae..c35a717 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -62,7 +62,6 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
switch ( mop->event )
{
-#if CONFIG_X86
case XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG:
{
struct arch_domain *ad = &d->arch;
@@ -100,7 +99,6 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
break;
}
-#endif
case XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST:
{
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 53dc048..e0f999e 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -824,7 +824,6 @@ int vm_event_monitor_traps(struct vcpu *v, uint8_t sync,
return 1;
}
-#if CONFIG_X86
bool_t vm_event_monitor_cr(unsigned int index, unsigned long value,
unsigned long old)
{
@@ -852,7 +851,6 @@ bool_t vm_event_monitor_cr(unsigned int index, unsigned long value,
return 0;
}
-#endif
void vm_event_monitor_guest_request(void)
{
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 370cdeb..83f0952 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -40,6 +40,26 @@ struct vtimer {
uint64_t cval;
};
+enum monitor_write_status
+{
+ MWS_NOWRITE = 0,
+ MWS_SCTLR,
+ MWS_TTBR0,
+ MWS_TTBR1,
+ MWS_TTBR0_32,
+ MWS_TTBR1_32,
+ MWS_TTBCR,
+};
+
+struct monitor_write_data {
+ enum monitor_write_status status;
+ uint64_t value;
+};
+
+struct arch_vm_event {
+ struct monitor_write_data write_data;
+};
+
struct arch_domain
{
#ifdef CONFIG_ARM_64
@@ -127,6 +147,14 @@ struct arch_domain
paddr_t efi_acpi_gpa;
paddr_t efi_acpi_len;
#endif
+
+ /* Arch-specific monitor options */
+ struct {
+ unsigned int write_ctrlreg_enabled : 4;
+ unsigned int write_ctrlreg_sync : 4;
+ unsigned int write_ctrlreg_onchangeonly : 4;
+ } monitor;
+
} __cacheline_aligned;
struct arch_vcpu
@@ -258,6 +286,8 @@ struct arch_vcpu
struct vtimer phys_timer;
struct vtimer virt_timer;
bool_t vtimer_initialized;
+
+ struct arch_vm_event vm_event;
} __cacheline_aligned;
void vcpu_show_execution_state(struct vcpu *);
diff --git a/xen/include/asm-arm/traps.h b/xen/include/asm-arm/traps.h
new file mode 100644
index 0000000..9e246a7
--- /dev/null
+++ b/xen/include/asm-arm/traps.h
@@ -0,0 +1,253 @@
+/*
+ * include/asm-arm/traps.h
+ *
+ * ARM Trap handlers
+ *
+ * Copyright (c) 2016, Bitdefender S.R.L.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ARM_TRAPS_H__
+#define __ASM_ARM_TRAPS_H__
+
+#include <xen/vm_event.h>
+#include <asm/regs.h>
+#include <public/vm_event.h>
+
+/* used to force expansion of args before calling macro */
+#define CALL_MACRO(macro, args...) macro(args)
+
+/* used for easy manipulation of low/high 32-bits of 64-bit system registers */
+typedef union {
+ uint64_t val64;
+ struct {
+ uint32_t low32;
+ uint32_t high32;
+ };
+} sysreg64_t;
+
+#if CONFIG_ARM_64
+
+/*
+ * Emulation of system-register trapped writes that do not cause
+ * VM_EVENT_REASON_WRITE_CTRLREG monitor vm-events.
+ * Such writes are collaterally trapped due to setting the HCR_EL2.TVM bit.
+ *
+ * Regarding aarch32 domains, note that from Xen's perspective system-registers
+ * of such domains are architecturally-mapped to aarch64 registers in one of
+ * three ways:
+ * - low 32-bits mapping (e.g. aarch32 DFAR -> aarch64 FAR_EL1[31:0])
+ * - high 32-bits mapping (e.g. aarch32 IFAR -> aarch64 FAR_EL1[63:32])
+ * - full mapping (e.g. aarch32 SCTLR -> aarch64 SCTLR_EL1)
+ *
+ * Hence we define 2 macro variants:
+ * - TVM_EMUL_SZ variant, for full mappings
+ * - TVM_EMUL_LH variant, for low/high 32-bits mappings
+ */
+#define TVM_EMUL_SZ(regs, hsr, val, sz, r...) \
+{ \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ WRITE_SYSREG##sz((uint##sz##_t) (val), r); \
+}
+#define TVM_EMUL_LH(regs, hsr, val, l_or_h, r...) \
+{ \
+ sysreg64_t _new; \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ _new.val64 = READ_SYSREG64(r); \
+ _new.l_or_h = (uint32_t) (val); \
+ WRITE_SYSREG64(_new.val64, r); \
+}
+
+/*
+ * Emulation of system-register writes that cause VM_EVENT_REASON_WRITE_CTRLREG
+ * monitor vm-events.
+ * SZ/LH variants, reasoning is the same as above.
+ */
+#define TVM_EMUL_SZ_VMEVT(v, regs, hsr, val, cridx, mws, sz, r) \
+{ \
+ unsigned long _old; \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ ASSERT(MWS_NOWRITE == (v)->arch.vm_event.write_data.status); \
+ (v)->arch.vm_event.write_data.status = mws; \
+ (v)->arch.vm_event.write_data.value = (uint##sz##_t) (val); \
+ _old = READ_SYSREG##sz(r); \
+ vm_event_monitor_cr(cridx, \
+ (uint##sz##_t) (val), \
+ _old); \
+}
+#define TVM_EMUL_LH_VMEVT(v, regs, hsr, val, cridx, mws, l_or_h, r) \
+{ \
+ sysreg64_t _old, _new; \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ _new.val64 = (_old.val64 = READ_SYSREG64(r)); \
+ _new.l_or_h = (uint32_t) (val); \
+ ASSERT(MWS_NOWRITE == (v)->arch.vm_event.write_data.status); \
+ (v)->arch.vm_event.write_data.status = mws; \
+ (v)->arch.vm_event.write_data.value = _new.val64; \
+ vm_event_monitor_cr(cridx, \
+ _new.val64, \
+ _old.val64); \
+}
+
+#define PART_FULL32 SZ,32 /* SZ variant, 32-bit counterpart */
+#define PART_FULL64 SZ,64 /* SZ variant, 64-bit counterpart */
+#define PART_LOW LH,low32 /* LH variant, low 32-bits */
+#define PART_HIGH LH,high32 /* LH variant, high 32-bits */
+
+/*
+ * HCR_EL2.TVM trapped registers info (size in bits) for an aarch64 domain.
+ *
+ * ARMv8 (DDI 0487A.e): D1-1569 Table D1-34 (traps from AArch64 state)
+ */
+#define TVMINF_ESR_EL1 PART_FULL32, ESR_EL1
+#define TVMINF_FAR_EL1 PART_FULL64, FAR_EL1
+#define TVMINF_AFSR0_EL1 PART_FULL32, AFSR0_EL1
+#define TVMINF_AFSR1_EL1 PART_FULL32, AFSR1_EL1
+#define TVMINF_MAIR_EL1 PART_FULL64, MAIR_EL1
+#define TVMINF_AMAIR_EL1 PART_FULL64, AMAIR_EL1
+#define TVMINF_CONTEXTIDR_EL1 PART_FULL32, CONTEXTIDR_EL1
+
+#define TVMINF_VMEVT_SCTLR_EL1 VM_EVENT_ARM_SCTLR, MWS_SCTLR, \
+ PART_FULL32, SCTLR_EL1
+#define TVMINF_VMEVT_TTBR0_EL1 VM_EVENT_ARM_TTBR0, MWS_TTBR0, \
+ PART_FULL64, TTBR0_EL1
+#define TVMINF_VMEVT_TTBR1_EL1 VM_EVENT_ARM_TTBR1, MWS_TTBR1, \
+ PART_FULL64, TTBR1_EL1
+#define TVMINF_VMEVT_TCR_EL1 VM_EVENT_ARM_TTBCR, MWS_TTBCR, \
+ PART_FULL64, TCR_EL1
+
+/*
+ * HCR_EL2.TVM trapped registers info for an aarch32 domain.
+ * Specifies the architecturally-mapped aarch64 counterpart register
+ * as well as the actual part the aarch32 register is mapped-to
+ * (full register/low 32-bits/high 32-bits).
+ *
+ * ARMv8 (DDI 0487A.e): D1-1569 Table D1-34 (traps from aarch32 state)
+ */
+#define TVMINF_DACR PART_FULL32, DACR32_EL2
+#define TVMINF_DFSR PART_FULL32, ESR_EL1
+#define TVMINF_IFSR PART_FULL32, IFSR32_EL2
+#define TVMINF_DFAR PART_LOW, FAR_EL1
+#define TVMINF_IFAR PART_HIGH, FAR_EL1
+#define TVMINF_ADFSR PART_FULL32, AFSR0_EL1
+#define TVMINF_AIFSR PART_FULL32, AFSR1_EL1
+#define TVMINF_MAIR0 PART_LOW, MAIR_EL1 /* AKA PRRR */
+#define TVMINF_MAIR1 PART_HIGH, MAIR_EL1 /* AKA NMRR */
+#define TVMINF_AMAIR0 PART_LOW, AMAIR_EL1
+#define TVMINF_AMAIR1 PART_HIGH, AMAIR_EL1
+#define TVMINF_CONTEXTIDR PART_FULL32, CONTEXTIDR_EL1
+
+#define TVMINF_VMEVT_SCTLR VM_EVENT_ARM_SCTLR, MWS_SCTLR, \
+ PART_FULL32, SCTLR_EL1
+#define TVMINF_VMEVT_TTBR0_64 VM_EVENT_ARM_TTBR0, MWS_TTBR0, \
+ PART_FULL64, TTBR0_EL1
+#define TVMINF_VMEVT_TTBR1_64 VM_EVENT_ARM_TTBR1, MWS_TTBR1, \
+ PART_FULL64, TTBR1_EL1
+#define TVMINF_VMEVT_TTBR0_32 VM_EVENT_ARM_TTBR0, MWS_TTBR0, \
+ PART_LOW, TTBR0_EL1
+#define TVMINF_VMEVT_TTBR1_32 VM_EVENT_ARM_TTBR1, MWS_TTBR1, \
+ PART_LOW, TTBR1_EL1
+#define TVMINF_VMEVT_TTBCR VM_EVENT_ARM_TTBCR, MWS_TTBCR, \
+ PART_LOW, TCR_EL1
+
+/*
+ * Wrappers over TVM_EMUL_{SZ,LH}/TVM_EMUL_{SZ,LH}_VMEVT variants which use
+ * the TVMINF_* defs.
+ */
+#define TVM_EMUL_VAR(regs, hsr, val, var, sz_or_lh, r...) \
+ TVM_EMUL_##var(regs, hsr, val, sz_or_lh, r)
+#define TVM_EMUL_VAR_VMEVT(v, regs, hsr, val, cridx, mws, var, sz_or_lh, r...) \
+ TVM_EMUL_##var##_VMEVT(v, regs, hsr, val, cridx, mws, sz_or_lh, r)
+#define TVM_EMUL(regs, hsr, val, r) \
+ CALL_MACRO(TVM_EMUL_VAR, regs, hsr, val, TVMINF_##r)
+#define TVM_EMUL_VMEVT(v, regs, hsr, val, r) \
+ CALL_MACRO(TVM_EMUL_VAR_VMEVT, v, regs, hsr, val, TVMINF_VMEVT_##r)
+
+#elif CONFIG_ARM_32
+
+/*
+ * Emulation of system-register trapped writes that do not cause
+ * VM_EVENT_REASON_WRITE_CTRLREG monitor vm-events.
+ * Such writes are collaterally trapped due to setting the HCR.TVM bit.
+ */
+#define TVM_EMUL_SZ(regs, hsr, val, sz, r...) \
+{ \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ WRITE_SYSREG##sz((uint##sz##_t) (val), r); \
+}
+
+/*
+ * Emulation of system-register writes that cause VM_EVENT_REASON_WRITE_CTRLREG
+ * monitor vm-events.
+ */
+#define TVM_EMUL_SZ_VMEVT(v, regs, hsr, val, cridx, mws, sz, r...) \
+{ \
+ unsigned long _old; \
+ if ( psr_mode_is_user(regs) ) \
+ return inject_undef_exception(regs, hsr); \
+ ASSERT(MWS_NOWRITE == (v)->arch.vm_event.write_data.status); \
+ (v)->arch.vm_event.write_data.status = mws; \
+ (v)->arch.vm_event.write_data.value = (uint##sz##_t) (val); \
+ _old = READ_SYSREG##sz(r); \
+ vm_event_monitor_cr(cridx, \
+ (uint##sz##_t) (val), \
+ _old); \
+}
+
+/*
+ * HCR.TVM trapped registers info (size in bits).
+ *
+ * ARMv7 (DDI 0406C.b): B1.14.13
+ */
+#define TVMINF_DACR 32,DACR
+#define TVMINF_DFSR 32,DFSR
+#define TVMINF_IFSR 32,IFSR
+#define TVMINF_DFAR 32,DFAR
+#define TVMINF_IFAR 32,IFAR
+#define TVMINF_ADFSR 32,ADFSR
+#define TVMINF_AIFSR 32,AIFSR
+#define TVMINF_MAIR0 32,MAIR0 /* AKA PRRR */
+#define TVMINF_MAIR1 32,MAIR1 /* AKA NMRR */
+#define TVMINF_AMAIR0 32,AMAIR0
+#define TVMINF_AMAIR1 32,AMAIR1
+#define TVMINF_CONTEXTIDR 32,CONTEXTIDR
+
+#define TVMINF_VMEVT_SCTLR VM_EVENT_ARM_SCTLR, MWS_SCTLR, \
+ 32,SCTLR
+#define TVMINF_VMEVT_TTBR0_64 VM_EVENT_ARM_TTBR0, MWS_TTBR0, \
+ 64,TTBR0
+#define TVMINF_VMEVT_TTBR1_64 VM_EVENT_ARM_TTBR1, MWS_TTBR1, \
+ 64,TTBR1
+#define TVMINF_VMEVT_TTBR0_32 VM_EVENT_ARM_TTBR0, MWS_TTBR0_32, \
+ 32,TTBR0_32
+#define TVMINF_VMEVT_TTBR1_32 VM_EVENT_ARM_TTBR1, MWS_TTBR1_32, \
+ 32,TTBR1_32
+#define TVMINF_VMEVT_TTBCR VM_EVENT_ARM_TTBCR, MWS_TTBCR, \
+ 32,TTBCR
+
+/* Wrappers over TVM_EMUL_SZ/TVM_EMUL_SZ_VMEVT which use the TVMINF_* defs. */
+#define TVM_EMUL(regs, hsr, val, r) \
+ CALL_MACRO(TVM_EMUL_SZ, regs, hsr, val, TVMINF_##r)
+#define TVM_EMUL_VMEVT(v, regs, hsr, val, r) \
+ CALL_MACRO(TVM_EMUL_SZ_VMEVT, v, regs, hsr, val, TVMINF_VMEVT_##r)
+
+#endif
+
+#endif /* __ASM_ARM_TRAPS_H__ */
diff --git a/xen/include/asm-arm/vm_event.h b/xen/include/asm-arm/vm_event.h
index 4e5a272..edf9654 100644
--- a/xen/include/asm-arm/vm_event.h
+++ b/xen/include/asm-arm/vm_event.h
@@ -30,6 +30,12 @@ static inline int vm_event_init_domain(struct domain *d)
static inline void vm_event_cleanup_domain(struct domain *d)
{
+ struct vcpu *v;
+
+ for_each_vcpu ( d, v )
+ memset(&v->arch.vm_event, 0, sizeof(v->arch.vm_event));
+
+ memset(&d->arch.monitor, 0, sizeof(d->arch.monitor));
memset(&d->monitor, 0, sizeof(d->monitor));
}
@@ -41,7 +47,13 @@ static inline void vm_event_toggle_singlestep(struct domain *d, struct vcpu *v)
static inline
void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
{
- /* Not supported on ARM. */
+ /* X86 VM_EVENT_REASON_MOV_TO_MSR could (but shouldn't) end-up here too. */
+ if ( unlikely(VM_EVENT_REASON_WRITE_CTRLREG != rsp->reason) )
+ return;
+
+ if ( (rsp->flags & VM_EVENT_FLAG_DENY) &&
+ (rsp->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
+ v->arch.vm_event.write_data.status = MWS_NOWRITE;
}
static inline
@@ -55,10 +67,7 @@ static inline void vm_event_fill_regs(vm_event_request_t *req)
/* Not supported on ARM. */
}
-static inline void arch_vm_event_vcpu_enter(struct vcpu *v)
-{
- /* Nothing to do. */
-}
+void arch_vm_event_vcpu_enter(struct vcpu *v);
/*
* Monitor vm-events.
@@ -67,7 +76,8 @@ static inline uint32_t vm_event_monitor_get_capabilities(struct domain *d)
{
uint32_t capabilities = 0;
- capabilities = (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST);
+ capabilities = (1U << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
+ (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST);
return capabilities;
}
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 8f94e20..ec3eaca 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -121,12 +121,18 @@
/* An event has been requested via HVMOP_guest_request_vm_event. */
#define VM_EVENT_REASON_GUEST_REQUEST 8
-/* Supported values for the vm_event_write_ctrlreg index. */
+/* Supported values for the vm_event_write_ctrlreg index (x86). */
#define VM_EVENT_X86_CR0 0
#define VM_EVENT_X86_CR3 1
#define VM_EVENT_X86_CR4 2
#define VM_EVENT_X86_XCR0 3
+/* Supported values for the vm_event_write_ctrlreg index (arm). */
+#define VM_EVENT_ARM_SCTLR 0 /* SCTLR_EL1 (aarch64), SCTLR (aarch32) */
+#define VM_EVENT_ARM_TTBR0 1 /* TTBR0_EL1 (aarch64), TTBR0 (aarch32) */
+#define VM_EVENT_ARM_TTBR1 2 /* TTBR1_EL1 (aarch64), TTBR1 (aarch32) */
+#define VM_EVENT_ARM_TTBCR 3 /* TCR_EL1 (aarch64), TTBCR (aarch32) */
+
/*
* Using a custom struct (not hvm_hw_cpu) so as to not fill
* the vm_event ring buffer too quickly.
diff --git a/xen/include/xen/monitor.h b/xen/include/xen/monitor.h
index 422fd93..dc5b9d7 100644
--- a/xen/include/xen/monitor.h
+++ b/xen/include/xen/monitor.h
@@ -25,9 +25,7 @@
struct domain;
struct xen_domctl_monitor_op;
-#if CONFIG_X86
#define monitor_ctrlreg_bitmask(ctrlreg_index) (1U << (ctrlreg_index))
-#endif
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op);
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 71ae84a..8b1acd0 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -96,7 +96,6 @@ void vm_event_vcpu_unpause(struct vcpu *v);
int vm_event_monitor_traps(struct vcpu *v, uint8_t sync,
vm_event_request_t *req);
-#if CONFIG_X86
/*
* Called for the current vCPU on control-register changes by guest.
* The event might not fire if the client has subscribed to it in onchangeonly
@@ -104,7 +103,6 @@ int vm_event_monitor_traps(struct vcpu *v, uint8_t sync,
*/
bool_t vm_event_monitor_cr(unsigned int index, unsigned long value,
unsigned long old);
-#endif
void vm_event_monitor_guest_request(void);
--
2.5.0
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2016-06-16 14:13 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-16 14:04 [PATCH 0/7] vm-event: Implement ARM support for control-register writes Corneliu ZUZU
2016-06-16 14:06 ` [PATCH 1/7] minor (formatting) fixes Corneliu ZUZU
2016-06-16 14:24 ` Jan Beulich
2016-06-16 19:19 ` Corneliu ZUZU
2016-06-17 7:06 ` Jan Beulich
2016-06-17 10:46 ` Corneliu ZUZU
2016-06-16 16:02 ` Tamas K Lengyel
2016-06-17 8:33 ` Corneliu ZUZU
2016-06-17 8:36 ` Razvan Cojocaru
2016-06-17 9:29 ` Andrew Cooper
2016-06-17 9:35 ` Jan Beulich
2016-06-17 9:33 ` Jan Beulich
2016-06-17 9:36 ` Razvan Cojocaru
2016-06-17 9:40 ` Jan Beulich
2016-06-17 9:42 ` Razvan Cojocaru
2016-06-17 19:05 ` Tamas K Lengyel
2016-06-16 14:07 ` [PATCH 2/7] vm-event: VM_EVENT_FLAG_DENY requires VM_EVENT_FLAG_VCPU_PAUSED Corneliu ZUZU
2016-06-16 16:11 ` Tamas K Lengyel
2016-06-17 8:43 ` Corneliu ZUZU
2016-06-21 11:26 ` Corneliu ZUZU
2016-06-21 15:09 ` Tamas K Lengyel
2016-06-22 8:34 ` Corneliu ZUZU
2016-06-16 14:08 ` [PATCH 3/7] vm-event: introduce vm_event_vcpu_enter Corneliu ZUZU
2016-06-16 14:51 ` Jan Beulich
2016-06-16 20:10 ` Corneliu ZUZU
2016-06-16 20:33 ` Razvan Cojocaru
2016-06-17 10:41 ` Corneliu ZUZU
2016-06-17 7:17 ` Jan Beulich
2016-06-17 11:13 ` Corneliu ZUZU
2016-06-17 11:27 ` Jan Beulich
2016-06-17 12:13 ` Corneliu ZUZU
2016-06-16 16:17 ` Tamas K Lengyel
2016-06-17 9:19 ` Corneliu ZUZU
2016-06-17 8:55 ` Julien Grall
2016-06-17 11:40 ` Corneliu ZUZU
2016-06-17 13:22 ` Julien Grall
2016-06-16 14:09 ` [PATCH 4/7] vm-event/x86: use vm_event_vcpu_enter properly Corneliu ZUZU
2016-06-16 15:00 ` Jan Beulich
2016-06-16 20:20 ` Corneliu ZUZU
2016-06-17 7:20 ` Jan Beulich
2016-06-17 11:23 ` Corneliu ZUZU
2016-06-16 16:27 ` Tamas K Lengyel
2016-06-17 9:24 ` Corneliu ZUZU
2016-06-16 14:10 ` [PATCH 5/7] x86: replace monitor_write_data.do_write with enum Corneliu ZUZU
2016-06-16 14:12 ` [PATCH 6/7] vm-event/arm: move hvm_event_cr->common vm_event_monitor_cr Corneliu ZUZU
2016-06-16 15:16 ` Jan Beulich
2016-06-17 8:25 ` Corneliu ZUZU
2016-06-17 8:38 ` Jan Beulich
2016-06-17 11:31 ` Corneliu ZUZU
2016-06-21 7:08 ` Corneliu ZUZU
2016-06-21 7:20 ` Jan Beulich
2016-06-21 15:22 ` Tamas K Lengyel
2016-06-22 6:33 ` Jan Beulich
2016-06-16 16:55 ` Tamas K Lengyel
2016-06-17 10:37 ` Corneliu ZUZU
2016-06-16 14:13 ` Corneliu ZUZU [this message]
2016-06-16 14:26 ` [PATCH 7/7] vm-event/arm: implement support for control-register write vm-events Julien Grall
2016-06-16 19:24 ` Corneliu ZUZU
2016-06-16 21:28 ` Julien Grall
2016-06-17 11:46 ` Corneliu ZUZU
2016-06-16 16:49 ` Julien Grall
2016-06-17 10:36 ` Corneliu ZUZU
2016-06-17 13:18 ` Julien Grall
2016-06-22 16:35 ` Corneliu ZUZU
2016-06-22 17:17 ` Julien Grall
2016-06-22 18:39 ` Corneliu ZUZU
2016-06-22 19:37 ` Corneliu ZUZU
2016-06-22 19:41 ` Julien Grall
2016-06-23 5:31 ` Corneliu ZUZU
2016-06-23 5:49 ` Corneliu ZUZU
2016-06-23 11:11 ` Julien Grall
2016-06-24 9:32 ` Corneliu ZUZU
2016-06-23 11:00 ` Julien Grall
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1466086403-7749-1-git-send-email-czuzu@bitdefender.com \
--to=czuzu@bitdefender.com \
--cc=julien.grall@arm.com \
--cc=rcojocaru@bitdefender.com \
--cc=sstabellini@kernel.org \
--cc=tamas@tklengyel.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).