- // static int rmap_dirs_per_page = Arch::page_size / sizeof(RMapNode *);
- static int rmap_dir_shift = Arch::page_shift - _LL_LONG_LOGBYTES;
- static int rmap_lastlevel_shift = rmap_shift + Arch::page_shift;
-
- static int rmap_dir_levels = (64 - rmap_lastlevel_shift - 1)
- / rmap_dir_shift;
-
- static int rmap_toplevel_shift = rmap_dir_shift * rmap_dir_levels
- + rmap_lastlevel_shift;
-
- static inline u64 addr_to_dir_offset(u64 addr, int shift)
- {
- return (addr >> shift) & ((1ULL << rmap_dir_shift) - 1);
- }
-
- static inline u64 addr_to_offset(u64 addr)
- {
- return (addr >> Arch::page_shift) & ((1ULL << rmap_shift) - 1);
- }
-
- RMapTable::RMapTable()
- {
- // All RMap tables must have at least one dir level, in order to
- // simplify the code. If it turns out that a lot of memory is
- // wasted due to this, the code could be made more complex in order
- // to allow one-level rmap tables. Currently, on 4KiB-page systems,
- // a page is wasted per under-512KiB aspace (32-bit) or under-256KiB
- // aspace (64-bit).
- //
- // Dynamic levels would have to be implemented in generic-pte for
- // the wastage here to be meaningful.
-
- toplevel_shift = rmap_lastlevel_shift;
- toplevel = Mem::alloc_pages(1);
- bzero(toplevel, Arch::page_size);
- }
-
- RMapNode *RMapTable::get_rmap(u64 virtaddr, bool add)
- {
- assert(rmap_lock.held_by_curthread());
- int shift = toplevel_shift;
- void *table = toplevel;
-
- while (toplevel_shift < rmap_toplevel_shift &&
- (virtaddr >> (toplevel_shift + rmap_dir_shift)))
- {
- if (!add)
- return NULL;
-
- shift += rmap_dir_shift;
- toplevel_shift += rmap_dir_shift;
-
- toplevel = Mem::alloc_pages(1);
- bzero(toplevel, Arch::page_size);
-
- static_cast<void **>(toplevel)[0] = table;
- table = toplevel;
- }
-
- while (shift >= rmap_lastlevel_shift) {
- int off = addr_to_dir_offset(virtaddr, shift);
- void *new_table = static_cast<void **>(table)[off];
-
- if (!new_table) {
- new_table = Mem::alloc_pages(1);
- bzero(new_table, Arch::page_size);
- static_cast<void **>(table)[off] = new_table;
- }
-
- table = new_table;
- shift -= rmap_dir_shift;
- }
-
- assert(shift + rmap_dir_shift - rmap_shift == Arch::page_shift);
-
- int off = addr_to_offset(virtaddr);
- return &static_cast<RMapNode *>(table)[off];
- }
-