]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/paging-arm.cpp
update
[l4.git] / kernel / fiasco / src / kern / arm / paging-arm.cpp
1 INTERFACE [arm]:
2
3 #include "mem_unit.h"
4
5 class PF {};
6 class Page
7 {
8 };
9
10
11 //-------------------------------------------------------------------------------------
12 INTERFACE [arm && !arm_lpae]:
13
14 class Pte_ptr
15 {
16 public:
17   typedef Mword Entry;
18   enum
19   {
20     Super_level    = 0,
21   };
22
23   Pte_ptr() = default;
24   Pte_ptr(void *p, unsigned char level) : pte((Mword*)p), level(level) {}
25
26   bool is_valid() const { return *pte & 3; }
27   void clear() { *pte = 0; }
28   bool is_leaf() const
29   {
30     switch (level)
31       {
32       case 0: return (*pte & 3) == 2;
33       default: return true;
34       };
35   }
36
37   Mword next_level() const
38   {
39     // 1KB second level tables
40     return cxx::mask_lsb(*pte, 10);
41   }
42
43   void set_next_level(Mword phys)
44   {
45     write_now(pte, phys | 1);
46   }
47
48   unsigned char page_order() const
49   {
50     if (level == 0)
51       return 20; // 1MB
52     else
53       { // no tiny pages !!!
54         if ((*pte & 3) == 1)
55           return 16;
56         else
57           return 12;
58       }
59   }
60
61   Mword page_addr() const
62   { return cxx::mask_lsb(*pte, page_order()); }
63
64   Mword *pte;
65   unsigned char level;
66 };
67
68 EXTENSION class Page
69 { public: enum { Ttbcr_bits = 0, Mair0_bits = 0 }; };
70
71 //-----------------------------------------------------------------------------
72 INTERFACE [arm && arm_lpae]:
73
74 class Pte_ptr
75 {
76 public:
77   typedef Unsigned64 Entry;
78
79   enum
80   {
81     Super_level    = 1,
82   };
83
84   Pte_ptr() = default;
85   Pte_ptr(void *p, unsigned char level) : pte((Unsigned64*)p), level(level) {}
86
87   bool is_valid() const { return *pte & 1; }
88   void clear() { *pte = 0; }
89   bool is_leaf() const
90   {
91     if (level >= 2)
92       return true;
93     return (*pte & 3) == 1;
94   }
95
96   Unsigned64 next_level() const
97   {
98     // 1KB second level tables
99     return cxx::get_lsb(cxx::mask_lsb(*pte, 12), 40);
100   }
101
102   void set_next_level(Unsigned64 phys)
103   {
104     write_now(pte, phys | 3);
105   }
106
107   Mword page_addr() const
108   { return cxx::mask_lsb(*pte, page_order()); }
109
110   Unsigned64 *pte;
111   unsigned char level;
112 };
113
114 EXTENSION class Page
115 {
116 public:
117   enum
118   {
119     Ttbcr_bits =   (1 << 31) // EAE
120                  | (2 << 12) // SH0
121                  | (1 << 10) // ORGN0
122                  | (1 << 8), // IRGN0
123     Mair0_bits = 0x00ff4400
124   };
125 };
126
127 //---------------------------------------------------------------------------
128 IMPLEMENTATION [arm && arm_lpae]:
129
130 PUBLIC inline
131 unsigned char
132 Pte_ptr::page_order() const
133 { return Pdir::page_order_for_level(level); }
134
135
136 //-----------------------------------------------------------------------------
137 INTERFACE [arm && armv5]:
138
139 #include "types.h"
140
141 EXTENSION class Page
142 {
143 public:
144   typedef Unsigned32 Attribs;
145
146   enum Attribs_enum
147   {
148     Cache_mask    = 0x0c,
149     NONCACHEABLE  = 0x00, ///< Caching is off
150     CACHEABLE     = 0x0c, ///< Cache is enabled
151
152     // The next are ARM specific
153     WRITETHROUGH = 0x08, ///< Write through cached
154     BUFFERED     = 0x04, ///< Write buffer enabled
155   };
156
157   enum Default_entries : Mword
158   {
159     Section_cachable = 0x40e,
160     Section_no_cache = 0x402,
161     Section_local    = 0,
162     Section_global   = 0,
163   };
164 };
165
166 EXTENSION class Pte_ptr
167 {
168   // we have virtually tagged caches so need a cache flush before enabling
169   // a page table
170   enum { Need_cache_clean = false }; // we have virtuially tagged caches
171 };
172
173
174
175 //---------------------------------------------------------------------------
176 INTERFACE [arm && armv6plus && (mpcore || armca9)]:
177
178 EXTENSION class Page
179 {
180 public:
181   enum
182   {
183     Section_shared = 1UL << 16,
184     Mp_set_shared = 0x400,
185   };
186 };
187
188 //---------------------------------------------------------------------------
189 INTERFACE [arm && armv6plus && !(mpcore || armca9)]:
190
191 EXTENSION class Page
192 {
193 public:
194   enum
195   {
196     Section_shared = 0,
197     Mp_set_shared = 0,
198   };
199 };
200
201 //---------------------------------------------------------------------------
202 INTERFACE [arm && (armv5 || (armv6 && !mpcore))]:
203
204 EXTENSION class Page
205 { public: enum { Ttbr_bits = 0 }; };
206
207 //---------------------------------------------------------------------------
208 INTERFACE [arm && mpcore]:
209
210 EXTENSION class Page
211 { public: enum { Ttbr_bits = 0xa }; };
212
213 //---------------------------------------------------------------------------
214 INTERFACE [arm && armca9 && !arm_lpae]:
215
216 // S Sharable | RGN = Outer WB-WA | IRGN = Inner WB-WA | NOS
217 EXTENSION class Page
218 { public: enum { Ttbr_bits = 0x6a }; };
219
220 //---------------------------------------------------------------------------
221 INTERFACE [arm && armca9 && arm_lpae]:
222
223 EXTENSION class Page
224 { public: enum { Ttbr_bits = 0 }; };
225
226 //---------------------------------------------------------------------------
227 INTERFACE [arm && armca8]: // armv7 w/o multiprocessing ext.
228
229 EXTENSION class Page
230 { public: enum { Ttbr_bits = 0x2b }; };
231
232 //----------------------------------------------------------------------------
233 INTERFACE [arm && (armv6 || armv7) && !arm_lpae]:
234
235 #include "types.h"
236
237 EXTENSION class Page
238 {
239 public:
240   enum Attribs_enum
241   {
242     Cache_mask    = 0x1cc,
243     NONCACHEABLE  = 0x000, ///< Caching is off
244     CACHEABLE     = 0x144, ///< Cache is enabled
245
246     // The next are ARM specific
247     WRITETHROUGH = 0x08, ///< Write through cached
248     BUFFERED     = 0x40, ///< Write buffer enabled -- Normal, non-cached
249   };
250
251   enum Default_entries : Mword
252   {
253     Section_cachable = 0x5406 | Section_shared,
254     Section_no_cache = 0x0402 | Section_shared,
255     Section_local    = (1 << 17),
256     Section_global   = 0,
257   };
258 };
259
260 //-----------------------------------------------------------------------------
261 INTERFACE [arm && !arm_lpae]:
262
263 #include "ptab_base.h"
264
265 typedef Ptab::List< Ptab::Traits< Unsigned32, 20, 12, true>,
266                     Ptab::Traits< Unsigned32, 12, 8, true> > Ptab_traits;
267
268 typedef Ptab::Shift<Ptab_traits, Virt_addr::Shift>::List Ptab_traits_vpn;
269 typedef Ptab::Page_addr_wrap<Page_number, Virt_addr::Shift> Ptab_va_vpn;
270
271 //-----------------------------------------------------------------------------
272 INTERFACE [arm && arm_lpae]:
273
274 #include "ptab_base.h"
275 #include "types.h"
276
277 EXTENSION class Page
278 {
279 public:
280   enum Attribs_enum
281   {
282     Cache_mask    = 0x01c,
283     NONCACHEABLE  = 0x000, ///< Caching is off
284     CACHEABLE     = 0x008, ///< Cache is enabled
285     BUFFERED      = 0x004, ///< Write buffer enabled -- Normal, non-cached
286   };
287 };
288
289 typedef Ptab::Tupel< Ptab::Traits< Unsigned64, 30, 2, true>,
290                      Ptab::Traits< Unsigned64, 21, 9, true>,
291                      Ptab::Traits< Unsigned64, 12, 9, true> >::List Ptab_traits;
292
293 typedef Ptab::Shift<Ptab_traits, Virt_addr::Shift>::List Ptab_traits_vpn;
294 typedef Ptab::Page_addr_wrap<Page_number, Virt_addr::Shift> Ptab_va_vpn;
295
296 //---------------------------------------------------------------------------
297 IMPLEMENTATION [arm && armv5]:
298
299 PUBLIC static inline
300 bool
301 Pte_ptr::need_cache_write_back(bool current_pt)
302 { return current_pt; }
303
304 PUBLIC inline
305 void
306 Pte_ptr::write_back_if(bool current_pt, Mword /*asid*/ = 0)
307 {
308   if (current_pt)
309     Mem_unit::clean_dcache(pte);
310 }
311
312 PUBLIC static inline
313 void
314 Pte_ptr::write_back(void *start, void *end)
315 { Mem_unit::clean_dcache(start, end); }
316
317 //---------------------------------------------------------------------------
318 IMPLEMENTATION [arm && armv6]:
319
320 PUBLIC static inline
321 bool
322 Pte_ptr::need_cache_write_back(bool)
323 { return true; }
324
325 PUBLIC inline
326 void
327 Pte_ptr::write_back_if(bool, Mword asid = Mem_unit::Asid_invalid)
328 {
329   Mem_unit::clean_dcache(pte);
330   if (asid != Mem_unit::Asid_invalid)
331     Mem_unit::tlb_flush(asid);
332 }
333
334 PUBLIC static inline
335 void
336 Pte_ptr::write_back(void *start, void *end)
337 { Mem_unit::clean_dcache(start, end); }
338
339 //---------------------------------------------------------------------------
340 IMPLEMENTATION [arm && armv7]:
341
342 PUBLIC static inline
343 bool
344 Pte_ptr::need_cache_write_back(bool)
345 { return false; }
346
347 PUBLIC inline
348 void
349 Pte_ptr::write_back_if(bool, Mword asid = Mem_unit::Asid_invalid)
350 {
351   if (asid != Mem_unit::Asid_invalid)
352     Mem_unit::tlb_flush(asid);
353 }
354
355 PUBLIC static inline
356 void
357 Pte_ptr::write_back(void *, void *)
358 {}
359
360
361 //---------------------------------------------------------------------------
362 IMPLEMENTATION [arm && armv5]:
363
364 PUBLIC static inline
365 Mword PF::is_alignment_error(Mword error)
366 { return (error & 0xf0000d) == 0x400001; }
367
368 PRIVATE inline
369 Pte_ptr::Entry
370 Pte_ptr::_attribs_mask() const
371 {
372   if (level == 0)
373     return ~Entry(0x00000c0c);
374   else
375     return ~Entry(0x00000ffc);
376 }
377
378 PRIVATE inline
379 Mword
380 Pte_ptr::_attribs(Page::Attr attr) const
381 {
382   static const unsigned short perms[] = {
383       0x1 << 10, // 0000: none, hmmm
384       0x1 << 10, // 000X: kernel rw (there is no ro)
385       0x1 << 10, // 00W0:
386       0x1 << 10, // 00WX:
387
388       0x1 << 10, // 0R00:
389       0x1 << 10, // 0R0X:
390       0x1 << 10, // 0RW0:
391       0x1 << 10, // 0RWX:
392
393       0x1 << 10, // U000:
394       0x0 << 10, // U00X:
395       0x3 << 10, // U0W0:
396       0x3 << 10, // U0WX:
397
398       0x0 << 10, // UR00:
399       0x0 << 10, // UR0X:
400       0x3 << 10, // URW0:
401       0x3 << 10  // URWX:
402   };
403
404   typedef Page::Type T;
405   typedef Page::Kern K;
406   Mword r = 0;
407   if (attr.type == T::Normal())   r |= Page::CACHEABLE;
408   if (attr.type == T::Buffered()) r |= Page::BUFFERED;
409   if (attr.type == T::Uncached()) r |= Page::NONCACHEABLE;
410   if (level == 0)
411     return r | perms[cxx::int_value<L4_fpage::Rights>(attr.rights)];
412   else
413     {
414       Mword p = perms[cxx::int_value<L4_fpage::Rights>(attr.rights)];
415       p |= p >> 2;
416       p |= p >> 4;
417       return r | p;
418     }
419 }
420
421 PUBLIC inline
422 Page::Attr
423 Pte_ptr::attribs() const
424 {
425   auto r = access_once(pte);
426   auto c = r & 0xc;
427   r &= 0xc00;
428
429   typedef L4_fpage::Rights R;
430   typedef Page::Type T;
431
432   R rights;
433   switch (r)
434     {
435     case 0x000: rights = R::URX(); break;
436     default:
437     case 0x400: rights = R::RWX(); break;
438     case 0xc00: rights = R::URWX(); break;
439     }
440
441   T type;
442   switch (c)
443     {
444     default:
445     case Page::CACHEABLE: type = T::Normal(); break;
446     case Page::BUFFERED:  type = T::Buffered(); break;
447     case Page::NONCACHEABLE: type = T::Uncached(); break;
448     }
449   return Page::Attr(rights, type);
450 }
451
452 PUBLIC inline NEEDS[Pte_ptr::_attribs, Pte_ptr::_attribs_mask]
453 void
454 Pte_ptr::set_attribs(Page::Attr attr)
455 {
456   Mword p = access_once(pte);
457   p = (p & _attribs_mask()) | _attribs(attr);
458   write_now(pte, p);
459 }
460
461 PUBLIC inline NEEDS[Pte_ptr::_attribs]
462 void
463 Pte_ptr::create_page(Phys_mem_addr addr, Page::Attr attr)
464 {
465   Mword p = 2 | _attribs(attr) | cxx::int_value<Phys_mem_addr>(addr);
466   write_now(pte, p);
467 }
468
469 PUBLIC inline
470 bool
471 Pte_ptr::add_attribs(Page::Attr attr)
472 {
473   typedef L4_fpage::Rights R;
474
475   if (attr.rights & R::W())
476     {
477       auto p = access_once(pte);
478       if ((p & 0xc00) == 0x000)
479         {
480           p |= level == 0 ? 0xc00 : 0xff0;
481           write_now(pte, p);
482           return true;
483         }
484     }
485   return false;
486 }
487
488 PUBLIC inline
489 Page::Rights
490 Pte_ptr::access_flags() const
491 { return Page::Rights(0); }
492
493 PUBLIC inline
494 void
495 Pte_ptr::del_rights(L4_fpage::Rights r)
496 {
497   if (!(r & L4_fpage::Rights::W()))
498     return;
499
500   auto p = access_once(pte);
501   if ((p & 0xc00) == 0xc00)
502     {
503       p &= (level == 0) ? ~Mword(0xc00) : ~Mword(0xff0);
504       write_now(pte, p);
505     }
506 }
507
508
509 //---------------------------------------------------------------------------
510 IMPLEMENTATION [arm && !arm_lpae && (armv6 || armv7)]:
511
512 PRIVATE inline
513 Pte_ptr::Entry
514 Pte_ptr::_attribs_mask() const
515 {
516   if (level == 0)
517     return ~Entry(0x0000881c);
518   else
519     return ~Entry(0x0000022d);
520 }
521
522 PRIVATE inline
523 Mword
524 Pte_ptr::_attribs(Page::Attr attr) const
525 {
526   typedef L4_fpage::Rights R;
527   typedef Page::Type T;
528   typedef Page::Kern K;
529
530   Mword lower = Page::Mp_set_shared;
531   if (attr.type == T::Normal())   lower |= Page::CACHEABLE;
532   if (attr.type == T::Buffered()) lower |= Page::BUFFERED;
533   if (attr.type == T::Uncached()) lower |= Page::NONCACHEABLE;
534   Mword upper = lower & ~0x0f;
535   lower &= 0x0f;
536
537   if (!(attr.kern & K::Global()))
538     upper |= 0x800;
539
540   if (!(attr.rights & R::W()))
541     upper |= 0x200;
542
543   if (attr.rights & R::U())
544     upper |= 0x20;
545
546   if (!(attr.rights & R::X()))
547     {
548       if (level == 0)
549         lower |= 0x10;
550       else
551         lower |= 0x01;
552     }
553
554   if (level == 0)
555     return lower | (upper << 6);
556   else
557     return lower | upper;
558 }
559
560 PUBLIC inline
561 Page::Attr
562 Pte_ptr::attribs() const
563 {
564   typedef L4_fpage::Rights R;
565   typedef Page::Type T;
566   typedef Page::Kern K;
567
568   auto c = access_once(pte);
569
570   R rights = R::R();
571
572   if (level == 0)
573     {
574       if (!(c & 0x10))
575         rights |= R::X();
576
577       c = (c & 0x0f) | ((c >> 6) & 0xfff0);
578     }
579   else if (!(c & 0x01))
580     rights |= R::X();
581
582   if (!(c & 0x200))
583     rights |= R::W();
584   if (c & 0x20)
585     rights |= R::U();
586
587   T type;
588   switch (c & Page::Cache_mask)
589     {
590     default:
591     case Page::CACHEABLE: type = T::Normal(); break;
592     case Page::BUFFERED:  type = T::Buffered(); break;
593     case Page::NONCACHEABLE: type = T::Uncached(); break;
594     }
595
596   K k(0);
597   if (!(c & 0x800))
598     k |= K::Global();
599
600   return Page::Attr(rights, type, k);
601 }
602
603 PUBLIC inline NEEDS[Pte_ptr::_attribs]
604 void
605 Pte_ptr::create_page(Phys_mem_addr addr, Page::Attr attr)
606 {
607   Mword p = 2 | _attribs(attr) | cxx::int_value<Phys_mem_addr>(addr);
608   if (level == 0)
609     p |= 0x400;  // AP[0]
610   else
611     p |= 0x10;   // AP[0]
612
613   write_now(pte, p);
614 }
615
616 PUBLIC inline
617 bool
618 Pte_ptr::add_attribs(Page::Attr attr)
619 {
620   typedef L4_fpage::Rights R;
621   Mword n_attr = 0;
622
623   if (attr.rights & R::W())
624     {
625       if (level == 0)
626         n_attr = 0x200 << 6;
627       else
628         n_attr = 0x200;
629     }
630
631   if (attr.rights & R::X())
632     {
633       if (level == 0)
634         n_attr |= 0x10;
635       else
636         n_attr |= 0x01;
637     }
638
639
640   auto p = access_once(pte);
641   if (p & n_attr)
642     {
643       p &= ~n_attr;
644       write_now(pte, p);
645       return true;
646     }
647
648   return false;
649 }
650
651 PUBLIC inline
652 Page::Rights
653 Pte_ptr::access_flags() const
654 { return Page::Rights(0); }
655
656 PUBLIC inline
657 void
658 Pte_ptr::del_rights(L4_fpage::Rights r)
659 {
660   Mword n_attr = 0;
661   if (r & L4_fpage::Rights::W())
662     {
663       if (level == 0)
664         n_attr = 0x200 << 6;
665       else
666         n_attr = 0x200;
667     }
668
669   if (r & L4_fpage::Rights::X())
670     {
671       if (level == 0)
672         n_attr |= 0x10;
673       else
674         n_attr |= 0x01;
675     }
676
677   if (!n_attr)
678     return;
679
680   auto p = access_once(pte);
681   if ((p & n_attr) != n_attr)
682     {
683       p |= n_attr;
684       write_now(pte, p);
685     }
686 }
687
688
689 //---------------------------------------------------------------------------
690 IMPLEMENTATION [arm && arm_lpae && (armv6 || armv7)]:
691
692 PRIVATE inline
693 Pte_ptr::Entry
694 Pte_ptr::_attribs_mask() const
695 { return ~Entry(0x00400000000008dc); }
696
697 PRIVATE inline
698 Pte_ptr::Entry
699 Pte_ptr::_attribs(Page::Attr attr) const
700 {
701   typedef L4_fpage::Rights R;
702   typedef Page::Type T;
703   typedef Page::Kern K;
704
705   Entry lower = 0x300; // inner sharable
706   if (attr.type == T::Normal())   lower |= Page::CACHEABLE;
707   if (attr.type == T::Buffered()) lower |= Page::BUFFERED;
708   if (attr.type == T::Uncached()) lower |= Page::NONCACHEABLE;
709
710   if (!(attr.kern & K::Global()))
711     lower |= 0x800;
712
713   if (!(attr.rights & R::W()))
714     lower |= 0x080;
715
716   if (attr.rights & R::U())
717     lower |= 0x040;
718
719   if (!(attr.rights & R::X()))
720     lower |= 0x0040000000000000;
721
722   return lower;
723 }
724
725 PUBLIC inline
726 Page::Attr
727 Pte_ptr::attribs() const
728 {
729   typedef L4_fpage::Rights R;
730   typedef Page::Type T;
731   typedef Page::Kern K;
732
733   auto c = access_once(pte);
734
735   R rights = R::R();
736   if (!(c & 0x80))
737     rights |= R::W();
738   if (c & 0x40)
739     rights |= R::U();
740
741   if (!(c & 0x0040000000000000))
742     rights |= R::X();
743
744   T type;
745   switch (c & Page::Cache_mask)
746     {
747     default:
748     case Page::CACHEABLE: type = T::Normal(); break;
749     case Page::BUFFERED:  type = T::Buffered(); break;
750     case Page::NONCACHEABLE: type = T::Uncached(); break;
751     }
752
753   K k(0);
754   if (!(c & 0x800))
755     k |= K::Global();
756
757   return Page::Attr(rights, type, k);
758 }
759
760 PUBLIC inline NEEDS[Pte_ptr::_attribs]
761 void
762 Pte_ptr::create_page(Phys_mem_addr addr, Page::Attr attr)
763 {
764   Entry p = 0x400 | _attribs(attr) | cxx::int_value<Phys_mem_addr>(addr);
765   if (level == Pdir::Depth)
766     p |= 3;
767   else
768     p |= 1;
769
770   write_now(pte, p);
771 }
772
773 PUBLIC inline
774 bool
775 Pte_ptr::add_attribs(Page::Attr attr)
776 {
777   typedef L4_fpage::Rights R;
778
779   Entry n_attr = 0;
780
781   if (attr.rights & R::W())
782     n_attr = 0x80;
783
784   if (attr.rights & R::X())
785     n_attr |= 0x0040000000000000;
786
787   if (!n_attr)
788     return false;
789
790   auto p = access_once(pte);
791   if (p & n_attr)
792     {
793       p &= ~n_attr;
794       write_now(pte, p);
795       return true;
796     }
797   return false;
798 }
799
800 PUBLIC inline
801 Page::Rights
802 Pte_ptr::access_flags() const
803 { return Page::Rights(0); }
804
805 PUBLIC inline
806 void
807 Pte_ptr::del_rights(L4_fpage::Rights r)
808 {
809   Entry n_attr = 0;
810   if (r & L4_fpage::Rights::W())
811     n_attr = 0x80;
812
813   if (r & L4_fpage::Rights::X())
814     n_attr |= 0x0040000000000000;
815
816   if (!n_attr)
817     return;
818
819   auto p = access_once(pte);
820   if ((p & n_attr) != n_attr)
821     {
822       p |= n_attr;
823       write_now(pte, p);
824     }
825 }
826
827
828
829
830 //---------------------------------------------------------------------------
831 IMPLEMENTATION [arm && (armv6 || armv7) && !arm_lpae]:
832
833 PUBLIC static inline
834 Mword PF::is_alignment_error(Mword error)
835 { return (error & 0xf0040f) == 0x400001; }
836
837 //---------------------------------------------------------------------------
838 IMPLEMENTATION [arm && (armv6 || armv7) && arm_lpae]:
839
840 PUBLIC static inline
841 Mword PF::is_alignment_error(Mword error)
842 { return (error & 0xf0003f) == 0x400021; }
843
844 //---------------------------------------------------------------------------
845 IMPLEMENTATION [arm && (armv6 || armv7)]:
846
847 PUBLIC inline NEEDS[Pte_ptr::_attribs, Pte_ptr::_attribs_mask]
848 void
849 Pte_ptr::set_attribs(Page::Attr attr)
850 {
851   Entry p = access_once(pte);
852   p = (p & _attribs_mask()) | _attribs(attr);
853   write_now(pte, p);
854 }
855
856
857
858 //---------------------------------------------------------------------------
859 IMPLEMENTATION [arm && !arm_lpae]:
860
861 IMPLEMENT inline
862 Mword PF::is_translation_error( Mword error )
863 {
864   return (error & 0x0d/*FSR_STATUS_MASK*/) == 0x05/*FSR_TRANSL*/;
865 }
866
867 //---------------------------------------------------------------------------
868 IMPLEMENTATION [arm && arm_lpae]:
869
870 IMPLEMENT inline
871 Mword PF::is_translation_error(Mword error)
872 {
873   return (error & 0x3c) == 0x04;
874 }
875
876 //---------------------------------------------------------------------------
877 IMPLEMENTATION [arm]:
878
879 IMPLEMENT inline
880 Mword PF::is_usermode_error( Mword error )
881 {
882   return (error & 0x00010000/*PF_USERMODE*/);
883 }
884
885 IMPLEMENT inline
886 Mword PF::is_read_error( Mword error )
887 {
888   return !(error & (1UL << 11));
889 }
890
891 IMPLEMENT inline
892 Mword PF::addr_to_msgword0( Address pfa, Mword error )
893 {
894   Mword a = pfa & ~3;
895   if(is_translation_error( error ))
896     a |= 1;
897   if(!is_read_error(error))
898     a |= 2;
899   return a;
900 }
901