source: mainline/kernel/arch/sparc64/src/mm/tlb.c@ 06e1e95

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 06e1e95 was 7bb6b06, checked in by Jakub Jermar <jakub@…>, 19 years ago

Small improvements here and there.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (C) 2005 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sparc64mm
30 * @{
31 */
32/** @file
33 */
34
35#include <arch/mm/tlb.h>
36#include <mm/tlb.h>
37#include <mm/as.h>
38#include <mm/asid.h>
39#include <arch/mm/frame.h>
40#include <arch/mm/page.h>
41#include <arch/mm/mmu.h>
42#include <arch/interrupt.h>
43#include <interrupt.h>
44#include <arch.h>
45#include <print.h>
46#include <arch/types.h>
47#include <typedefs.h>
48#include <config.h>
49#include <arch/trap/trap.h>
50#include <arch/trap/exception.h>
51#include <panic.h>
52#include <arch/asm.h>
53
54static void dtlb_pte_copy(pte_t *t, bool ro);
55static void itlb_pte_copy(pte_t *t);
56static void do_fast_instruction_access_mmu_miss_fault(istate_t *istate, const char *str);
57static void do_fast_data_access_mmu_miss_fault(istate_t *istate, tlb_tag_access_reg_t tag, const char *str);
58static void do_fast_data_access_protection_fault(istate_t *istate, tlb_tag_access_reg_t tag, const char *str);
59
60char *context_encoding[] = {
61 "Primary",
62 "Secondary",
63 "Nucleus",
64 "Reserved"
65};
66
67void tlb_arch_init(void)
68{
69 /*
70 * TLBs are actually initialized early
71 * in start.S.
72 */
73}
74
75/** Insert privileged mapping into DMMU TLB.
76 *
77 * @param page Virtual page address.
78 * @param frame Physical frame address.
79 * @param pagesize Page size.
80 * @param locked True for permanent mappings, false otherwise.
81 * @param cacheable True if the mapping is cacheable, false otherwise.
82 */
83void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize, bool locked, bool cacheable)
84{
85 tlb_tag_access_reg_t tag;
86 tlb_data_t data;
87 page_address_t pg;
88 frame_address_t fr;
89
90 pg.address = page;
91 fr.address = frame;
92
93 tag.value = ASID_KERNEL;
94 tag.vpn = pg.vpn;
95
96 dtlb_tag_access_write(tag.value);
97
98 data.value = 0;
99 data.v = true;
100 data.size = pagesize;
101 data.pfn = fr.pfn;
102 data.l = locked;
103 data.cp = cacheable;
104 data.cv = cacheable;
105 data.p = true;
106 data.w = true;
107 data.g = false;
108
109 dtlb_data_in_write(data.value);
110}
111
112/** Copy PTE to TLB.
113 *
114 * @param t Page Table Entry to be copied.
115 * @param ro If true, the entry will be created read-only, regardless of its w field.
116 */
117void dtlb_pte_copy(pte_t *t, bool ro)
118{
119 tlb_tag_access_reg_t tag;
120 tlb_data_t data;
121 page_address_t pg;
122 frame_address_t fr;
123
124 pg.address = t->page;
125 fr.address = t->frame;
126
127 tag.value = 0;
128 tag.context = t->as->asid;
129 tag.vpn = pg.vpn;
130
131 dtlb_tag_access_write(tag.value);
132
133 data.value = 0;
134 data.v = true;
135 data.size = PAGESIZE_8K;
136 data.pfn = fr.pfn;
137 data.l = false;
138 data.cp = t->c;
139 data.cv = t->c;
140 data.p = t->k; /* p like privileged */
141 data.w = ro ? false : t->w;
142 data.g = t->g;
143
144 dtlb_data_in_write(data.value);
145}
146
147void itlb_pte_copy(pte_t *t)
148{
149 tlb_tag_access_reg_t tag;
150 tlb_data_t data;
151 page_address_t pg;
152 frame_address_t fr;
153
154 pg.address = t->page;
155 fr.address = t->frame;
156
157 tag.value = 0;
158 tag.context = t->as->asid;
159 tag.vpn = pg.vpn;
160
161 itlb_tag_access_write(tag.value);
162
163 data.value = 0;
164 data.v = true;
165 data.size = PAGESIZE_8K;
166 data.pfn = fr.pfn;
167 data.l = false;
168 data.cp = t->c;
169 data.cv = t->c;
170 data.p = t->k; /* p like privileged */
171 data.w = false;
172 data.g = t->g;
173
174 itlb_data_in_write(data.value);
175}
176
177/** ITLB miss handler. */
178void fast_instruction_access_mmu_miss(int n, istate_t *istate)
179{
180 uintptr_t va = ALIGN_DOWN(istate->tpc, PAGE_SIZE);
181 pte_t *t;
182
183 page_table_lock(AS, true);
184 t = page_mapping_find(AS, va);
185 if (t && PTE_EXECUTABLE(t)) {
186 /*
187 * The mapping was found in the software page hash table.
188 * Insert it into ITLB.
189 */
190 t->a = true;
191 itlb_pte_copy(t);
192 page_table_unlock(AS, true);
193 } else {
194 /*
195 * Forward the page fault to the address space page fault handler.
196 */
197 page_table_unlock(AS, true);
198 if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
199 do_fast_instruction_access_mmu_miss_fault(istate, __FUNCTION__);
200 }
201 }
202}
203
204/** DTLB miss handler.
205 *
206 * Note that some faults (e.g. kernel faults) were already resolved
207 * by the low-level, assembly language part of the fast_data_access_mmu_miss
208 * handler.
209 */
210void fast_data_access_mmu_miss(int n, istate_t *istate)
211{
212 tlb_tag_access_reg_t tag;
213 uintptr_t va;
214 pte_t *t;
215
216 tag.value = dtlb_tag_access_read();
217 va = tag.vpn << PAGE_WIDTH;
218
219 if (tag.context == ASID_KERNEL) {
220 if (!tag.vpn) {
221 /* NULL access in kernel */
222 do_fast_data_access_mmu_miss_fault(istate, tag, __FUNCTION__);
223 }
224 do_fast_data_access_mmu_miss_fault(istate, tag, "Unexpected kernel page fault.");
225 }
226
227 page_table_lock(AS, true);
228 t = page_mapping_find(AS, va);
229 if (t) {
230 /*
231 * The mapping was found in the software page hash table.
232 * Insert it into DTLB.
233 */
234 t->a = true;
235 dtlb_pte_copy(t, true);
236 page_table_unlock(AS, true);
237 } else {
238 /*
239 * Forward the page fault to the address space page fault handler.
240 */
241 page_table_unlock(AS, true);
242 if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
243 do_fast_data_access_mmu_miss_fault(istate, tag, __FUNCTION__);
244 }
245 }
246}
247
248/** DTLB protection fault handler. */
249void fast_data_access_protection(int n, istate_t *istate)
250{
251 tlb_tag_access_reg_t tag;
252 uintptr_t va;
253 pte_t *t;
254
255 tag.value = dtlb_tag_access_read();
256 va = tag.vpn << PAGE_WIDTH;
257
258 page_table_lock(AS, true);
259 t = page_mapping_find(AS, va);
260 if (t && PTE_WRITABLE(t)) {
261 /*
262 * The mapping was found in the software page hash table and is writable.
263 * Demap the old mapping and insert an updated mapping into DTLB.
264 */
265 t->a = true;
266 t->d = true;
267 dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_SECONDARY, va);
268 dtlb_pte_copy(t, false);
269 page_table_unlock(AS, true);
270 } else {
271 /*
272 * Forward the page fault to the address space page fault handler.
273 */
274 page_table_unlock(AS, true);
275 if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) {
276 do_fast_data_access_protection_fault(istate, tag, __FUNCTION__);
277 }
278 }
279}
280
281/** Print contents of both TLBs. */
282void tlb_print(void)
283{
284 int i;
285 tlb_data_t d;
286 tlb_tag_read_reg_t t;
287
288 printf("I-TLB contents:\n");
289 for (i = 0; i < ITLB_ENTRY_COUNT; i++) {
290 d.value = itlb_data_access_read(i);
291 t.value = itlb_tag_read_read(i);
292
293 printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n",
294 i, t.vpn, t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag, d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
295 }
296
297 printf("D-TLB contents:\n");
298 for (i = 0; i < DTLB_ENTRY_COUNT; i++) {
299 d.value = dtlb_data_access_read(i);
300 t.value = dtlb_tag_read_read(i);
301
302 printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n",
303 i, t.vpn, t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag, d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
304 }
305
306}
307
308void do_fast_instruction_access_mmu_miss_fault(istate_t *istate, const char *str)
309{
310 fault_if_from_uspace(istate, "%s\n", str);
311 dump_istate(istate);
312 panic("%s\n", str);
313}
314
315void do_fast_data_access_mmu_miss_fault(istate_t *istate, tlb_tag_access_reg_t tag, const char *str)
316{
317 uintptr_t va;
318
319 va = tag.vpn << PAGE_WIDTH;
320
321 fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d)\n", str, va, tag.context);
322 dump_istate(istate);
323 printf("Faulting page: %p, ASID=%d\n", va, tag.context);
324 panic("%s\n", str);
325}
326
327void do_fast_data_access_protection_fault(istate_t *istate, tlb_tag_access_reg_t tag, const char *str)
328{
329 uintptr_t va;
330
331 va = tag.vpn << PAGE_WIDTH;
332
333 fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d)\n", str, va, tag.context);
334 printf("Faulting page: %p, ASID=%d\n", va, tag.context);
335 dump_istate(istate);
336 panic("%s\n", str);
337}
338
339/** Invalidate all unlocked ITLB and DTLB entries. */
340void tlb_invalidate_all(void)
341{
342 int i;
343 tlb_data_t d;
344 tlb_tag_read_reg_t t;
345
346 for (i = 0; i < ITLB_ENTRY_COUNT; i++) {
347 d.value = itlb_data_access_read(i);
348 if (!d.l) {
349 t.value = itlb_tag_read_read(i);
350 d.v = false;
351 itlb_tag_access_write(t.value);
352 itlb_data_access_write(i, d.value);
353 }
354 }
355
356 for (i = 0; i < DTLB_ENTRY_COUNT; i++) {
357 d.value = dtlb_data_access_read(i);
358 if (!d.l) {
359 t.value = dtlb_tag_read_read(i);
360 d.v = false;
361 dtlb_tag_access_write(t.value);
362 dtlb_data_access_write(i, d.value);
363 }
364 }
365
366}
367
368/** Invalidate all ITLB and DTLB entries that belong to specified ASID (Context).
369 *
370 * @param asid Address Space ID.
371 */
372void tlb_invalidate_asid(asid_t asid)
373{
374 tlb_context_reg_t pc_save, ctx;
375
376 /* switch to nucleus because we are mapped by the primary context */
377 nucleus_enter();
378
379 ctx.v = pc_save.v = mmu_primary_context_read();
380 ctx.context = asid;
381 mmu_primary_context_write(ctx.v);
382
383 itlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_PRIMARY, 0);
384 dtlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_PRIMARY, 0);
385
386 mmu_primary_context_write(pc_save.v);
387
388 nucleus_leave();
389}
390
391/** Invalidate all ITLB and DTLB entries for specified page range in specified address space.
392 *
393 * @param asid Address Space ID.
394 * @param page First page which to sweep out from ITLB and DTLB.
395 * @param cnt Number of ITLB and DTLB entries to invalidate.
396 */
397void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt)
398{
399 int i;
400 tlb_context_reg_t pc_save, ctx;
401
402 /* switch to nucleus because we are mapped by the primary context */
403 nucleus_enter();
404
405 ctx.v = pc_save.v = mmu_primary_context_read();
406 ctx.context = asid;
407 mmu_primary_context_write(ctx.v);
408
409 for (i = 0; i < cnt; i++) {
410 itlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY, page + i * PAGE_SIZE);
411 dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY, page + i * PAGE_SIZE);
412 }
413
414 mmu_primary_context_write(pc_save.v);
415
416 nucleus_leave();
417}
418
419/** @}
420 */
Note: See TracBrowser for help on using the repository browser.