File: /usr/src/linux/arch/mips64/lib/dump_tlb.c

1     /*
2      * Dump R4x00 TLB for debugging purposes.
3      *
4      * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
5      * Copyright (C) 1999 by Silicon Graphics, Inc.
6      */
7     #include <linux/kernel.h>
8     #include <linux/mm.h>
9     #include <linux/sched.h>
10     #include <linux/string.h>
11     
12     #include <asm/bootinfo.h>
13     #include <asm/cachectl.h>
14     #include <asm/mipsregs.h>
15     #include <asm/page.h>
16     #include <asm/pgtable.h>
17     
18     #define mips_tlb_entries 64
19     
20     void
21     dump_tlb(int first, int last)
22     {
23     	unsigned long s_entryhi, entryhi, entrylo0, entrylo1, asid;
24     	unsigned int s_index, pagemask, c0, c1, i;
25     
26     	s_entryhi = get_entryhi();
27     	s_index = get_index();
28     	asid = s_entryhi & 0xff;
29     
30     	for (i = first; i <= last; i++) {
31     		write_32bit_cp0_register(CP0_INDEX, i);
32     		__asm__ __volatile__(
33     			".set\tnoreorder\n\t"
34     			"nop;nop;nop;nop\n\t"
35     			"tlbr\n\t"
36     			"nop;nop;nop;nop\n\t"
37     			".set\treorder");
38     		pagemask = read_32bit_cp0_register(CP0_PAGEMASK);
39     		entryhi  = get_entryhi();
40     		entrylo0 = get_entrylo0();
41     		entrylo1 = get_entrylo1();
42     
43     		/* Unused entries have a virtual address of CKSEG0.  */
44     		if ((entryhi & ~0x1ffffUL) != CKSEG0
45     		    && (entryhi & 0xff) == asid) {
46     			/*
47     			 * Only print entries in use
48     			 */
49     			printk("Index: %2d pgmask=%08x ", i, pagemask);
50     
51     			c0 = (entrylo0 >> 3) & 7;
52     			c1 = (entrylo1 >> 3) & 7;
53     
54     			printk("va=%08lx asid=%02lx"
55     			       "  [pa=%06lx c=%d d=%d v=%d g=%ld]"
56     			       "  [pa=%06lx c=%d d=%d v=%d g=%ld]\n",
57     			       (entryhi & ~0x1fffUL),
58     			       entryhi & 0xff,
59     			       entrylo0 & PAGE_MASK, c0,
60     			       (entrylo0 & 4) ? 1 : 0,
61     			       (entrylo0 & 2) ? 1 : 0,
62     			       (entrylo0 & 1),
63     			       entrylo1 & PAGE_MASK, c1,
64     			       (entrylo1 & 4) ? 1 : 0,
65     			       (entrylo1 & 2) ? 1 : 0,
66     			       (entrylo1 & 1));
67     			       
68     		}
69     	}
70     	printk("\n");
71     
72     	set_entryhi(s_entryhi);
73     	set_index(s_index);
74     }
75     
76     void
77     dump_tlb_all(void)
78     {
79     	dump_tlb(0, mips_tlb_entries - 1);
80     }
81     
82     void
83     dump_tlb_wired(void)
84     {
85     	int	wired;
86     
87     	wired = read_32bit_cp0_register(CP0_WIRED);
88     	printk("Wired: %d", wired);
89     	dump_tlb(0, read_32bit_cp0_register(CP0_WIRED));
90     }
91     
92     #define BARRIER						\
93     	__asm__ __volatile__(				\
94     		".set\tnoreorder\n\t"			\
95     		"nop;nop;nop;nop;nop;nop;nop\n\t"	\
96     		".set\treorder");
97     
98     void
99     dump_tlb_addr(unsigned long addr)
100     {
101     	unsigned int flags, oldpid;
102     	int index;
103     
104     	__save_and_cli(flags);
105     	oldpid = get_entryhi() & 0xff;
106     	BARRIER;
107     	set_entryhi((addr & PAGE_MASK) | oldpid);
108     	BARRIER;
109     	tlb_probe();
110     	BARRIER;
111     	index = get_index();
112     	set_entryhi(oldpid);
113     	__restore_flags(flags);
114     
115     	if (index < 0) {
116     		printk("No entry for address 0x%08lx in TLB\n", addr);
117     		return;
118     	}
119     
120     	printk("Entry %d maps address 0x%08lx\n", index, addr);
121     	dump_tlb(index, index);
122     }
123     
124     void
125     dump_tlb_nonwired(void)
126     {
127     	dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_tlb_entries - 1);
128     }
129     
130     void
131     dump_list_process(struct task_struct *t, void *address)
132     {
133     	pgd_t	*page_dir, *pgd;
134     	pmd_t	*pmd;
135     	pte_t	*pte, page;
136     	unsigned long addr;
137     	unsigned long val;
138     
139     	addr = (unsigned long) address;
140     
141     	printk("Addr                 == %08lx\n", addr);
142     	printk("tasks->mm.pgd        == %08lx\n", (unsigned long) t->mm->pgd);
143     
144     	page_dir = pgd_offset(t->mm, 0);
145     	printk("page_dir == %08lx\n", (unsigned long) page_dir);
146     
147     	pgd = pgd_offset(t->mm, addr);
148     	printk("pgd == %08lx, ", (unsigned long) pgd);
149     
150     	pmd = pmd_offset(pgd, addr);
151     	printk("pmd == %08lx, ", (unsigned long) pmd);
152     
153     	pte = pte_offset(pmd, addr);
154     	printk("pte == %08lx, ", (unsigned long) pte);
155     
156     	page = *pte;
157     	printk("page == %08lx\n", (unsigned long) pte_val(page));
158     
159     	val = pte_val(page);
160     	if (val & _PAGE_PRESENT) printk("present ");
161     	if (val & _PAGE_READ) printk("read ");
162     	if (val & _PAGE_WRITE) printk("write ");
163     	if (val & _PAGE_ACCESSED) printk("accessed ");
164     	if (val & _PAGE_MODIFIED) printk("modified ");
165     	if (val & _PAGE_R4KBUG) printk("r4kbug ");
166     	if (val & _PAGE_GLOBAL) printk("global ");
167     	if (val & _PAGE_VALID) printk("valid ");
168     	printk("\n");
169     }
170     
171     void dump_list_current(void *address)
172     {
173     	dump_list_process(current, address);
174     }
175     
176     unsigned int vtop(void *address)
177     {
178     	pgd_t	*pgd;
179     	pmd_t	*pmd;
180     	pte_t	*pte;
181     	unsigned int addr, paddr;
182     
183     	addr = (unsigned long) address;
184     	pgd = pgd_offset(current->mm, addr);
185     	pmd = pmd_offset(pgd, addr);
186     	pte = pte_offset(pmd, addr);
187     	paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
188     	paddr |= (addr & ~PAGE_MASK);
189     
190     	return paddr;
191     }
192     
193     void dump16(unsigned long *p)
194     {
195     	int i;
196     
197     	for(i=0;i<8;i++)
198     	{
199     		printk("*%08lx == %08lx, ",
200     		       (unsigned long)p, (unsigned long)*p);
201     		p++;
202     		printk("*%08lx == %08lx\n",
203     		       (unsigned long)p, (unsigned long)*p);
204     		p++;
205     	}
206     }
207