-// This is a generic pagetable implementation that most architectures
-// should be able to use as is, though architectures with weird paging
-// hardware can provide their own implementation. It corresponds to
-// mem/pagetable.cc.
-
#ifndef _KERN_PAGETABLE_H
#define _KERN_PAGETABLE_H
#include <kern/mem.h>
-#include <util/lock.h>
-#include <arch/pagetable.h>
+#include <kern/rmap.h>
namespace Mem {
- template<typename PTE>
- class PageTableImpl : public PageTable {
+ class PageTable {
public:
+ void *toplevel;
+ RMapTable rmap_table;
+ const bool is_process;
+
typedef Mem::PTEFlags Flags;
typedef System::Mem::Region Region;
typedef System::Mem::RegionWithOffset RegionWithOffset;
- typedef typename PTE::VirtAddr VirtAddr;
- typedef typename PTE::DirPTE DirPTE;
-
- private:
- // The lock of any page table may nest in the lock of any
- // aspace.
- Lock::Lock lock;
-
- // For non-process aspaces, the number of levels may be more or
- // less than what the hardware provides (in particular, large file
- // mappings on 32-bit targets will need more levels). For process
- // aspaces, num_levels must equal PTE::num_levels. Levels for
- // non-process address spaces can be added dynamically as needed.
- // Non-proc aspaces may also use a different PTE format.
-
- int num_levels;
- int toplevel_shift, lastlevel_shift;
-
- static uint pages_per_table()
+ PageTable(bool process) : is_process(process)
{
- return 1 << PTE::shift_per_level;
}
-
- static uint pages_per_dtable()
+
+ virtual ~PageTable()
{
- return 1 << DirPTE::shift_per_level;
}
- void end_map(RegionWithOffset region, PTE flags, void *table);
-
- void end_unmap(Region region, void *table);
+ // Region is virtual, offset is physical
+ virtual void map(RegionWithOffset region, Flags flags) = 0;
+ virtual void unmap(Region region) = 0;
- void end_set_flags(Region region, PTE flags, PTE mask, void *table);
-
- void rec_map(RegionWithOffset region, PTE flags,
- void *table, int shift);
+ // Sets the flags which are set in mask to their value in flags.
+ // Flags not set in mask are untouched.
- void rec_unmap(Region region, void *table, int shift);
-
- void rec_set_flags(Region region, PTE flags,
- PTE mask, void *table, int shift);
-
- public:
- PageTableImpl(bool process);
- PageTableImpl(void *table);
+ virtual void set_flags(Region region, Flags flags, Flags mask) = 0;
- virtual ~PageTableImpl();
-
- virtual void map(RegionWithOffset region, Flags flags);
- virtual void unmap(Region region);
- virtual void set_flags(Region region, Flags flags, Flags mask);
- virtual void get_mapping(u64 addr, u64 *phys, Flags *flags);
-
- virtual void get_size(u64 *size)
- {
- if (is_process)
- *size = 1ULL << (PTE::num_levels * PTE::shift_per_level);
- else
- *size = 1ULL << (64 - PTE::page_shift);
- }
+ // Returns the physical address and flags associated with a given
+ // virtual address. If flags.Valid is not set, then phys and all
+ // other flags are undefined. This function is mainly used for
+ // propagating stacked aspace PTEs.
+
+ virtual void get_mapping(u64 vaddr, u64 *phys, Flags *flags) = 0;
+
+ virtual void get_size(u64 *size) = 0;
+
+ // This is called when a PTE is replaced. It handles refcounting,
+ // dirty page queueing, and TLB invalidation. vaddr is only
+ // valid for process address spaces, so it doesn't need to be
+ // 64-bit (except on 64-bit hardware, of course). When it is
+ // known that only flags are changing, set no_release so that
+ // the page refcount is not decremented.
+
+ void kill_pte(ulong vaddr, u64 physaddr, bool dirty, bool valid,
+ bool no_release = false);
};
}