]> xenbits.xensource.com Git - xen.git/commitdiff
Add new hypercall "set_callback" taking a callback identifier and the
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Thu, 6 Apr 2006 11:03:53 +0000 (12:03 +0100)
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Thu, 6 Apr 2006 11:03:53 +0000 (12:03 +0100)
callback address.

This new hypercall incorporates the functionality of the existing set_callbacks
hypercall in a more flexible manner. set_callbacks is retained for compatibility.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
12 files changed:
linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h
linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h
linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_32/traps.c
xen/arch/x86/x86_64/entry.S
xen/arch/x86/x86_64/traps.c
xen/include/public/arch-x86_32.h
xen/include/public/arch-x86_64.h
xen/include/public/callback.h [new file with mode: 0644]
xen/include/public/xen.h

index 20977d0b80783c77532c736571be8aed3c609691..d789fa3ae0bcfdd910377cc8d95ded05c112e291 100644 (file)
@@ -329,6 +329,14 @@ HYPERVISOR_nmi_op(
        return _hypercall2(int, nmi_op, op, arg);
 }
 
+static inline int
+HYPERVISOR_callback_op(
+       int cmd,
+       void *arg)
+{
+       return _hypercall2(int, callback_op, cmd, arg);
+}
+
 #endif /* __HYPERCALL_H__ */
 
 /*
index 646cf78578ea377392b7f61f15d41ddbabd4286b..ef697fde730b31a3ae1c788bdc66328f2509fac2 100644 (file)
@@ -6,6 +6,8 @@
  *     use of all of the static functions.
  **/
 
+#include <xen/interface/callback.h>
+
 static char * __init machine_specific_memory_setup(void)
 {
        unsigned long max_pfn = xen_start_info->nr_pages;
@@ -23,6 +25,14 @@ extern void nmi(void);
 static void __init machine_specific_arch_setup(void)
 {
        struct xen_platform_parameters pp;
+       callback_register_t event = {
+               .type = CALLBACKTYPE_event,
+               .address = { __KERNEL_CS, (unsigned long)hypervisor_callback },
+       };
+       callback_register_t failsafe = {
+               .type = CALLBACKTYPE_failsafe,
+               .address = { __KERNEL_CS, (unsigned long)failsafe_callback },
+       };
        struct xennmi_callback cb;
 
        if (xen_feature(XENFEAT_auto_translated_physmap) &&
@@ -32,9 +42,8 @@ static void __init machine_specific_arch_setup(void)
                memset(empty_zero_page, 0, sizeof(empty_zero_page));
        }
 
-       HYPERVISOR_set_callbacks(
-           __KERNEL_CS, (unsigned long)hypervisor_callback,
-           __KERNEL_CS, (unsigned long)failsafe_callback);
+       HYPERVISOR_callback_op(CALLBACKOP_register, &event);
+       HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
 
        cb.handler_address = (unsigned long)&nmi;
        HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
index 6b7411f4c5ceec134a37814c3371286e47dff31f..24f07623741725de766a001a8b4feb9c1924c26d 100644 (file)
@@ -330,6 +330,13 @@ HYPERVISOR_nmi_op(
        return _hypercall2(int, nmi_op, op, arg);
 }
 
+static inline int
+HYPERVISOR_callback_op(
+       int cmd, void *arg)
+{
+       return _hypercall2(int, callback_op, cmd, arg);
+}
+
 #endif /* __HYPERCALL_H__ */
 
 /*
index 701190a49bd936e23468fdad4ce3921b64fbea24..c48ef6cbb3526b1ace4633a20d5f57cfc9a188ba 100644 (file)
@@ -6,20 +6,33 @@
  *     use of all of the static functions.
  **/
 
+#include <xen/interface/callback.h>
+
 extern void hypervisor_callback(void);
 extern void failsafe_callback(void);
 extern void nmi(void);
 
 static void __init machine_specific_arch_setup(void)
 {
+       callback_register_t event = {
+               .type = CALLBACKTYPE_event,
+               .address = (unsigned long) hypervisor_callback,
+       };
+       callback_register_t failsafe = {
+               .type = CALLBACKTYPE_failsafe,
+               .address = (unsigned long)failsafe_callback,
+       };
+       callback_register_t syscall = {
+               .type = CALLBACKTYPE_syscall,
+               .address = (unsigned long)system_call,
+       };
 #ifdef CONFIG_X86_LOCAL_APIC
        struct xennmi_callback cb;
 #endif
 
-       HYPERVISOR_set_callbacks(
-                (unsigned long) hypervisor_callback,
-                (unsigned long) failsafe_callback,
-                (unsigned long) system_call);
+       HYPERVISOR_callback_op(CALLBACKOP_register, &event);
+       HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
+       HYPERVISOR_callback_op(CALLBACKOP_register, &syscall);
 
 #ifdef CONFIG_X86_LOCAL_APIC
        cb.handler_address = (unsigned long)&nmi;
index b19796bbac8678cfc8d8f15b75ad3ef043383ba4..049dc5ced56ab328b802f2aac06fdbd2f177cf3b 100644 (file)
@@ -648,6 +648,7 @@ ENTRY(hypercall_table)
         .long do_acm_op
         .long do_nmi_op
         .long do_arch_sched_op
+        .long do_callback_op        /* 30 */
         .rept NR_hypercalls-((.-hypercall_table)/4)
         .long do_ni_hypercall
         .endr
@@ -683,6 +684,7 @@ ENTRY(hypercall_args_table)
         .byte 1 /* do_acm_op            */
         .byte 2 /* do_nmi_op            */
         .byte 2 /* do_arch_sched_op     */
+        .byte 2 /* do_callback_op       */  /* 30 */
         .rept NR_hypercalls-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
index 59d1a845a850356c1a93c8ff5c5af4f0e75d52be..f0dc66182161a2b8d708ded38d8d11b3e9d99cdb 100644 (file)
@@ -14,6 +14,8 @@
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 
+#include <public/callback.h>
+
 /* All CPUs have their own IDT to allow int80 direct trap. */
 idt_entry_t *idt_tables[NR_CPUS] = { 0 };
 
@@ -315,20 +317,102 @@ void init_int80_direct_trap(struct vcpu *v)
         set_int80_direct_trap(v);
 }
 
+static long register_guest_callback(struct callback_register *reg)
+{
+    long ret = 0;
+    struct vcpu *v = current;
+
+    if ( reg->address.cs )
+        fixup_guest_code_selector(reg->address.cs);
+
+    switch ( reg->type )
+    {
+    case CALLBACKTYPE_event:
+        v->arch.guest_context.event_callback_cs     = reg->address.cs;
+        v->arch.guest_context.event_callback_eip    = reg->address.eip;
+        break;
+
+    case CALLBACKTYPE_failsafe:
+        v->arch.guest_context.failsafe_callback_cs  = reg->address.cs;
+        v->arch.guest_context.failsafe_callback_eip = reg->address.eip;
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static long unregister_guest_callback(struct callback_unregister *unreg)
+{
+    long ret;
+
+    switch ( unreg->type )
+    {
+    default:
+        ret = -EINVAL;
+        break;
+    }
+    return ret;
+}
+
+
+long do_callback_op(int cmd, GUEST_HANDLE(void) arg)
+{
+    long ret;
+
+    switch ( cmd )
+    {
+    case CALLBACKOP_register:
+    {
+        struct callback_register reg;
+
+        ret = -EFAULT;
+        if ( copy_from_guest( &reg, arg, 1 ) )
+            break;
+
+        ret = register_guest_callback(&reg);
+    }
+    break;
+
+    case CALLBACKOP_unregister:
+    {
+        struct callback_unregister unreg;
+
+        ret = -EFAULT;
+        if ( copy_from_guest( &unreg, arg, 1 ) )
+            break;
+
+        ret = unregister_guest_callback(&unreg);
+    }
+    break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
 long do_set_callbacks(unsigned long event_selector,
                       unsigned long event_address,
                       unsigned long failsafe_selector,
                       unsigned long failsafe_address)
 {
-    struct vcpu *d = current;
-
-    fixup_guest_code_selector(event_selector);
-    fixup_guest_code_selector(failsafe_selector);
-
-    d->arch.guest_context.event_callback_cs     = event_selector;
-    d->arch.guest_context.event_callback_eip    = event_address;
-    d->arch.guest_context.failsafe_callback_cs  = failsafe_selector;
-    d->arch.guest_context.failsafe_callback_eip = failsafe_address;
+    struct callback_register event = {
+        .type = CALLBACKTYPE_event,
+        .address = { event_selector, event_address },
+    };
+    struct callback_register failsafe = {
+        .type = CALLBACKTYPE_failsafe,
+        .address = { failsafe_selector, failsafe_address },
+    };
+
+    register_guest_callback(&event);
+    register_guest_callback(&failsafe);
 
     return 0;
 }
index 6176188a850ad350e1cc9f76c7899d98ff723255..622ca4d7cc1ee25031f55cf8a968899105b924af 100644 (file)
@@ -557,6 +557,7 @@ ENTRY(hypercall_table)
         .quad do_acm_op
         .quad do_nmi_op
         .quad do_arch_sched_op
+        .quad do_callback_op        /* 30 */
         .rept NR_hypercalls-((.-hypercall_table)/8)
         .quad do_ni_hypercall
         .endr
@@ -592,6 +593,7 @@ ENTRY(hypercall_args_table)
         .byte 1 /* do_acm_op            */
         .byte 2 /* do_nmi_op            */
         .byte 2 /* do_arch_sched_op     */
+        .byte 2 /* do_callback_op       */  /* 30 */
         .rept NR_hypercalls-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
index 6794cefecf5107fa95c80f3672adf10bb56e1ee0..ddf7b0aa30d475372b5660bb5691c4f1698c1479 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 
+#include <public/callback.h>
+
 void show_registers(struct cpu_user_regs *regs)
 {
     struct cpu_user_regs fault_regs = *regs;
@@ -312,15 +314,105 @@ void __init percpu_traps_init(void)
     wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);
 }
 
+static long register_guest_callback(struct callback_register *reg)
+{
+    long ret = 0;
+    struct vcpu *v = current;
+
+    switch ( reg->type )
+    {
+    case CALLBACKTYPE_event:
+        v->arch.guest_context.event_callback_eip    = reg->address;
+        break;
+
+    case CALLBACKTYPE_failsafe:
+        v->arch.guest_context.failsafe_callback_eip = reg->address;
+        break;
+
+    case CALLBACKTYPE_syscall:
+        v->arch.guest_context.syscall_callback_eip  = reg->address;
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static long unregister_guest_callback(struct callback_unregister *unreg)
+{
+    long ret;
+
+    switch ( unreg->type )
+    {
+    default:
+        ret = -EINVAL;
+        break;
+    }
+    return ret;
+}
+
+
+long do_callback_op(int cmd, GUEST_HANDLE(void) arg)
+{
+    long ret;
+
+    switch ( cmd )
+    {
+    case CALLBACKOP_register:
+    {
+        struct callback_register reg;
+
+        ret = -EFAULT;
+        if ( copy_from_guest( &reg, arg, 1 ) )
+            break;
+
+        ret = register_guest_callback(&reg);
+    }
+    break;
+
+    case CALLBACKOP_unregister:
+    {
+        struct callback_unregister unreg;
+
+        ret = -EFAULT;
+        if ( copy_from_guest( &unreg, arg, 1 ) )
+            break;
+
+        ret = unregister_guest_callback(&unreg);
+    }
+    break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
 long do_set_callbacks(unsigned long event_address,
                       unsigned long failsafe_address,
                       unsigned long syscall_address)
 {
-    struct vcpu *d = current;
-
-    d->arch.guest_context.event_callback_eip    = event_address;
-    d->arch.guest_context.failsafe_callback_eip = failsafe_address;
-    d->arch.guest_context.syscall_callback_eip  = syscall_address;
+    callback_register_t event = {
+        .type = CALLBACKTYPE_event,
+        .address = event_address,
+    };
+    callback_register_t failsafe = {
+        .type = CALLBACKTYPE_failsafe,
+        .address = failsafe_address,
+    };
+    callback_register_t syscall = {
+        .type = CALLBACKTYPE_syscall,
+        .address = syscall_address,
+    };
+
+    register_guest_callback(&event);
+    register_guest_callback(&failsafe);
+    register_guest_callback(&syscall);
 
     return 0;
 }
index 1ae2df6f14c2e4354c9f458f634e456cb57d203a..a723837f48ecfe663fc09b1b478bdea0563e1eb2 100644 (file)
@@ -168,6 +168,11 @@ typedef struct {
     unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */
 } arch_vcpu_info_t;
 
+typedef struct {
+    unsigned long cs;
+    unsigned long eip;
+} xen_callback_t;
+
 #endif /* !__ASSEMBLY__ */
 
 /*
index 98948c4ff5fd8883e7a03ec95d2caf73f36b8454..d8b978436a0ee47e514f3c792b4f29327f4ab3ef 100644 (file)
@@ -244,6 +244,8 @@ typedef struct {
     unsigned long pad; /* sizeof(vcpu_info_t) == 64 */
 } arch_vcpu_info_t;
 
+typedef unsigned long xen_callback_t;
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/xen/include/public/callback.h b/xen/include/public/callback.h
new file mode 100644 (file)
index 0000000..479333d
--- /dev/null
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * callback.h
+ *
+ * Register guest OS callbacks with Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_PUBLIC_CALLBACK_H__
+#define __XEN_PUBLIC_CALLBACK_H__
+
+#include "xen.h"
+
+/*
+ * Prototype for this hypercall is:
+ *   long callback_op(int cmd, void *extra_args)
+ * @cmd        == CALLBACKOP_??? (callback operation).
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+#define CALLBACKTYPE_event                 0
+#define CALLBACKTYPE_failsafe              1
+#define CALLBACKTYPE_syscall               2 /* x86_64 only */
+
+/*
+ * Register a callback.
+ */
+#define CALLBACKOP_register                0
+typedef struct callback_register {
+     int type;
+     xen_callback_t address;
+} callback_register_t;
+DEFINE_GUEST_HANDLE(callback_register_t);
+
+/*
+ * Unregister a callback.
+ *
+ * Not all callbacks can be unregistered. -EINVAL will be returned if
+ * you attempt to unregister such a callback.
+ */
+#define CALLBACKOP_unregister              1
+typedef struct callback_unregister {
+     int type;
+} callback_unregister_t;
+DEFINE_GUEST_HANDLE(callback_unregister_t);
+
+#endif /* __XEN_PUBLIC_CALLBACK_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 1da6ede0057d4b03ec5cd12196ddd1bb9b4bfb2c..8dba3ad541ea4496d2152a969804288d71f31007 100644 (file)
@@ -60,6 +60,7 @@
 #define __HYPERVISOR_acm_op               27
 #define __HYPERVISOR_nmi_op               28
 #define __HYPERVISOR_sched_op             29
+#define __HYPERVISOR_callback_op          30
 
 /* 
  * VIRTUAL INTERRUPTS