[PATCH] fbdev: Fix incorrect unaligned access in little-endian machines
The drawing function cfbfillrect does not work correctly when access is not unsigned-long aligned. It manifests as extra lines of pixels that are not complete drawn. Reversing the shift operator solves the problem, so I would presume that this bug would manifest only on little endian machines. The function cfbcopyarea may also have this bug. Aligned access should present no problems. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
7275b4b6bc
commit
be0d9b6c7a
|
@ -64,8 +64,8 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
|
|||
int const shift = dst_idx-src_idx;
|
||||
int left, right;
|
||||
|
||||
first = ~0UL >> dst_idx;
|
||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
||||
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||
|
||||
if (!shift) {
|
||||
// Same alignment for source and dest
|
||||
|
@ -216,8 +216,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
|
|||
|
||||
shift = dst_idx-src_idx;
|
||||
|
||||
first = ~0UL << (bits - 1 - dst_idx);
|
||||
last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits)));
|
||||
first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
|
||||
last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
|
||||
|
||||
if (!shift) {
|
||||
// Same alignment for source and dest
|
||||
|
|
|
@ -110,8 +110,8 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsi
|
|||
if (!n)
|
||||
return;
|
||||
|
||||
first = ~0UL >> dst_idx;
|
||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
||||
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||
|
||||
if (dst_idx+n <= bits) {
|
||||
// Single word
|
||||
|
@ -167,8 +167,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
|
|||
if (!n)
|
||||
return;
|
||||
|
||||
first = ~0UL >> dst_idx;
|
||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
||||
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||
|
||||
if (dst_idx+n <= bits) {
|
||||
// Single word
|
||||
|
@ -221,8 +221,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
|
|||
if (!n)
|
||||
return;
|
||||
|
||||
first = ~0UL >> dst_idx;
|
||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
||||
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||
|
||||
if (dst_idx+n <= bits) {
|
||||
// Single word
|
||||
|
@ -290,8 +290,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat
|
|||
if (!n)
|
||||
return;
|
||||
|
||||
first = ~0UL >> dst_idx;
|
||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
||||
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||
|
||||
if (dst_idx+n <= bits) {
|
||||
// Single word
|
||||
|
|
|
@ -76,18 +76,6 @@ static u32 cfb_tab32[] = {
|
|||
#define FB_WRITEL fb_writel
|
||||
#define FB_READL fb_readl
|
||||
|
||||
#if defined (__BIG_ENDIAN)
|
||||
#define LEFT_POS(bpp) (32 - bpp)
|
||||
#define SHIFT_HIGH(val, bits) ((val) >> (bits))
|
||||
#define SHIFT_LOW(val, bits) ((val) << (bits))
|
||||
#define BIT_NR(b) (7 - (b))
|
||||
#else
|
||||
#define LEFT_POS(bpp) (0)
|
||||
#define SHIFT_HIGH(val, bits) ((val) << (bits))
|
||||
#define SHIFT_LOW(val, bits) ((val) >> (bits))
|
||||
#define BIT_NR(b) (b)
|
||||
#endif
|
||||
|
||||
static inline void color_imageblit(const struct fb_image *image,
|
||||
struct fb_info *p, u8 __iomem *dst1,
|
||||
u32 start_index,
|
||||
|
@ -109,7 +97,7 @@ static inline void color_imageblit(const struct fb_image *image,
|
|||
val = 0;
|
||||
|
||||
if (start_index) {
|
||||
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
|
||||
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
|
||||
val = FB_READL(dst) & start_mask;
|
||||
shift = start_index;
|
||||
}
|
||||
|
@ -119,20 +107,20 @@ static inline void color_imageblit(const struct fb_image *image,
|
|||
color = palette[*src];
|
||||
else
|
||||
color = *src;
|
||||
color <<= LEFT_POS(bpp);
|
||||
val |= SHIFT_HIGH(color, shift);
|
||||
color <<= FB_LEFT_POS(bpp);
|
||||
val |= FB_SHIFT_HIGH(color, shift);
|
||||
if (shift >= null_bits) {
|
||||
FB_WRITEL(val, dst++);
|
||||
|
||||
val = (shift == null_bits) ? 0 :
|
||||
SHIFT_LOW(color, 32 - shift);
|
||||
FB_SHIFT_LOW(color, 32 - shift);
|
||||
}
|
||||
shift += bpp;
|
||||
shift &= (32 - 1);
|
||||
src++;
|
||||
}
|
||||
if (shift) {
|
||||
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
|
||||
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
|
||||
|
||||
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
||||
}
|
||||
|
@ -162,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||
u32 i, j, l;
|
||||
|
||||
dst2 = (u32 __iomem *) dst1;
|
||||
fgcolor <<= LEFT_POS(bpp);
|
||||
bgcolor <<= LEFT_POS(bpp);
|
||||
fgcolor <<= FB_LEFT_POS(bpp);
|
||||
bgcolor <<= FB_LEFT_POS(bpp);
|
||||
|
||||
for (i = image->height; i--; ) {
|
||||
shift = val = 0;
|
||||
|
@ -174,21 +162,21 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||
|
||||
/* write leading bits */
|
||||
if (start_index) {
|
||||
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
|
||||
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
|
||||
val = FB_READL(dst) & start_mask;
|
||||
shift = start_index;
|
||||
}
|
||||
|
||||
while (j--) {
|
||||
l--;
|
||||
color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor;
|
||||
val |= SHIFT_HIGH(color, shift);
|
||||
color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor;
|
||||
val |= FB_SHIFT_HIGH(color, shift);
|
||||
|
||||
/* Did the bitshift spill bits to the next long? */
|
||||
if (shift >= null_bits) {
|
||||
FB_WRITEL(val, dst++);
|
||||
val = (shift == null_bits) ? 0 :
|
||||
SHIFT_LOW(color,32 - shift);
|
||||
FB_SHIFT_LOW(color,32 - shift);
|
||||
}
|
||||
shift += bpp;
|
||||
shift &= (32 - 1);
|
||||
|
@ -197,7 +185,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||
|
||||
/* write trailing bits */
|
||||
if (shift) {
|
||||
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
|
||||
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
|
||||
|
||||
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
||||
}
|
||||
|
|
|
@ -833,6 +833,18 @@ struct fb_info {
|
|||
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
|
||||
#define fb_memset memset
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (__BIG_ENDIAN)
|
||||
#define FB_LEFT_POS(bpp) (32 - bpp)
|
||||
#define FB_SHIFT_HIGH(val, bits) ((val) >> (bits))
|
||||
#define FB_SHIFT_LOW(val, bits) ((val) << (bits))
|
||||
#define FB_BIT_NR(b) (7 - (b))
|
||||
#else
|
||||
#define FB_LEFT_POS(bpp) (0)
|
||||
#define FB_SHIFT_HIGH(val, bits) ((val) << (bits))
|
||||
#define FB_SHIFT_LOW(val, bits) ((val) >> (bits))
|
||||
#define FB_BIT_NR(b) (b)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue