[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/3] Some "make check" tests for xen/common
Signed-off-by: Tony Breeds <tony@xxxxxxxxxxxxxxxxxx> ----- Forwarded message from Rusty Russell <rusty@xxxxxxxxxxxxxxx> ----- To: Tony Breeds <tony@xxxxxxxxxxxxxxxxxx> From: Rusty Russell <rusty@xxxxxxxxxxxxxxx> Subject: [PATCH 3/3] Some "make check" tests for xen/common Date: Fri, 09 Dec 2005 16:47:43 +1100 Some of these tests could probably be improved, but this is a first cut. Not all the files are tested yet, just enough to know we're on the right track. Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx> diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_ac_timer.c xen-unstable.hg-check/xen/common/test/test_ac_timer.c --- xen-unstable.hg-mainline/xen/common/test/test_ac_timer.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_ac_timer.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,241 @@ +/* Tests for timers. + Copyright (C) 2005 Rusty Russell IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> + +#include "fake-support.h" + +#define AC_TIMER_SOFTIRQ 0 +typedef void (*softirq_handler)(void); +static softirq_handler _test_handler; +static inline void open_softirq(int nr, softirq_handler handler) +{ + test_cond(nr == AC_TIMER_SOFTIRQ); + _test_handler = handler; +} + +#include "../../include/xen/ac_timer.h" +#include "../ac_timer.c" + +#define TEST_NUM_TIMERS 10 + +struct test_timer +{ + struct ac_timer timer; + unsigned int timer_count; + unsigned long expiry; +}; +static struct test_timer _test_timers[TEST_NUM_TIMERS]; + +static void _test_timer(void *data) +{ + struct test_timer *t = data; + + t->timer_count++; + + /* Previous timer should have gone off before us. */ + if (t != _test_timers) + test_cond(t[-1].timer_count == t[0].timer_count); + + /* Should be about the right time. */ + test_cond(t->expiry < NOW() + TIMER_SLOP); +} + +static int _test_reprogram = 1; +static int _test_reprogram_timeout = 1; +int reprogram_ac_timer(s_time_t timeout) +{ + _test_reprogram_timeout = timeout; + return _test_reprogram; +} + +static s_time_t _test_now = 0; +s_time_t NOW(void) +{ + return _test_now; +} + +static int _test_selfadd = 1; +static void _test_timer_selfadd(void *data) +{ + if (_test_selfadd) + set_ac_timer(data, _test_now + TIMER_SLOP*2); +} + +static int _test_smp_processor_id = 0; +int smp_processor_id(void) +{ + return _test_smp_processor_id; +} + +void printk(const char *fmt, ...) +{ + va_list arglist; + + va_start(arglist, fmt); + vfprintf(stderr, fmt, arglist); + va_end(arglist); +} + +int main(int argc, char *argv[]) +{ + unsigned int i; + struct ac_timer timer; + + parse_test_args(argc, argv); + register_suppression("../ac_timer.c", 128); + + /* Initialize first. */ + ac_timer_init(); + + /* Self-adding timer should work. */ + _test_now = 0; + init_ac_timer(&timer, _test_timer_selfadd, &timer, 0); + fake_expect_xmalloc = 1; + set_ac_timer(&timer, 1); + _test_now = 1; + _test_handler(); + test_cond(active_ac_timer(&timer)); + /* Timer should still be running. */ + test_cond(_test_reprogram_timeout != 0); + _test_selfadd = 0; + _test_now = LONG_MAX; + _test_handler(); + test_cond(!active_ac_timer(&timer)); + /* Timer should be stopped. */ + test_cond(_test_reprogram_timeout == 0); + + /* Adding timer on other CPU should work. */ + _test_now = 0; + init_ac_timer(&timer, _test_timer_selfadd, &timer, 1); + fake_expect_xmalloc = 1; + set_ac_timer(&timer, 1); + test_cond(active_ac_timer(&timer)); + /* Wrong CPU, will do nothing. */ + _test_handler(); + test_cond(active_ac_timer(&timer)); + _test_smp_processor_id = 1; + _test_handler(); + test_cond(!active_ac_timer(&timer)); + _test_smp_processor_id = 0; + + /* Create them in expiry order, with +/- 1.. */ + for (i = 0; i < TEST_NUM_TIMERS; i++) { + _test_timers[i].timer_count = 0; + init_ac_timer(&_test_timers[i].timer, _test_timer, + &_test_timers[i], 0); + _test_timers[i].expiry + = LONG_MAX/(TEST_NUM_TIMERS/3+1)*((i+3)/3) + i%3; + } + + /* Add them all. */ + for (i = 0; i < TEST_NUM_TIMERS; i++) + set_ac_timer(&_test_timers[i].timer, _test_timers[i].expiry); + /* They can be re-added (noop) */ + for (i = 0; i < TEST_NUM_TIMERS; i++) + set_ac_timer(&_test_timers[i].timer, _test_timers[i].expiry); + + /* Delete in random order then re-add. */ + for (i = 0; i < TEST_NUM_TIMERS/2; i++) + rem_ac_timer(&_test_timers[i*2].timer); + for (i = 0; i < TEST_NUM_TIMERS/2; i++) + rem_ac_timer(&_test_timers[i*2+1].timer); + for (i = 0; i < TEST_NUM_TIMERS; i++) + test_cond(!active_ac_timer(&_test_timers[i].timer)); + + for (i = 0; i < TEST_NUM_TIMERS; i++) + set_ac_timer(&_test_timers[i].timer, _test_timers[i].expiry); + + for (i = 0; i < TEST_NUM_TIMERS; i++) + test_cond(active_ac_timer(&_test_timers[i].timer)); + + /* Expire them in order. */ + _test_now = 0; + for (i = 1; i <= TEST_NUM_TIMERS/3; i++) { + _test_now = LONG_MAX/(TEST_NUM_TIMERS/3+1)*i; + _test_handler(); + } + _test_now = LONG_MAX; + _test_handler(); + + /* They must have all gone off */ + for (i = 0; i < TEST_NUM_TIMERS; i++) { + test_cond(!active_ac_timer(&_test_timers[i].timer)); + test_cond(_test_timers[i].timer_count == 1); + } + + /* Add them in backwards order. */ + for (i = 0; i < TEST_NUM_TIMERS; i++) + set_ac_timer(&_test_timers[TEST_NUM_TIMERS-1-i].timer, + _test_timers[TEST_NUM_TIMERS-1-i].expiry); + + for (i = 0; i < TEST_NUM_TIMERS; i++) + test_cond(active_ac_timer(&_test_timers[i].timer)); + + /* Expire them in order. */ + _test_now = 0; + for (i = 1; i <= TEST_NUM_TIMERS/3; i++) { + _test_now = LONG_MAX/(TEST_NUM_TIMERS/3+1)*i; + _test_handler(); + } + _test_now = LONG_MAX; + _test_handler(); + + /* They must have all gone off */ + for (i = 0; i < TEST_NUM_TIMERS; i++) { + test_cond(!active_ac_timer(&_test_timers[i].timer)); + test_cond(_test_timers[i].timer_count == 2); + } + + /* Add them in "random" order. */ + test_cond(TEST_NUM_TIMERS%2 == 0); + for (i = 0; i < TEST_NUM_TIMERS/2; i++) + set_ac_timer(&_test_timers[i*2].timer, + _test_timers[i*2].expiry); + + for (i = 0; i < TEST_NUM_TIMERS/2; i++) + set_ac_timer(&_test_timers[i*2+1].timer, + _test_timers[i*2+1].expiry); + + for (i = 0; i < TEST_NUM_TIMERS; i++) + test_cond(active_ac_timer(&_test_timers[i].timer)); + + /* Expire them in order. */ + _test_now = 0; + for (i = 1; i <= TEST_NUM_TIMERS/3; i++) { + _test_now = LONG_MAX/(TEST_NUM_TIMERS/3+1)*i; + _test_handler(); + } + _test_now = LONG_MAX; + _test_handler(); + + /* They must have all gone off */ + for (i = 0; i < TEST_NUM_TIMERS; i++) { + test_cond(!active_ac_timer(&_test_timers[i].timer)); + test_cond(_test_timers[i].timer_count == 3); + } + + return 0; +} diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_acm_ops.c xen-unstable.hg-check/xen/common/test/test_acm_ops.c --- xen-unstable.hg-mainline/xen/common/test/test_acm_ops.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_acm_ops.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,192 @@ +/* Tests for acm_ops + Copyright (C) 2005 Tony Breeds IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> + +#include "fake-support.h" + +#include "../../include/public/acm.h" +#include "../../include/public/acm_ops.h" + +#define _TEST_ERROR -1 + +/* BEGIN: Move to fake-include.h / fake .c */ +struct acm_ssid_domain { + ssidref_t ssidref; +}; +/* END: Move to fake-include.h / fake .c */ + +static int _test_acm_error = 0; +static int _test_find_error = 0; +static struct domain *_test_domain; + +static int acm_set_policy(void *buf, u32 buf_size, int isuserbuffer) +{ + return !_test_acm_error?ACM_OK:_TEST_ERROR; +} +static int acm_get_policy(void *buf, u32 buf_size) +{ + return !_test_acm_error?ACM_OK:_TEST_ERROR; +} +static int acm_dump_statistics(void *buf, u16 buf_size) +{ + return !_test_acm_error?ACM_OK:_TEST_ERROR; +} +static int acm_get_ssid(ssidref_t ssidref, u8 *buf, u16 buf_size) +{ + return !_test_acm_error?ACM_OK:_TEST_ERROR; +} +static int acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, + enum acm_hook_type hook) +{ + return !_test_acm_error?ACM_OK:_TEST_ERROR; +} + +/* FIXME: Use fake.c's version. */ +struct domain *find_domain_by_id(domid_t dom) +{ + return !_test_find_error?_test_domain:NULL; +} + +/* Kill printks */ +#define printkd(fmt, args...) +#define printk(fmt, args...) + +/* Force the non-trivial case */ +#define ACM_SECURITY + +/* Defined in "../acm_ops.c" */ +long do_acm_op(struct acm_op * u_acm_op); +enum acm_operation; +int acm_authorize_acm_ops(struct domain *d, enum acm_operation pops); + +/* Avoid ref counting */ +#define put_domain(d) do { } while (0) + +#include "../acm_ops.c" + +int main(int argc, char *argv[]) +{ + enum acm_operation acm_op; + struct acm_op *user_acm_op; + + parse_test_args(argc, argv); + + current = calloc(sizeof(struct vcpu), 1); + current->domain = calloc(sizeof(struct domain), 1); + user_acm_op = calloc(sizeof(struct acm_op), 1); + + _test_domain = calloc(sizeof(struct domain), 1); + _test_domain->ssid = calloc(sizeof(struct acm_ssid_domain), 1); + + /* Test acm_authorize_acm_ops */ + fake_IS_PRIV_out = 0; + test_cond(acm_authorize_acm_ops(current->domain, acm_op) == + -EPERM); + + fake_IS_PRIV_out = 1; + test_cond(!acm_authorize_acm_ops(current->domain, acm_op)); + + /* Test do_acm_op */ + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -EACCES); + user_acm_op->interface_version = ACM_INTERFACE_VERSION; + + /* Arbtrary invalid command */ + user_acm_op->cmd = -1; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->cmd = ACM_SETPOLICY; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + user_acm_op->cmd = ACM_GETPOLICY; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + user_acm_op->cmd = ACM_DUMPSTATS; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + + _test_acm_error=1; + user_acm_op->cmd = ACM_SETPOLICY; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -EPERM); + user_acm_op->cmd = ACM_GETPOLICY; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -EPERM); + user_acm_op->cmd = ACM_DUMPSTATS; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -EPERM); + _test_acm_error=0; + + user_acm_op->cmd = ACM_GETSSID; + user_acm_op->u.getssid.get_ssid_by = UNSET; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->u.getssid.get_ssid_by = SSIDREF; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + + user_acm_op->u.getssid.get_ssid_by = DOMAINID; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + _test_find_error = 1; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + _test_find_error = 0; + free(_test_domain->ssid); + _test_domain->ssid = NULL; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->u.getssid.get_ssid_by = SSIDREF; + _test_acm_error = 1; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == _TEST_ERROR); + _test_acm_error = 0; + + _test_domain->ssid = calloc(sizeof(struct acm_ssid_domain), 1); + + user_acm_op->cmd = ACM_GETDECISION; + user_acm_op->u.getdecision.get_decision_by1 = UNSET; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->u.getdecision.get_decision_by1 = SSIDREF; + user_acm_op->u.getdecision.get_decision_by2 = UNSET; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->u.getdecision.get_decision_by2 = SSIDREF; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + + user_acm_op->u.getdecision.get_decision_by1 = DOMAINID; + user_acm_op->u.getdecision.get_decision_by2 = DOMAINID; + test_cond(!do_acm_op(fake_to_user(user_acm_op))); + + _test_find_error = 1; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + _test_find_error = 0; + free(_test_domain->ssid); + _test_domain->ssid = NULL; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + + user_acm_op->u.getdecision.get_decision_by1 = SSIDREF; + user_acm_op->u.getdecision.get_decision_by2 = SSIDREF; + _test_acm_error = 1; + test_cond(do_acm_op(fake_to_user(user_acm_op)) == -ESRCH); + _test_acm_error = 0; + + free(_test_domain); + free(user_acm_op); + free(current->domain); + free(current); + + return 0; +} diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_bitmap.c xen-unstable.hg-check/xen/common/test/test_bitmap.c --- xen-unstable.hg-mainline/xen/common/test/test_bitmap.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_bitmap.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,344 @@ +/* Tests for bitmap ops. + Copyright (C) 2005 Rusty Russell IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> + +#include "fake-support.h" + +#include "../../include/xen/bitmap.h" +#include "../bitmap.c" + +static void _test_set_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit/BITS_PER_LONG] |= (1UL << (bit%BITS_PER_LONG)); +} + +static void _test_clear_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit/BITS_PER_LONG] ^= (1UL << (bit%BITS_PER_LONG)); +} + +static void _test_bitmap_clone(unsigned long *dst, unsigned long *src, + int length) +{ + test_cond(length>0); + memcpy(dst, src, length); +} + +static int _test_hweight(unsigned long *bitmap, int bits) +{ + int i; + int count = 0; + + for(i=0; i<bits; i++) { + if (bitmap[i/BITS_PER_LONG] & (1UL << (i%BITS_PER_LONG))) { + count++; + } + } + + return count; +} + +int main(int argc, char *argv[]) +{ + unsigned long *bitmap1 = calloc(sizeof(long), 2); + unsigned long *bitmap2 = calloc(sizeof(long), 2); + long i; + /* Used in testing the *region() functions. Effectively + * lg(BITS_PER_LONG) */ + int order = 0; + + parse_test_args(argc, argv); + + /* Test __bitmap_empty. */ + test_cond(__bitmap_empty(bitmap1, BITS_PER_LONG*2)); + for (i = BITS_PER_LONG*2-1; i >= 0; i--) { + _test_set_bit(bitmap1, i); + test_cond(__bitmap_empty(bitmap1, i)); + test_cond(!__bitmap_empty(bitmap1, i+1)); + } + /* Test __bitmap_full. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + + test_cond(__bitmap_full(bitmap1, BITS_PER_LONG*2)); + for (i = BITS_PER_LONG*2-1; i >= 0; i--) { + _test_clear_bit(bitmap1, i); + test_cond(__bitmap_full(bitmap1, i)); + test_cond(!__bitmap_full(bitmap1, i+1)); + } + + /* Test __bitmap_equal. */ + bitmap1[0] = 0xaa; /* 0+2+0+8+ 0+32+ 0+128 */ + bitmap1[1] = 0UL; + bitmap2[0] = 0x55; /* 1+0+4+0+16+ 0+64+ 0 */ + bitmap2[1] = 0UL; + + /* Setup alternatng bit pattern bitmaps */ + for(i=0; i< 2; i++) { + int j; + + for(j=0; j< sizeof(long); j++) { + bitmap1[i] = (bitmap1[i] << CHAR_BIT) | 0xaa; + bitmap2[i] = (bitmap2[i] << CHAR_BIT) | 0x55; + } + } + + for(i = 0; i < BITS_PER_LONG*2; i++) { + test_cond(!__bitmap_equal(bitmap1, bitmap2, i+1)); + _test_set_bit(bitmap1, i); + _test_set_bit(bitmap2, i); + test_cond(__bitmap_equal(bitmap1, bitmap2, i+1)); + } + + /* Test __bitmap_compliment. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + + __bitmap_complement(bitmap2, bitmap1, BITS_PER_LONG*2); + test_cond(__bitmap_empty(bitmap2, BITS_PER_LONG*2)); + for (i = BITS_PER_LONG*2-1; i >= 0; i--) { + _test_clear_bit(bitmap1, i); + + __bitmap_complement(bitmap2, bitmap1, i); + test_cond(__bitmap_empty(bitmap2, i)); + + __bitmap_complement(bitmap1, bitmap2, i); + test_cond(__bitmap_full(bitmap1, i)); + } + + /* Test __bitmap_shift_right. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + + _test_set_bit(bitmap1, BITS_PER_LONG*2-1); + for (i = BITS_PER_LONG*2-1; i > 0; i--) { + unsigned long *shifttest = calloc(sizeof(long), 2); + + __bitmap_shift_right(bitmap2, bitmap1, 1, BITS_PER_LONG*2); + test_cond(__bitmap_empty(bitmap2, i-1)); + test_cond(!__bitmap_empty(bitmap2, i)); + + _test_bitmap_clone(bitmap1, bitmap2, sizeof(long)*2); + + /* Shift bitmap2 by the number of itterations of this loop + * executed so far. The result should be the same as bitmap1 + */ + bitmap2[0] = 0; + bitmap2[1] = 0; + _test_set_bit(bitmap2, BITS_PER_LONG*2-1); + __bitmap_shift_right(shifttest, bitmap2, (BITS_PER_LONG*2)-i, + BITS_PER_LONG*2); + + test_cond(__bitmap_equal(shifttest, bitmap1, BITS_PER_LONG*2)); + free(shifttest); + } + + /* Test __bitmap_shift_left. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + + _test_set_bit(bitmap1, 0); + for (i = 1; i < BITS_PER_LONG*2; i++) { + unsigned long *shifttest = calloc(sizeof(long), 2); + + __bitmap_shift_left(bitmap2, bitmap1, 1, BITS_PER_LONG*2); + test_cond(__bitmap_empty(bitmap2, i)); + test_cond(!__bitmap_empty(bitmap2, i+1)); + + _test_bitmap_clone(bitmap1, bitmap2, sizeof(long)*2); + + bitmap2[0] = 0; + bitmap2[1] = 0; + _test_set_bit(bitmap2, 0); + __bitmap_shift_left(shifttest, bitmap2, i, BITS_PER_LONG*2); + test_cond(__bitmap_equal(shifttest, bitmap1, BITS_PER_LONG*2)); + free(shifttest); + } + + /* Test __bitmap_and. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + + for(i = 0; i < BITS_PER_LONG*2; i++) { + unsigned long *andtest = calloc(sizeof(long), 2); + + _test_set_bit(bitmap2, i); + __bitmap_and(andtest, bitmap1, bitmap2, i+1); + test_cond(__bitmap_equal(andtest, bitmap2, i)); + + free(andtest); + } + + /* Test __bitmap_or. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + + for(i = 0; i < BITS_PER_LONG*2; i++) { + unsigned long *ortest = calloc(sizeof(long), 2); + + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + _test_set_bit(bitmap2, i); + + __bitmap_or(ortest, bitmap2, bitmap2, i+1); + test_cond(__bitmap_equal(ortest, bitmap2, i+1)); + __bitmap_or(ortest, bitmap2, bitmap1, i+1); + test_cond(__bitmap_equal(ortest, bitmap1, i+1)); + + free(ortest); + } + + /* Test __bitmap_xor. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + + for(i = 0; i < BITS_PER_LONG*2; i++) { + unsigned long *xortest = calloc(sizeof(long), 2); + unsigned long *complement = calloc(sizeof(long), 2); + + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + _test_set_bit(bitmap2, i); + __bitmap_complement(complement, bitmap2, i+1); + __bitmap_xor(xortest, bitmap1, bitmap2, i+1); + + test_cond(__bitmap_equal(xortest, complement, i+1)); + + free(complement); + free(xortest); + } + + /* Test __bitmap_andnot. */ + bitmap1[0] = ULONG_MAX; + bitmap1[1] = ULONG_MAX; + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + + for(i = 0; i < BITS_PER_LONG*2; i++) { + unsigned long *andnottest = calloc(sizeof(long), 2); + + __bitmap_andnot(andnottest, bitmap1, bitmap2, i+1); + test_cond(__bitmap_full(andnottest, i+1)); + + free(andnottest); + } + + /* Test __bitmap_intersects. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + + test_cond(!__bitmap_intersects(bitmap1, bitmap2, BITS_PER_LONG*2)); + for(i = 0; i < BITS_PER_LONG*2; i++) { + _test_set_bit(bitmap1, i); + __bitmap_complement(bitmap2, bitmap1, i+1); + test_cond(!__bitmap_intersects(bitmap1, bitmap2, i+1)); + } + + /* Test __bitmap_subset. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + bitmap2[0] = 0UL; + bitmap2[1] = 0UL; + + test_cond(__bitmap_subset(bitmap1, bitmap2, BITS_PER_LONG*2)); + for(i = 0; i < BITS_PER_LONG*2; i++) { + _test_set_bit(bitmap1, i); + __bitmap_complement(bitmap2, bitmap1, i+1); + test_cond(!__bitmap_subset(bitmap1, bitmap2, i+1)); + + } + + /* Test __bitmap_weight. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + for(i = 0; i < BITS_PER_LONG*2; i++) { + _test_set_bit(bitmap1, i); + + test_cond(_test_hweight(bitmap1, BITS_PER_LONG*2) == i+1); + test_cond(__bitmap_weight(bitmap1, BITS_PER_LONG*2) == + _test_hweight(bitmap1, BITS_PER_LONG*2)); + } + + /* Test bitmap_find_free_region. */ + i = BITS_PER_LONG; + while (i>1) { + i >>=1; + order++; + } + + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + bitmap2[0] = ULONG_MAX; + bitmap2[1] = ULONG_MAX; + + for(i=0; i<=order; i++) { + unsigned long *freetest = calloc(sizeof(long), 2); + int pos; + + pos = bitmap_find_free_region(bitmap1, BITS_PER_LONG*2, i); + test_cond(pos >= 0); + + __bitmap_shift_right(freetest, bitmap1, pos ,BITS_PER_LONG*2); + test_cond(__bitmap_full(freetest, i)); + + /* bitmap2 is busy this must fail */ + pos = bitmap_find_free_region(bitmap2, BITS_PER_LONG*2, i); + test_cond(pos < 0); + + free(freetest); + } + /* check for ((1<<order) > BITS_PER_LONG) which results in -EINVAL */ + test_cond(bitmap_find_free_region(bitmap1, BITS_PER_LONG*2, order+1) < 0); + + /* Test bitmap_release_region and bitmap_allocate_region. */ + bitmap1[0] = 0UL; + bitmap1[1] = 0UL; + bitmap2[0] = ULONG_MAX; + bitmap2[1] = ULONG_MAX; + + for(i=0; i<=order; i++) { + int j; + for(j=0; j < BITS_PER_LONG*2; j++) { + test_cond(!bitmap_allocate_region(bitmap1, j, i)); + test_cond(!__bitmap_empty(bitmap1, BITS_PER_LONG*2)); + + bitmap_release_region(bitmap1, j, i); + test_cond(__bitmap_empty(bitmap1, BITS_PER_LONG*2)); + + /* bitmap2 is busy this must fail */ + test_cond(bitmap_allocate_region(bitmap2, j, i) <0); + } + } + + + bitmap1[0] = 0UL; + + free(bitmap1); + free(bitmap2); + return 0; +} diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_dom0_ops.c xen-unstable.hg-check/xen/common/test/test_dom0_ops.c --- xen-unstable.hg-mainline/xen/common/test/test_dom0_ops.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_dom0_ops.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,644 @@ +/* Tests for dom0 ops. + Copyright (C) 2005 Rusty Russell IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#define _GNU_SOURCE +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> +#include <stdbool.h> + +#include <fake-support.h> + + +#include "../../include/public/dom0_ops.h" + +static int _test_acm_pre_dom0_op = 0; +static int acm_pre_dom0_op(dom0_op_t *op, void **ssid) +{ + return _test_acm_pre_dom0_op; +} + +static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) +{ return; } + +static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid) +{ return; } + +static int _test_set_info_guest_out; +static int set_info_guest(struct domain *d, + dom0_setdomaininfo_t *setdomaininfo) +{ + return _test_set_info_guest_out; +} + +static int _test_count_domain_pause_by_systemcontroller; +void domain_pause_by_systemcontroller(struct domain *d); +void domain_pause_by_systemcontroller(struct domain *d) +{ + _test_count_domain_pause_by_systemcontroller++; +} + +static int _test_count_domain_unpause_by_systemcontroller; +void domain_unpause_by_systemcontroller(struct domain *d); +void domain_unpause_by_systemcontroller(struct domain *d) +{ + _test_count_domain_unpause_by_systemcontroller++; +} + +static struct domain *_test_domain_kill; +void domain_kill(struct domain *d); +void domain_kill(struct domain *d) +{ + _test_domain_kill = d; +} + +#define for_each_vcpu(_d,_v) \ + for ( (_v) = (_d)->vcpu[0]; \ + (_v) != NULL; \ + (_v) = (_v)->next_in_list ) + + /* Has the FPU been initialised? */ +#define _VCPUF_fpu_initialised 0 +#define VCPUF_fpu_initialised (1UL<<_VCPUF_fpu_initialised) + /* Has the FPU been used since it was last saved? */ +#define _VCPUF_fpu_dirtied 1 +#define VCPUF_fpu_dirtied (1UL<<_VCPUF_fpu_dirtied) + /* Domain is blocked waiting for an event. */ +#define _VCPUF_blocked 2 +#define VCPUF_blocked (1UL<<_VCPUF_blocked) + /* Currently running on a CPU? */ +#define _VCPUF_running 3 +#define VCPUF_running (1UL<<_VCPUF_running) + /* Disables auto-migration between CPUs. */ +#define _VCPUF_cpu_pinned 4 +#define VCPUF_cpu_pinned (1UL<<_VCPUF_cpu_pinned) + /* Domain migrated between CPUs. */ +#define _VCPUF_cpu_migrated 5 +#define VCPUF_cpu_migrated (1UL<<_VCPUF_cpu_migrated) + /* Initialization completed. */ +#define _VCPUF_initialised 6 +#define VCPUF_initialised (1UL<<_VCPUF_initialised) + /* VCPU is not-runnable */ +#define _VCPUF_down 7 +#define VCPUF_down (1UL<<_VCPUF_down) + +/* + * Per-domain flags (domain_flags). + */ + /* Is this one of the per-CPU idle domains? */ +#define _DOMF_idle_domain 0 +#define DOMF_idle_domain (1UL<<_DOMF_idle_domain) + /* Is this domain privileged? */ +#define _DOMF_privileged 1 +#define DOMF_privileged (1UL<<_DOMF_privileged) + /* May this domain do IO to physical devices? */ +#define _DOMF_physdev_access 2 +#define DOMF_physdev_access (1UL<<_DOMF_physdev_access) + /* Guest shut itself down for some reason. */ +#define _DOMF_shutdown 3 +#define DOMF_shutdown (1UL<<_DOMF_shutdown) + /* Guest is in process of shutting itself down (becomes DOMF_shutdown). */ +#define _DOMF_shuttingdown 4 +#define DOMF_shuttingdown (1UL<<_DOMF_shuttingdown) + /* Death rattle. */ +#define _DOMF_dying 5 +#define DOMF_dying (1UL<<_DOMF_dying) + /* Domain is paused by controller software. */ +#define _DOMF_ctrl_pause 6 +#define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause) + +#define ACM_DEFAULT_SSID 0x0 + +typedef uint32_t ssidref_t; +struct acm_ssid_domain { + ssidref_t ssidref; /* combined security reference */ +}; + +#define __pa(x) ((unsigned long)(x) + 1001) +#define __va(x) ((unsigned long)(x) - 1001) +#define PAGE_SHIFT 10 +#define for_each_domain(_d) \ + for ( (_d) = current->domain; \ + (_d) != NULL; \ + (_d) = NULL ) +#define smp_num_siblings 1 +#define num_online_cpus() 1 +rwlock_t domlist_lock = RW_LOCK_UNLOCKED; + +static struct vcpu *_test_alloc_vcpu_out; +static struct vcpu *alloc_vcpu(struct domain *d, unsigned int vcpu_id, + unsigned int cpu_id) +{ + return _test_alloc_vcpu_out; +} + +static struct vcpu *_test_new_vcpu(void) +{ + struct vcpu *vcpu = malloc(sizeof(struct vcpu)); + + vcpu->processor = 0; + vcpu->next_in_list = NULL; + return vcpu; +} + +static struct domain *_test_new_domain(void) +{ + struct domain *d = malloc(sizeof(struct domain)); + atomic_set(&d->refcnt, 0); + memset(d->vcpu, 0, sizeof(d->vcpu)); + d->vcpu[0] = _test_new_vcpu(); + return d; +} + +static struct domain *_test_do_createdomain_out; +static domid_t _test_do_createdomain_domid; +static unsigned int _test_do_createdomain_cpu; +static struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) +{ + fake_must_have_spinlock("&dom0_lock"); + _test_do_createdomain_domid = dom_id; + _test_do_createdomain_cpu = cpu; + if (_test_do_createdomain_out) + _test_do_createdomain_out->domain_id = dom_id; + return _test_do_createdomain_out; +} + +static long test_arch_do_dom0_op_out; +static long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) +{ + fake_must_have_spinlock("&dom0_lock"); + return test_arch_do_dom0_op_out; +} + +static unsigned int find_first_set_bit(unsigned long word) +{ + return ffsl(word); +} + +static struct vcpu *test_vcpu_pause_in_v; +static void vcpu_pause(struct vcpu *v) +{ + fake_must_have_spinlock("&dom0_lock"); + test_vcpu_pause_in_v = v; +} + +static struct vcpu *test_arch_getdomaininfo_ctxt_in_vcpu; +static void arch_getdomaininfo_ctxt(struct vcpu *vcpu, + struct vcpu_guest_context *ctx) +{ + fake_must_have_spinlock("&dom0_lock"); + test_arch_getdomaininfo_ctxt_in_vcpu = vcpu; +} + +static int test_vcpu_migrate_cpu_in_newcpu; +static void vcpu_migrate_cpu(struct vcpu *v, int newcpu) +{ + fake_must_have_spinlock("&dom0_lock"); + assert(v == test_vcpu_pause_in_v); + test_vcpu_migrate_cpu_in_newcpu = newcpu; +} + +static void vcpu_unpause(struct vcpu *v) +{ + fake_must_have_spinlock("&dom0_lock"); + assert(v == test_vcpu_pause_in_v); +} + +static long sched_ctl(struct sched_ctl_cmd *cmd) +{ + fake_must_have_spinlock("&dom0_lock"); + memset(cmd, 0, sizeof(cmd)); + return 102; +} + +static long sched_adjdom(struct sched_adjdom_cmd *cmd) +{ + fake_must_have_spinlock("&dom0_lock"); + memset(cmd, 0, sizeof(cmd)); + return 103; +} + +static unsigned long test_do_settime_in_secs; +static unsigned long test_do_settime_in_nsecs; +static unsigned long test_do_settime_in_system_time_base; +static void do_settime(unsigned long secs, unsigned long nsecs, + u64 system_time_base) +{ + fake_must_have_spinlock("&dom0_lock"); + test_do_settime_in_secs = secs; + test_do_settime_in_nsecs = nsecs; + test_do_settime_in_system_time_base = system_time_base; +} + +static int test_tb_control_out; +static int tb_control(dom0_tbufcontrol_t *tbc) +{ + fake_must_have_spinlock("&dom0_lock"); + return test_tb_control_out; +} + +static long test_read_console_ring_out; +static int test_read_console_ring_in_clear; +static long read_console_ring(char **pstr, u32 *pcount, int clear) +{ + fake_must_have_spinlock("&dom0_lock"); + (*pstr)++; + **pstr = 'A'; + *pcount = 1; + test_read_console_ring_in_clear = clear; + return test_read_console_ring_out; +} + +static int test_sched_id_out; +static int sched_id(void) +{ + fake_must_have_spinlock("&dom0_lock"); + return test_sched_id_out; +} + +/* Prototype to suppress warning (usually only called from asm) */ +long do_dom0_op(dom0_op_t *u_dom0_op); + +#include "../../include/public/dom0_ops.h" +#include "../dom0_ops.c" + +/* Use dynamic allocation so valgrind can find problems. */ +static dom0_op_t *_test_op(int cmd) +{ + dom0_op_t *op = malloc(sizeof(*op)); + op->interface_version = DOM0_INTERFACE_VERSION; + op->cmd = cmd; + return op; +} + +int main(int argc, char *argv[]) +{ + struct domain *me; + dom0_op_t *op; + + parse_test_args(argc, argv); + + me = _test_new_domain(); + current = me->vcpu[0]; + current->domain = me; + me->domain_flags = 0; + atomic_inc(&me->refcnt); + + /* Unpriv'd domains should be immediately shown the door. */ + fake_IS_PRIV_out = 0; + test_cond(do_dom0_op(fake_to_user(NULL)) == -EPERM); + test_cond(fake_lock_count == 0); + + /* Wrong version should be failed without looking at command. */ + fake_IS_PRIV_out = 1; + op = malloc(sizeof(*op)); + op->interface_version = DOM0_INTERFACE_VERSION - 1; + test_cond(do_dom0_op(fake_to_user(op)) == -EACCES); + test_cond(fake_lock_count == 0); + + /* ACM hook should result in immediate refusal, too. */ + op->interface_version = DOM0_INTERFACE_VERSION; + _test_acm_pre_dom0_op = 1; + test_cond(do_dom0_op(fake_to_user(op)) == -EPERM); + test_cond(fake_lock_count == 0); + _test_acm_pre_dom0_op = 0; + + op = _test_op(DOM0_SETDOMAININFO); + op->u.setdomaininfo.domain = 100; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_lock_count == 0); + fake_find_domain_out = current->domain; + _test_set_info_guest_out = -1000; + test_cond(do_dom0_op(fake_to_user(op)) == -1000); + test_cond(fake_lock_count == 0); + + op = _test_op(DOM0_PAUSEDOMAIN); + op->u.pausedomain.domain = 101; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_lock_count == 0); + fake_find_domain_out = current->domain; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(_test_count_domain_pause_by_systemcontroller == 1); + test_cond(fake_lock_count == 0); + + op = _test_op(DOM0_UNPAUSEDOMAIN); + op->u.unpausedomain.domain = 101; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_lock_count == 0); + fake_find_domain_out = current->domain; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + fake_find_domain_out->vcpu[0]->vcpu_flags = 0; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + fake_find_domain_out->vcpu[0]->vcpu_flags = (1 << _VCPUF_initialised); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(fake_lock_count == 0); + + op = _test_op(DOM0_CREATEDOMAIN); + op->u.createdomain.domain = 101; + fake_find_domain_out = current->domain; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + fake_find_domain_out = NULL; + _test_do_createdomain_out = _test_new_domain(); + /* Not fair to test failing very first allocation. */ + op->u.createdomain.domain = 0; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(op->u.createdomain.domain == 1); + test_cond(_test_do_createdomain_domid == 1); + fake_find_domain_out = current->domain; + op->u.createdomain.domain = 0; + test_cond(do_dom0_op(fake_to_user(op)) == -ENOMEM); + fake_find_domain_out = current->domain; + fake_find_domain_out = NULL; + _test_do_createdomain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ENOMEM); + _test_do_createdomain_out = _test_new_domain(); + /* It copies back to us, so we must set valid bits. */ + memset(op, 0, sizeof(*op)); + op->cmd = DOM0_CREATEDOMAIN; + op->interface_version = DOM0_INTERFACE_VERSION; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + fake_check_memory(op, sizeof(*op)); + test_cond(_test_do_createdomain_domid != 0); + test_cond(_test_do_createdomain_domid == op->u.createdomain.domain); + test_cond(_test_do_createdomain_cpu == 0); + op->u.createdomain.domain = 101; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + fake_check_memory(op, sizeof(*op)); + test_cond(_test_do_createdomain_domid == 101); + test_cond(op->u.createdomain.domain == 101); + test_cond(_test_do_createdomain_cpu == 0); + + op = _test_op(DOM0_MAX_VCPUS); + op->u.max_vcpus.max = MAX_VIRT_CPUS+1; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + op->u.max_vcpus.max = MAX_VIRT_CPUS; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + fake_find_domain_out->vcpu[0]->vcpu_flags = (1 << _VCPUF_initialised); + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + fake_find_domain_out->vcpu[0]->vcpu_flags = 0; + _test_alloc_vcpu_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ENOMEM); + test_cond(fake_lock_count == 0); + _test_alloc_vcpu_out = _test_new_vcpu(); + fake_find_domain_out = _test_new_domain(); + atomic_inc(&fake_find_domain_out->refcnt); + fake_find_domain_out->vcpu[0] = _test_new_vcpu(); + fake_find_domain_out->vcpu[0]->vcpu_flags = 0; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(fake_lock_count == 0); + op->u.max_vcpus.max = 0; + _test_alloc_vcpu_out = _test_new_vcpu(); + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + + op = _test_op(DOM0_DESTROYDOMAIN); + op->u.destroydomain.domain = 101; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_lock_count == 0); + fake_find_domain_out = current->domain; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + test_cond(fake_lock_count == 0); + fake_find_domain_out = _test_new_domain(); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(fake_lock_count == 0); + test_cond(_test_domain_kill == fake_find_domain_out); + + op = _test_op(DOM0_PINCPUDOMAIN); + op->u.pincpudomain.domain = 101; + op->u.pincpudomain.vcpu = 0; + op->u.pincpudomain.cpumap = 1; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + fake_find_domain_out = current->domain; + op->u.pincpudomain.vcpu = MAX_VIRT_CPUS; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + op->u.pincpudomain.vcpu = 1; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + /* FIXME: Unreachable ESRCH return --RR */ + op->u.pincpudomain.vcpu = 0; + current->domain->vcpu[0] = current; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + current->domain->vcpu[0] = _test_new_vcpu(); + current->domain->vcpu[0]->vcpu_flags = (1<<_VCPUF_cpu_pinned); + op->u.pincpudomain.cpumap = CPUMAP_RUNANYWHERE; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(current->domain->vcpu[0]->vcpu_flags == 0); + op->u.pincpudomain.cpumap = 1; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(current->domain->vcpu[0]->vcpu_flags + == (1<<_VCPUF_cpu_pinned)); + test_cond(test_vcpu_pause_in_v == current->domain->vcpu[0]); + test_cond(test_vcpu_migrate_cpu_in_newcpu == 0); + + op = _test_op(DOM0_SCHEDCTL); + test_cond(do_dom0_op(fake_to_user(op)) == 102); + + op = _test_op(DOM0_ADJUSTDOM); + test_cond(do_dom0_op(fake_to_user(op)) == 103); + + op = _test_op(DOM0_GETDOMAININFO); + current->domain->vcpu[0] = current; + current->domain->domain_id = 1; + op->u.getdomaininfo.domain = 2; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + op->u.getdomaininfo.domain = 1; + fake_get_domain_out = 0; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + test_cond(fake_get_domain_in_d == current->domain); + fake_get_domain_out = 1; + memset(&op->u.getdomaininfo, 0, sizeof(op->u.getdomaininfo)); + current->domain->tot_pages = 104; + current->domain->max_pages = 105; + current->domain->shared_info = (void *)__va(106 << PAGE_SHIFT); + current->cpu_time = 107; + current->vcpu_id = 1; + current->vcpu_flags = VCPUF_running; + current->domain->ssid = NULL; + current->domain->shutdown_code = 0; + memset(current->domain->handle, 0, sizeof(current->domain->handle)); + strcpy((char *)current->domain->handle, "handle"); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + fake_check_memory(&op->u.getdomaininfo, sizeof(op->u.getdomaininfo)); + test_cond(op->u.getdomaininfo.domain == 1); + test_cond(op->u.getdomaininfo.flags == DOMFLAGS_RUNNING); + test_cond(op->u.getdomaininfo.tot_pages == 104); + test_cond(op->u.getdomaininfo.max_pages == 105); + test_cond(op->u.getdomaininfo.nr_online_vcpus == 1); + test_cond(op->u.getdomaininfo.shared_info_frame == 106); + test_cond(op->u.getdomaininfo.cpu_time == 107); + test_cond(op->u.getdomaininfo.nr_online_vcpus == 1); + test_cond(op->u.getdomaininfo.max_vcpu_id == 1); + test_cond(op->u.getdomaininfo.ssidref == ACM_DEFAULT_SSID); + test_cond(strcmp((char *)op->u.getdomaininfo.handle, "handle") == 0); + + op = _test_op(DOM0_GETDOMAININFOLIST); + { + dom0_getdomaininfo_t *buffer = malloc(sizeof(*buffer)); + + op->u.getdomaininfolist.buffer = fake_to_user(buffer); + op->u.getdomaininfolist.first_domain = 0; + op->u.getdomaininfolist.max_domains = 0; + /* FIXME: Redundant NULL test in for_each_domain(). */ + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(op->u.getdomaininfolist.num_domains == 0); + op->u.getdomaininfolist.max_domains = 1; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(op->u.getdomaininfolist.num_domains == 1); + /* FIXME: Contains 2 uninitialized bytes, but we're dom0. */ + /* fake_check_memory(buffer, sizeof(*buffer)); */ + test_cond(buffer->domain == 1); + test_cond(buffer->flags == DOMFLAGS_RUNNING); + test_cond(buffer->tot_pages == 104); + test_cond(buffer->max_pages == 105); + test_cond(buffer->shared_info_frame == 106); + test_cond(buffer->cpu_time == 107); + test_cond(buffer->nr_online_vcpus == 1); + test_cond(buffer->max_vcpu_id == 1); + test_cond(buffer->ssidref == ACM_DEFAULT_SSID); + test_cond(memcmp(buffer->handle, current->domain->handle, + sizeof(buffer->handle)) == 0); + } + + op = _test_op(DOM0_GETVCPUCONTEXT); + op->u.getvcpucontext.domain = 101; + op->u.getvcpucontext.vcpu = 0; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + fake_find_domain_out = current->domain; + op->u.getvcpucontext.vcpu = MAX_VIRT_CPUS; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + op->u.getvcpucontext.vcpu = 1; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + op->u.getvcpucontext.vcpu = 0; + test_vcpu_pause_in_v = NULL; + { + vcpu_guest_context_t *ctxt = malloc(sizeof *ctxt); + op->u.getvcpucontext.ctxt = fake_to_user(ctxt); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + } + test_cond(test_arch_getdomaininfo_ctxt_in_vcpu == current); + test_cond(test_vcpu_pause_in_v == NULL); + /* Non-current vcpu must be paused. */ + fake_find_domain_out = _test_new_domain(); + atomic_inc(&fake_find_domain_out->refcnt); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(test_arch_getdomaininfo_ctxt_in_vcpu + == fake_find_domain_out->vcpu[0]); + test_cond(test_vcpu_pause_in_v == fake_find_domain_out->vcpu[0]); + + + op = _test_op(DOM0_GETVCPUINFO); + op->u.getvcpuinfo.domain = 101; + op->u.getvcpuinfo.vcpu = 0; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + fake_find_domain_out = current->domain; + op->u.getvcpuinfo.vcpu = MAX_VIRT_CPUS; + test_cond(do_dom0_op(fake_to_user(op)) == -EINVAL); + op->u.getvcpuinfo.vcpu = 1; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + op->u.getvcpuinfo.vcpu = 0; + current->cpu_time = 108; + current->processor = 1; + current->cpumap = 7; + current->vcpu_flags = (1 << _VCPUF_running); + op->u.getvcpuinfo.vcpu = 0; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(op->u.getvcpuinfo.online); + test_cond(!op->u.getvcpuinfo.blocked); + test_cond(op->u.getvcpuinfo.running); + test_cond(op->u.getvcpuinfo.cpu_time == 108); + test_cond(op->u.getvcpuinfo.cpu == 1); + test_cond(op->u.getvcpuinfo.cpumap == 7); + + op = _test_op(DOM0_SETTIME); + op->u.settime.secs = 109; + op->u.settime.nsecs = 110; + op->u.settime.system_time = 111; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(test_do_settime_in_secs == 109); + test_cond(test_do_settime_in_nsecs == 110); + test_cond(test_do_settime_in_system_time_base == 111); + + op = _test_op(DOM0_TBUFCONTROL); + test_tb_control_out = 112; + test_cond(do_dom0_op(fake_to_user(op)) == 112); + + op = _test_op(DOM0_READCONSOLE); + { + char buf[2]; + test_read_console_ring_out = 113; + op->u.readconsole.buffer = buf; + op->u.readconsole.count = 100; + op->u.readconsole.clear = 1; + test_cond(do_dom0_op(fake_to_user(op)) == 113); + test_cond(test_read_console_ring_in_clear == 1); + test_cond(buf[1] == 'A'); + test_cond(op->u.readconsole.buffer == buf+1); + test_cond(op->u.readconsole.count == 1); + } + + op = _test_op(DOM0_SCHED_ID); + test_sched_id_out = 114; + /* FIXME: Doesn't return -EFAULT on copy_to_user failing. */ + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(op->u.sched_id.sched_id == 114); + + op = _test_op(DOM0_SETDOMAINMAXMEM); + op->u.setdomainmaxmem.domain = 115; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + fake_find_domain_out = current->domain; + op->u.setdomainmaxmem.max_memkb = 116; + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(current->domain->max_pages == 116*1024/(1<<PAGE_SHIFT)); + + op = _test_op(DOM0_SETDOMAINHANDLE); + op->u.setdomainhandle.domain = 117; + fake_find_domain_out = NULL; + test_cond(do_dom0_op(fake_to_user(op)) == -ESRCH); + fake_find_domain_out = current->domain; + strcpy((char *)op->u.setdomainhandle.handle, "handle2"); + test_cond(do_dom0_op(fake_to_user(op)) == 0); + test_cond(strcmp((char *)current->domain->handle, "handle2") == 0); + + op = _test_op(10001); + test_arch_do_dom0_op_out = 118; + test_cond(do_dom0_op(fake_to_user(op)) == 118); + return 0; +} diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_domain.c xen-unstable.hg-check/xen/common/test/test_domain.c --- xen-unstable.hg-mainline/xen/common/test/test_domain.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_domain.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,832 @@ +/* Tests for domain.c + Copyright (C) 2005 Tony Breeds IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> + +#include "fake-support.h" + +/* BEGIN: Stuff for fake */ +/* Attribute tags */ + +#define DOMAIN_HASH_SIZE 256 +#define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1)) + +/* + * Commands to HYPERVISOR_vm_assist(). + */ +#define VMASST_CMD_enable 0 +#define VMASST_CMD_disable 1 +#define VMASST_TYPE_4gb_segments 0 +#define VMASST_TYPE_4gb_segments_notify 1 +#define VMASST_TYPE_writable_pagetables 2 +#define MAX_VMASST_TYPE 2 + +#define for_each_domain(_d) \ + for ( (_d) = domain_list; \ + (_d) != NULL; \ + (_d) = (_d)->next_in_list ) + +#define for_each_vcpu(_d,_v) \ + for ( (_v) = (_d)->vcpu[0]; \ + (_v) != NULL; \ + (_v) = (_v)->next_in_list ) + +/* + * Per-VCPU flags (vcpu_flags). + */ + /* Has the FPU been initialised? */ +#define _VCPUF_fpu_initialised 0 +#define VCPUF_fpu_initialised (1UL<<_VCPUF_fpu_initialised) + /* Has the FPU been used since it was last saved? */ +#define _VCPUF_fpu_dirtied 1 +#define VCPUF_fpu_dirtied (1UL<<_VCPUF_fpu_dirtied) + /* Domain is blocked waiting for an event. */ +#define _VCPUF_blocked 2 +#define VCPUF_blocked (1UL<<_VCPUF_blocked) + /* Currently running on a CPU? */ +#define _VCPUF_running 3 +#define VCPUF_running (1UL<<_VCPUF_running) + /* Disables auto-migration between CPUs. */ +#define _VCPUF_cpu_pinned 4 +#define VCPUF_cpu_pinned (1UL<<_VCPUF_cpu_pinned) + /* Domain migrated between CPUs. */ +#define _VCPUF_cpu_migrated 5 +#define VCPUF_cpu_migrated (1UL<<_VCPUF_cpu_migrated) + /* Initialization completed. */ +#define _VCPUF_initialised 6 +#define VCPUF_initialised (1UL<<_VCPUF_initialised) + /* VCPU is not-runnable */ +#define _VCPUF_down 7 +#define VCPUF_down (1UL<<_VCPUF_down) + +#define VCPUOP_initialise 0 +#define VCPUOP_up 1 +#define VCPUOP_down 2 +#define VCPUOP_is_up 3 + + +#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS) +static inline int __cpus_empty(const cpumask_t *srcp, int nbits) +{ + return *srcp == 0UL; +} + +#define LOCK_BIGLOCK(_d) spin_lock_recursive(&(_d)->big_lock) +#define UNLOCK_BIGLOCK(_d) spin_unlock_recursive(&(_d)->big_lock) +static void cleanup_writable_pagetable(struct domain *d) {} +#define sync_pagetable_state(d) \ + do { \ + LOCK_BIGLOCK(d); \ + cleanup_writable_pagetable(d); \ + UNLOCK_BIGLOCK(d); \ + } while ( 0 ) + +/* + * VIRTUAL INTERRUPTS + * + * Virtual interrupts that a guest OS may receive from Xen. + */ +#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ +#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ +#define NR_VIRQS 7 + + +/* + * Per-domain flags (domain_flags). + */ + /* Is this one of the per-CPU idle domains? */ +#define _DOMF_idle_domain 0 +#define DOMF_idle_domain (1UL<<_DOMF_idle_domain) + /* Is this domain privileged? */ +#define _DOMF_privileged 1 +#define DOMF_privileged (1UL<<_DOMF_privileged) + /* May this domain do IO to physical devices? */ +#define _DOMF_physdev_access 2 +#define DOMF_physdev_access (1UL<<_DOMF_physdev_access) + /* Guest shut itself down for some reason. */ +#define _DOMF_shutdown 3 +#define DOMF_shutdown (1UL<<_DOMF_shutdown) + /* Guest is in process of shutting itself down (becomes DOMF_shutdown). */ +#define _DOMF_shuttingdown 4 +#define DOMF_shuttingdown (1UL<<_DOMF_shuttingdown) + /* Death rattle. */ +#define _DOMF_dying 5 +#define DOMF_dying (1UL<<_DOMF_dying) + /* Domain is paused by controller software. */ +#define _DOMF_ctrl_pause 6 +#define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause) + + +/* + * Reason codes for SCHEDOP_shutdown. These may be interpreted by controller + * software to determine the appropriate action. For the most part, Xen does + * not care about the shutdown code. + */ +#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ +#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ +#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ +#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */ +/* END: Stuff for fake */ + +#define _TEST_DOMAIN_DESTRUCTED_POWER 31 /* Keep these 2 in sync */ +#define DOMAIN_DESTRUCTED (1<<31) /* assumes atomic_t is >= 32 bits */ + +/* Empty functions */ +static void debugger_trap_immediate(void) {} +static void sched_rem_domain(struct vcpu *v) {} +static void vcpu_sleep_sync(struct vcpu *v) {} +static void vcpu_sleep_nosync(struct vcpu *v) {} +static void vcpu_wake(struct vcpu *v) {} +static void show_registers(struct cpu_user_regs *regs) {} + +static void domain_relinquish_resources(struct domain *d) {} +static inline void send_guest_virq(struct vcpu *v, int virq) {} +static void free_perdomain_pt(struct domain *d) {} +#define free_xenheap_page(v) (free_xenheap_pages(v,0)) +static void free_xenheap_pages(void *v, unsigned int order) {} +static void arch_do_createdomain(struct vcpu *v) {} + +/* Override fake printk (it abort()s) */ +void printk(const char *format, ...) {} + +/* Only one softirq used in domain.c. */ +#define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6 + +typedef void (*softirq_handler)(void); +softirq_handler _test_handler; + +static inline void open_softirq(int nr, softirq_handler handler) +{ + test_cond(nr == DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ); + _test_handler = handler; +} + +static void do_softirq(void) +{ + _test_handler(); +} + +static inline void raise_softirq(unsigned int nr) {} + +typedef struct { + /* IN variables. */ + domid_t domain; + uint16_t vcpu; + /* IN/OUT parameters */ + vcpu_guest_context_t *ctxt; +} dom0_setdomaininfo_t; + +/* Forward declarations for functions from ../domain.c */ +/* FIXME: Move prototypes from sched.h to domain.h */ +struct domain *do_createdomain(domid_t dom_id, unsigned int cpu); +struct domain *find_domain_by_id(domid_t dom); +void domain_kill(struct domain *d); +void domain_crash(struct domain *d); +void domain_crash_synchronous(void); +static void domain_shutdown_finalise(void); +static __init int domain_shutdown_finaliser_init(void); +void domain_shutdown(struct domain *d, u8 reason); +void domain_pause_for_debugger(void); +void domain_destruct(struct domain *d); +void vcpu_pause(struct vcpu *v); +void domain_pause(struct domain *d); +void vcpu_unpause(struct vcpu *v); +void domain_unpause(struct domain *d); +void domain_pause_by_systemcontroller(struct domain *d); +void domain_unpause_by_systemcontroller(struct domain *d); +int set_info_guest(struct domain *d, dom0_setdomaininfo_t *setdomaininfo); +int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt); +long do_vcpu_op(int cmd, int vcpuid, void *arg); +long vm_assist(struct domain *p, unsigned int cmd, unsigned int type); + +/* FIXME: Use a list to track allocation/frees of domains and vcpus */ +static int _test_alloc_domain_error = 0; +static struct domain *alloc_domain(void) +{ + struct domain *d; + + + if (_test_alloc_domain_error) + return NULL; + + d = malloc(sizeof(struct domain)); + test_cond(d != NULL); + /* FIXME: don't use memset it will defeat valgrind's memcheck */ + memset(d, 0, sizeof(struct domain)); + return d; +} + +static void free_domain(struct domain *d) +{ + int i; + struct vcpu *v; + + for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- ) { + if ( d->vcpu[i] != NULL ) { + v = d->vcpu[i]; + test_cond(v->next_in_list == NULL); + + if ( v->vcpu_id != 0 ) { + v->domain->vcpu[v->vcpu_id - 1]->next_in_list = NULL; + } + free(v); + } + } + + free(d); +} + +static int _test_alloc_vcpu_error = 0; +static struct vcpu *alloc_vcpu(struct domain *d, unsigned int vcpu_id, + unsigned int cpu_id) +{ + struct vcpu *v; + + if (_test_alloc_vcpu_error) + return NULL; + + test_cond(d->vcpu[vcpu_id] == NULL); + + v = malloc(sizeof(struct vcpu)); + test_cond(v != NULL); + /* FIXME: don't use memset it will defeat valgrind's memcheck */ + memset(v, 0, sizeof(struct vcpu)); + + v->domain = d; + v->vcpu_id = vcpu_id; + v->processor = cpu_id; + atomic_set(&v->pausecnt, 0); + d->vcpu[vcpu_id] = v; + + /* from sched_add_domain */ + if ( is_idle_task(d) ) { + set_bit(_VCPUF_running, &v->vcpu_flags); + } + + if ( vcpu_id != 0 ) { + d->vcpu[v->vcpu_id-1]->next_in_list = v; + set_bit(_VCPUF_down, &v->vcpu_flags); + } + + return v; +} + + +/* from common/event_channel.c */ +static int _test_evtchn[DOMAIN_HASH_SIZE] = + { [0 ... DOMAIN_HASH_SIZE-1] = 42 }; +static int _test_evtchn_error = 0; +static int evtchn_init(struct domain *d) +{ + int retval; + int slot = d->domain_id; + + /* Event Channels are not created for IDLE_DOMAIN_ID */ + test_cond(d->domain_id != IDLE_DOMAIN_ID); + + if (slot >= DOMAIN_HASH_SIZE) { + slot /= DOMAIN_HASH_SIZE; + } + + test_cond(slot <= DOMAIN_HASH_SIZE-1); + + if (!_test_evtchn_error) { + _test_evtchn[slot] = 24; + retval = 0; + } else { + _test_evtchn[slot] = 42; + retval = -EINVAL; + } + + return retval; +} + +static void evtchn_destroy(struct domain *d) +{ + int slot = d->domain_id; + + /* Event Channels are not created for IDLE_DOMAIN_ID + * so destorying them makes no sense. + * event_channel.c handles this better than this test suite */ + if (d->domain_id == IDLE_DOMAIN_ID) + return; + + if (slot >= DOMAIN_HASH_SIZE) { + slot /= DOMAIN_HASH_SIZE; + } + + test_cond(slot <= DOMAIN_HASH_SIZE-1); + + _test_evtchn[slot] = 42; +} + +/* from common/grant_table.c */ +static int _test_granttable[DOMAIN_HASH_SIZE] = + { [0 ... DOMAIN_HASH_SIZE-1] = 42 }; +static int _test_granttable_error = 0; +static int grant_table_create(struct domain *d) +{ + int retval; + int slot = d->domain_id; + + /* Grant tables are not created for IDLE_DOMAIN_ID */ + test_cond(d->domain_id != IDLE_DOMAIN_ID); + + if (slot >= DOMAIN_HASH_SIZE) { + slot /= DOMAIN_HASH_SIZE; + } + + test_cond(slot <= DOMAIN_HASH_SIZE-1); + + if (!_test_granttable_error) { + _test_granttable[slot] = 24; + retval = 0; + } else { + _test_granttable[slot] = 42; + retval = -ENOMEM; + } + + return retval; +} + +static void grant_table_destroy(struct domain *d) +{ + int slot = d->domain_id; + + /* Grant tables are not created for IDLE_DOMAIN_ID + * so destorying them makes no sense. + * grant_table.c handles this better than this test suite */ + if (d->domain_id == IDLE_DOMAIN_ID) + return; + + if (slot >= DOMAIN_HASH_SIZE) { + slot /= DOMAIN_HASH_SIZE; + } + + test_cond(slot <= DOMAIN_HASH_SIZE-1); + + _test_granttable[slot] = 42; +} + +int _test_arch_set_info_guest_result = 0; +static int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) +{ + return _test_arch_set_info_guest_result; +} + +#define guest_cpu_user_regs() (NULL) + +/* FIXME: The real versions of machine_halt/machine_restart are + * noreturns, which means that the tail end of domain_shutdown + * is never executed in the domain_id == 0 case. + * #define'ing them to return will not work becuase there is no symbol + * for the extern to match */ +static int _test_machine_state = 0; +static void machine_restart(char __attribute__((unused)) *addr) +{ + _test_machine_state = 1; +} + +static void machine_halt(void) +{ + _test_machine_state = 2; +} + +#include "../domain.c" + +/* FIXME: do not re-use allocations. malloc again! */ +int main(int argc, char *argv[]) +{ + int i; + struct domain *_test_domains[DOMAIN_HASH_SIZE] = + {[0 ... DOMAIN_HASH_SIZE-1] = NULL}; + struct vcpu *_test_vcpus[10] = {[0 ... 9] = NULL}; + domid_t domain_id; + struct domain *d; + struct vcpu_guest_context *_test_guest_context; + dom0_setdomaininfo_t *_test_setdomaininfo; + + parse_test_args(argc, argv); + + /* build current() */ + current = malloc(sizeof(struct vcpu)); + current->domain = malloc(sizeof(struct domain)); + + current->domain->vcpu[0] = current; + dom0 = current->domain; + spin_lock_init(¤t->domain->big_lock); + + /* Test domain_shutdown_finaliser_init */ + test_cond(_test_handler == NULL); + domain_shutdown_finaliser_init(); + test_cond(_test_handler == domain_shutdown_finalise); + + /* Test vm_assist */ + test_cond(vm_assist(current->domain, -1, MAX_VMASST_TYPE) == -ENOSYS); + test_cond(vm_assist(current->domain, VMASST_CMD_enable, MAX_VMASST_TYPE+1) + == -EINVAL); + + current->domain->vm_assist = 0UL; + test_cond(!vm_assist(current->domain, VMASST_CMD_enable, + VMASST_TYPE_4gb_segments)); + test_cond(current->domain->vm_assist != 0); + + test_cond(!vm_assist(current->domain, VMASST_CMD_disable, + VMASST_TYPE_4gb_segments)); + test_cond(current->domain->vm_assist == 0); + + test_cond(!vm_assist(current->domain, VMASST_CMD_enable, + VMASST_TYPE_4gb_segments_notify)); + test_cond(current->domain->vm_assist != 0); + + test_cond(!vm_assist(current->domain, VMASST_CMD_disable, + VMASST_TYPE_4gb_segments_notify)); + test_cond(current->domain->vm_assist == 0); + + test_cond(!vm_assist(current->domain, VMASST_CMD_enable, + VMASST_TYPE_writable_pagetables)); + test_cond(current->domain->vm_assist != 0); + + test_cond(!vm_assist(current->domain, VMASST_CMD_disable, + VMASST_TYPE_writable_pagetables)); + test_cond(current->domain->vm_assist == 0); + + /* Nothing to test for boot_vcpu(), it will either BUG_ON or + * pass back the result of arch_set_info_guest() */ + + /* Test do_createdomain failure paths */ + _test_alloc_domain_error = 1; + _test_domains[0] = do_createdomain(0, 0); + test_cond(_test_domains[0] == NULL); + _test_alloc_domain_error = 0; + + _test_granttable_error = 1; + _test_domains[0] = do_createdomain(0, 0); + test_cond(_test_domains[0] == NULL); + test_cond(_test_evtchn[0] == 42); + _test_granttable_error = 0; + + _test_evtchn_error = 1; + _test_domains[0] = do_createdomain(0, 0); + test_cond(_test_domains[0] == NULL); + /* check event channel was destroyed */ + test_cond(_test_evtchn[0] == 42); + _test_evtchn_error = 0; + + _test_alloc_vcpu_error = 1; + _test_evtchn[0] = 99; + _test_granttable[0] = 99; + _test_domains[0] = do_createdomain(IDLE_DOMAIN_ID, 0); + test_cond(_test_domains[0] == NULL); + test_cond(_test_evtchn[0] == 99); + test_cond(_test_granttable[0] == 99); + + _test_evtchn[0] = 42; + _test_granttable[0] = 42; + _test_domains[0] = do_createdomain(0, 0); + test_cond(_test_domains[0] == NULL); + /* check granttable was destroyed */ + test_cond(_test_granttable[0] == 42); + _test_alloc_vcpu_error = 0; + + /* Test do_createdomain and domain_destruct */ + for(i=DOMAIN_HASH_SIZE-1; i>=0; i--) { + _test_domains[i] = do_createdomain(i, 0); + test_cond(_test_domains[i] != NULL); + test_cond(_test_domains[i]->next_in_hashbucket == NULL); + test_cond(_atomic_read(_test_domains[i]->refcnt) == 1); + test_cond(_test_evtchn[i] == 24); + } + + + /* Walk the list checking sorted by domain_id, and all domains are + * found */ + domain_id = domain_list->domain_id; + d = domain_list; + i=0; + + while (d->next_in_list != NULL) { + test_cond(domain_id <= d->domain_id); + d = d->next_in_list; + domain_id = d->domain_id; + i++; + } + test_cond(i == DOMAIN_HASH_SIZE-1); + + /* check each hasbucket got excactly one domain */ + for(i = 0; i< DOMAIN_HASH_SIZE; i++) { + int hash_val = DOMAIN_HASH(_test_domains[i]->domain_id); + + test_cond(domain_hash[hash_val] == _test_domains[i]); + test_cond(domain_hash[hash_val]->next_in_hashbucket == NULL); + } + + for(i = 0; i< DOMAIN_HASH_SIZE; i++) { + domid_t old_domainid = _test_domains[i]->domain_id; + + test_cond(domain_list->domain_id == _test_domains[i]->domain_id); + test_cond(_atomic_read(domain_list->refcnt) == 1); + + set_bit(_DOMF_dying, &_test_domains[i]->domain_flags); + domain_destruct(_test_domains[i]); + + test_cond(domain_list->domain_id == _test_domains[i]->domain_id); + + _atomic_set(domain_list->refcnt, 0); + domain_destruct(_test_domains[i]); + + if (i == DOMAIN_HASH_SIZE-1) { + test_cond(domain_list == NULL); + } else { + test_cond(domain_list->domain_id != old_domainid); + } + + test_cond(_test_evtchn[i] == 42); + _test_domains[i] = NULL; + } + + /* Test find_domain_by_id (Uses hashbucket ops) */ + /* Interleave domain creation requests */ + for(i=1; i<=2; i++) { + int j; + for(j=(DOMAIN_HASH_SIZE/4)-i; j>=0; j-=2) { + int k = j*DOMAIN_HASH_SIZE; + _test_domains[j] = do_createdomain(k, 0); + test_cond(_test_domains[j] != NULL); + } + } + + domain_id = domain_list->domain_id; + d = domain_list; + i=0; + + while (d->next_in_hashbucket != NULL) { + test_cond(domain_id <= d->domain_id); + d = d->next_in_hashbucket; + domain_id = d->domain_id; + i++; + } + test_cond(i == (DOMAIN_HASH_SIZE/4)-1); + + /* find_domain_by_id will fail if the domain is DOMAIN_DESTRUCTED */ + fake_get_domain_out = 0; + test_cond(get_domain(_test_domains[0]) == 0); + test_cond(find_domain_by_id(_test_domains[0]->domain_id) == NULL); + fake_get_domain_out = 1; + + /* Check ref counts work as expected */ + for(i = 0; i< (DOMAIN_HASH_SIZE/4); i++) { + int refcnt = _atomic_read(_test_domains[i]->refcnt); + + test_cond(refcnt == 1); + test_cond(find_domain_by_id(_test_domains[i]->domain_id) != NULL); + test_cond(_atomic_read(_test_domains[i]->refcnt) == refcnt+1); + + put_domain(_test_domains[i]); + test_cond(_atomic_read(_test_domains[i]->refcnt) == refcnt); + } + + /* destroty the created domains and structures */ + for(i = 0; i< (DOMAIN_HASH_SIZE/4); i++) { + set_bit(_DOMF_dying, &_test_domains[i]->domain_flags); + _atomic_set(domain_list->refcnt, 0); + domain_destruct(_test_domains[i]); + + test_cond(_test_evtchn[i] == 42); + } + + /* Test do_vcpu_op */ + current->domain->vcpu[0] = NULL; + test_cond(do_vcpu_op(-1, -1, NULL) == -EINVAL); + test_cond(do_vcpu_op(-1, MAX_VIRT_CPUS-1, NULL) == -ENOENT); + + current->domain->vcpu[0] = current; + + /* What protects against invalid cmds? */ + test_cond(!do_vcpu_op(-1, 0, NULL)); + + /* Need instrumentation to fail copy_to/from_user */ + _test_guest_context = malloc(sizeof(struct vcpu_guest_context)); + /* FIXME: don't use memset it will defeat valgrind's memcheck */ + memset(_test_guest_context, 0, sizeof(struct vcpu_guest_context)); + + set_bit(_VCPUF_initialised, ¤t->vcpu_flags); + test_cond(do_vcpu_op(VCPUOP_initialise, 0, + fake_to_user(_test_guest_context)) == -EEXIST); + clear_bit(_VCPUF_initialised, ¤t->vcpu_flags); + + /* do_vcpu_op(VCPUOP_initialise,...) should pass back the result of + * boot_vcpu, which passes back the arch_set_info_guest() result */ + _test_arch_set_info_guest_result = -EINVAL; + test_cond(do_vcpu_op(VCPUOP_initialise, 0, + fake_to_user(_test_guest_context)) == + _test_arch_set_info_guest_result); + _test_arch_set_info_guest_result = 0; + test_cond(do_vcpu_op(VCPUOP_initialise, 0, + fake_to_user(_test_guest_context)) == + _test_arch_set_info_guest_result); + + current->vcpu_flags = 0UL; + test_cond(do_vcpu_op(VCPUOP_up, 0, NULL) == -EINVAL); + + set_bit(_VCPUF_initialised, ¤t->vcpu_flags); + test_cond(!do_vcpu_op(VCPUOP_up, 0, NULL)); + + set_bit(_VCPUF_down, ¤t->vcpu_flags); + test_cond(!do_vcpu_op(VCPUOP_up, 0, NULL)); + test_cond(!test_bit(_VCPUF_down, ¤t->vcpu_flags)); + + test_cond(do_vcpu_op(VCPUOP_is_up, 0, NULL) == + !test_bit(_VCPUF_down, ¤t->vcpu_flags)); + + test_cond(!do_vcpu_op(VCPUOP_down, 0, NULL)); + test_cond(test_bit(_VCPUF_down, ¤t->vcpu_flags)); + + /* Test set_info_guest */ + _test_setdomaininfo = malloc(sizeof(dom0_setdomaininfo_t)); + + current->domain->vcpu[0] = NULL; + _test_setdomaininfo->vcpu = MAX_VIRT_CPUS; + current->domain->domain_flags = 0UL; + _test_setdomaininfo->ctxt = fake_from_user(_test_guest_context); + + test_cond(set_info_guest(current->domain, _test_setdomaininfo) == -EINVAL); + _test_setdomaininfo->vcpu = 0; + test_cond(set_info_guest(current->domain, _test_setdomaininfo) == -EINVAL); + current->domain->vcpu[0] = current; + + test_cond(set_info_guest(current->domain, _test_setdomaininfo) == -EINVAL); + set_bit(_DOMF_ctrl_pause, ¤t->domain->domain_flags); + + _test_arch_set_info_guest_result = -ENOSYS; + test_cond(set_info_guest(current->domain, _test_setdomaininfo) == + _test_arch_set_info_guest_result); + _test_arch_set_info_guest_result = 0; + + /* Test domain_unpause_by_systemcontroller and + * domain_unpause_by_systemcontroller */ + _test_domains[0] = do_createdomain(0, 0); + _test_domains[0]->domain_flags = 0UL; + current->domain->domain_flags = 0UL; + set_bit(_DOMF_ctrl_pause, &_test_domains[0]->domain_flags ); + + domain_unpause_by_systemcontroller(_test_domains[0]); + test_cond(!test_bit(_DOMF_ctrl_pause, &_test_domains[0]->domain_flags)); + domain_pause_by_systemcontroller(_test_domains[0]); + test_cond(test_bit(_DOMF_ctrl_pause, &_test_domains[0]->domain_flags)); + + free_domain(_test_domains[0]); + + /* Test vcpu_pause/vcpu_unpause and domain_pause/domain_unpause */ + for(i=0;i<10;i++) { + _test_vcpus[i] = malloc(sizeof(struct vcpu)); + test_cond(_test_vcpus[i] != NULL); + _test_vcpus[i]->domain = malloc(sizeof(struct domain)); + test_cond(_test_vcpus[i]->domain != NULL); + + atomic_set(&_test_vcpus[i]->pausecnt, 0); + _test_vcpus[i]->domain->vcpu[0] = _test_vcpus[i]; + spin_lock_init(&_test_vcpus[i]->domain->big_lock); + } + + for(i=0;i<10;i++) { + int j; + for(j=1;j<=9;j++) { + vcpu_pause(_test_vcpus[i]); + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == j); + } + + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == 9); + + for(j=9;j>=1;j--) { + vcpu_unpause(_test_vcpus[i]); + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == j-1); + } + + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == 0); + } + + for(i=0;i<10;i++) { + int j; + for(j=1;j<=9;j++) { + domain_pause(_test_vcpus[i]->domain); + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == j); + } + + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == 9); + + for(j=9;j>=1;j--) { + domain_unpause(_test_vcpus[i]->domain); + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == j-1); + } + + test_cond(atomic_read(&_test_vcpus[i]->pausecnt) == 0); + } + + for(i=0;i<10;i++) { + test_cond(_test_vcpus[i]->domain->big_lock._l == 88); + free(_test_vcpus[i]->domain); + free(_test_vcpus[i]); + } + + /* Test domain_pause_for_debugger */ + current->domain->domain_flags = 0UL; + domain_pause_for_debugger(); + test_cond(test_bit(_DOMF_ctrl_pause, ¤t->domain->domain_flags)); + + /* Test domain_shutdown */ + _test_vcpus[0] = malloc(sizeof(struct vcpu)); + test_cond(_test_vcpus[0] != NULL); + _test_vcpus[0]->domain = malloc(sizeof(struct domain)); + test_cond(_test_vcpus[0]->domain != NULL); + _test_vcpus[0]->domain->vcpu[0] = _test_vcpus[0]; + _test_domains[0] = _test_vcpus[0]->domain; + + atomic_set(&_test_vcpus[0]->pausecnt, 0); + spin_lock_init(&_test_vcpus[0]->domain->big_lock); + + _test_domains[0]->domain_id = 1; + set_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags); + test_cond(domain_shuttingdown[smp_processor_id()] != _test_domains[0]); + + domain_shutdown(_test_domains[0], 255); + test_cond(_test_domains[0]->shutdown_code == 255); + test_cond(test_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags)); + + clear_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags); + domain_shutdown(_test_domains[0], 254); + test_cond(_test_domains[0]->shutdown_code == 254); + test_cond(domain_shuttingdown[smp_processor_id()] == _test_domains[0]); + + /* Now test the dodgy domain_id = 0 cases */ + _test_domains[0]->domain_id = 0; + _test_domains[0]->shutdown_code = 0; + set_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags); + domain_shuttingdown[smp_processor_id()] = NULL; + + domain_shutdown(_test_domains[0], 254); + test_cond(_test_machine_state == 1); + _test_machine_state = 0; + + domain_shutdown(_test_domains[0], SHUTDOWN_poweroff); + test_cond(_test_machine_state == 2); + _test_machine_state = 0; + + /* Test domain_shutdown_finalise */ + _test_domains[0]->domain_flags = 0UL; + set_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags); + domain_shuttingdown[smp_processor_id()] = _test_domains[0]; + + domain_shutdown_finalise(); + test_cond(!test_bit(_DOMF_shuttingdown, &_test_domains[0]->domain_flags)); + test_cond(test_bit(_DOMF_shutdown, &_test_domains[0]->domain_flags)); + + /* domain_crash/domain_crash_synchronous call previously tested + * functions */ + + /* Test domain_kill */ + atomic_set(&_test_vcpus[0]->pausecnt, 0); + atomic_set(&_test_domains[0]->refcnt, 2); + _test_domains[0]->domain_flags = 0UL; + set_bit(_DOMF_dying, &_test_domains[0]->domain_flags); + domain_kill(_test_domains[0]); + test_cond(atomic_read(&_test_vcpus[0]->pausecnt) == 1); + test_cond(test_bit(_DOMF_dying, &_test_domains[0]->domain_flags)); + + clear_bit(_DOMF_dying, &_test_domains[0]->domain_flags); + + domain_kill(_test_domains[0]); + test_cond(atomic_read(&_test_vcpus[0]->pausecnt) == 2); + test_cond(atomic_read(&_test_domains[0]->refcnt) == 1); + + free(_test_vcpus[0]->domain); + free(_test_vcpus[0]); + + free(_test_setdomaininfo); + free(_test_guest_context); + + free(current->domain); + free(current); + + return 0; +} diff -urN --exclude=.hg --exclude='*~' --exclude='*.aux' xen-unstable.hg-mainline/xen/common/test/test_event_channel.c xen-unstable.hg-check/xen/common/test/test_event_channel.c --- xen-unstable.hg-mainline/xen/common/test/test_event_channel.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/common/test/test_event_channel.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,768 @@ +/* Tests for event_channel.c + * + Copyright (C) 2005 Tony Breeds IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> + +#include "fake-support.h" + +#define BUG() +#define DPRINTK(...) + +#define for_each_vcpu(_d,_v) \ + for ( (_v) = (_d)->vcpu[0]; \ + (_v) != NULL; \ + (_v) = NULL) + +/* Override fake printk (it abort()s) */ +void printk(const char *format, ...) {} + +static struct vcpu *_test_evtchn_set_pending_in_v; +static int _test_evtchn_set_pending_in_port; +static void evtchn_set_pending(struct vcpu *v, int port) +{ + _test_evtchn_set_pending_in_v = v; + _test_evtchn_set_pending_in_port = port; +} + +static struct vcpu *_test_pirq_guest_bind_in_v; +static int _test_pirq_guest_bind_in_irq; +static int _test_pirq_guest_bind_in_will_share; +static int _test_pirq_guest_bind_out = 0; +static int pirq_guest_bind(struct vcpu *v, int irq, int will_share) +{ + _test_pirq_guest_bind_in_v = v; + _test_pirq_guest_bind_in_irq = irq; + _test_pirq_guest_bind_in_will_share = will_share; + + return _test_pirq_guest_bind_out; +} + +static struct domain *_test_pirq_guest_unbind_in_d; +static int _test_pirq_guest_unbind_in_irq; +static int _test_pirq_guest_unbind_out = 0; +static int pirq_guest_unbind(struct domain *d, int irq) +{ + _test_pirq_guest_unbind_in_d = d; + _test_pirq_guest_unbind_in_irq = irq; + + return _test_pirq_guest_unbind_out; +} + +/* Setup a minimal vcpu/domain pair, ensuring that commonly used fields + * contain sensible defaults */ +static struct vcpu *test_alloc_vcpu(void) +{ + struct vcpu *v; + + v = malloc(sizeof(struct vcpu)); + v->domain = malloc(sizeof(struct domain)); + + v->domain->vcpu[0] = v; + v->domain->domain_id = 0; + atomic_set(&v->domain->refcnt, 0); + spin_lock_init(&v->domain->evtchn_lock); + + /* Ensure that all event channels are empty */ + memset(v->domain->evtchn, 0, + NR_EVTCHN_BUCKETS * sizeof(v->domain->evtchn[0])); + + return v; +} + +#include "../../include/public/event_channel.h" + +/* needs evtchn_op_t from public/event_channel.h */ + +static evtchn_op_t *test_alloc_evtchn_op(int cmd) +{ + evtchn_op_t *op; + + op = malloc(sizeof(evtchn_op_t)); + op->cmd = cmd; + + return op; +} + + +static evtchn_op_t *_test_acm_pre_event_channel_in_op; +static int _test_acm_pre_event_channel_out = 0; +static inline int acm_pre_event_channel(evtchn_op_t *op) +{ + _test_acm_pre_event_channel_in_op = op; + return _test_acm_pre_event_channel_out; +} + + +/* Forward declarations for event_channel.c */ +long evtchn_send(int lport); +void send_guest_pirq(struct domain *d, int pirq); +long do_event_channel_op(evtchn_op_t *uop); +int evtchn_init(struct domain *d); +void evtchn_destroy(struct domain *d); + + +#include "../event_channel.c" + +int main(int argc, char *argv[]) +{ + int i; + + struct vcpu *remote_vcpu = NULL; + evtchn_close_t *close_opts; + evtchn_op_t *uop; + evtchn_alloc_unbound_t *unbound_alloc; + evtchn_bind_interdomain_t *interdomain_bind; + evtchn_bind_virq_t *virq_bind; + evtchn_bind_ipi_t *ipi_bind; + evtchn_bind_pirq_t *pirq_bind; + evtchn_status_t *status; + evtchn_bind_vcpu_t *vcpu_bind; + + current = test_alloc_vcpu(); + + parse_test_args(argc, argv); + + /* Test get_free_port */ + for(i=0; i<MAX_EVTCHNS; i++) { + int port = get_free_port(current->domain); + + if ((port%EVTCHNS_PER_BUCKET) == 0) + fake_expect_xmalloc = 1; + test_cond(port == i); + test_cond(evtchn_from_port(current->domain, port)->state == + ECS_FREE); + evtchn_from_port(current->domain, port)->state = ECS_RESERVED; + } + + test_cond(get_free_port(current->domain) == -ENOSPC); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + current->domain->evtchn[i] = NULL; + } + fake_xmalloc_expected = 0; + + /* Test evtchn_init */ + current = test_alloc_vcpu(); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_RESERVED); + test_cond(evtchn_init(current->domain) == -EINVAL); + + /* evtchn_init relies on evtchn_destroy to free the allocated memory */ + xfree(current->domain->evtchn[0]); + current->domain->evtchn[0] = NULL; + fake_xmalloc_expected = 0; + + /* Test __evtchn_close */ + current = test_alloc_vcpu(); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + + test_cond(__evtchn_close(current->domain, -1) == -EINVAL); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + test_cond(__evtchn_close(current->domain, 0) == -EINVAL); + + evtchn_from_port(current->domain, 0)->state = ECS_RESERVED; + test_cond(__evtchn_close(current->domain, 0) == -EINVAL); + + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(__evtchn_close(current->domain, 0) == 0); + + evtchn_from_port(current->domain, 0)->state = ECS_PIRQ; + evtchn_from_port(current->domain, 0)->u.pirq = 0; + _test_pirq_guest_unbind_out = 0; + test_cond(__evtchn_close(current->domain, 0) == 0); + + evtchn_from_port(current->domain, 0)->state = ECS_PIRQ; + evtchn_from_port(current->domain, 0)->u.pirq = ~0; + _test_pirq_guest_unbind_out = -1; + test_cond(__evtchn_close(current->domain, 0) == -1); + _test_pirq_guest_unbind_out = 0; + + evtchn_from_port(current->domain, 0)->state = ECS_VIRQ; + evtchn_from_port(current->domain, 0)->u.virq = 0; + current->virq_to_evtchn[0] = 1; + test_cond(__evtchn_close(current->domain, 0) == 0); + test_cond(current->virq_to_evtchn[0] == 1); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_FREE); + + evtchn_from_port(current->domain, 0)->state = ECS_VIRQ; + evtchn_from_port(current->domain, 0)->u.virq = 0; + current->virq_to_evtchn[0] = 0; + test_cond(__evtchn_close(current->domain, 0) == 0); + test_cond(current->virq_to_evtchn[0] == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_FREE); + + evtchn_from_port(current->domain, 0)->state = ECS_IPI; + test_cond(__evtchn_close(current->domain, 0) == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_FREE); + + remote_vcpu = test_alloc_vcpu(); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(remote_vcpu->domain) == 0); + + /* bump refcnt to avoid domain_destruct from freeing the memory */ + atomic_set(¤t->domain->refcnt, 10); + atomic_set(&remote_vcpu->domain->refcnt, 10); + + evtchn_from_port(current->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_INTERDOMAIN; + + evtchn_from_port(current->domain, 0)->u.interdomain.remote_dom = + remote_vcpu->domain; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_port = 0; + evtchn_from_port(remote_vcpu->domain, 0)->u.interdomain.remote_dom = + current->domain; + evtchn_from_port(remote_vcpu->domain, 0)->u.interdomain.remote_port = 0; + + test_cond(__evtchn_close(current->domain, 0) == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_FREE); + + /* Check alternate locking order */ + + evtchn_from_port(current->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_dom = + remote_vcpu->domain; + evtchn_from_port(remote_vcpu->domain, 0)->u.interdomain.remote_dom = + current->domain; + evtchn_from_port(remote_vcpu->domain, 0)->u.interdomain.remote_port = 0; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_port = 0; + test_cond(__evtchn_close(remote_vcpu->domain, 0) == 0); + test_cond(evtchn_from_port(remote_vcpu->domain, 0)->state == ECS_FREE); + + evtchn_from_port(current->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_INTERDOMAIN; + + /* Fail to get_domain() */ + fake_get_domain_out = 0; + test_cond(__evtchn_close(current->domain, 0) == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == + ECS_INTERDOMAIN); + fake_get_domain_out = 1; + + /* Clear out the allocated event_ channels */ + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(remote_vcpu->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + + /* Test evtchn_close */ + current = test_alloc_vcpu(); + close_opts = malloc(sizeof(evtchn_close_t)); + close_opts->port = 0; + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(evtchn_close(close_opts) == 0); + test_cond(evtchn_from_port(current->domain, 0)->state == ECS_FREE); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + + free(close_opts); + + /* Test evtchn_destroy */ + current = test_alloc_vcpu(); + fake_xfree_in_ptr = NULL; + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + + fake_check_status(__FILE__, __LINE__); + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + test_cond(fake_xfree_in_ptr != NULL); + + /* Test evtchn_send */ + current = test_alloc_vcpu(); + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + test_cond(evtchn_send(-1) == -EINVAL); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + test_cond(evtchn_send(0) == -EINVAL); + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(evtchn_send(0) == 0); + evtchn_from_port(current->domain, 0)->state = ECS_IPI; + evtchn_from_port(current->domain, 0)->notify_vcpu_id = 0; + test_cond(evtchn_send(0) == 0); + + remote_vcpu = test_alloc_vcpu(); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(remote_vcpu->domain) == 0); + + evtchn_from_port(current->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_dom = + remote_vcpu->domain; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_port = 0; + + evtchn_from_port(remote_vcpu->domain, 0)->notify_vcpu_id = 0; + test_cond(evtchn_send(0) == 0); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + evtchn_destroy(remote_vcpu->domain); + fake_xmalloc_expected = 0; + + /* Test evtchn_alloc_unbound */ + current = test_alloc_vcpu(); + unbound_alloc = malloc(sizeof(evtchn_alloc_unbound_t)); + unbound_alloc->dom = DOMID_SELF-1; + + fake_IS_PRIV_out = 0; + fake_find_domain_out = NULL; + + test_cond(evtchn_alloc_unbound(unbound_alloc) == -EPERM); + fake_IS_PRIV_out = 1; + + unbound_alloc->dom = DOMID_SELF; + test_cond(evtchn_alloc_unbound(unbound_alloc) == -ESRCH); + fake_find_domain_out = current->domain; + + /* Bump the refcnt to avoid put_domain() freeing the domain */ + atomic_set(¤t->domain->refcnt, 10); + + /* Not testing for get_free_port failures here */ + + current->domain->domain_id = 1; + unbound_alloc->remote_dom = DOMID_SELF; + unbound_alloc->dom = DOMID_SELF; + unbound_alloc->port = -1; + fake_expect_xmalloc = 1; + test_cond(evtchn_alloc_unbound(unbound_alloc) == 0); + test_cond(unbound_alloc->port != -1); + + test_cond(evtchn_from_port(current->domain, + unbound_alloc->port)->state == ECS_UNBOUND); + test_cond(evtchn_from_port(current->domain, + unbound_alloc->port)->u.unbound.remote_domid + == current->domain->domain_id); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + free(unbound_alloc); + + /* Test evtchn_bind_interdomain */ + current = test_alloc_vcpu(); + interdomain_bind = malloc(sizeof(evtchn_bind_interdomain_t)); + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + test_cond(get_free_port(current->domain) == 1); + + interdomain_bind->remote_dom = DOMID_SELF; + + fake_find_domain_out = NULL; + test_cond(evtchn_bind_interdomain(interdomain_bind) == -ESRCH); + fake_find_domain_out = current->domain; + + atomic_set(¤t->domain->refcnt, 10); + /* not testing get_free_port failures here */ + + interdomain_bind->remote_port = -1; + test_cond(evtchn_bind_interdomain(interdomain_bind) == -EINVAL); + + interdomain_bind->remote_port = 1; + evtchn_from_port(current->domain, 1)->state = ECS_RESERVED; + test_cond(evtchn_bind_interdomain(interdomain_bind) == -EINVAL); + + remote_vcpu = test_alloc_vcpu(); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(remote_vcpu->domain) == 0); + atomic_set(&remote_vcpu->domain->refcnt, 10); + + fake_find_domain_out = remote_vcpu->domain; + remote_vcpu->domain->domain_id = 42; + interdomain_bind->remote_dom = 42; + interdomain_bind->remote_port = 0; + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_UNBOUND; + current->domain->domain_id = 1; + evtchn_from_port(remote_vcpu->domain, 0)->u.unbound.remote_domid = 0; + + test_cond(evtchn_bind_interdomain(interdomain_bind) == -EINVAL); + + current->domain->domain_id = 1; + evtchn_from_port(remote_vcpu->domain, 0)->u.unbound.remote_domid = 1; + test_cond(evtchn_bind_interdomain(interdomain_bind) == 0); + + test_cond(evtchn_from_port(remote_vcpu->domain, 0)->state == + ECS_INTERDOMAIN); + test_cond(evtchn_from_port(current->domain, + interdomain_bind->local_port)->state == + ECS_INTERDOMAIN); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(remote_vcpu->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + + /* Test the current > remote case */ + remote_vcpu = test_alloc_vcpu(); + current = test_alloc_vcpu(); + + /* This /should/ be good enough to ensure the correct ordering */ + if (current < remote_vcpu) { + struct vcpu *tmp = remote_vcpu; + remote_vcpu = current; + current = tmp; + } + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(remote_vcpu->domain) == 0); + + atomic_set(¤t->domain->refcnt, 10); + atomic_set(&remote_vcpu->domain->refcnt, 10); + + current->domain->domain_id = 1; + remote_vcpu->domain->domain_id = 2; + + interdomain_bind->remote_dom = 2; + interdomain_bind->remote_port = 0; + fake_find_domain_out = remote_vcpu->domain; + + evtchn_from_port(remote_vcpu->domain, 0)->state = ECS_UNBOUND; + evtchn_from_port(remote_vcpu->domain, 0)->u.unbound.remote_domid = 1; + test_cond(evtchn_bind_interdomain(interdomain_bind) == 0); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(remote_vcpu->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + free(interdomain_bind); + + /* Test evtchn_bind_virq */ + current = test_alloc_vcpu(); + virq_bind = malloc(sizeof(evtchn_bind_virq_t)); + + virq_bind->virq = ARRAY_SIZE(current->virq_to_evtchn) +1; + virq_bind->vcpu = ARRAY_SIZE(current->domain->vcpu) +1; + current->domain->vcpu[0] = NULL; + current->virq_to_evtchn[0] = 1; + + test_cond(evtchn_bind_virq(virq_bind) == -EINVAL); + + virq_bind->virq = 0; + test_cond(evtchn_bind_virq(virq_bind) == -ENOENT); + virq_bind->vcpu = 0; + test_cond(evtchn_bind_virq(virq_bind) == -ENOENT); + current->domain->vcpu[0] = current; + test_cond(evtchn_bind_virq(virq_bind) == -EEXIST); + current->virq_to_evtchn[0] = 0; + /* not testing get_free_port failures here */ + fake_expect_xmalloc = 1; + test_cond(evtchn_bind_virq(virq_bind) == 0); + fake_check_status(__FILE__, __LINE__); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + free(virq_bind); + + /* Test evtchn_bind_ipi */ + current = test_alloc_vcpu(); + ipi_bind = malloc(sizeof(evtchn_bind_ipi_t)); + + ipi_bind->vcpu = ARRAY_SIZE(current->domain->vcpu) +1; + current->domain->vcpu[0] = NULL; + + test_cond(evtchn_bind_ipi(ipi_bind) == -ENOENT); + ipi_bind->vcpu = 0; + test_cond(evtchn_bind_ipi(ipi_bind) == -ENOENT); + current->domain->vcpu[0] = current; + /* not testing get_free_port failures here */ + fake_expect_xmalloc = 1; + test_cond(evtchn_bind_ipi(ipi_bind) == 0); + fake_check_status(__FILE__, __LINE__); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + free(ipi_bind); + + /* Test evtchn_bind_pirq */ + current = test_alloc_vcpu(); + pirq_bind = malloc(sizeof(evtchn_bind_pirq_t)); + + pirq_bind->pirq = ARRAY_SIZE(current->domain->pirq_to_evtchn) +1; + current->domain->pirq_to_evtchn[0] = 1; + + test_cond(evtchn_bind_pirq(pirq_bind) == -EINVAL); + pirq_bind->pirq = 0; + test_cond(evtchn_bind_pirq(pirq_bind) == -EEXIST); + current->domain->pirq_to_evtchn[0] = 0; + /* not testing get_free_port failures here */ + + _test_pirq_guest_bind_out = -1; + fake_expect_xmalloc = 1; + test_cond(evtchn_bind_pirq(pirq_bind) == _test_pirq_guest_bind_out); + _test_pirq_guest_bind_out = 0; + test_cond(evtchn_bind_pirq(pirq_bind) == 0); + fake_check_status(__FILE__, __LINE__); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + + free(pirq_bind); + + /* FIXME: Not testing send_guest_pirq */ + + /* Testing evtchn_status */ + current = test_alloc_vcpu(); + status= malloc(sizeof(evtchn_status_t)); + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + atomic_set(¤t->domain->refcnt, 10); + + status->dom = 0; + status->port = -1; + fake_find_domain_out = NULL; + + fake_IS_PRIV_out = 0; + test_cond(evtchn_status(status) == -EPERM); + fake_IS_PRIV_out = 1; + status->dom = DOMID_SELF; + + test_cond(evtchn_status(status) == -ESRCH); + fake_find_domain_out = current->domain; + test_cond(evtchn_status(status) == -EINVAL); + + status->port = 0; + status->status = EVTCHNSTAT_closed+1; + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_closed); + + status->status = EVTCHNSTAT_unbound+1; + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_unbound); + + status->status = EVTCHNSTAT_interdomain+1; + evtchn_from_port(current->domain, 0)->state = ECS_INTERDOMAIN; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_dom = + current->domain; + evtchn_from_port(current->domain, 0)->u.interdomain.remote_port = 1; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_interdomain); + test_cond(status->u.interdomain.port == 1); + + status->status = EVTCHNSTAT_pirq+1; + evtchn_from_port(current->domain, 0)->state = ECS_PIRQ; + evtchn_from_port(current->domain, 0)->u.pirq = 1; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_pirq); + test_cond(status->u.pirq == 1); + + status->status = EVTCHNSTAT_virq+1; + evtchn_from_port(current->domain, 0)->state = ECS_VIRQ; + evtchn_from_port(current->domain, 0)->u.virq = 10; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_virq); + test_cond(status->u.pirq == 10); + + status->status = EVTCHNSTAT_ipi+1; + evtchn_from_port(current->domain, 0)->state = ECS_IPI; + test_cond(evtchn_status(status) == 0); + test_cond(status->status == EVTCHNSTAT_ipi); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + + free(status); + + /* Test evtchn_bind_vcpu */ + current = test_alloc_vcpu(); + vcpu_bind = malloc(sizeof(evtchn_bind_vcpu_t)); + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + + vcpu_bind->port = -1; + vcpu_bind->vcpu=ARRAY_SIZE(current->domain->vcpu) +1; + current->domain->vcpu[0] = NULL; + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_from_port(current->domain, 0)->notify_vcpu_id = 10; + + test_cond(evtchn_bind_vcpu(vcpu_bind) == -ENOENT); + vcpu_bind->vcpu=0; + test_cond(evtchn_bind_vcpu(vcpu_bind) == -ENOENT); + + current->domain->vcpu[0] = current; + test_cond(evtchn_bind_vcpu(vcpu_bind) == -EINVAL); + + vcpu_bind->port = 0; + test_cond(evtchn_bind_vcpu(vcpu_bind) == -EINVAL); + + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(evtchn_bind_vcpu(vcpu_bind) == 0); + test_cond(evtchn_from_port(current->domain, 0)->notify_vcpu_id == 0); + + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + evtchn_destroy(current->domain); + fake_xmalloc_expected = 0; + + free(vcpu_bind); + + /* Test do_event_channel_op */ + current = test_alloc_vcpu(); + uop = test_alloc_evtchn_op(15); + + fake_expect_xmalloc = 1; + test_cond(evtchn_init(current->domain) == 0); + atomic_set(¤t->domain->refcnt, 10); + + _test_acm_pre_event_channel_out = 1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -EACCES); + _test_acm_pre_event_channel_out = 0; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ENOSYS); + + /* Setup helper functions to fail to test an overall failure of + * do_event_channel_op */ + fake_IS_PRIV_out = 1; + fake_find_domain_out = NULL; + + uop = test_alloc_evtchn_op(EVTCHNOP_alloc_unbound); + uop->u.alloc_unbound.dom = DOMID_SELF +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ESRCH); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_interdomain); + uop->u.bind_interdomain.remote_dom = DOMID_SELF +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ESRCH); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_virq); + uop->u.bind_virq.virq = NR_VIRQS +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -EINVAL); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_ipi); + uop->u.bind_ipi.vcpu = MAX_VIRT_CPUS +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ENOENT); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_pirq); + uop->u.bind_pirq.pirq = NR_PIRQS +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -EINVAL); + + uop = test_alloc_evtchn_op(EVTCHNOP_close); + uop->cmd = EVTCHNOP_close; + uop->u.close.port = -1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -EINVAL); + + uop = test_alloc_evtchn_op(EVTCHNOP_send); + uop->u.send.port = -1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -EINVAL); + + uop = test_alloc_evtchn_op(EVTCHNOP_status); + uop->u.status.dom = DOMID_SELF +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ESRCH); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_vcpu); + uop->u.bind_vcpu.vcpu = MAX_VIRT_CPUS +1; + test_cond(do_event_channel_op(fake_from_user(uop)) == -ENOENT); + + /* Setup helper functions to succeed to test an overall success of + * do_event_channel_op */ + fake_IS_PRIV_out = 1; + fake_find_domain_out = current->domain; + + uop = test_alloc_evtchn_op(EVTCHNOP_alloc_unbound); + uop->u.alloc_unbound.remote_dom = DOMID_SELF; + uop->u.alloc_unbound.dom = DOMID_SELF; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_interdomain); + uop->u.bind_interdomain.remote_dom = DOMID_SELF; + uop->u.bind_interdomain.remote_port = 0; + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + evtchn_from_port(current->domain, 0)->u.unbound.remote_domid = + current->domain->domain_id; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_virq); + uop->u.bind_virq.virq = 0; + uop->u.bind_virq.vcpu = 0; + current->virq_to_evtchn[0] = 0; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_ipi); + uop->u.bind_ipi.vcpu = 0; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_pirq); + uop->u.bind_pirq.pirq = 0; + current->domain->pirq_to_evtchn[0] = 0; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_close); + uop->u.close.port = 0; + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_send); + uop->u.send.port = 0; + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_status); + uop->u.status.dom = DOMID_SELF; + uop->u.status.port = 0; + evtchn_from_port(current->domain, 0)->state = ECS_FREE; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + uop = test_alloc_evtchn_op(EVTCHNOP_bind_vcpu); + uop->u.bind_vcpu.vcpu = 0; + uop->u.bind_vcpu.port = 0; + evtchn_from_port(current->domain, 0)->state = ECS_UNBOUND; + test_cond(do_event_channel_op(fake_from_user(uop)) == 0); + + free(uop); + + for(i=0; i<NR_EVTCHN_BUCKETS; i++) { + xfree(current->domain->evtchn[i]); + } + fake_xmalloc_expected = 0; + + fake_check_status(__FILE__, __LINE__); + return 0; +} -- ccontrol: http://freshmeat.net/projects/ccontrol ----- End forwarded message ----- Yours Tony linux.conf.au http://linux.conf.au/ || http://lca2006.linux.org.au/ Jan 23-28 2006 The Australian Linux Technical Conference! _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |