]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/paging-ia32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / paging-ia32.cpp
1 INTERFACE [ia32 || amd64 || ux]:
2
3 #include "types.h"
4 #include "config.h"
5
6
7 EXTENSION class Page
8 {
9 public:
10   enum Attribs_enum
11   {
12     MAX_ATTRIBS   = 0x00000006,
13     Cache_mask    = 0x00000018, ///< Cache attrbute mask
14     CACHEABLE     = 0x00000000,
15     BUFFERED      = 0x00000010,
16     NONCACHEABLE  = 0x00000018,
17   };
18 };
19
20 EXTENSION class Pt_entry
21 {
22 private:
23   static Unsigned32 _cpu_global;
24   static unsigned _super_level;
25   static bool _have_superpages;
26 };
27
28 EXTENSION class Pte_ptr : private Pt_entry
29 {
30 public:
31   using Pt_entry::Super_level;
32 };
33
34
35 //---------------------------------------------------------------------------
36 IMPLEMENTATION [ia32 || amd64 || ux]:
37
38 #include "atomic.h"
39
40 bool Pt_entry::_have_superpages;
41 unsigned  Pt_entry::_super_level;
42
43 PUBLIC static inline
44 void
45 Pt_entry::have_superpages(bool yes)
46 {
47   _have_superpages = yes;
48   _super_level = yes ? Super_level : (Super_level + 1);
49 }
50
51 PUBLIC static inline
52 unsigned
53 Pt_entry::super_level()
54 { return _super_level; }
55
56
57 PUBLIC inline
58 bool
59 Pte_ptr::is_valid() const
60 { return *pte & Valid; }
61
62 PUBLIC inline
63 bool
64 Pte_ptr::is_leaf() const
65 { return level == Pdir::Depth || (*pte & Pse_bit); }
66
67 /**
68  * \pre is_leaf() == false
69  */
70 PUBLIC inline
71 Mword
72 Pte_ptr::next_level() const
73 { return cxx::mask_lsb(*pte, (unsigned)Config::PAGE_SHIFT); }
74
75 /**
76  * \pre cxx::get_lsb(phys_addr, Config::PAGE_SHIFT) == 0
77  */
78 PUBLIC inline
79 void
80 Pte_ptr::set_next_level(Mword phys_addr)
81 { *pte = phys_addr | Valid | User | Writable; }
82
83 PUBLIC inline
84 void
85 Pte_ptr::set_page(Mword phys, Mword attr)
86 {
87   Mword v = phys | Valid | attr;
88   if (level < Pdir::Depth)
89     v |= Pse_bit;
90   *pte = v;
91 }
92
93 PUBLIC inline
94 Pte_ptr const &
95 Pte_ptr::operator ++ ()
96 {
97   ++pte;
98   return *this;
99 }
100
101 PUBLIC inline
102 Mword
103 Pte_ptr::page_addr() const
104 { return cxx::mask_lsb(*pte, Pdir::page_order_for_level(level)) & ~Mword(XD); }
105
106
107 PUBLIC inline
108 void
109 Pte_ptr::set_attribs(Page::Attr attr)
110 {
111   typedef L4_fpage::Rights R;
112   typedef Page::Type T;
113   typedef Page::Kern K;
114   Mword r = 0;
115   if (attr.rights & R::W()) r |= Writable;
116   if (attr.rights & R::U()) r |= User;
117   if (!(attr.rights & R::X())) r |= XD;
118   if (attr.type == T::Normal()) r |= Page::CACHEABLE;
119   if (attr.type == T::Buffered()) r |= Page::BUFFERED;
120   if (attr.type == T::Uncached()) r |= Page::NONCACHEABLE;
121   if (attr.kern & K::Global()) r |= global();
122   *pte = (*pte & ~(ATTRIBS_MASK | Page::Cache_mask)) | r;
123 }
124
125 PUBLIC inline
126 void
127 Pte_ptr::create_page(Phys_mem_addr addr, Page::Attr attr)
128 {
129   Mword r = (level < Pdir::Depth) ? (Mword)Pse_bit : 0;
130   typedef L4_fpage::Rights R;
131   typedef Page::Type T;
132   typedef Page::Kern K;
133   if (attr.rights & R::W()) r |= Writable;
134   if (attr.rights & R::U()) r |= User;
135   if (!(attr.rights & R::X())) r |= XD;
136   if (attr.type == T::Normal()) r |= Page::CACHEABLE;
137   if (attr.type == T::Buffered()) r |= Page::BUFFERED;
138   if (attr.type == T::Uncached()) r |= Page::NONCACHEABLE;
139   if (attr.kern & K::Global()) r |= global();
140   *pte = cxx::int_value<Phys_mem_addr>(addr) | r | Valid;
141 }
142
143 PUBLIC inline
144 Page::Attr
145 Pte_ptr::attribs() const
146 {
147   typedef L4_fpage::Rights R;
148   typedef Page::Type T;
149
150   Mword _raw = *pte;
151   R r = R::R();
152   if (_raw & Writable) r |= R::W();
153   if (_raw & User) r |= R::U();
154   if (!(_raw & XD)) r |= R::X();
155
156   T t;
157   switch (_raw & Page::Cache_mask)
158     {
159     default:
160     case Page::CACHEABLE:    t = T::Normal(); break;
161     case Page::BUFFERED:     t = T::Buffered(); break;
162     case Page::NONCACHEABLE: t = T::Uncached(); break;
163     }
164   // do not care for kernel special flags, as this is used for user
165   // level mappings
166   return Page::Attr(r, t);
167 }
168
169 PUBLIC inline
170 bool
171 Pte_ptr::add_attribs(Page::Attr attr)
172 {
173   typedef L4_fpage::Rights R;
174   unsigned long a = 0;
175
176   if (attr.rights & R::W())
177     a = Writable;
178
179   if (attr.rights & R::X())
180     a |= XD;
181
182   if (!a)
183     return false;
184
185   auto p = access_once(pte);
186   auto o = p;
187   p ^= XD;
188   p |= a;
189   p ^= XD;
190
191   if (o != p)
192     {
193       write_now(pte, p);
194       return true;
195     }
196   return false;
197 }
198
199 PUBLIC inline
200 void
201 Pte_ptr::add_attribs(Mword attr)
202 { *pte |= attr; }
203
204 PUBLIC inline
205 unsigned char
206 Pte_ptr::page_order() const
207 { return Pdir::page_order_for_level(level); }
208
209 PUBLIC inline NEEDS["atomic.h"]
210 L4_fpage::Rights
211 Pte_ptr::access_flags() const
212 {
213
214   if (!is_valid())
215     return L4_fpage::Rights(0);
216
217   L4_fpage::Rights r;
218   for (;;)
219     {
220       auto raw = *pte;
221
222       if (raw & Dirty)
223         r = L4_fpage::Rights::RW();
224       else if (raw & Referenced)
225         r = L4_fpage::Rights::R();
226       else
227         return L4_fpage::Rights(0);
228
229       if (mp_cas(pte, raw, raw & ~(Dirty | Referenced)))
230         return r;
231     }
232 }
233
234 PUBLIC inline
235 void
236 Pte_ptr::clear()
237 { *pte = 0; }
238
239 PUBLIC static inline
240 void
241 Pte_ptr::write_back(void *, void *)
242 {}
243
244 PUBLIC static inline
245 void
246 Pte_ptr::write_back_if(bool)
247 {}
248
249 PUBLIC inline
250 void
251 Pte_ptr::del_attribs(Mword attr)
252 { *pte &= ~attr; }
253
254 PUBLIC inline
255 void
256 Pte_ptr::del_rights(L4_fpage::Rights r)
257 {
258   if (r & L4_fpage::Rights::W())
259     *pte &= ~Writable;
260
261   if (r & L4_fpage::Rights::X())
262     *pte |= XD;
263 }
264
265 Unsigned32 Pt_entry::_cpu_global = Pt_entry::L4_global;
266
267 PUBLIC static inline
268 void
269 Pt_entry::enable_global()
270 { _cpu_global |= Cpu_global; }
271
272 /**
273  * Global entries are entries that are not automatically flushed when the
274  * page-table base register is reloaded. They are intended for kernel data
275  * that is shared between all tasks.
276  * @return global page-table--entry flags
277  */
278 PUBLIC static inline
279 Unsigned32
280 Pt_entry::global()
281 { return _cpu_global; }
282
283
284 //--------------------------------------------------------------------------
285 #include "cpu.h"
286 #include "mem_layout.h"
287 #include "regdefs.h"
288
289 IMPLEMENT inline NEEDS["regdefs.h"]
290 Mword PF::is_translation_error(Mword error)
291 {
292   return !(error & PF_ERR_PRESENT);
293 }
294
295 IMPLEMENT inline NEEDS["regdefs.h"]
296 Mword PF::is_usermode_error(Mword error)
297 {
298   return (error & PF_ERR_USERMODE);
299 }
300
301 IMPLEMENT inline NEEDS["regdefs.h"]
302 Mword PF::is_read_error(Mword error)
303 {
304   return !(error & PF_ERR_WRITE);
305 }
306
307 IMPLEMENT inline NEEDS["regdefs.h"]
308 Mword PF::addr_to_msgword0(Address pfa, Mword error)
309 {
310   Mword v = (pfa & ~0x7) | (error &  (PF_ERR_PRESENT | PF_ERR_WRITE));
311   if (error & (1 << 4)) v |= 0x4;
312   return v;
313 }
314