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

c-r3k.c (7615B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * r2300.c: R2000 and R3000 specific mmu/cache code.
      4 *
      5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
      6 *
      7 * with a lot of changes to make this thing work for R3000s
      8 * Tx39XX R4k style caches added. HK
      9 * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
     10 * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
     11 * Copyright (C) 2001, 2004, 2007  Maciej W. Rozycki
     12 */
     13#include <linux/kernel.h>
     14#include <linux/sched.h>
     15#include <linux/smp.h>
     16#include <linux/mm.h>
     17
     18#include <asm/page.h>
     19#include <asm/mmu_context.h>
     20#include <asm/isadep.h>
     21#include <asm/io.h>
     22#include <asm/bootinfo.h>
     23#include <asm/cpu.h>
     24
     25static unsigned long icache_size, dcache_size;		/* Size in bytes */
     26static unsigned long icache_lsize, dcache_lsize;	/* Size in bytes */
     27
     28unsigned long r3k_cache_size(unsigned long ca_flags)
     29{
     30	unsigned long flags, status, dummy, size;
     31	volatile unsigned long *p;
     32
     33	p = (volatile unsigned long *) KSEG0;
     34
     35	flags = read_c0_status();
     36
     37	/* isolate cache space */
     38	write_c0_status((ca_flags|flags)&~ST0_IEC);
     39
     40	*p = 0xa5a55a5a;
     41	dummy = *p;
     42	status = read_c0_status();
     43
     44	if (dummy != 0xa5a55a5a || (status & ST0_CM)) {
     45		size = 0;
     46	} else {
     47		for (size = 128; size <= 0x40000; size <<= 1)
     48			*(p + size) = 0;
     49		*p = -1;
     50		for (size = 128;
     51		     (size <= 0x40000) && (*(p + size) == 0);
     52		     size <<= 1)
     53			;
     54		if (size > 0x40000)
     55			size = 0;
     56	}
     57
     58	write_c0_status(flags);
     59
     60	return size * sizeof(*p);
     61}
     62
     63unsigned long r3k_cache_lsize(unsigned long ca_flags)
     64{
     65	unsigned long flags, status, lsize, i;
     66	volatile unsigned long *p;
     67
     68	p = (volatile unsigned long *) KSEG0;
     69
     70	flags = read_c0_status();
     71
     72	/* isolate cache space */
     73	write_c0_status((ca_flags|flags)&~ST0_IEC);
     74
     75	for (i = 0; i < 128; i++)
     76		*(p + i) = 0;
     77	*(volatile unsigned char *)p = 0;
     78	for (lsize = 1; lsize < 128; lsize <<= 1) {
     79		*(p + lsize);
     80		status = read_c0_status();
     81		if (!(status & ST0_CM))
     82			break;
     83	}
     84	for (i = 0; i < 128; i += lsize)
     85		*(volatile unsigned char *)(p + i) = 0;
     86
     87	write_c0_status(flags);
     88
     89	return lsize * sizeof(*p);
     90}
     91
     92static void r3k_probe_cache(void)
     93{
     94	dcache_size = r3k_cache_size(ST0_ISC);
     95	if (dcache_size)
     96		dcache_lsize = r3k_cache_lsize(ST0_ISC);
     97
     98	icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
     99	if (icache_size)
    100		icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC);
    101}
    102
    103static void r3k_flush_icache_range(unsigned long start, unsigned long end)
    104{
    105	unsigned long size, i, flags;
    106	volatile unsigned char *p;
    107
    108	size = end - start;
    109	if (size > icache_size || KSEGX(start) != KSEG0) {
    110		start = KSEG0;
    111		size = icache_size;
    112	}
    113	p = (char *)start;
    114
    115	flags = read_c0_status();
    116
    117	/* isolate cache space */
    118	write_c0_status((ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
    119
    120	for (i = 0; i < size; i += 0x080) {
    121		asm(	"sb\t$0, 0x000(%0)\n\t"
    122			"sb\t$0, 0x004(%0)\n\t"
    123			"sb\t$0, 0x008(%0)\n\t"
    124			"sb\t$0, 0x00c(%0)\n\t"
    125			"sb\t$0, 0x010(%0)\n\t"
    126			"sb\t$0, 0x014(%0)\n\t"
    127			"sb\t$0, 0x018(%0)\n\t"
    128			"sb\t$0, 0x01c(%0)\n\t"
    129			"sb\t$0, 0x020(%0)\n\t"
    130			"sb\t$0, 0x024(%0)\n\t"
    131			"sb\t$0, 0x028(%0)\n\t"
    132			"sb\t$0, 0x02c(%0)\n\t"
    133			"sb\t$0, 0x030(%0)\n\t"
    134			"sb\t$0, 0x034(%0)\n\t"
    135			"sb\t$0, 0x038(%0)\n\t"
    136			"sb\t$0, 0x03c(%0)\n\t"
    137			"sb\t$0, 0x040(%0)\n\t"
    138			"sb\t$0, 0x044(%0)\n\t"
    139			"sb\t$0, 0x048(%0)\n\t"
    140			"sb\t$0, 0x04c(%0)\n\t"
    141			"sb\t$0, 0x050(%0)\n\t"
    142			"sb\t$0, 0x054(%0)\n\t"
    143			"sb\t$0, 0x058(%0)\n\t"
    144			"sb\t$0, 0x05c(%0)\n\t"
    145			"sb\t$0, 0x060(%0)\n\t"
    146			"sb\t$0, 0x064(%0)\n\t"
    147			"sb\t$0, 0x068(%0)\n\t"
    148			"sb\t$0, 0x06c(%0)\n\t"
    149			"sb\t$0, 0x070(%0)\n\t"
    150			"sb\t$0, 0x074(%0)\n\t"
    151			"sb\t$0, 0x078(%0)\n\t"
    152			"sb\t$0, 0x07c(%0)\n\t"
    153			: : "r" (p) );
    154		p += 0x080;
    155	}
    156
    157	write_c0_status(flags);
    158}
    159
    160static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
    161{
    162	unsigned long size, i, flags;
    163	volatile unsigned char *p;
    164
    165	size = end - start;
    166	if (size > dcache_size || KSEGX(start) != KSEG0) {
    167		start = KSEG0;
    168		size = dcache_size;
    169	}
    170	p = (char *)start;
    171
    172	flags = read_c0_status();
    173
    174	/* isolate cache space */
    175	write_c0_status((ST0_ISC|flags)&~ST0_IEC);
    176
    177	for (i = 0; i < size; i += 0x080) {
    178		asm(	"sb\t$0, 0x000(%0)\n\t"
    179			"sb\t$0, 0x004(%0)\n\t"
    180			"sb\t$0, 0x008(%0)\n\t"
    181			"sb\t$0, 0x00c(%0)\n\t"
    182			"sb\t$0, 0x010(%0)\n\t"
    183			"sb\t$0, 0x014(%0)\n\t"
    184			"sb\t$0, 0x018(%0)\n\t"
    185			"sb\t$0, 0x01c(%0)\n\t"
    186			"sb\t$0, 0x020(%0)\n\t"
    187			"sb\t$0, 0x024(%0)\n\t"
    188			"sb\t$0, 0x028(%0)\n\t"
    189			"sb\t$0, 0x02c(%0)\n\t"
    190			"sb\t$0, 0x030(%0)\n\t"
    191			"sb\t$0, 0x034(%0)\n\t"
    192			"sb\t$0, 0x038(%0)\n\t"
    193			"sb\t$0, 0x03c(%0)\n\t"
    194			"sb\t$0, 0x040(%0)\n\t"
    195			"sb\t$0, 0x044(%0)\n\t"
    196			"sb\t$0, 0x048(%0)\n\t"
    197			"sb\t$0, 0x04c(%0)\n\t"
    198			"sb\t$0, 0x050(%0)\n\t"
    199			"sb\t$0, 0x054(%0)\n\t"
    200			"sb\t$0, 0x058(%0)\n\t"
    201			"sb\t$0, 0x05c(%0)\n\t"
    202			"sb\t$0, 0x060(%0)\n\t"
    203			"sb\t$0, 0x064(%0)\n\t"
    204			"sb\t$0, 0x068(%0)\n\t"
    205			"sb\t$0, 0x06c(%0)\n\t"
    206			"sb\t$0, 0x070(%0)\n\t"
    207			"sb\t$0, 0x074(%0)\n\t"
    208			"sb\t$0, 0x078(%0)\n\t"
    209			"sb\t$0, 0x07c(%0)\n\t"
    210			: : "r" (p) );
    211		p += 0x080;
    212	}
    213
    214	write_c0_status(flags);
    215}
    216
    217static inline void r3k_flush_cache_all(void)
    218{
    219}
    220
    221static inline void r3k___flush_cache_all(void)
    222{
    223	r3k_flush_dcache_range(KSEG0, KSEG0 + dcache_size);
    224	r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
    225}
    226
    227static void r3k_flush_cache_mm(struct mm_struct *mm)
    228{
    229}
    230
    231static void r3k_flush_cache_range(struct vm_area_struct *vma,
    232				  unsigned long start, unsigned long end)
    233{
    234}
    235
    236static void r3k_flush_cache_page(struct vm_area_struct *vma,
    237				 unsigned long addr, unsigned long pfn)
    238{
    239	unsigned long kaddr = KSEG0ADDR(pfn << PAGE_SHIFT);
    240	int exec = vma->vm_flags & VM_EXEC;
    241	struct mm_struct *mm = vma->vm_mm;
    242	pmd_t *pmdp;
    243	pte_t *ptep;
    244
    245	pr_debug("cpage[%08llx,%08lx]\n",
    246		 cpu_context(smp_processor_id(), mm), addr);
    247
    248	/* No ASID => no such page in the cache.  */
    249	if (cpu_context(smp_processor_id(), mm) == 0)
    250		return;
    251
    252	pmdp = pmd_off(mm, addr);
    253	ptep = pte_offset_kernel(pmdp, addr);
    254
    255	/* Invalid => no such page in the cache.  */
    256	if (!(pte_val(*ptep) & _PAGE_PRESENT))
    257		return;
    258
    259	r3k_flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
    260	if (exec)
    261		r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE);
    262}
    263
    264static void local_r3k_flush_data_cache_page(void *addr)
    265{
    266}
    267
    268static void r3k_flush_data_cache_page(unsigned long addr)
    269{
    270}
    271
    272static void r3k_flush_kernel_vmap_range(unsigned long vaddr, int size)
    273{
    274	BUG();
    275}
    276
    277static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
    278{
    279	/* Catch bad driver code */
    280	BUG_ON(size == 0);
    281
    282	iob();
    283	r3k_flush_dcache_range(start, start + size);
    284}
    285
    286void r3k_cache_init(void)
    287{
    288	extern void build_clear_page(void);
    289	extern void build_copy_page(void);
    290
    291	r3k_probe_cache();
    292
    293	flush_cache_all = r3k_flush_cache_all;
    294	__flush_cache_all = r3k___flush_cache_all;
    295	flush_cache_mm = r3k_flush_cache_mm;
    296	flush_cache_range = r3k_flush_cache_range;
    297	flush_cache_page = r3k_flush_cache_page;
    298	flush_icache_range = r3k_flush_icache_range;
    299	local_flush_icache_range = r3k_flush_icache_range;
    300	__flush_icache_user_range = r3k_flush_icache_range;
    301	__local_flush_icache_user_range = r3k_flush_icache_range;
    302
    303	__flush_kernel_vmap_range = r3k_flush_kernel_vmap_range;
    304
    305	local_flush_data_cache_page = local_r3k_flush_data_cache_page;
    306	flush_data_cache_page = r3k_flush_data_cache_page;
    307
    308	_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
    309	_dma_cache_wback = r3k_dma_cache_wback_inv;
    310	_dma_cache_inv = r3k_dma_cache_wback_inv;
    311
    312	pr_info("Primary instruction cache %ldkB, linesize %ld bytes.\n",
    313		icache_size >> 10, icache_lsize);
    314	pr_info("Primary data cache %ldkB, linesize %ld bytes.\n",
    315		dcache_size >> 10, dcache_lsize);
    316
    317	build_clear_page();
    318	build_copy_page();
    319}