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

access.c (6629B)


      1/*
      2 * Common INTC2 register accessors
      3 *
      4 * Copyright (C) 2007, 2008 Magnus Damm
      5 * Copyright (C) 2009, 2010 Paul Mundt
      6 *
      7 * This file is subject to the terms and conditions of the GNU General Public
      8 * License.  See the file "COPYING" in the main directory of this archive
      9 * for more details.
     10 */
     11#include <linux/io.h>
     12#include "internals.h"
     13
     14unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
     15{
     16	struct intc_window *window;
     17	int k;
     18
     19	/* scan through physical windows and convert address */
     20	for (k = 0; k < d->nr_windows; k++) {
     21		window = d->window + k;
     22
     23		if (address < window->phys)
     24			continue;
     25
     26		if (address >= (window->phys + window->size))
     27			continue;
     28
     29		address -= window->phys;
     30		address += (unsigned long)window->virt;
     31
     32		return address;
     33	}
     34
     35	/* no windows defined, register must be 1:1 mapped virt:phys */
     36	return address;
     37}
     38
     39unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
     40{
     41	unsigned int k;
     42
     43	address = intc_phys_to_virt(d, address);
     44
     45	for (k = 0; k < d->nr_reg; k++) {
     46		if (d->reg[k] == address)
     47			return k;
     48	}
     49
     50	BUG();
     51	return 0;
     52}
     53
     54unsigned int intc_set_field_from_handle(unsigned int value,
     55					unsigned int field_value,
     56					unsigned int handle)
     57{
     58	unsigned int width = _INTC_WIDTH(handle);
     59	unsigned int shift = _INTC_SHIFT(handle);
     60
     61	value &= ~(((1 << width) - 1) << shift);
     62	value |= field_value << shift;
     63	return value;
     64}
     65
     66unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
     67{
     68	unsigned int width = _INTC_WIDTH(handle);
     69	unsigned int shift = _INTC_SHIFT(handle);
     70	unsigned int mask = ((1 << width) - 1) << shift;
     71
     72	return (value & mask) >> shift;
     73}
     74
     75static unsigned long test_8(unsigned long addr, unsigned long h,
     76			    unsigned long ignore)
     77{
     78	void __iomem *ptr = (void __iomem *)addr;
     79	return intc_get_field_from_handle(__raw_readb(ptr), h);
     80}
     81
     82static unsigned long test_16(unsigned long addr, unsigned long h,
     83			     unsigned long ignore)
     84{
     85	void __iomem *ptr = (void __iomem *)addr;
     86	return intc_get_field_from_handle(__raw_readw(ptr), h);
     87}
     88
     89static unsigned long test_32(unsigned long addr, unsigned long h,
     90			     unsigned long ignore)
     91{
     92	void __iomem *ptr = (void __iomem *)addr;
     93	return intc_get_field_from_handle(__raw_readl(ptr), h);
     94}
     95
     96static unsigned long write_8(unsigned long addr, unsigned long h,
     97			     unsigned long data)
     98{
     99	void __iomem *ptr = (void __iomem *)addr;
    100	__raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
    101	(void)__raw_readb(ptr);	/* Defeat write posting */
    102	return 0;
    103}
    104
    105static unsigned long write_16(unsigned long addr, unsigned long h,
    106			      unsigned long data)
    107{
    108	void __iomem *ptr = (void __iomem *)addr;
    109	__raw_writew(intc_set_field_from_handle(0, data, h), ptr);
    110	(void)__raw_readw(ptr);	/* Defeat write posting */
    111	return 0;
    112}
    113
    114static unsigned long write_32(unsigned long addr, unsigned long h,
    115			      unsigned long data)
    116{
    117	void __iomem *ptr = (void __iomem *)addr;
    118	__raw_writel(intc_set_field_from_handle(0, data, h), ptr);
    119	(void)__raw_readl(ptr);	/* Defeat write posting */
    120	return 0;
    121}
    122
    123static unsigned long modify_8(unsigned long addr, unsigned long h,
    124			      unsigned long data)
    125{
    126	void __iomem *ptr = (void __iomem *)addr;
    127	unsigned long flags;
    128	unsigned int value;
    129	local_irq_save(flags);
    130	value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
    131	__raw_writeb(value, ptr);
    132	(void)__raw_readb(ptr);	/* Defeat write posting */
    133	local_irq_restore(flags);
    134	return 0;
    135}
    136
    137static unsigned long modify_16(unsigned long addr, unsigned long h,
    138			       unsigned long data)
    139{
    140	void __iomem *ptr = (void __iomem *)addr;
    141	unsigned long flags;
    142	unsigned int value;
    143	local_irq_save(flags);
    144	value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
    145	__raw_writew(value, ptr);
    146	(void)__raw_readw(ptr);	/* Defeat write posting */
    147	local_irq_restore(flags);
    148	return 0;
    149}
    150
    151static unsigned long modify_32(unsigned long addr, unsigned long h,
    152			       unsigned long data)
    153{
    154	void __iomem *ptr = (void __iomem *)addr;
    155	unsigned long flags;
    156	unsigned int value;
    157	local_irq_save(flags);
    158	value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
    159	__raw_writel(value, ptr);
    160	(void)__raw_readl(ptr);	/* Defeat write posting */
    161	local_irq_restore(flags);
    162	return 0;
    163}
    164
    165static unsigned long intc_mode_field(unsigned long addr,
    166				     unsigned long handle,
    167				     unsigned long (*fn)(unsigned long,
    168						unsigned long,
    169						unsigned long),
    170				     unsigned int irq)
    171{
    172	return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
    173}
    174
    175static unsigned long intc_mode_zero(unsigned long addr,
    176				    unsigned long handle,
    177				    unsigned long (*fn)(unsigned long,
    178					       unsigned long,
    179					       unsigned long),
    180				    unsigned int irq)
    181{
    182	return fn(addr, handle, 0);
    183}
    184
    185static unsigned long intc_mode_prio(unsigned long addr,
    186				    unsigned long handle,
    187				    unsigned long (*fn)(unsigned long,
    188					       unsigned long,
    189					       unsigned long),
    190				    unsigned int irq)
    191{
    192	return fn(addr, handle, intc_get_prio_level(irq));
    193}
    194
    195unsigned long (*intc_reg_fns[])(unsigned long addr,
    196				unsigned long h,
    197				unsigned long data) = {
    198	[REG_FN_TEST_BASE + 0] = test_8,
    199	[REG_FN_TEST_BASE + 1] = test_16,
    200	[REG_FN_TEST_BASE + 3] = test_32,
    201	[REG_FN_WRITE_BASE + 0] = write_8,
    202	[REG_FN_WRITE_BASE + 1] = write_16,
    203	[REG_FN_WRITE_BASE + 3] = write_32,
    204	[REG_FN_MODIFY_BASE + 0] = modify_8,
    205	[REG_FN_MODIFY_BASE + 1] = modify_16,
    206	[REG_FN_MODIFY_BASE + 3] = modify_32,
    207};
    208
    209unsigned long (*intc_enable_fns[])(unsigned long addr,
    210				   unsigned long handle,
    211				   unsigned long (*fn)(unsigned long,
    212					    unsigned long,
    213					    unsigned long),
    214				   unsigned int irq) = {
    215	[MODE_ENABLE_REG] = intc_mode_field,
    216	[MODE_MASK_REG] = intc_mode_zero,
    217	[MODE_DUAL_REG] = intc_mode_field,
    218	[MODE_PRIO_REG] = intc_mode_prio,
    219	[MODE_PCLR_REG] = intc_mode_prio,
    220};
    221
    222unsigned long (*intc_disable_fns[])(unsigned long addr,
    223				    unsigned long handle,
    224				    unsigned long (*fn)(unsigned long,
    225					     unsigned long,
    226					     unsigned long),
    227				    unsigned int irq) = {
    228	[MODE_ENABLE_REG] = intc_mode_zero,
    229	[MODE_MASK_REG] = intc_mode_field,
    230	[MODE_DUAL_REG] = intc_mode_field,
    231	[MODE_PRIO_REG] = intc_mode_zero,
    232	[MODE_PCLR_REG] = intc_mode_field,
    233};
    234
    235unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
    236					  unsigned long handle,
    237					  unsigned long (*fn)(unsigned long,
    238						unsigned long,
    239						unsigned long),
    240					  unsigned int irq) = {
    241	[MODE_ENABLE_REG] = intc_mode_field,
    242	[MODE_MASK_REG] = intc_mode_zero,
    243	[MODE_DUAL_REG] = intc_mode_field,
    244	[MODE_PRIO_REG] = intc_mode_field,
    245	[MODE_PCLR_REG] = intc_mode_field,
    246};