]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ppc32/mem_space-ppc32.cpp
b3a81baaabf14f9b9be08b86ce5805ff7cb7b287
[l4.git] / kernel / fiasco / src / kern / ppc32 / mem_space-ppc32.cpp
1 INTERFACE [ppc32]:
2
3 #include "entry_frame.h"
4
5 extern "C"
6 Mword
7 pagefault_entry(Address, Mword, Mword, Return_frame *);
8
9 EXTENSION class Mem_space
10 {
11 public:
12
13   typedef Pdir Dir_type;
14
15   /** Return status of v_insert. */
16   enum //Status
17   {
18     Insert_ok = 0,              ///< Mapping was added successfully.
19     Insert_warn_exists,         ///< Mapping already existed
20     Insert_warn_attrib_upgrade, ///< Mapping already existed, attribs upgrade
21     Insert_err_nomem,           ///< Couldn't alloc new page table
22     Insert_err_exists           ///< A mapping already exists at the target addr
23   };
24
25   /** Attribute masks for page mappings. */
26   enum Page_attrib
27     {
28       Page_no_attribs = 0,
29       /// Page is writable.
30       Page_writable = Pt_entry::Writable,
31       Page_cacheable = 0,
32       /// Page is noncacheable.
33       Page_noncacheable = Pt_entry::Noncacheable | Pt_entry::Write_through,
34       /// it's a user page.
35       Page_user_accessible = Pt_entry::User,
36       /// Page has been referenced
37       Page_referenced = Pt_entry::Referenced,
38       /// Page is dirty
39       Page_dirty = Pt_entry::Dirty,
40       Page_references = Page_referenced | Page_dirty,
41       /// A mask which contains all mask bits
42       Page_all_attribs = Page_writable | Page_noncacheable |
43                          Page_user_accessible | Page_referenced | Page_dirty,
44     };
45
46   // Mapping utilities
47   enum                          // Definitions for map_util
48   {
49     Need_insert_tlb_flush = 0,
50     Map_page_size = Config::PAGE_SIZE,
51     Page_shift = Config::PAGE_SHIFT,
52     Map_superpage_size = Config::SUPERPAGE_SIZE,
53     Map_max_address = Mem_layout::User_max,
54     Whole_space = MWORD_BITS,
55     Identity_map = 0,
56   };
57
58   bool try_htab_fault(Address virt);
59 protected:
60   // DATA
61   Dir_type *_dir;
62 };
63
64
65 //----------------------------------------------------------------------------
66 IMPLEMENTATION [ppc32]:
67
68 #include <cstring>
69 #include <cstdio>
70 #include "cpu.h"
71 #include "kdb_ke.h"
72 #include "l4_types.h"
73 #include "mem_layout.h"
74 #include "paging.h"
75 #include "std_macros.h"
76 #include "kmem.h"
77 #include "logdefs.h"
78 #include "panic.h"
79 #include "lock_guard.h"
80 #include "cpu_lock.h"
81 #include "warn.h"
82
83
84
85
86 PUBLIC explicit inline
87 Mem_space::Mem_space(Ram_quota *q) : _quota(q), _dir(0) {}
88
89 PROTECTED inline
90 bool
91 Mem_space::initialize()
92 {
93   void *b;
94   if (EXPECT_FALSE(!(b = Kmem_alloc::allocator()
95           ->q_alloc(_quota, Config::PAGE_SHIFT))))
96     return false;
97
98   _dir = static_cast<Dir_type*>(b);
99   _dir->clear();        // initialize to zero
100   return true; // success
101 }
102
103 PROTECTED inline
104 void
105 Mem_space::sync_kernel()
106 {
107 }
108
109 PUBLIC
110 Mem_space::Mem_space(Ram_quota *q, Dir_type* pdir)
111   : _quota(q), _dir(pdir)
112 {
113   _kernel_space = this;
114   _current.cpu(0) = this;
115 }
116
117 //XXX cbass: check;
118 PUBLIC static inline
119 Mword
120 Mem_space::xlate_flush(unsigned char rights)
121 {
122   Mword a = Page_references;
123   if (rights & L4_fpage::RX)
124     a |= Page_all_attribs;
125   else if (rights & L4_fpage::W)
126     a |= Page_writable;
127
128   return a;
129 }
130
131 //XXX cbass: check;
132 PUBLIC static inline
133 Mword
134 Mem_space::is_full_flush(unsigned char rights)
135 {
136   return rights & L4_fpage::RX;
137 }
138
139 PUBLIC static inline
140 unsigned char
141 Mem_space::xlate_flush_result(Mword attribs)
142 {
143   unsigned char r = 0;
144   if (attribs & Page_referenced)
145     r |= L4_fpage::RX;
146
147   if (attribs & Page_dirty)
148     r |= L4_fpage::W;
149
150   return r;
151 }
152
153 PUBLIC inline NEEDS["cpu.h"]
154 static bool
155 Mem_space::has_superpages()
156 {
157   return Cpu::have_superpages();
158 }
159
160 //we flush tlb in htab implementation
161 PUBLIC static inline NEEDS["mem_unit.h"]
162 void
163 Mem_space::tlb_flush(bool = false)
164 {
165   //Mem_unit::tlb_flush();
166 }
167
168
169 PUBLIC inline
170 bool
171 Mem_space::set_attributes(Address virt, unsigned page_attribs)
172 {
173 /*
174   Pdir::Iter i = _dir->walk(virt);
175
176   if (!i.e->valid() || i.shift() != Config::PAGE_SHIFT)
177     return 0;
178
179   i.e->del_attr(Page::MAX_ATTRIBS);
180   i.e->add_attr(page_attribs);
181   return true;
182 */
183   NOT_IMPL_PANIC;
184   (void)virt; (void)page_attribs;
185   return false;
186 }
187
188 PROTECTED inline
189 void
190 Mem_space::destroy()
191 {}
192
193
194 /**
195  * Destructor.  Deletes the address space and unregisters it from
196  * Space_index.
197  */
198 PRIVATE
199 void
200 Mem_space::dir_shutdown()
201 {
202
203   // free ldt memory if it was allocated
204   //free_ldt_memory();
205
206   // free all page tables we have allocated for this address space
207   // except the ones in kernel space which are always shared
208   /*
209   _dir->alloc_cast<Mem_space_q_alloc>()
210     ->destroy(0, Kmem::mem_user_max, Pdir::Depth - 1,
211               Mem_space_q_alloc(_quota, Kmem_alloc::allocator()));
212 */
213   NOT_IMPL_PANIC;
214 }
215
216 IMPLEMENT inline
217 Mem_space *
218 Mem_space::current_mem_space(unsigned cpu) /// XXX: do not fix, deprecated, remove!
219 {
220   return _current.cpu(cpu);
221 }
222
223 /** Insert a page-table entry, or upgrade an existing entry with new
224     attributes.
225     @param phys Physical address (page-aligned).
226     @param virt Virtual address for which an entry should be created.
227     @param size Size of the page frame -- 4KB or 4MB.
228     @param page_attribs Attributes for the mapping (see
229                         Mem_space::Page_attrib).
230     @return Insert_ok if a new mapping was created;
231              Insert_warn_exists if the mapping already exists;
232              Insert_warn_attrib_upgrade if the mapping already existed but
233                                         attributes could be upgraded;
234              Insert_err_nomem if the mapping could not be inserted because
235                               the kernel is out of memory;
236              Insert_err_exists if the mapping could not be inserted because
237                                another mapping occupies the virtual-address
238                                range
239     @pre phys and virt need to be size-aligned according to the size argument.
240  */
241 IMPLEMENT inline
242 Mem_space::Status
243 Mem_space::v_insert(Phys_addr phys, Vaddr virt, Vsize size,
244                     unsigned page_attribs, bool /*upgrade_ignore_size*/)
245 {
246   assert(size == Size(Config::PAGE_SIZE) 
247          || size == Size(Config::SUPERPAGE_SIZE));
248 /*
249   printf("v_insert: phys %08lx virt %08lx (%s) %p\n", phys, virt, 
250          page_attribs & Page_writable?"rw":"ro", this);*/
251   Pte_base e(phys.value());
252   unsigned attribs = e.to_htab_entry(page_attribs);
253
254   Status status = v_insert_cache(&e, Virt_addr(virt).value(),
255                                  Virt_size(size).value(), attribs);
256   return status;
257 }
258
259 IMPLEMENT
260 bool
261 Mem_space::try_htab_fault(Address virt)
262 {
263   bool super;
264   Evict evict;
265   Address pte_ptr, phys;
266   Dir_type *dir = _dir;
267
268   if(virt >= Mem_layout::User_max)
269     dir = Kmem::kdir();
270
271   Pdir::Iter i = dir->walk(Addr(virt), Pdir::Super_level);
272
273   if(!i.e->valid())
274     return false;
275
276   super = i.e->is_super_page();
277
278   i = dir->walk(Addr(virt));
279
280   if(!i.e->is_htab_entry() && !super)
281     return false;
282
283   if(super && !i.e->valid())
284     {
285       i = dir->walk(Addr(virt & Config::SUPERPAGE_MASK));
286       phys = Pte_htab::pte_to_addr(i.e);
287       phys += (virt & Config::PAGE_MASK) - (phys & Config::PAGE_MASK);
288     }
289   else
290       phys = i.e->raw();
291
292   Status status;
293   // insert in htab
294   {
295      auto guard = lock_guard(cpu_lock);
296
297      status = v_insert_htab(phys, virt, &pte_ptr, &evict);
298
299      // something had to be replaced update  in cache-page table
300      if(EXPECT_FALSE(status == Insert_err_nomem)) 
301       {
302         Pte_base e(evict.phys);
303         e.to_htab_entry();
304         //printf("EVICTING: virt: %lx phys: %lx\n", evict.virt, e.raw());
305         status = v_insert_cache(&e, evict.virt, Config::PAGE_SIZE, 0, evict.dir);
306       }
307   }
308
309
310   if(EXPECT_FALSE(status != Insert_ok))
311     return false;
312
313   // set pointer in cache
314   Pte_base e(pte_ptr);
315   e.to_htab_ptr();
316   assert(e.addr());
317
318   status  = v_insert_cache(&e, virt, Config::PAGE_SIZE, 0, dir);
319
320   if(EXPECT_FALSE(status != Insert_ok))
321     return false;
322
323   return true;
324 }
325
326 /**
327  * Simple page-table lookup.
328  *
329  * @param virt Virtual address.  This address does not need to be page-aligned.
330  * @return Physical address corresponding to a.
331  */
332 PUBLIC inline NEEDS ["paging.h"]
333 Address
334 Mem_space::virt_to_phys (Address virt) const
335 {
336   return dir()->virt_to_phys(virt);
337 }
338
339 PUBLIC inline
340 virtual Address
341 Mem_space::virt_to_phys_s0(void *a) const
342 {
343   return dir()->virt_to_phys((Address)a);
344 }
345
346 PUBLIC inline
347 Address
348 Mem_space::pmem_to_phys (Address virt) const
349 {
350   return virt;
351 }
352
353
354
355 /** Look up a page-table entry.
356     @param virt Virtual address for which we try the look up.
357     @param phys Meaningful only if we find something (and return true).
358                 If not 0, we fill in the physical address of the found page
359                 frame.
360     @param page_attribs Meaningful only if we find something (and return true).
361                 If not 0, we fill in the page attributes for the found page
362                 frame (see Mem_space::Page_attrib).
363     @param size If not 0, we fill in the size of the page-table slot.  If an
364                 entry was found (and we return true), this is the size
365                 of the page frame.  If no entry was found (and we
366                 return false), this is the size of the free slot.  In
367                 either case, it is either 4KB or 4MB.
368     @return True if an entry was found, false otherwise.
369  */
370 IMPLEMENT
371 bool
372 Mem_space::v_lookup(Vaddr virt, Phys_addr *phys = 0, Size *size = 0,
373                     unsigned *page_attribs = 0)
374 {
375   Pdir::Iter i = _dir->walk(virt, Pdir::Super_level);
376
377   if(size) *size = Size(1UL << i.shift());
378
379   if(!i.e->valid())
380     return false;
381
382   unsigned shift = i.e->is_super_page() ? Config::SUPERPAGE_SHIFT
383                    : Config::PAGE_SHIFT;
384   unsigned mask = (~0UL << shift);
385
386   i = _dir->walk(virt & Addr(mask));
387
388   if(!i.e->valid())
389     return false;
390
391   if(size) *size = Size(1UL << i.shift());
392
393   if(phys || page_attribs)
394     {
395       Address addr = phys->value();
396       Pte_htab::pte_lookup(i.e, &addr, page_attribs);
397       *phys = Phys_addr(addr);
398     }
399   if(page_attribs)
400     *page_attribs = to_kernel_fmt(*page_attribs, i.e->is_htab_entry());
401
402   return true;
403 }
404
405 /** Delete page-table entries, or some of the entries' attributes.  This
406     function works for one or multiple mappings (in contrast to v_insert!).
407     @param virt Virtual address of the memory region that should be changed.
408     @param size Size of the memory region that should be changed.
409     @param page_attribs If nonzero, delete only the given page attributes.
410                         Otherwise, delete the whole entries.
411     @return Combined (bit-ORed) page attributes that were removed.  In
412             case of errors, ~Page_all_attribs is additionally bit-ORed in.
413  */
414 IMPLEMENT
415 unsigned long
416 Mem_space::v_delete(Vaddr virt, Vsize size,
417                     unsigned long page_attribs = Page_all_attribs)
418 {
419   unsigned ret = 0;
420   // delete pages from page tables
421   //printf("v_delete: %lx dir: %p\n", virt, _dir);
422   assert (size == Size(Config::PAGE_SIZE) 
423           || size == Size(Config::SUPERPAGE_SIZE));
424
425   unsigned shift = (size == Virt_size(Config::SUPERPAGE_SIZE)) ?
426                     Config::SUPERPAGE_SHIFT : Config::PAGE_SHIFT;
427
428   Address offs = Virt_addr(virt).value() & (~0UL << shift);
429   Pdir::Iter i = _dir->walk(Addr(offs));
430   Pt_entry *e = nonull_static_cast<Pt_entry*>(i.e);
431   for(offs = 0;
432       offs < ((Virt_size(size).value() / Config::PAGE_SIZE) *sizeof(Mword));
433       offs += sizeof(Mword))
434     {
435       e = reinterpret_cast<Pt_entry*>(e + offs);
436
437       if(!e->valid())
438         continue;
439
440       //in htab ?
441       if(!e->is_htab_entry())
442         {
443           ret = v_delete_htab(e->raw(), page_attribs);
444
445           if(page_attribs & Page_user_accessible)
446             v_delete_cache(e, page_attribs);
447         }
448       else
449         ret = v_delete_cache(e, page_attribs);
450     }
451
452   if(size != Virt_size(Config::SUPERPAGE_SIZE) && !(page_attribs & Page_user_accessible))
453     return ret;
454
455   //check for and delete super page
456   i = _dir->walk(virt, Pdir::Super_level);
457   i.e = 0;
458
459   return ret;
460 }
461
462 PUBLIC static inline
463 Page_number
464 Mem_space::canonize(Page_number v)
465 { return v; }