]> rtime.felk.cvut.cz Git - l4.git/blob - tools/preprocess/test/mapping.cpp
Inital import
[l4.git] / tools / preprocess / test / mapping.cpp
1 INTERFACE:
2
3 #include <flux/x86/types.h>     // for vm_offset_t, vm_size_t
4 #include "space.h"              // for space_index_t
5
6 enum mapping_type_t { Map_mem = 0, Map_io };
7
8 class mapping_tree_t;           // forward decls
9 struct mapping_s;
10
11 // 
12 // class mapping_t
13 // 
14 class mapping_t 
15 {
16   friend class mapdb_t;
17   friend class mapping_tree_t;
18   friend class jdb;
19
20   // CREATORS
21   mapping_t(const mapping_t&);  // this constructor is undefined.
22
23   // DATA
24   char _data[5];  
25 } __attribute__((packed));
26
27 class kmem_slab_t;
28 struct physframe_data;
29
30 // 
31 // class mapdb_t: The mapping database
32 // 
33 class mapdb_t
34 {
35   friend class jdb;
36
37 public:
38   enum { Size_factor = 4, 
39          Size_id_max = 8 /* can be up to 15 (4 bits) */ };
40
41 private:
42   // DATA
43   physframe_data *physframe;
44   kmem_slab_t *allocator_for_treesize[Size_id_max + 1];
45 };
46
47 IMPLEMENTATION:
48
49 // The mapping database.
50
51 // This implementation encodes mapping trees in very compact arrays of
52 // fixed sizes, prefixed by a tree header (mapping_tree_t).  Array
53 // sizes can vary from 4 mappings to 4<<15 mappings.  For each size,
54 // we set up a slab allocator.  To grow or shrink the size of an
55 // array, we have to allocate a larger or smaller tree from the
56 // corresponding allocator and then copy the array elements.
57 // 
58 // The array elements (mapping_t) contain a tree depth element.  This
59 // depth and the relative position in the array is all information we
60 // need to derive tree structure information.  Here is an example:
61 // 
62 // array
63 // element   depth
64 // number    value    comment
65 // --------------------------
66 // 0         0        Sigma0 mapping
67 // 1         1        child of element #0 with depth 0
68 // 2         2        child of element #1 with depth 1
69 // 3         2        child of element #1 with depth 1
70 // 4         3        child of element #3 with depth 2
71 // 5         2        child of element #1 with depth 1
72 // 6         3        child of element #5 with depth 2
73 // 7         1        child of element #0 with depth 0
74 // 
75 // This array is a pre-order encoding of the following tree:
76 // 
77 //                   0
78 //                /     \ 
79 //               1       7
80 //            /  |  \                   
81 //           2   3   5
82 //               |   |
83 //               4   6
84                    
85 // IDEAS for enhancing this implementation: 
86
87 // We often have to find a tree header corresponding to a mapping.
88 // Currently, we do this by iterating backwards over the array
89 // containing the mappings until we find the Sigma0 mapping, from
90 // whose address we can compute the address of the tree header.  If
91 // this becomes a problem, we could add one more byte to the mappings
92 // with a hint (negative array offset) where to find the sigma0
93 // mapping.  (If the hint value overflows, just iterate using the hint
94 // value of the mapping we find with the first hint value.)  Another
95 // idea (from Adam) would be to just look up the tree header by using
96 // the physical address from the page-table lookup, but we would need
97 // to change the interface of the mapping database for that (pass in
98 // the physical address at all times), or we would have to include the
99 // physical address (or just the address of the tree header) in the
100 // mapdb_t-user-visible mapping_t (which could be different from the
101 // internal tree representation).  (XXX: Implementing one of these
102 // ideas is probably worthwile doing!)
103
104 // Instead of copying whole trees around when they grow or shrink a
105 // lot, or copying parts of trees when inserting an element, we could
106 // give up the array representation and add a "next" pointer to the
107 // elements -- that is, keep the tree of mappings in a
108 // pre-order-encoded singly-linked list (credits to: Christan Szmajda
109 // and Adam Wiggins).  24 bits would probably be enough to encode that
110 // pointer.  Disadvantages: Mapping entries would be larger, and the
111 // cache-friendly space-locality of tree entries would be lost.
112
113 // The current handling of superpages sucks rocks both in this module
114 // and in our user, ipc_map.cc.  We could support multiple page sizes
115 // by not using a physframe[] array only for the largest page size.
116 // (Entries of that array point to the top-level mappings -- sigma0
117 // mappings.)  Mapping-tree entries would then either be regular
118 // mappings or pointers to an array of mappings of the next-smaller
119 // size. (credits: Christan Szmajda)
120 //
121 //        physframe[]
122 //        -------------------------------
123 //        | | | | | | | | | | | | | | | | array of ptr to 4M mapping_tree_t's
124 //        ---|---------------------------
125 //           |
126 //           v a mapping_tree_t
127 //           ---------------
128 //           |             | tree header
129 //           |-------------|
130 //           |             | mapping_t *or* ptr to array of ptr to 4K trees
131 //           |             | e.g.
132 //           |      ----------------|
133 //           |             |        v array of ptr to 4M mapping_tree_t's
134 //           ---------------        -------------------------------
135 //                                  | | | | | | | | | | | | | | | |
136 //                                  ---|---------------------------
137 //                                     |
138 //                                     v a mapping_tree_t
139 //                                     ---------------
140 //                                     |             | tree header
141 //                                     |-------------|
142 //                                     |             | mapping_t
143 //                                     |             |
144 //                                     |             |
145 //                                     |             |
146 //                                     ---------------
147 //-
148
149 #include <assert.h>
150 #include <string.h>
151
152 #ifndef offsetof                // should be defined in stddef.h, but isn't
153 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
154 #endif
155
156 // For implementation of mapping_t functions, we need mapping_tree_t.
157
158 // 
159 // class mapping_tree_t
160 // 
161 class mapping_tree_t
162 {
163   friend class mapping_t;
164   friend class mapdb_t;
165   friend class jdb;
166
167   // DATA
168   unsigned _count: 16;
169   unsigned _size_id: 4;
170   unsigned _empty_count: 11;
171   unsigned _unused: 1;          // make this 32 bits to avoid a compiler bug
172
173   mapping_t _mappings[0] __attribute__((packed));
174
175 } __attribute__((packed));
176
177 // public routines with inline implementations
178 inline
179 unsigned 
180 mapping_tree_t::number_of_entries() const
181 {
182   return mapdb_t::Size_factor << _size_id;
183 }
184
185 inline
186 mapping_t *
187 mapping_tree_t::mappings()
188 {
189   return & _mappings[0];
190 }
191
192 // Define (otherwise private) stuff needed by public inline
193 // functions.
194
195 enum mapping_depth_t 
196 {
197   Depth_sigma0_mapping = 0, Depth_max = 253, 
198   Depth_empty = 254, Depth_end = 255 
199 };
200
201 struct mapping_s
202 {
203   unsigned space:11;
204   unsigned size:1;
205   unsigned address:20;
206   mapping_depth_t depth:8;
207   unsigned do_not_touch: 24; // make this 64 bits, and make sure the
208                              // compiler never touches memory after the 
209                              // real data
210 };
211
212 inline 
213 mapping_t::mapping_t()
214 {}
215
216 inline 
217 mapping_s *
218 mapping_t::data()
219 {
220   return reinterpret_cast<mapping_s*>(_data);
221 }
222
223 PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
224 space_index_t 
225 mapping_t::space()
226 {
227   return space_index_t(data()->space);
228 }
229
230 PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
231 vm_offset_t 
232 mapping_t::vaddr()
233 {
234   return (data()->address << PAGE_SHIFT);
235 }
236
237 PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
238 vm_size_t 
239 mapping_t::size()
240 {
241   if ( data()->size ) 
242     return SUPERPAGE_SIZE;
243   else 
244     return PAGE_SIZE;
245 }
246
247 PUBLIC inline 
248 mapping_type_t 
249 mapping_t::type()
250 {
251   // return data()->type;;
252   return Map_mem;
253 }
254
255 inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
256 bool
257 mapping_t::unused()
258 {
259   return (data()->depth > Depth_max);
260 }
261
262 mapping_tree_t *
263 mapping_t::tree()
264 {
265   mapping_t *m = this;
266
267   while (m->data()->depth > Depth_sigma0_mapping)
268     {
269       // jump in bigger steps if this is not a free mapping
270       if (! m->unused())
271         {
272           m -= m->data()->depth;
273           continue;
274         }
275
276       m--;
277     }
278
279   return reinterpret_cast<mapping_tree_t *>
280     (reinterpret_cast<char *>(m) - offsetof(mapping_tree_t, _mappings));
281 }
282
283 // 
284 // more of class mapping_t
285 // 
286
287 PUBLIC mapping_t *
288 mapping_t::parent()
289 {
290   if (data()->depth <= Depth_sigma0_mapping)
291     {
292       // Sigma0 mappings don't have a parent.
293       return 0;
294     }
295
296   // Iterate over mapping entries of this tree backwards until we find
297   // an entry with a depth smaller than ours.  (We assume here that
298   // "special" depths (empty, end) are larger than Depth_max.)
299   mapping_t *m = this - 1;
300
301   while (m->data()->depth >= data()->depth)
302     m--;
303
304   return m;
305 }
306
307 PUBLIC mapping_t *
308 mapping_t::next_iter()
309 {
310   mapping_tree_t *t = tree();
311   mapping_t *last_in_tree = t->mappings() + t->number_of_entries() - 1;
312
313   mapping_t *m = this;
314
315   // Look for a valid element in the tree structure.
316   while (m != last_in_tree)
317     {
318       m++;
319       if (! m->unused())
320         return m;               // Found a valid entry!
321
322       // Don't iterate to end of tree if this is the last tree entry.
323       if (m->data()->depth == Depth_end)
324         return 0;
325     }
326
327   // Couldn't find a non-empty element behind ourselves in the tree
328   // structure.
329   return 0;
330 }
331
332 PUBLIC mapping_t *
333 mapping_t::next_child(mapping_t *parent)
334 {
335   // Find the next valid entry in the tree structure.
336   mapping_t *m = next_iter();
337
338   // If we didn't find an entry, or if the entry cannot be a child of
339   // "parent", return 0
340   if (m == 0
341       || m->data()->depth <= parent->data()->depth)
342     return 0;
343
344   return m;                     // Found!
345 }
346
347 // helpers
348
349 // 
350 // class mapping_tree_t
351 // 
352
353 // This function copies the elements of mapping tree src to mapping
354 // tree dst, ignoring empty elements (that is, compressing the
355 // source tree.  In-place compression is supported.
356 PUBLIC static void 
357 mapping_tree_t::copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src)
358 {
359   dst->_count = 0;
360   dst->_empty_count = 0;
361   
362   mapping_t *d = dst->mappings();     
363   
364   for (mapping_t *s = src->mappings();
365        s < src->mappings() + src->number_of_entries();
366        s++)
367     {
368       if (s->unused())          // entry free
369         {
370           if (s->data()->depth == Depth_end)
371             break;
372           continue;
373         }
374       
375       *d++ = *s;
376       dst->_count += 1;
377     }
378   
379   assert (dst->_count == src->_count);
380   assert (d < dst->mappings() + dst->number_of_entries());
381   
382   d->data()->depth = Depth_end;
383   dst->mappings()[dst->number_of_entries() - 1].data()->depth = Depth_end;
384 } // copy_compact_tree()
385
386 // 
387 // class mapdb
388 // 
389
390 #include "lock.h"
391 #include "kmem_slab.h"
392
393 struct physframe_data {
394   mapping_tree_t *tree;
395   helping_lock_t lock;
396 };
397
398 PUBLIC
399 mapdb_t::mapdb_t()
400 {
401   vm_offset_t page_number = kmem::info()->main_memory.high / PAGE_SIZE + 1;
402   
403   // allocate physframe array
404   check ( physframe = reinterpret_cast<physframe_data *>
405           (kmem::alloc(page_number * sizeof(physframe_data))) );
406
407   memset(physframe, 0, page_number * sizeof(physframe_data));
408
409   // create a slab for each mapping tree size
410   for (int slab_number = 0;
411        slab_number <= Size_id_max;
412        slab_number++ )
413     {
414       unsigned elem_size = 
415         (Size_factor << slab_number) * sizeof(mapping_t) 
416         + sizeof(mapping_tree_t);
417
418       allocator_for_treesize[slab_number] =
419         new kmem_slab_t(((PAGE_SIZE / elem_size) < 40
420                          ? 8*PAGE_SIZE : PAGE_SIZE),
421                         elem_size, 1);
422     }
423
424   // create a sigma0 mapping for all physical pages
425   for (unsigned page_id = 0; page_id < page_number; page_id++)
426     {
427       mapping_tree_t *t;
428       check( (t = physframe[page_id].tree
429               = reinterpret_cast<mapping_tree_t*>
430                   (allocator_for_treesize[0]->alloc())) );
431       
432       t->_count = 1;            // 1 valid mapping
433       t->_size_id = 0;          // size is equal to Size_factor << 0
434       t->_empty_count = 0;      // no gaps in tree representation
435
436       t->mappings()[0].data()->depth = Depth_sigma0_mapping;
437       t->mappings()[0].data()->address = page_id;
438       t->mappings()[0].data()->space = config::sigma0_taskno;
439       t->mappings()[0].data()->size = 0;
440
441       t->mappings()[1].data()->depth = Depth_end;
442
443       // We also always set the end tag on last entry so that we can
444       // check whether it has been overwritten.
445       t->mappings()[t->number_of_entries() - 1].data()->depth = Depth_end;
446     }    
447 } // mapdb_t()
448
449
450 // insert a new mapping entry with the given values as child of
451 // "parent" After locating the right place for the new entry, it will
452 // be stored there (if this place is empty) or the following entries
453 // moved by one entry.
454
455 // We assume that there is at least one free entry at the end of the
456 // array so that at least one insert() operation can succeed between a
457 // lock()/free() pair of calls.  This is guaranteed by the free()
458 // operation which allocates a larger tree if the current one becomes
459 // to small.
460 PUBLIC mapping_t *
461 mapdb_t::insert(mapping_t *parent,
462                 space_t *space, 
463                 vm_offset_t va, 
464                 vm_size_t size,
465                 mapping_type_t type)
466 {
467   assert(type == Map_mem);      // we don't yet support Map_io
468
469   mapping_tree_t *t = parent->tree();
470
471   // We cannot continue if the last array entry is not free.  This
472   // only happens if an earlier call to free() with this mapping tree
473   // couldn't allocate a bigger array.  In this case, signal an
474   // out-of-memory condition.
475   if (! t->mappings()[t->number_of_entries() - 1].unused())
476     return 0;
477
478   // If the parent mapping already has the maximum depth, we cannot
479   // insert a child.
480   if (parent->data()->depth == Depth_max)
481     return 0;
482
483   mapping_t *insert = 0;
484
485   bool 
486     found_free_entry = false,
487     need_to_move = false;
488
489   mapping_t temp;
490
491   // Find a free entry in the array encoding the tree, and find the
492   // insertion point for the new entry.  These two entries might not
493   // be equivalent, so we may need to move entries backwards in the
494   // array.  In this implementation, we move entries as we traverse
495   // the array, instead of doing one big memmove
496   for (mapping_t *m = parent + 1;
497        m < t->mappings() + t->number_of_entries();
498        m++)
499     {
500       if (m->unused())
501         {
502           // We found a free entry in the tree -- allocate it.
503           found_free_entry = true;
504           t->_count += 1;
505
506           // Did we find an empty element != the end tag?
507           if (m->data()->depth == Depth_empty)
508             {
509               t->_empty_count -= 1;
510             }
511           // Else we have found the end tag.  If there is another
512           // array entry left, apply a new end tag to the array
513           else if (m + 1 < t->mappings() + t->number_of_entries())
514             {
515               (m + 1)->data()->depth = Depth_end;
516             }
517
518           // if we haven't identified a place for inserting the new
519           // element, this is it.
520           if (! need_to_move)
521             insert = m;
522         }
523       else if (! need_to_move
524                && m->data()->depth <= parent->data()->depth)
525         {
526           // we found a non-descendant of ourselves -- need to make
527           // space for new child
528           need_to_move = true;
529           insert = m;
530           temp = *insert;
531
532           continue;
533         }
534
535       if (need_to_move)
536         {
537           // replace *m with temp (which used to be *(m - 1); but 
538           // *(m - 1) has since been overwritten), and load temp with 
539           // the old value of *m
540           mapping_t temp2;
541
542           temp2 = *m;
543           *m = temp;
544           temp = temp2;
545         }
546
547       if (found_free_entry)
548         break;
549     }
550
551   assert(insert && found_free_entry);
552
553   // found a place to insert new child.
554   insert->data()->depth = mapping_depth_t(parent->data()->depth + 1);
555   insert->data()->address = va >> PAGE_SHIFT;
556   insert->data()->space = space->space();
557   insert->data()->size = (size == SUPERPAGE_SIZE);
558
559   return insert;
560 } // insert()
561
562 PUBLIC mapping_t *
563 mapdb_t::lookup(space_t *space,
564                 vm_offset_t va,
565                 mapping_type_t type)
566 {
567   vm_offset_t phys = space->virt_to_phys(va);
568
569   if (phys == 0xffffffff)
570     return 0;
571
572   mapping_tree_t *t;
573
574   // get and lock the tree.
575   // XXX For now, use a simple lock with helping.  Later
576   // unify locking with our request scheme.
577   physframe[phys >> PAGE_SHIFT].lock.lock();
578   
579   t = physframe[phys >> PAGE_SHIFT].tree;
580   assert(t);
581
582   mapping_t *m;
583
584   for (m = t->mappings();
585        m->data()->depth != Depth_end
586          && m < t->mappings() + t->number_of_entries();
587        m++)
588     {
589       if (m->data()->space == space->space()
590           && m->data()->address == va >> PAGE_SHIFT)
591         {
592           // found!
593           return m;
594         }
595     }
596
597   // not found -- unlock tree
598   physframe[phys >> PAGE_SHIFT].lock.clear();
599
600   return 0;
601 } // lookup()
602
603 PUBLIC void 
604 mapdb_t::free(mapping_t* mapping_of_tree)
605 {
606   mapping_tree_t *t = mapping_of_tree->tree();
607
608   // We assume that the zeroth mapping of the tree is a sigma0
609   // mapping, that is, its virtual address == the page's physical
610   // address.
611   vm_offset_t phys_pno = t->mappings()[0].data()->address;
612
613   // We are the owner of the tree lock.
614   assert(physframe[phys_pno].lock.lock_owner() == current());
615
616   // Before we unlock the tree, we need to make sure that there is
617   // room for at least one new mapping.  In particular, this means
618   // that the last entry of the array encoding the tree must be free.
619
620   // (1) When we use up less than a quarter of all entries of the
621   // array encoding the tree, copy to a smaller tree.  Otherwise, (2)
622   // if the last entry is free, do nothing.  Otherwise, (3) if less
623   // than 3/4 of the entries are used, compress the tree.  Otherwise,
624   // (4) copy to a larger tree.
625
626   bool maybe_out_of_memory = false;
627
628   do // (this is not actually a loop, just a block we can "break" out of)
629     {
630       // (1) Do we need to allocate a smaller tree?
631       if (t->_size_id > 0       // must not be smallest size
632           && (t->_count << 2) < t->number_of_entries())
633         {
634           mapping_tree_t *new_t = 
635             reinterpret_cast<mapping_tree_t *>
636               (allocator_for_treesize[t->_size_id - 1]->alloc());
637
638           if (new_t)
639             {
640               // XXX should be asserted by allocator:
641               new_t->_size_id = t->_size_id - 1; 
642               new_t->mappings()[new_t->number_of_entries() - 1].data()->depth 
643                 = Depth_end;
644               
645               mapping_tree_t::copy_compact_tree(new_t, t);
646               
647               // Register new tree.
648               physframe[phys_pno].tree = new_t;
649               
650               allocator_for_treesize[t->_size_id]->free(t);
651               t = new_t;
652               
653               break;
654             }
655         }
656
657       // (2) Is last entry is free?
658       if (t->mappings()[t->number_of_entries() - 1].unused())
659         break;                  // OK, last entry is free.
660
661       // Last entry is not free -- either compress current array
662       // (i.e., move free entries to end of array), or allocate bigger
663       // array.
664
665       // (3) Should we compress the tree?  
666       // We also try to compress if we cannot allocate a bigger
667       // tree because there is no bigger tree size.
668       if (t->_count < (t->number_of_entries() >> 2)
669                       + (t->number_of_entries() >> 1)
670           || t->_size_id == Size_id_max) // cannot enlarge?
671         {
672           if (t->_size_id == Size_id_max)
673             maybe_out_of_memory = true;
674
675           mapping_tree_t::copy_compact_tree(t, t); // in-place compression
676
677           break;
678         }
679
680       // (4) OK, allocate a bigger array.
681
682       mapping_tree_t *new_t = 
683         reinterpret_cast<mapping_tree_t*>
684           (allocator_for_treesize[t->_size_id + 1]->alloc());
685
686       if (new_t)
687         {
688           // XXX should be asserted by allocator:
689           new_t->_size_id = t->_size_id + 1; 
690           new_t->mappings()[new_t->number_of_entries() - 1].data()->depth 
691             = Depth_end;
692
693           mapping_tree_t::copy_compact_tree(new_t, t);
694
695           // Register new tree. 
696           physframe[phys_pno].tree = new_t;
697           
698           allocator_for_treesize[t->_size_id]->free(t);
699           t = new_t;
700         }
701       else
702         {
703           // out of memory -- just do tree compression and hope that helps.
704           maybe_out_of_memory = true;
705
706           mapping_tree_t::copy_compact_tree(t, t); // in-place compression
707         }
708     } 
709   while (false);
710
711   // The last entry of the tree should now be free -- exept if we're
712   // out of memory.
713   assert(t->mappings()[t->number_of_entries() - 1].unused()
714          || maybe_out_of_memory);
715
716   // Unlock tree.
717   physframe[phys_pno].lock.clear();
718 } // free()
719
720 // Delete mappings from a tree.  This is easy to do: We just have to
721 // iterate over the array encoding the tree.
722 PUBLIC bool 
723 mapdb_t::flush(mapping_t *m, bool me_too)
724 {
725   mapping_tree_t *t = m->tree();
726   mapping_t *start_of_deletions = m;
727   unsigned m_depth = m->data()->depth;
728   unsigned deleted = 0, empty_elems_passed = 0;
729
730   if (me_too)
731     {
732       m->data()->depth = Depth_empty;
733       t->_count -= 1;
734       deleted++;
735     }
736   else
737     start_of_deletions++;
738
739   m++;
740
741   for (;
742        m < t->mappings() + t->number_of_entries()
743          && m->data()->depth != Depth_end;
744        m++)
745     {
746       if (unsigned (m->data()->depth) <= m_depth)
747         {
748           // Found another data element -- stop deleting.  Since we
749           // created holes in the tree representation, account for it.
750           t->_empty_count += deleted;
751
752           return true;
753         }
754
755       if (m->data()->depth == Depth_empty)
756         {
757           empty_elems_passed++;
758           continue;
759         }
760
761       // Delete the element.
762       m->data()->depth = Depth_empty;
763       t->_count -= 1;
764       deleted++;
765     }
766
767   // We deleted stuff at the end of the array -- move end tag
768   if (start_of_deletions < t->mappings() + t->number_of_entries())
769     {
770       start_of_deletions->data()->depth = Depth_end;
771
772       // also, reduce number of free entries
773       t->_empty_count -= empty_elems_passed;
774     }
775
776   return true;
777 } // flush()
778
779 PUBLIC void 
780 mapdb_t::grant(mapping_t *m, space_t *new_space, vm_offset_t va)
781 {
782   m->data()->space = new_space->space();
783   m->data()->address = va >> PAGE_SHIFT;
784 } // grant()