Commit be0d9b6c authored by Antonino A. Daplas's avatar Antonino A. Daplas Committed by Linus Torvalds

[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: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7275b4b6
...@@ -64,8 +64,8 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src ...@@ -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 const shift = dst_idx-src_idx;
int left, right; int left, right;
first = ~0UL >> dst_idx; first = FB_SHIFT_HIGH(~0UL, dst_idx);
last = ~(~0UL >> ((dst_idx+n) % bits)); last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
if (!shift) { if (!shift) {
// Same alignment for source and dest // Same alignment for source and dest
...@@ -216,8 +216,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem ...@@ -216,8 +216,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
shift = dst_idx-src_idx; shift = dst_idx-src_idx;
first = ~0UL << (bits - 1 - dst_idx); first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits))); last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
if (!shift) { if (!shift) {
// Same alignment for source and dest // Same alignment for source and dest
......
...@@ -110,8 +110,8 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsi ...@@ -110,8 +110,8 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsi
if (!n) if (!n)
return; return;
first = ~0UL >> dst_idx; first = FB_SHIFT_HIGH(~0UL, dst_idx);
last = ~(~0UL >> ((dst_idx+n) % bits)); last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) { if (dst_idx+n <= bits) {
// Single word // Single word
...@@ -167,8 +167,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, ...@@ -167,8 +167,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
if (!n) if (!n)
return; return;
first = ~0UL >> dst_idx; first = FB_SHIFT_HIGH(~0UL, dst_idx);
last = ~(~0UL >> ((dst_idx+n) % bits)); last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) { if (dst_idx+n <= bits) {
// Single word // Single word
...@@ -221,8 +221,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, ...@@ -221,8 +221,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
if (!n) if (!n)
return; return;
first = ~0UL >> dst_idx; first = FB_SHIFT_HIGH(~0UL, dst_idx);
last = ~(~0UL >> ((dst_idx+n) % bits)); last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) { if (dst_idx+n <= bits) {
// Single word // Single word
...@@ -290,8 +290,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat ...@@ -290,8 +290,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat
if (!n) if (!n)
return; return;
first = ~0UL >> dst_idx; first = FB_SHIFT_HIGH(~0UL, dst_idx);
last = ~(~0UL >> ((dst_idx+n) % bits)); last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) { if (dst_idx+n <= bits) {
// Single word // Single word
......
...@@ -76,18 +76,6 @@ static u32 cfb_tab32[] = { ...@@ -76,18 +76,6 @@ static u32 cfb_tab32[] = {
#define FB_WRITEL fb_writel #define FB_WRITEL fb_writel
#define FB_READL fb_readl #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, static inline void color_imageblit(const struct fb_image *image,
struct fb_info *p, u8 __iomem *dst1, struct fb_info *p, u8 __iomem *dst1,
u32 start_index, u32 start_index,
...@@ -109,7 +97,7 @@ static inline void color_imageblit(const struct fb_image *image, ...@@ -109,7 +97,7 @@ static inline void color_imageblit(const struct fb_image *image,
val = 0; val = 0;
if (start_index) { 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; val = FB_READL(dst) & start_mask;
shift = start_index; shift = start_index;
} }
...@@ -119,20 +107,20 @@ static inline void color_imageblit(const struct fb_image *image, ...@@ -119,20 +107,20 @@ static inline void color_imageblit(const struct fb_image *image,
color = palette[*src]; color = palette[*src];
else else
color = *src; color = *src;
color <<= LEFT_POS(bpp); color <<= FB_LEFT_POS(bpp);
val |= SHIFT_HIGH(color, shift); val |= FB_SHIFT_HIGH(color, shift);
if (shift >= null_bits) { if (shift >= null_bits) {
FB_WRITEL(val, dst++); FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 : val = (shift == null_bits) ? 0 :
SHIFT_LOW(color, 32 - shift); FB_SHIFT_LOW(color, 32 - shift);
} }
shift += bpp; shift += bpp;
shift &= (32 - 1); shift &= (32 - 1);
src++; src++;
} }
if (shift) { 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); 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 * ...@@ -162,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
u32 i, j, l; u32 i, j, l;
dst2 = (u32 __iomem *) dst1; dst2 = (u32 __iomem *) dst1;
fgcolor <<= LEFT_POS(bpp); fgcolor <<= FB_LEFT_POS(bpp);
bgcolor <<= LEFT_POS(bpp); bgcolor <<= FB_LEFT_POS(bpp);
for (i = image->height; i--; ) { for (i = image->height; i--; ) {
shift = val = 0; shift = val = 0;
...@@ -174,21 +162,21 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * ...@@ -174,21 +162,21 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write leading bits */ /* write leading bits */
if (start_index) { 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; val = FB_READL(dst) & start_mask;
shift = start_index; shift = start_index;
} }
while (j--) { while (j--) {
l--; l--;
color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor; color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor;
val |= SHIFT_HIGH(color, shift); val |= FB_SHIFT_HIGH(color, shift);
/* Did the bitshift spill bits to the next long? */ /* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) { if (shift >= null_bits) {
FB_WRITEL(val, dst++); FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 : val = (shift == null_bits) ? 0 :
SHIFT_LOW(color,32 - shift); FB_SHIFT_LOW(color,32 - shift);
} }
shift += bpp; shift += bpp;
shift &= (32 - 1); shift &= (32 - 1);
...@@ -197,7 +185,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * ...@@ -197,7 +185,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write trailing bits */ /* write trailing bits */
if (shift) { 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); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
} }
......
...@@ -833,6 +833,18 @@ struct fb_info { ...@@ -833,6 +833,18 @@ struct fb_info {
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b)) #define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
#define fb_memset memset #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 #endif
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment