@@ -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
new file mode 100644
@@ -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:
+ */
@@ -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)
@@ -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
@@ -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__ */
@@ -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_* */
@@ -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 {