diff --git a/xen/common/bitmap.c b/xen/common/bitmap.c index 3da63a32a6..6c4af09c18 100644 --- a/xen/common/bitmap.c +++ b/xen/common/bitmap.c @@ -40,21 +40,6 @@ * for the best explanations of this ordering. */ -/* - * If a bitmap has a number of bits which is not a multiple of 8 then - * the last few bits of the last byte of the bitmap can be - * unexpectedly set which can confuse consumers (e.g. in the tools) - * who also round up their loops to 8 bits. Ensure we clear those left - * over bits so as to prevent surprises. - */ -static void clamp_last_byte(uint8_t *bp, unsigned int nbits) -{ - unsigned int remainder = nbits % 8; - - if (remainder) - bp[nbits/8] &= (1U << remainder) - 1; -} - int __bitmap_empty(const unsigned long *bitmap, unsigned int bits) { int k, lim = bits/BITS_PER_LONG; @@ -338,7 +323,6 @@ static void bitmap_long_to_byte(uint8_t *bp, const unsigned long *lp, nbits -= 8; } } - clamp_last_byte(bp, nbits); } static void bitmap_byte_to_long(unsigned long *lp, const uint8_t *bp, @@ -359,12 +343,11 @@ static void bitmap_byte_to_long(unsigned long *lp, const uint8_t *bp, #elif defined(__LITTLE_ENDIAN) -static void bitmap_long_to_byte(uint8_t *bp, const unsigned long *lp, - unsigned int nbits) -{ - memcpy(bp, lp, DIV_ROUND_UP(nbits, BITS_PER_BYTE)); - clamp_last_byte(bp, nbits); -} +#define LITTLE_ENDIAN 1 /* For IS_ENABLED(). */ + +/* Unused function, but a declaration is needed. */ +void bitmap_long_to_byte(uint8_t *bp, const unsigned long *lp, + unsigned int nbits); static void bitmap_byte_to_long(unsigned long *lp, const uint8_t *bp, unsigned int nbits) @@ -384,21 +367,45 @@ int bitmap_to_xenctl_bitmap(struct xenctl_bitmap *xenctl_bitmap, uint8_t zero = 0; int err = 0; unsigned int xen_bytes = DIV_ROUND_UP(nbits, BITS_PER_BYTE); - uint8_t *bytemap = xmalloc_array(uint8_t, xen_bytes); + const uint8_t *bytemap; + uint8_t last, *buf = NULL; - if ( !bytemap ) - return -ENOMEM; + if ( !IS_ENABLED(LITTLE_ENDIAN) ) + { + buf = xmalloc_array(uint8_t, xen_bytes); + if ( !buf ) + return -ENOMEM; + + bitmap_long_to_byte(buf, bitmap, nbits); + + bytemap = buf; + } + else + bytemap = (const uint8_t *)bitmap; guest_bytes = DIV_ROUND_UP(xenctl_bitmap->nr_bits, BITS_PER_BYTE); copy_bytes = min(guest_bytes, xen_bytes); - bitmap_long_to_byte(bytemap, bitmap, nbits); - - if ( copy_bytes && - copy_to_guest(xenctl_bitmap->bitmap, bytemap, copy_bytes) ) + if ( copy_bytes > 1 && + copy_to_guest(xenctl_bitmap->bitmap, bytemap, copy_bytes - 1) ) err = -EFAULT; - xfree(bytemap); + /* + * If a bitmap has a number of bits which is not a multiple of 8 then the + * last few bits of the last byte of the bitmap can be unexpectedly set, + * which can confuse consumers (e.g. in the tools), who also may round up + * their loops to 8 bits. Ensure we clear those left over bits so as to + * prevent surprises. + */ + last = bytemap[nbits / 8]; + if ( nbits % 8 ) + last &= (1U << (nbits % 8)) - 1; + + xfree(buf); + + if ( copy_bytes && + copy_to_guest_offset(xenctl_bitmap->bitmap, copy_bytes - 1, &last, 1) ) + err = -EFAULT; for ( i = copy_bytes; !err && i < guest_bytes; i++ ) if ( copy_to_guest_offset(xenctl_bitmap->bitmap, i, &zero, 1) )