aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/kexec.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-02-28 10:45:47 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-02-28 10:45:47 +0000
commit2b982798afc5a3184851cdecc87d12511b58746d (patch)
treee90c093f9b798bb7b9a0bc21060d6dc927bd1596 /xen/common/kexec.c
parent081d18a09a3afe9f3f4c3c6ae7d4219b71f71b7e (diff)
downloadxen-2b982798afc5a3184851cdecc87d12511b58746d.tar.gz
xen-2b982798afc5a3184851cdecc87d12511b58746d.tar.bz2
xen-2b982798afc5a3184851cdecc87d12511b58746d.zip
kexec: limit scope of the use of compat_kexec_range_t
Unless I am mistaken, the compat functions are provided a stable ABI. This includes providing a stable version of xen_kexec_range_t in the form of compat_kexec_range_t. However, internally it doesn't really matter how xen represents the data. Currently the code provides for the creation of a compat version of all kexec range functions, which use the compat_kexec_range_t function. This is difficult to extend if range code exists outside of xen/common/kexec.c. The existence of "#ifdef CONFIG_X86_64" in the code suggests that some of the range code might be better off in architecture specific code. Furthermore, subsequent patches will introduce ia64-specific range handling code, which really would be much better off somewhere in arch/ia64/. With this in mind, the handling of compat_kexec_range_t is changed such that the code which reads and returns data from user-space translates between compat_kexec_range_t and xen_kexec_range_t. As, padding aside, the two structures are currently the same this is quite easy. Things may get more tricky in the future, but I don't believe this change is likely to make things significantly worse (or better) in that regard. In any case, refactoring can occur again as required. Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'xen/common/kexec.c')
-rw-r--r--xen/common/kexec.c79
1 files changed, 62 insertions, 17 deletions
diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index 4e95cf319d..f1aa784e93 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -153,11 +153,7 @@ static int sizeof_note(const char *name, int descsz)
ELFNOTE_ALIGN(descsz));
}
-#define kexec_get(x) kexec_get_##x
-
-#endif
-
-static int kexec_get(reserve)(xen_kexec_range_t *range)
+static int kexec_get_reserve(xen_kexec_range_t *range)
{
if ( kexec_crash_area.size > 0 && kexec_crash_area.start > 0) {
range->start = kexec_crash_area.start;
@@ -168,7 +164,7 @@ static int kexec_get(reserve)(xen_kexec_range_t *range)
return 0;
}
-static int kexec_get(xen)(xen_kexec_range_t *range)
+static int kexec_get_xen(xen_kexec_range_t *range)
{
#ifdef CONFIG_X86_64
range->start = xenheap_phys_start;
@@ -179,7 +175,7 @@ static int kexec_get(xen)(xen_kexec_range_t *range)
return 0;
}
-static int kexec_get(cpu)(xen_kexec_range_t *range)
+static int kexec_get_cpu(xen_kexec_range_t *range)
{
int nr = range->nr;
int nr_bytes = 0;
@@ -223,33 +219,78 @@ static int kexec_get(cpu)(xen_kexec_range_t *range)
return 0;
}
-static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg)
+static int kexec_get_range_internal(xen_kexec_range_t *range)
{
- xen_kexec_range_t range;
int ret = -EINVAL;
- if ( unlikely(copy_from_guest(&range, uarg, 1)) )
- return -EFAULT;
-
- switch ( range.range )
+ switch ( range->range )
{
case KEXEC_RANGE_MA_CRASH:
- ret = kexec_get(reserve)(&range);
+ ret = kexec_get_reserve(range);
break;
case KEXEC_RANGE_MA_XEN:
- ret = kexec_get(xen)(&range);
+ ret = kexec_get_xen(range);
break;
case KEXEC_RANGE_MA_CPU:
- ret = kexec_get(cpu)(&range);
+ ret = kexec_get_cpu(range);
break;
}
+ return ret;
+}
+
+static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg)
+{
+ xen_kexec_range_t range;
+ int ret = -EINVAL;
+
+ if ( unlikely(copy_from_guest(&range, uarg, 1)) )
+ return -EFAULT;
+
+ ret = kexec_get_range_internal(&range);
+
if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) )
return -EFAULT;
return ret;
}
+#else /* COMPAT */
+
+#ifdef CONFIG_COMPAT
+static int kexec_get_range_compat(XEN_GUEST_HANDLE(void) uarg)
+{
+ xen_kexec_range_t range;
+ compat_kexec_range_t compat_range;
+ int ret = -EINVAL;
+
+ if ( unlikely(copy_from_guest(&compat_range, uarg, 1)) )
+ return -EFAULT;
+
+ range.range = compat_range.range;
+ range.nr = compat_range.nr;
+ range.size = compat_range.size;
+ range.start = compat_range.start;
+
+ ret = kexec_get_range_internal(&range);
+
+ if ( ret == 0 ) {
+ range.range = compat_range.range;
+ range.nr = compat_range.nr;
+ range.size = compat_range.size;
+ range.start = compat_range.start;
+
+ if ( unlikely(copy_to_guest(uarg, &compat_range, 1)) )
+ return -EFAULT;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+#endif /* COMPAT */
+
+
#ifndef COMPAT
static int kexec_load_get_bits(int type, int *base, int *bit)
@@ -375,7 +416,11 @@ ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
switch ( op )
{
case KEXEC_CMD_kexec_get_range:
- ret = kexec_get(range)(uarg);
+#ifndef COMPAT
+ ret = kexec_get_range(uarg);
+#else
+ ret = kexec_get_range_compat(uarg);
+#endif
break;
case KEXEC_CMD_kexec_load:
case KEXEC_CMD_kexec_unload: