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

spram.c (4545B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * MIPS SPRAM support
      4 *
      5 * Copyright (C) 2007, 2008 MIPS Technologies, Inc.
      6 */
      7#include <linux/kernel.h>
      8#include <linux/ptrace.h>
      9#include <linux/stddef.h>
     10
     11#include <asm/fpu.h>
     12#include <asm/mipsregs.h>
     13#include <asm/r4kcache.h>
     14#include <asm/hazards.h>
     15
     16/*
     17 * These definitions are correct for the 24K/34K/74K SPRAM sample
     18 * implementation. The 4KS interpreted the tags differently...
     19 */
     20#define SPRAM_TAG0_ENABLE	0x00000080
     21#define SPRAM_TAG0_PA_MASK	0xfffff000
     22#define SPRAM_TAG1_SIZE_MASK	0xfffff000
     23
     24#define SPRAM_TAG_STRIDE	8
     25
     26#define ERRCTL_SPRAM		(1 << 28)
     27
     28/* errctl access */
     29#define read_c0_errctl(x) read_c0_ecc(x)
     30#define write_c0_errctl(x) write_c0_ecc(x)
     31
     32/*
     33 * Different semantics to the set_c0_* function built by __BUILD_SET_C0
     34 */
     35static unsigned int bis_c0_errctl(unsigned int set)
     36{
     37	unsigned int res;
     38	res = read_c0_errctl();
     39	write_c0_errctl(res | set);
     40	return res;
     41}
     42
     43static void ispram_store_tag(unsigned int offset, unsigned int data)
     44{
     45	unsigned int errctl;
     46
     47	/* enable SPRAM tag access */
     48	errctl = bis_c0_errctl(ERRCTL_SPRAM);
     49	ehb();
     50
     51	write_c0_taglo(data);
     52	ehb();
     53
     54	cache_op(Index_Store_Tag_I, CKSEG0|offset);
     55	ehb();
     56
     57	write_c0_errctl(errctl);
     58	ehb();
     59}
     60
     61
     62static unsigned int ispram_load_tag(unsigned int offset)
     63{
     64	unsigned int data;
     65	unsigned int errctl;
     66
     67	/* enable SPRAM tag access */
     68	errctl = bis_c0_errctl(ERRCTL_SPRAM);
     69	ehb();
     70	cache_op(Index_Load_Tag_I, CKSEG0 | offset);
     71	ehb();
     72	data = read_c0_taglo();
     73	ehb();
     74	write_c0_errctl(errctl);
     75	ehb();
     76
     77	return data;
     78}
     79
     80static void dspram_store_tag(unsigned int offset, unsigned int data)
     81{
     82	unsigned int errctl;
     83
     84	/* enable SPRAM tag access */
     85	errctl = bis_c0_errctl(ERRCTL_SPRAM);
     86	ehb();
     87	write_c0_dtaglo(data);
     88	ehb();
     89	cache_op(Index_Store_Tag_D, CKSEG0 | offset);
     90	ehb();
     91	write_c0_errctl(errctl);
     92	ehb();
     93}
     94
     95
     96static unsigned int dspram_load_tag(unsigned int offset)
     97{
     98	unsigned int data;
     99	unsigned int errctl;
    100
    101	errctl = bis_c0_errctl(ERRCTL_SPRAM);
    102	ehb();
    103	cache_op(Index_Load_Tag_D, CKSEG0 | offset);
    104	ehb();
    105	data = read_c0_dtaglo();
    106	ehb();
    107	write_c0_errctl(errctl);
    108	ehb();
    109
    110	return data;
    111}
    112
    113static void probe_spram(char *type,
    114	    unsigned int base,
    115	    unsigned int (*read)(unsigned int),
    116	    void (*write)(unsigned int, unsigned int))
    117{
    118	unsigned int firstsize = 0, lastsize = 0;
    119	unsigned int firstpa = 0, lastpa = 0, pa = 0;
    120	unsigned int offset = 0;
    121	unsigned int size, tag0, tag1;
    122	unsigned int enabled;
    123	int i;
    124
    125	/*
    126	 * The limit is arbitrary but avoids the loop running away if
    127	 * the SPRAM tags are implemented differently
    128	 */
    129
    130	for (i = 0; i < 8; i++) {
    131		tag0 = read(offset);
    132		tag1 = read(offset+SPRAM_TAG_STRIDE);
    133		pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n",
    134			 type, i, tag0, tag1);
    135
    136		size = tag1 & SPRAM_TAG1_SIZE_MASK;
    137
    138		if (size == 0)
    139			break;
    140
    141		if (i != 0) {
    142			/* tags may repeat... */
    143			if ((pa == firstpa && size == firstsize) ||
    144			    (pa == lastpa && size == lastsize))
    145				break;
    146		}
    147
    148		/* Align base with size */
    149		base = (base + size - 1) & ~(size-1);
    150
    151		/* reprogram the base address base address and enable */
    152		tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE;
    153		write(offset, tag0);
    154
    155		base += size;
    156
    157		/* reread the tag */
    158		tag0 = read(offset);
    159		pa = tag0 & SPRAM_TAG0_PA_MASK;
    160		enabled = tag0 & SPRAM_TAG0_ENABLE;
    161
    162		if (i == 0) {
    163			firstpa = pa;
    164			firstsize = size;
    165		}
    166
    167		lastpa = pa;
    168		lastsize = size;
    169
    170		if (strcmp(type, "DSPRAM") == 0) {
    171			unsigned int *vp = (unsigned int *)(CKSEG1 | pa);
    172			unsigned int v;
    173#define TDAT	0x5a5aa5a5
    174			vp[0] = TDAT;
    175			vp[1] = ~TDAT;
    176
    177			mb();
    178
    179			v = vp[0];
    180			if (v != TDAT)
    181				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
    182				       vp, TDAT, v);
    183			v = vp[1];
    184			if (v != ~TDAT)
    185				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
    186				       vp+1, ~TDAT, v);
    187		}
    188
    189		pr_info("%s%d: PA=%08x,Size=%08x%s\n",
    190			type, i, pa, size, enabled ? ",enabled" : "");
    191		offset += 2 * SPRAM_TAG_STRIDE;
    192	}
    193}
    194void spram_config(void)
    195{
    196	unsigned int config0;
    197
    198	switch (current_cpu_type()) {
    199	case CPU_24K:
    200	case CPU_34K:
    201	case CPU_74K:
    202	case CPU_1004K:
    203	case CPU_1074K:
    204	case CPU_INTERAPTIV:
    205	case CPU_PROAPTIV:
    206	case CPU_P5600:
    207	case CPU_QEMU_GENERIC:
    208	case CPU_I6400:
    209	case CPU_P6600:
    210		config0 = read_c0_config();
    211		/* FIXME: addresses are Malta specific */
    212		if (config0 & MIPS_CONF_ISP) {
    213			probe_spram("ISPRAM", 0x1c000000,
    214				    &ispram_load_tag, &ispram_store_tag);
    215		}
    216		if (config0 & MIPS_CONF_DSP)
    217			probe_spram("DSPRAM", 0x1c100000,
    218				    &dspram_load_tag, &dspram_store_tag);
    219	}
    220}