cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

syscopyarea.c (8730B)


      1/*
      2 *  Generic Bit Block Transfer for frame buffers located in system RAM with
      3 *  packed pixels of any depth.
      4 *
      5 *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
      6 *  on Geert Uytterhoeven's copyarea routine)
      7 *
      8 *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
      9 *
     10 *  This file is subject to the terms and conditions of the GNU General Public
     11 *  License.  See the file COPYING in the main directory of this archive for
     12 *  more details.
     13 *
     14 */
     15#include <linux/module.h>
     16#include <linux/kernel.h>
     17#include <linux/string.h>
     18#include <linux/fb.h>
     19#include <asm/types.h>
     20#include <asm/io.h>
     21#include "fb_draw.h"
     22
     23    /*
     24     *  Generic bitwise copy algorithm
     25     */
     26
     27static void
     28bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
     29	const unsigned long *src, unsigned src_idx, int bits, unsigned n)
     30{
     31	unsigned long first, last;
     32	int const shift = dst_idx-src_idx;
     33	int left, right;
     34
     35	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
     36	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
     37
     38	if (!shift) {
     39		/* Same alignment for source and dest */
     40		if (dst_idx+n <= bits) {
     41			/* Single word */
     42			if (last)
     43				first &= last;
     44			*dst = comp(*src, *dst, first);
     45		} else {
     46			/* Multiple destination words */
     47			/* Leading bits */
     48 			if (first != ~0UL) {
     49				*dst = comp(*src, *dst, first);
     50				dst++;
     51				src++;
     52				n -= bits - dst_idx;
     53			}
     54
     55			/* Main chunk */
     56			n /= bits;
     57			while (n >= 8) {
     58				*dst++ = *src++;
     59				*dst++ = *src++;
     60				*dst++ = *src++;
     61				*dst++ = *src++;
     62				*dst++ = *src++;
     63				*dst++ = *src++;
     64				*dst++ = *src++;
     65				*dst++ = *src++;
     66				n -= 8;
     67			}
     68			while (n--)
     69				*dst++ = *src++;
     70
     71			/* Trailing bits */
     72			if (last)
     73				*dst = comp(*src, *dst, last);
     74		}
     75	} else {
     76		unsigned long d0, d1;
     77		int m;
     78
     79		/* Different alignment for source and dest */
     80		right = shift & (bits - 1);
     81		left = -shift & (bits - 1);
     82
     83		if (dst_idx+n <= bits) {
     84			/* Single destination word */
     85			if (last)
     86				first &= last;
     87			if (shift > 0) {
     88				/* Single source word */
     89				*dst = comp(*src << left, *dst, first);
     90			} else if (src_idx+n <= bits) {
     91				/* Single source word */
     92				*dst = comp(*src >> right, *dst, first);
     93			} else {
     94				/* 2 source words */
     95				d0 = *src++;
     96				d1 = *src;
     97				*dst = comp(d0 >> right | d1 << left, *dst,
     98					    first);
     99			}
    100		} else {
    101			/* Multiple destination words */
    102			/** We must always remember the last value read,
    103			    because in case SRC and DST overlap bitwise (e.g.
    104			    when moving just one pixel in 1bpp), we always
    105			    collect one full long for DST and that might
    106			    overlap with the current long from SRC. We store
    107			    this value in 'd0'. */
    108			d0 = *src++;
    109			/* Leading bits */
    110			if (shift > 0) {
    111				/* Single source word */
    112				*dst = comp(d0 << left, *dst, first);
    113				dst++;
    114				n -= bits - dst_idx;
    115			} else {
    116				/* 2 source words */
    117				d1 = *src++;
    118				*dst = comp(d0 >> right | d1 << left, *dst,
    119					    first);
    120				d0 = d1;
    121				dst++;
    122				n -= bits - dst_idx;
    123			}
    124
    125			/* Main chunk */
    126			m = n % bits;
    127			n /= bits;
    128			while (n >= 4) {
    129				d1 = *src++;
    130				*dst++ = d0 >> right | d1 << left;
    131				d0 = d1;
    132				d1 = *src++;
    133				*dst++ = d0 >> right | d1 << left;
    134				d0 = d1;
    135				d1 = *src++;
    136				*dst++ = d0 >> right | d1 << left;
    137				d0 = d1;
    138				d1 = *src++;
    139				*dst++ = d0 >> right | d1 << left;
    140				d0 = d1;
    141				n -= 4;
    142			}
    143			while (n--) {
    144				d1 = *src++;
    145				*dst++ = d0 >> right | d1 << left;
    146				d0 = d1;
    147			}
    148
    149			/* Trailing bits */
    150			if (m) {
    151				if (m <= bits - right) {
    152					/* Single source word */
    153					d0 >>= right;
    154				} else {
    155					/* 2 source words */
    156 					d1 = *src;
    157					d0 = d0 >> right | d1 << left;
    158				}
    159				*dst = comp(d0, *dst, last);
    160			}
    161		}
    162	}
    163}
    164
    165    /*
    166     *  Generic bitwise copy algorithm, operating backward
    167     */
    168
    169static void
    170bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
    171	   const unsigned long *src, unsigned src_idx, unsigned bits,
    172	   unsigned n)
    173{
    174	unsigned long first, last;
    175	int shift;
    176
    177	dst += (dst_idx + n - 1) / bits;
    178	src += (src_idx + n - 1) / bits;
    179	dst_idx = (dst_idx + n - 1) % bits;
    180	src_idx = (src_idx + n - 1) % bits;
    181
    182	shift = dst_idx-src_idx;
    183
    184	first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
    185	last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
    186
    187	if (!shift) {
    188		/* Same alignment for source and dest */
    189		if ((unsigned long)dst_idx+1 >= n) {
    190			/* Single word */
    191			if (first)
    192				last &= first;
    193			*dst = comp(*src, *dst, last);
    194		} else {
    195			/* Multiple destination words */
    196
    197			/* Leading bits */
    198			if (first) {
    199				*dst = comp(*src, *dst, first);
    200				dst--;
    201				src--;
    202				n -= dst_idx+1;
    203			}
    204
    205			/* Main chunk */
    206			n /= bits;
    207			while (n >= 8) {
    208				*dst-- = *src--;
    209				*dst-- = *src--;
    210				*dst-- = *src--;
    211				*dst-- = *src--;
    212				*dst-- = *src--;
    213				*dst-- = *src--;
    214				*dst-- = *src--;
    215				*dst-- = *src--;
    216				n -= 8;
    217			}
    218			while (n--)
    219				*dst-- = *src--;
    220			/* Trailing bits */
    221			if (last != -1UL)
    222				*dst = comp(*src, *dst, last);
    223		}
    224	} else {
    225		/* Different alignment for source and dest */
    226
    227		int const left = shift & (bits-1);
    228		int const right = -shift & (bits-1);
    229
    230		if ((unsigned long)dst_idx+1 >= n) {
    231			/* Single destination word */
    232			if (first)
    233				last &= first;
    234			if (shift < 0) {
    235				/* Single source word */
    236				*dst = comp(*src >> right, *dst, last);
    237			} else if (1+(unsigned long)src_idx >= n) {
    238				/* Single source word */
    239				*dst = comp(*src << left, *dst, last);
    240			} else {
    241				/* 2 source words */
    242				*dst = comp(*src << left | *(src-1) >> right,
    243					    *dst, last);
    244			}
    245		} else {
    246			/* Multiple destination words */
    247			/** We must always remember the last value read,
    248			    because in case SRC and DST overlap bitwise (e.g.
    249			    when moving just one pixel in 1bpp), we always
    250			    collect one full long for DST and that might
    251			    overlap with the current long from SRC. We store
    252			    this value in 'd0'. */
    253			unsigned long d0, d1;
    254			int m;
    255
    256			d0 = *src--;
    257			/* Leading bits */
    258			if (shift < 0) {
    259				/* Single source word */
    260				d1 = d0;
    261				d0 >>= right;
    262			} else {
    263				/* 2 source words */
    264				d1 = *src--;
    265				d0 = d0 << left | d1 >> right;
    266			}
    267			if (!first)
    268				*dst = d0;
    269			else
    270				*dst = comp(d0, *dst, first);
    271			d0 = d1;
    272			dst--;
    273			n -= dst_idx+1;
    274
    275			/* Main chunk */
    276			m = n % bits;
    277			n /= bits;
    278			while (n >= 4) {
    279				d1 = *src--;
    280				*dst-- = d0 << left | d1 >> right;
    281				d0 = d1;
    282				d1 = *src--;
    283				*dst-- = d0 << left | d1 >> right;
    284				d0 = d1;
    285				d1 = *src--;
    286				*dst-- = d0 << left | d1 >> right;
    287				d0 = d1;
    288				d1 = *src--;
    289				*dst-- = d0 << left | d1 >> right;
    290				d0 = d1;
    291				n -= 4;
    292			}
    293			while (n--) {
    294				d1 = *src--;
    295				*dst-- = d0 << left | d1 >> right;
    296				d0 = d1;
    297			}
    298
    299			/* Trailing bits */
    300			if (m) {
    301				if (m <= bits - left) {
    302					/* Single source word */
    303					d0 <<= left;
    304				} else {
    305					/* 2 source words */
    306					d1 = *src;
    307					d0 = d0 << left | d1 >> right;
    308				}
    309				*dst = comp(d0, *dst, last);
    310			}
    311		}
    312	}
    313}
    314
    315void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
    316{
    317	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
    318	u32 height = area->height, width = area->width;
    319	unsigned long const bits_per_line = p->fix.line_length*8u;
    320	unsigned long *base = NULL;
    321	int bits = BITS_PER_LONG, bytes = bits >> 3;
    322	unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
    323
    324	if (p->state != FBINFO_STATE_RUNNING)
    325		return;
    326
    327	/* if the beginning of the target area might overlap with the end of
    328	the source area, be have to copy the area reverse. */
    329	if ((dy == sy && dx > sx) || (dy > sy)) {
    330		dy += height;
    331		sy += height;
    332		rev_copy = 1;
    333	}
    334
    335	/* split the base of the framebuffer into a long-aligned address and
    336	   the index of the first bit */
    337	base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
    338	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
    339	/* add offset of source and target area */
    340	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
    341	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
    342
    343	if (p->fbops->fb_sync)
    344		p->fbops->fb_sync(p);
    345
    346	if (rev_copy) {
    347		while (height--) {
    348			dst_idx -= bits_per_line;
    349			src_idx -= bits_per_line;
    350			bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
    351				base + (src_idx / bits), src_idx % bits, bits,
    352				width*p->var.bits_per_pixel);
    353		}
    354	} else {
    355		while (height--) {
    356			bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
    357				base + (src_idx / bits), src_idx % bits, bits,
    358				width*p->var.bits_per_pixel);
    359			dst_idx += bits_per_line;
    360			src_idx += bits_per_line;
    361		}
    362	}
    363}
    364
    365EXPORT_SYMBOL(sys_copyarea);
    366
    367MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
    368MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
    369MODULE_LICENSE("GPL");
    370