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

dump_tlb.c (5524B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Dump R4x00 TLB for debugging purposes.
      4 *
      5 * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
      6 * Copyright (C) 1999 by Silicon Graphics, Inc.
      7 */
      8#include <linux/kernel.h>
      9#include <linux/mm.h>
     10
     11#include <asm/hazards.h>
     12#include <asm/mipsregs.h>
     13#include <asm/mmu_context.h>
     14#include <asm/page.h>
     15#include <asm/tlbdebug.h>
     16
     17void dump_tlb_regs(void)
     18{
     19	const int field = 2 * sizeof(unsigned long);
     20
     21	pr_info("Index    : %0x\n", read_c0_index());
     22	pr_info("PageMask : %0x\n", read_c0_pagemask());
     23	if (cpu_has_guestid)
     24		pr_info("GuestCtl1: %0x\n", read_c0_guestctl1());
     25	pr_info("EntryHi  : %0*lx\n", field, read_c0_entryhi());
     26	pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0());
     27	pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1());
     28	pr_info("Wired    : %0x\n", read_c0_wired());
     29	switch (current_cpu_type()) {
     30	case CPU_R10000:
     31	case CPU_R12000:
     32	case CPU_R14000:
     33	case CPU_R16000:
     34		pr_info("FrameMask: %0x\n", read_c0_framemask());
     35		break;
     36	}
     37	if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
     38		pr_info("PageGrain: %0x\n", read_c0_pagegrain());
     39	if (cpu_has_htw) {
     40		pr_info("PWField  : %0*lx\n", field, read_c0_pwfield());
     41		pr_info("PWSize   : %0*lx\n", field, read_c0_pwsize());
     42		pr_info("PWCtl    : %0x\n", read_c0_pwctl());
     43	}
     44}
     45
     46static inline const char *msk2str(unsigned int mask)
     47{
     48	switch (mask) {
     49	case PM_4K:	return "4kb";
     50	case PM_16K:	return "16kb";
     51	case PM_64K:	return "64kb";
     52	case PM_256K:	return "256kb";
     53#ifdef CONFIG_CPU_CAVIUM_OCTEON
     54	case PM_8K:	return "8kb";
     55	case PM_32K:	return "32kb";
     56	case PM_128K:	return "128kb";
     57	case PM_512K:	return "512kb";
     58	case PM_2M:	return "2Mb";
     59	case PM_8M:	return "8Mb";
     60	case PM_32M:	return "32Mb";
     61#endif
     62#ifndef CONFIG_CPU_VR41XX
     63	case PM_1M:	return "1Mb";
     64	case PM_4M:	return "4Mb";
     65	case PM_16M:	return "16Mb";
     66	case PM_64M:	return "64Mb";
     67	case PM_256M:	return "256Mb";
     68	case PM_1G:	return "1Gb";
     69#endif
     70	}
     71	return "";
     72}
     73
     74static void dump_tlb(int first, int last)
     75{
     76	unsigned long s_entryhi, entryhi, asid, mmid;
     77	unsigned long long entrylo0, entrylo1, pa;
     78	unsigned int s_index, s_pagemask, s_guestctl1 = 0;
     79	unsigned int pagemask, guestctl1 = 0, c0, c1, i;
     80	unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
     81	int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
     82	unsigned long s_mmid;
     83#ifdef CONFIG_32BIT
     84	bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
     85	int pwidth = xpa ? 11 : 8;
     86	int vwidth = 8;
     87#else
     88	bool xpa = false;
     89	int pwidth = 11;
     90	int vwidth = 11;
     91#endif
     92
     93	s_pagemask = read_c0_pagemask();
     94	s_entryhi = read_c0_entryhi();
     95	s_index = read_c0_index();
     96
     97	if (cpu_has_mmid)
     98		asid = s_mmid = read_c0_memorymapid();
     99	else
    100		asid = s_entryhi & asidmask;
    101
    102	if (cpu_has_guestid)
    103		s_guestctl1 = read_c0_guestctl1();
    104
    105	for (i = first; i <= last; i++) {
    106		write_c0_index(i);
    107		mtc0_tlbr_hazard();
    108		tlb_read();
    109		tlb_read_hazard();
    110		pagemask = read_c0_pagemask();
    111		entryhi	 = read_c0_entryhi();
    112		entrylo0 = read_c0_entrylo0();
    113		entrylo1 = read_c0_entrylo1();
    114
    115		if (cpu_has_mmid)
    116			mmid = read_c0_memorymapid();
    117		else
    118			mmid = entryhi & asidmask;
    119
    120		if (cpu_has_guestid)
    121			guestctl1 = read_c0_guestctl1();
    122
    123		/* EHINV bit marks entire entry as invalid */
    124		if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
    125			continue;
    126		/*
    127		 * Prior to tlbinv, unused entries have a virtual address of
    128		 * CKSEG0.
    129		 */
    130		if ((entryhi & ~0x1ffffUL) == CKSEG0)
    131			continue;
    132		/*
    133		 * ASID takes effect in absence of G (global) bit.
    134		 * We check both G bits, even though architecturally they should
    135		 * match one another, because some revisions of the SB1 core may
    136		 * leave only a single G bit set after a machine check exception
    137		 * due to duplicate TLB entry.
    138		 */
    139		if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (mmid != asid))
    140			continue;
    141
    142		/*
    143		 * Only print entries in use
    144		 */
    145		printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
    146
    147		c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
    148		c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
    149
    150		pr_cont("va=%0*lx asid=%0*lx",
    151			vwidth, (entryhi & ~0x1fffUL),
    152			asidwidth, mmid);
    153		if (cpu_has_guestid)
    154			pr_cont(" gid=%02lx",
    155				(guestctl1 & MIPS_GCTL1_RID)
    156					>> MIPS_GCTL1_RID_SHIFT);
    157		/* RI/XI are in awkward places, so mask them off separately */
    158		pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
    159		if (xpa)
    160			pa |= (unsigned long long)readx_c0_entrylo0() << 30;
    161		pa = (pa << 6) & PAGE_MASK;
    162		pr_cont("\n\t[");
    163		if (cpu_has_rixi)
    164			pr_cont("ri=%d xi=%d ",
    165				(entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
    166				(entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
    167		pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
    168			pwidth, pa, c0,
    169			(entrylo0 & ENTRYLO_D) ? 1 : 0,
    170			(entrylo0 & ENTRYLO_V) ? 1 : 0,
    171			(entrylo0 & ENTRYLO_G) ? 1 : 0);
    172		/* RI/XI are in awkward places, so mask them off separately */
    173		pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
    174		if (xpa)
    175			pa |= (unsigned long long)readx_c0_entrylo1() << 30;
    176		pa = (pa << 6) & PAGE_MASK;
    177		if (cpu_has_rixi)
    178			pr_cont("ri=%d xi=%d ",
    179				(entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
    180				(entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
    181		pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
    182			pwidth, pa, c1,
    183			(entrylo1 & ENTRYLO_D) ? 1 : 0,
    184			(entrylo1 & ENTRYLO_V) ? 1 : 0,
    185			(entrylo1 & ENTRYLO_G) ? 1 : 0);
    186	}
    187	printk("\n");
    188
    189	write_c0_entryhi(s_entryhi);
    190	write_c0_index(s_index);
    191	write_c0_pagemask(s_pagemask);
    192	if (cpu_has_guestid)
    193		write_c0_guestctl1(s_guestctl1);
    194}
    195
    196void dump_tlb_all(void)
    197{
    198	dump_tlb(0, current_cpu_data.tlbsize - 1);
    199}