blob: 59cb058217a0254195497d21b5267075921a5cba [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Paul Mundt811d50c2007-11-20 17:01:55 +09002 * The SH64 TLB miss.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Original code from fault.c
5 * Copyright (C) 2000, 2001 Paolo Alberelli
6 *
7 * Fast PTE->TLB refill path
8 * Copyright (C) 2003 Richard.Curnow@superh.com
9 *
10 * IMPORTANT NOTES :
Paul Mundt811d50c2007-11-20 17:01:55 +090011 * The do_fast_page_fault function is called from a context in entry.S
12 * where very few registers have been saved. In particular, the code in
13 * this file must be compiled not to use ANY caller-save registers that
14 * are not part of the restricted save set. Also, it means that code in
15 * this file must not make calls to functions elsewhere in the kernel, or
16 * else the excepting context will see corruption in its caller-save
17 * registers. Plus, the entry.S save area is non-reentrant, so this code
18 * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
19 * on any exception.
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 *
Paul Mundt811d50c2007-11-20 17:01:55 +090021 * This file is subject to the terms and conditions of the GNU General Public
22 * License. See the file "COPYING" in the main directory of this archive
23 * for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/signal.h>
26#include <linux/sched.h>
27#include <linux/kernel.h>
28#include <linux/errno.h>
29#include <linux/string.h>
30#include <linux/types.h>
31#include <linux/ptrace.h>
32#include <linux/mman.h>
33#include <linux/mm.h>
34#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/tlb.h>
37#include <asm/io.h>
38#include <asm/uaccess.h>
39#include <asm/pgalloc.h>
40#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Paul Mundt811d50c2007-11-20 17:01:55 +090042static int handle_vmalloc_fault(struct mm_struct *mm,
43 unsigned long protection_flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 unsigned long address)
45{
46 pgd_t *dir;
Paul Mundt811d50c2007-11-20 17:01:55 +090047 pud_t *pud;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 pmd_t *pmd;
Paul Mundtc06fd282012-05-14 15:52:28 +090049 pte_t *pte;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 pte_t entry;
51
52 dir = pgd_offset_k(address);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Paul Mundt811d50c2007-11-20 17:01:55 +090054 pud = pud_offset(dir, address);
55 if (pud_none_or_clear_bad(pud))
Paul Mundt4de51852012-05-14 16:44:45 +090056 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Paul Mundt811d50c2007-11-20 17:01:55 +090058 pmd = pmd_offset(pud, address);
59 if (pmd_none_or_clear_bad(pmd))
Paul Mundt4de51852012-05-14 16:44:45 +090060 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62 pte = pte_offset_kernel(pmd, address);
63 entry = *pte;
64
Paul Mundt811d50c2007-11-20 17:01:55 +090065 if (pte_none(entry) || !pte_present(entry))
Paul Mundt4de51852012-05-14 16:44:45 +090066 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +090067 if ((pte_val(entry) & protection_flags) != protection_flags)
Paul Mundt4de51852012-05-14 16:44:45 +090068 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Paul Mundtc06fd282012-05-14 15:52:28 +090070 update_mmu_cache(NULL, address, pte);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Paul Mundt4de51852012-05-14 16:44:45 +090072 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073}
74
Paul Mundt811d50c2007-11-20 17:01:55 +090075static int handle_tlbmiss(struct mm_struct *mm,
76 unsigned long long protection_flags,
Paul Mundt811d50c2007-11-20 17:01:55 +090077 unsigned long address)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 pgd_t *dir;
Paul Mundt811d50c2007-11-20 17:01:55 +090080 pud_t *pud;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 pmd_t *pmd;
82 pte_t *pte;
83 pte_t entry;
84
85 /* NB. The PGD currently only contains a single entry - there is no
86 page table tree stored for the top half of the address space since
87 virtual pages in that region should never be mapped in user mode.
88 (In kernel mode, the only things in that region are the 512Mb super
89 page (locked in), and vmalloc (modules) + I/O device pages (handled
90 by handle_vmalloc_fault), so no PGD for the upper half is required
91 by kernel mode either).
92
93 See how mm->pgd is allocated and initialised in pgd_alloc to see why
94 the next test is necessary. - RPC */
Paul Mundt811d50c2007-11-20 17:01:55 +090095 if (address >= (unsigned long) TASK_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 /* upper half - never has page table entries. */
Paul Mundt4de51852012-05-14 16:44:45 +090097 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Paul Mundt811d50c2007-11-20 17:01:55 +090099 dir = pgd_offset(mm, address);
100 if (pgd_none(*dir) || !pgd_present(*dir))
Paul Mundt4de51852012-05-14 16:44:45 +0900101 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +0900102 if (!pgd_present(*dir))
Paul Mundt4de51852012-05-14 16:44:45 +0900103 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +0900104
105 pud = pud_offset(dir, address);
106 if (pud_none(*pud) || !pud_present(*pud))
Paul Mundt4de51852012-05-14 16:44:45 +0900107 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +0900108
109 pmd = pmd_offset(pud, address);
110 if (pmd_none(*pmd) || !pmd_present(*pmd))
Paul Mundt4de51852012-05-14 16:44:45 +0900111 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +0900112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 pte = pte_offset_kernel(pmd, address);
114 entry = *pte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
Paul Mundt811d50c2007-11-20 17:01:55 +0900116 if (pte_none(entry) || !pte_present(entry))
Paul Mundt4de51852012-05-14 16:44:45 +0900117 return 1;
Paul Mundt811d50c2007-11-20 17:01:55 +0900118
119 /*
120 * If the page doesn't have sufficient protection bits set to
121 * service the kind of fault being handled, there's not much
122 * point doing the TLB refill. Punt the fault to the general
123 * handler.
124 */
125 if ((pte_val(entry) & protection_flags) != protection_flags)
Paul Mundt4de51852012-05-14 16:44:45 +0900126 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Paul Mundtc06fd282012-05-14 15:52:28 +0900128 update_mmu_cache(NULL, address, pte);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Paul Mundt4de51852012-05-14 16:44:45 +0900130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Paul Mundt811d50c2007-11-20 17:01:55 +0900133/*
134 * Put all this information into one structure so that everything is just
135 * arithmetic relative to a single base address. This reduces the number
136 * of movi/shori pairs needed just to load addresses of static data.
137 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138struct expevt_lookup {
139 unsigned short protection_flags[8];
140 unsigned char is_text_access[8];
141 unsigned char is_write_access[8];
142};
143
144#define PRU (1<<9)
145#define PRW (1<<8)
146#define PRX (1<<7)
147#define PRR (1<<6)
148
149#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
150#define YOUNG (_PAGE_ACCESSED)
151
152/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
153 the fault happened in user mode or privileged mode. */
154static struct expevt_lookup expevt_lookup_table = {
155 .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
156 .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0}
157};
158
159/*
160 This routine handles page faults that can be serviced just by refilling a
161 TLB entry from an existing page table entry. (This case represents a very
162 large majority of page faults.) Return 1 if the fault was successfully
163 handled. Return 0 if the fault could not be handled. (This leads into the
164 general fault handling in fault.c which deals with mapping file-backed
165 pages, stack growth, segmentation faults, swapping etc etc)
166 */
Paul Mundt811d50c2007-11-20 17:01:55 +0900167asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
168 unsigned long long expevt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 unsigned long address)
170{
171 struct task_struct *tsk;
172 struct mm_struct *mm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 unsigned long long protection_flags;
174 unsigned long long index;
175 unsigned long long expevt4;
176
Paul Mundt811d50c2007-11-20 17:01:55 +0900177 /* The next few lines implement a way of hashing EXPEVT into a
178 * small array index which can be used to lookup parameters
179 * specific to the type of TLBMISS being handled.
180 *
181 * Note:
182 * ITLBMISS has EXPEVT==0xa40
183 * RTLBMISS has EXPEVT==0x040
184 * WTLBMISS has EXPEVT==0x060
185 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 expevt4 = (expevt >> 4);
Paul Mundt811d50c2007-11-20 17:01:55 +0900187 /* TODO : xor ssr_md into this expression too. Then we can check
188 * that PRU is set when it needs to be. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 index = expevt4 ^ (expevt4 >> 5);
190 index &= 7;
Paul Mundtc06fd282012-05-14 15:52:28 +0900191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 protection_flags = expevt_lookup_table.protection_flags[index];
Paul Mundtc06fd282012-05-14 15:52:28 +0900193
194 if (expevt_lookup_table.is_text_access[index])
195 set_thread_fault_code(FAULT_CODE_ITLB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 /* SIM
198 * Note this is now called with interrupts still disabled
199 * This is to cope with being called for a missing IO port
Simon Arlott0a354772007-05-14 08:25:48 +0900200 * address with interrupts disabled. This should be fixed as
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 * soon as we have a better 'fast path' miss handler.
202 *
203 * Plus take care how you try and debug this stuff.
204 * For example, writing debug data to a port which you
205 * have just faulted on is not going to work.
206 */
207
208 tsk = current;
209 mm = tsk->mm;
210
Paul Mundt28080322012-05-14 15:33:28 +0900211 if (is_vmalloc_addr((void *)address)) {
Paul Mundt811d50c2007-11-20 17:01:55 +0900212 if (ssr_md)
213 /*
214 * Process-contexts can never have this address
215 * range mapped
216 */
Paul Mundt4de51852012-05-14 16:44:45 +0900217 if (handle_vmalloc_fault(mm, protection_flags, address) == 0)
218 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 } else if (!in_interrupt() && mm) {
Paul Mundt4de51852012-05-14 16:44:45 +0900220 if (handle_tlbmiss(mm, protection_flags, address) == 0)
221 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 }
223
Paul Mundt4de51852012-05-14 16:44:45 +0900224 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}