diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-03-03 10:58:06 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-03-03 10:58:06 +0000 |
commit | 2fc479d9df28a26283b8c2c97b1b59088120faa6 (patch) | |
tree | a169bb41748ed25a80ca106e9384daa383f40e4e /xen/common/kexec.c | |
parent | 3af17d6a103ff026360d7e098fd9349881330567 (diff) | |
download | xen-2fc479d9df28a26283b8c2c97b1b59088120faa6.tar.gz xen-2fc479d9df28a26283b8c2c97b1b59088120faa6.tar.bz2 xen-2fc479d9df28a26283b8c2c97b1b59088120faa6.zip |
kexec: Add explicit kexec_load_unload_compat()
Add an explicit kexec_load_unload_compat() using the same method
that was used to create kexec_range_compat()
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'xen/common/kexec.c')
-rw-r--r-- | xen/common/kexec.c | 102 |
1 files changed, 68 insertions, 34 deletions
diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 6f7abd1a96..ccb5363b53 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -29,8 +29,6 @@ #ifndef COMPAT -typedef long ret_t; - static DEFINE_PER_CPU(void *, crash_notes); static Elf_Note *xen_crash_note; @@ -248,9 +246,9 @@ static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) return ret; } -#ifdef CONFIG_COMPAT static int kexec_get_range_compat(XEN_GUEST_HANDLE(void) uarg) { +#ifdef CONFIG_COMPAT xen_kexec_range_t range; compat_kexec_range_t compat_range; int ret = -EINVAL; @@ -269,13 +267,10 @@ static int kexec_get_range_compat(XEN_GUEST_HANDLE(void) uarg) } return ret; -} +#else /* CONFIG_COMPAT */ + return 0; #endif /* CONFIG_COMPAT */ - -#endif /* COMPAT */ - - -#ifndef COMPAT +} static int kexec_load_get_bits(int type, int *base, int *bit) { @@ -295,19 +290,13 @@ static int kexec_load_get_bits(int type, int *base, int *bit) return 0; } -#endif - -static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +static int kexec_load_unload_internal(unsigned long op, xen_kexec_load_t *load) { - xen_kexec_load_t load; xen_kexec_image_t *image; int base, bit, pos; int ret = 0; - if ( unlikely(copy_from_guest(&load, uarg, 1)) ) - return -EFAULT; - - if ( kexec_load_get_bits(load.type, &base, &bit) ) + if ( kexec_load_get_bits(load->type, &base, &bit) ) return -EINVAL; pos = (test_bit(bit, &kexec_flags) != 0); @@ -319,13 +308,9 @@ static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */ -#ifndef COMPAT - memcpy(image, &load.image, sizeof(*image)); -#else - XLAT_kexec_image(image, &load.image); -#endif + memcpy(image, &load->image, sizeof(*image)); - if ( !(ret = machine_kexec_load(load.type, base + !pos, image)) ) + if ( !(ret = machine_kexec_load(load->type, base + !pos, image)) ) { /* Set image present bit */ set_bit((base + !pos), &kexec_flags); @@ -341,14 +326,48 @@ static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) if ( test_and_clear_bit((base + pos), &kexec_flags) ) { image = &kexec_image[base + pos]; - machine_kexec_unload(load.type, base + pos, image); + machine_kexec_unload(load->type, base + pos, image); } } return ret; } -#ifndef COMPAT +static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_load_t load; + + if ( unlikely(copy_from_guest(&load, uarg, 1)) ) + return -EFAULT; + + return kexec_load_unload_internal(op, &load); +} + +static int kexec_load_unload_compat(unsigned long op, + XEN_GUEST_HANDLE(void) uarg) +{ +#ifdef CONFIG_COMPAT + compat_kexec_load_t compat_load; + xen_kexec_load_t load; + + if ( unlikely(copy_from_guest(&compat_load, uarg, 1)) ) + return -EFAULT; + + /* This is a bit dodgy, load.image is inside load, + * but XLAT_kexec_load (which is automatically generated) + * doesn't translate load.image (correctly) + * Just copy load->type, the only other member, manually instead. + * + * XLAT_kexec_load(&load, &compat_load); + */ + load.type = compat_load.type; + XLAT_kexec_image(&load.image, &compat_load.image); + + return kexec_load_unload_internal(op, &load); +#else /* CONFIG_COMPAT */ + return 0; +#endif /* CONFIG_COMPAT */ +} static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) { @@ -383,9 +402,8 @@ static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) return -EINVAL; /* never reached */ } -#endif - -ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +int do_kexec_op_internal(unsigned long op, XEN_GUEST_HANDLE(void) uarg, + int compat) { unsigned long flags; int ret = -EINVAL; @@ -400,18 +418,20 @@ ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) switch ( op ) { case KEXEC_CMD_kexec_get_range: -#ifndef COMPAT - ret = kexec_get_range(uarg); -#else - ret = kexec_get_range_compat(uarg); -#endif + if (compat) + ret = kexec_get_range_compat(uarg); + else + ret = kexec_get_range(uarg); break; case KEXEC_CMD_kexec_load: case KEXEC_CMD_kexec_unload: spin_lock_irqsave(&kexec_lock, flags); if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) { - ret = kexec_load_unload(op, uarg); + if (compat) + ret = kexec_load_unload_compat(op, uarg); + else + ret = kexec_load_unload(op, uarg); } spin_unlock_irqrestore(&kexec_lock, flags); break; @@ -423,6 +443,20 @@ ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) return ret; } +long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +{ + return do_kexec_op_internal(op, uarg, 0); +} + +#ifdef CONFIG_COMPAT +int compat_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +{ + return do_kexec_op_internal(op, uarg, 1); +} +#endif + +#endif /* COMPAT */ + #if defined(CONFIG_COMPAT) && !defined(COMPAT) #include "compat/kexec.c" #endif |