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