Rev 901 | Rev 919 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 901 | Rev 902 | ||
---|---|---|---|
Line 30... | Line 30... | ||
30 | * TLB management. |
30 | * TLB management. |
31 | */ |
31 | */ |
32 | 32 | ||
33 | #include <mm/tlb.h> |
33 | #include <mm/tlb.h> |
34 | #include <mm/asid.h> |
34 | #include <mm/asid.h> |
- | 35 | #include <mm/page.h> |
|
- | 36 | #include <mm/as.h> |
|
35 | #include <arch/mm/tlb.h> |
37 | #include <arch/mm/tlb.h> |
36 | #include <arch/mm/page.h> |
38 | #include <arch/mm/page.h> |
37 | #include <arch/barrier.h> |
39 | #include <arch/barrier.h> |
38 | #include <arch/interrupt.h> |
40 | #include <arch/interrupt.h> |
39 | #include <typedefs.h> |
41 | #include <typedefs.h> |
40 | #include <panic.h> |
42 | #include <panic.h> |
41 | #include <print.h> |
43 | #include <arch.h> |
42 | 44 | ||
43 | /** Invalidate all TLB entries. */ |
45 | /** Invalidate all TLB entries. */ |
44 | void tlb_invalidate_all(void) |
46 | void tlb_invalidate_all(void) |
45 | { |
47 | { |
46 | /* TODO */ |
48 | /* TODO */ |
Line 85... | Line 87... | ||
85 | void tc_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtc) |
87 | void tc_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtc) |
86 | { |
88 | { |
87 | region_register rr; |
89 | region_register rr; |
88 | bool restore_rr = false; |
90 | bool restore_rr = false; |
89 | 91 | ||
90 | if (!(entry.p)) |
- | |
91 | return; |
- | |
92 | - | ||
93 | rr.word = rr_read(VA2VRN(va)); |
92 | rr.word = rr_read(VA2VRN(va)); |
94 | if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) { |
93 | if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) { |
95 | /* |
94 | /* |
96 | * The selected region register does not contain required RID. |
95 | * The selected region register does not contain required RID. |
97 | * Save the old content of the register and replace the RID. |
96 | * Save the old content of the register and replace the RID. |
Line 164... | Line 163... | ||
164 | void tr_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtr, index_t tr) |
163 | void tr_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtr, index_t tr) |
165 | { |
164 | { |
166 | region_register rr; |
165 | region_register rr; |
167 | bool restore_rr = false; |
166 | bool restore_rr = false; |
168 | 167 | ||
169 | if (!(entry.p)) |
- | |
170 | return; |
- | |
171 | - | ||
172 | rr.word = rr_read(VA2VRN(va)); |
168 | rr.word = rr_read(VA2VRN(va)); |
173 | if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) { |
169 | if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) { |
174 | /* |
170 | /* |
175 | * The selected region register does not contain required RID. |
171 | * The selected region register does not contain required RID. |
176 | * Save the old content of the register and replace the RID. |
172 | * Save the old content of the register and replace the RID. |
Line 214... | Line 210... | ||
214 | * @param asid Address space identifier. |
210 | * @param asid Address space identifier. |
215 | * @param entry The rest of TLB entry as required by TLB insertion format. |
211 | * @param entry The rest of TLB entry as required by TLB insertion format. |
216 | * @param dtr If true, insert into data translation register, use data translation cache otherwise. |
212 | * @param dtr If true, insert into data translation register, use data translation cache otherwise. |
217 | * @param tr Translation register if dtr is true, ignored otherwise. |
213 | * @param tr Translation register if dtr is true, ignored otherwise. |
218 | */ |
214 | */ |
219 | void dtlb_mapping_insert(__address page, __address frame, bool dtr, index_t tr) |
215 | void dtlb_kernel_mapping_insert(__address page, __address frame, bool dtr, index_t tr) |
220 | { |
216 | { |
221 | tlb_entry_t entry; |
217 | tlb_entry_t entry; |
222 | 218 | ||
223 | entry.word[0] = 0; |
219 | entry.word[0] = 0; |
224 | entry.word[1] = 0; |
220 | entry.word[1] = 0; |
Line 236... | Line 232... | ||
236 | dtr_mapping_insert(page, ASID_KERNEL, entry, tr); |
232 | dtr_mapping_insert(page, ASID_KERNEL, entry, tr); |
237 | else |
233 | else |
238 | dtc_mapping_insert(page, ASID_KERNEL, entry); |
234 | dtc_mapping_insert(page, ASID_KERNEL, entry); |
239 | } |
235 | } |
240 | 236 | ||
- | 237 | /** Copy content of PTE into data translation cache. |
|
- | 238 | * |
|
- | 239 | * @param t PTE. |
|
- | 240 | */ |
|
- | 241 | void dtc_pte_copy(pte_t *t) |
|
- | 242 | { |
|
- | 243 | tlb_entry_t entry; |
|
- | 244 | ||
- | 245 | entry.word[0] = 0; |
|
- | 246 | entry.word[1] = 0; |
|
- | 247 | ||
- | 248 | entry.p = t->p; |
|
- | 249 | entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE; |
|
- | 250 | entry.a = t->a; |
|
- | 251 | entry.d = t->d; |
|
- | 252 | entry.pl = t->k ? PL_KERNEL : PL_USER; |
|
- | 253 | entry.ar = t->w ? AR_WRITE : AR_READ; |
|
- | 254 | entry.ppn = t->frame >> PPN_SHIFT; |
|
- | 255 | entry.ps = PAGE_WIDTH; |
|
- | 256 | ||
- | 257 | dtc_mapping_insert(t->page, t->as->asid, entry); |
|
- | 258 | } |
|
- | 259 | ||
- | 260 | /** Copy content of PTE into instruction translation cache. |
|
- | 261 | * |
|
- | 262 | * @param t PTE. |
|
- | 263 | */ |
|
- | 264 | void itc_pte_copy(pte_t *t) |
|
- | 265 | { |
|
- | 266 | tlb_entry_t entry; |
|
- | 267 | ||
- | 268 | entry.word[0] = 0; |
|
- | 269 | entry.word[1] = 0; |
|
- | 270 | ||
- | 271 | ASSERT(t->x); |
|
- | 272 | ||
- | 273 | entry.p = t->p; |
|
- | 274 | entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE; |
|
- | 275 | entry.a = t->a; |
|
- | 276 | entry.pl = t->k ? PL_KERNEL : PL_USER; |
|
- | 277 | entry.ar = t->x ? (AR_EXECUTE | AR_READ) : AR_READ; |
|
- | 278 | entry.ppn = t->frame >> PPN_SHIFT; |
|
- | 279 | entry.ps = PAGE_WIDTH; |
|
- | 280 | ||
- | 281 | itc_mapping_insert(t->page, t->as->asid, entry); |
|
- | 282 | } |
|
- | 283 | ||
- | 284 | /** Instruction TLB fault handler for faults with VHPT turned off. |
|
- | 285 | * |
|
- | 286 | * @param vector Interruption vector. |
|
- | 287 | * @param pstate Structure with saved interruption state. |
|
- | 288 | */ |
|
241 | void alternate_instruction_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
289 | void alternate_instruction_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
242 | { |
290 | { |
- | 291 | region_register rr; |
|
- | 292 | __address va; |
|
- | 293 | pte_t *t; |
|
- | 294 | ||
- | 295 | va = pstate->cr_ifa; /* faulting address */ |
|
243 | panic("%s\n", __FUNCTION__); |
296 | t = page_mapping_find(AS, va); |
- | 297 | if (t) { |
|
- | 298 | /* |
|
- | 299 | * The mapping was found in software page hash table. |
|
- | 300 | * Insert it into data translation cache. |
|
- | 301 | */ |
|
- | 302 | itc_pte_copy(t); |
|
- | 303 | } else { |
|
- | 304 | /* |
|
- | 305 | * Forward the page fault to address space page fault handler. |
|
- | 306 | */ |
|
- | 307 | if (!as_page_fault(va)) { |
|
- | 308 | panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid); |
|
- | 309 | } |
|
- | 310 | } |
|
244 | } |
311 | } |
245 | 312 | ||
246 | /** Data TLB fault with VHPT turned off. |
313 | /** Data TLB fault handler for faults with VHPT turned off. |
247 | * |
314 | * |
248 | * @param vector Interruption vector. |
315 | * @param vector Interruption vector. |
249 | * @param pstate Structure with saved interruption state. |
316 | * @param pstate Structure with saved interruption state. |
250 | */ |
317 | */ |
251 | void alternate_data_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
318 | void alternate_data_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
252 | { |
319 | { |
253 | region_register rr; |
320 | region_register rr; |
254 | rid_t rid; |
321 | rid_t rid; |
255 | __address va; |
322 | __address va; |
- | 323 | pte_t *t; |
|
256 | 324 | ||
257 | va = pstate->cr_ifa; /* faulting address */ |
325 | va = pstate->cr_ifa; /* faulting address */ |
258 | rr.word = rr_read(VA2VRN(va)); |
326 | rr.word = rr_read(VA2VRN(va)); |
259 | rid = rr.map.rid; |
327 | rid = rr.map.rid; |
260 | if (RID2ASID(rid) == ASID_KERNEL) { |
328 | if (RID2ASID(rid) == ASID_KERNEL) { |
261 | if (VA2VRN(va) == VRN_KERNEL) { |
329 | if (VA2VRN(va) == VRN_KERNEL) { |
262 | /* |
330 | /* |
263 | * Provide KA2PA(identity) mapping for faulting piece of |
331 | * Provide KA2PA(identity) mapping for faulting piece of |
264 | * kernel address space. |
332 | * kernel address space. |
265 | */ |
333 | */ |
266 | dtlb_mapping_insert(va, KA2PA(va), false, 0); |
334 | dtlb_kernel_mapping_insert(va, KA2PA(va), false, 0); |
267 | return; |
335 | return; |
268 | } |
336 | } |
269 | } |
337 | } |
- | 338 | ||
- | 339 | t = page_mapping_find(AS, va); |
|
- | 340 | if (t) { |
|
- | 341 | /* |
|
- | 342 | * The mapping was found in software page hash table. |
|
- | 343 | * Insert it into data translation cache. |
|
- | 344 | */ |
|
- | 345 | dtc_pte_copy(t); |
|
- | 346 | } else { |
|
- | 347 | /* |
|
- | 348 | * Forward the page fault to address space page fault handler. |
|
- | 349 | */ |
|
- | 350 | if (!as_page_fault(va)) { |
|
270 | panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid); |
351 | panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid); |
- | 352 | } |
|
- | 353 | } |
|
271 | } |
354 | } |
272 | 355 | ||
- | 356 | /** Data nested TLB fault handler. |
|
- | 357 | * |
|
- | 358 | * This fault should not occur. |
|
- | 359 | * |
|
- | 360 | * @param vector Interruption vector. |
|
- | 361 | * @param pstate Structure with saved interruption state. |
|
- | 362 | */ |
|
273 | void data_nested_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
363 | void data_nested_tlb_fault(__u64 vector, struct exception_regdump *pstate) |
274 | { |
364 | { |
275 | panic("%s\n", __FUNCTION__); |
365 | panic("%s\n", __FUNCTION__); |
276 | } |
366 | } |
277 | 367 | ||
- | 368 | /** Data Dirty bit fault handler. |
|
- | 369 | * |
|
- | 370 | * @param vector Interruption vector. |
|
- | 371 | * @param pstate Structure with saved interruption state. |
|
- | 372 | */ |
|
278 | void data_dirty_bit_fault(__u64 vector, struct exception_regdump *pstate) |
373 | void data_dirty_bit_fault(__u64 vector, struct exception_regdump *pstate) |
279 | { |
374 | { |
- | 375 | pte_t *t; |
|
- | 376 | ||
280 | panic("%s\n", __FUNCTION__); |
377 | t = page_mapping_find(AS, pstate->cr_ifa); |
- | 378 | ASSERT(t && t->p); |
|
- | 379 | if (t && t->p) { |
|
- | 380 | /* |
|
- | 381 | * Update the Dirty bit in page tables and reinsert |
|
- | 382 | * the mapping into DTC. |
|
- | 383 | */ |
|
- | 384 | t->d = true; |
|
- | 385 | dtc_pte_copy(t); |
|
- | 386 | } |
|
281 | } |
387 | } |
282 | 388 | ||
- | 389 | /** Instruction access bit fault handler. |
|
- | 390 | * |
|
- | 391 | * @param vector Interruption vector. |
|
- | 392 | * @param pstate Structure with saved interruption state. |
|
- | 393 | */ |
|
283 | void instruction_access_bit_fault(__u64 vector, struct exception_regdump *pstate) |
394 | void instruction_access_bit_fault(__u64 vector, struct exception_regdump *pstate) |
284 | { |
395 | { |
- | 396 | pte_t *t; |
|
- | 397 | ||
285 | panic("%s\n", __FUNCTION__); |
398 | t = page_mapping_find(AS, pstate->cr_ifa); |
- | 399 | ASSERT(t && t->p); |
|
- | 400 | if (t && t->p) { |
|
- | 401 | /* |
|
- | 402 | * Update the Accessed bit in page tables and reinsert |
|
- | 403 | * the mapping into ITC. |
|
- | 404 | */ |
|
- | 405 | t->a = true; |
|
- | 406 | itc_pte_copy(t); |
|
- | 407 | } |
|
286 | } |
408 | } |
287 | 409 | ||
- | 410 | /** Data access bit fault handler. |
|
- | 411 | * |
|
- | 412 | * @param vector Interruption vector. |
|
- | 413 | * @param pstate Structure with saved interruption state. |
|
- | 414 | */ |
|
288 | void data_access_bit_fault(__u64 vector, struct exception_regdump *pstate) |
415 | void data_access_bit_fault(__u64 vector, struct exception_regdump *pstate) |
289 | { |
416 | { |
- | 417 | pte_t *t; |
|
- | 418 | ||
290 | panic("%s\n", __FUNCTION__); |
419 | t = page_mapping_find(AS, pstate->cr_ifa); |
- | 420 | ASSERT(t && t->p); |
|
- | 421 | if (t && t->p) { |
|
- | 422 | /* |
|
- | 423 | * Update the Accessed bit in page tables and reinsert |
|
- | 424 | * the mapping into DTC. |
|
- | 425 | */ |
|
- | 426 | t->a = true; |
|
- | 427 | dtc_pte_copy(t); |
|
- | 428 | } |
|
291 | } |
429 | } |
292 | 430 | ||
- | 431 | /** Page not present fault handler. |
|
- | 432 | * |
|
- | 433 | * @param vector Interruption vector. |
|
- | 434 | * @param pstate Structure with saved interruption state. |
|
- | 435 | */ |
|
293 | void page_not_present(__u64 vector, struct exception_regdump *pstate) |
436 | void page_not_present(__u64 vector, struct exception_regdump *pstate) |
294 | { |
437 | { |
- | 438 | region_register rr; |
|
- | 439 | __address va; |
|
- | 440 | pte_t *t; |
|
- | 441 | ||
- | 442 | va = pstate->cr_ifa; /* faulting address */ |
|
295 | panic("%s\n", __FUNCTION__); |
443 | t = page_mapping_find(AS, va); |
- | 444 | ASSERT(t); |
|
- | 445 | ||
- | 446 | if (t->p) { |
|
- | 447 | /* |
|
- | 448 | * If the Present bit is set in page hash table, just copy it |
|
- | 449 | * and update ITC/DTC. |
|
- | 450 | */ |
|
- | 451 | if (t->x) |
|
- | 452 | itc_pte_copy(t); |
|
- | 453 | else |
|
- | 454 | dtc_pte_copy(t); |
|
- | 455 | } else { |
|
- | 456 | if (!as_page_fault(va)) { |
|
- | 457 | panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid); |
|
- | 458 | } |
|
- | 459 | } |
|
296 | } |
460 | } |