diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-02-28 10:45:47 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-02-28 10:45:47 +0000 |
commit | 2b982798afc5a3184851cdecc87d12511b58746d (patch) | |
tree | e90c093f9b798bb7b9a0bc21060d6dc927bd1596 /xen/common/kexec.c | |
parent | 081d18a09a3afe9f3f4c3c6ae7d4219b71f71b7e (diff) | |
download | xen-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.c | 79 |
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: |