diff mbox

[v8,3/6] monitor: ARM SMC events

Message ID 1467743871-9644-3-git-send-email-tamas.lengyel@zentific.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tamas Lengyel July 5, 2016, 6:37 p.m. UTC
Add support for monitoring ARM SMC events. This patch only adds the required
bits to enable/disable monitoring and forwarding the event through vm_event.

Signed-off-by: Tamas K Lengyel <tamas.lengyel@zentific.com>
Acked-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/Makefile         |  1 +
 xen/arch/arm/monitor.c        | 82 +++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/traps.c          |  9 ++++-
 xen/include/asm-arm/domain.h  |  5 +++
 xen/include/asm-arm/monitor.h | 22 +++---------
 xen/include/public/domctl.h   |  1 +
 xen/include/public/vm_event.h | 10 ++++++
 7 files changed, 112 insertions(+), 18 deletions(-)
 create mode 100644 xen/arch/arm/monitor.c
diff mbox

Patch

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 9e38da3..ffb0e96 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -41,6 +41,7 @@  obj-y += decode.o
 obj-y += processor.o
 obj-y += smc.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
+obj-y += monitor.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/monitor.c b/xen/arch/arm/monitor.c
new file mode 100644
index 0000000..d609f4f
--- /dev/null
+++ b/xen/arch/arm/monitor.c
@@ -0,0 +1,82 @@ 
+/*
+ * arch/arm/monitor.c
+ *
+ * Arch-specific monitor_op domctl handler.
+ *
+ * Copyright (c) 2016 Tamas K Lengyel (tamas.lengyel@zentific.com)
+ *
+ * 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 <asm/monitor.h>
+#include <xen/monitor.h>
+
+int arch_monitor_domctl_event(struct domain *d,
+                              struct xen_domctl_monitor_op *mop)
+{
+    struct arch_domain *ad = &d->arch;
+    bool_t requested_status = (XEN_DOMCTL_MONITOR_OP_ENABLE == mop->op);
+
+    switch ( mop->event )
+    {
+    case XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL:
+    {
+        bool_t old_status = ad->monitor.privileged_call_enabled;
+
+        if ( unlikely(old_status == requested_status) )
+            return -EEXIST;
+
+        domain_pause(d);
+        ad->monitor.privileged_call_enabled = requested_status;
+        domain_unpause(d);
+        break;
+    }
+
+    default:
+        /*
+         * Should not be reached unless arch_monitor_get_capabilities() is
+         * not properly implemented.
+         */
+        ASSERT_UNREACHABLE();
+        return -EOPNOTSUPP;
+    }
+
+    return 0;
+}
+
+int monitor_smc()
+{
+    struct vcpu *curr = current;
+
+    if ( curr->domain->arch.monitor.privileged_call_enabled )
+    {
+        vm_event_request_t req = { 0 };
+
+        req.reason = VM_EVENT_REASON_PRIVILEGED_CALL;
+        req.vcpu_id = curr->vcpu_id;
+        req.u.privcall.type = PRIVCALL_SMC;
+
+        return monitor_traps(curr, 1, &req);
+    }
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 627e8c9..846ba26 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -42,6 +42,7 @@ 
 #include <asm/mmio.h>
 #include <asm/cpufeature.h>
 #include <asm/flushtlb.h>
+#include <asm/monitor.h>
 
 #include "decode.h"
 #include "vtimer.h"
@@ -2509,13 +2510,19 @@  bad_data_abort:
 
 static void do_trap_smc(struct cpu_user_regs *regs, const union hsr hsr)
 {
+    int rc;
+
     if ( !check_conditional_instr(regs, hsr) )
     {
         advance_pc(regs, hsr);
         return;
     }
 
-    inject_undef_exception(regs, hsr);
+    rc = monitor_smc();
+    if ( rc < 0 )
+        domain_crash_synchronous();
+    if ( !rc )
+        inject_undef_exception(regs, hsr);
 }
 
 static void enter_hypervisor_head(struct cpu_user_regs *regs)
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 979f7de..a97bee7 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -127,6 +127,11 @@  struct arch_domain
     paddr_t efi_acpi_gpa;
     paddr_t efi_acpi_len;
 #endif
+
+    /* Monitor options */
+    struct {
+        uint8_t privileged_call_enabled : 1;
+    } monitor;
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
index 4af707a..dcb0c5d 100644
--- a/xen/include/asm-arm/monitor.h
+++ b/xen/include/asm-arm/monitor.h
@@ -32,19 +32,8 @@  int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
     return -EOPNOTSUPP;
 }
 
-static inline
 int arch_monitor_domctl_event(struct domain *d,
-                              struct xen_domctl_monitor_op *mop)
-{
-    /*
-     * No arch-specific monitor vm-events on ARM.
-     *
-     * Should not be reached unless arch_monitor_get_capabilities() is not
-     * properly implemented.
-     */
-    ASSERT_UNREACHABLE();
-    return -EOPNOTSUPP;
-}
+                              struct xen_domctl_monitor_op *mop);
 
 static inline
 int arch_monitor_init_domain(struct domain *d)
@@ -61,11 +50,10 @@  void arch_monitor_cleanup_domain(struct domain *d)
 
 static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
 {
-    uint32_t capabilities = 0;
-
-    capabilities = (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST);
-
-    return capabilities;
+    return (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST) |
+           (1U << XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL);
 }
 
+int monitor_smc(void);
+
 #endif /* __ASM_ARM_MONITOR_H__ */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 30020ba..8503291 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1081,6 +1081,7 @@  DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 #define XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT   3
 #define XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST         4
 #define XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION       5
+#define XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL       6
 
 struct xen_domctl_monitor_op {
     uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 7bfe6cc..66e27b7 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -122,6 +122,8 @@ 
 #define VM_EVENT_REASON_GUEST_REQUEST           8
 /* A debug exception was caught */
 #define VM_EVENT_REASON_DEBUG_EXCEPTION         9
+/* Privileged call executed (e.g. SMC) */
+#define VM_EVENT_REASON_PRIVILEGED_CALL         10
 
 /* Supported values for the vm_event_write_ctrlreg index. */
 #define VM_EVENT_X86_CR0    0
@@ -222,6 +224,13 @@  struct vm_event_mov_to_msr {
     uint64_t value;
 };
 
+#define PRIVCALL_SMC    0
+
+struct vm_event_privcall {
+    uint32_t type; /* PRIVCALL_* */
+    uint32_t _pad;
+};
+
 #define MEM_PAGING_DROP_PAGE       (1 << 0)
 #define MEM_PAGING_EVICT_FAIL      (1 << 1)
 
@@ -260,6 +269,7 @@  typedef struct vm_event_st {
         struct vm_event_singlestep            singlestep;
         struct vm_event_debug                 software_breakpoint;
         struct vm_event_debug                 debug_exception;
+        struct vm_event_privcall              privcall;
     } u;
 
     union {