1 // Generic 64-bit PTE, mainly useful for non-process aspaces on 32-bit hosts,
2 // so that files, disks, etc. can address >4GiB. 64-bit hosts will probably
3 // want to use Arch::PTE instead, especially if direct copying between page
4 // tables of similar PTEs is implemented. 32-bit embedded systems may also
5 // wish to use Arch::PTE (for both less code and smaller page tables) if all
6 // storage can be addressed with 32 bits.
8 #ifndef _KERN_GENERIC_PTE_H
9 #define _KERN_GENERIC_PTE_H
11 #include <lowlevel/misc.h>
12 #include <lowlevel/atomic.h>
17 typedef ulong PhysAddr;
21 GenDirPTE() : raw(NULL)
25 GenDirPTE(void *RAW) : raw(RAW)
29 static uint addr_to_offset(VirtAddr addr, int shift)
31 int pages_per_table = Arch::page_size / sizeof(void *);
32 return (addr >> shift) & (pages_per_table - 1);
40 static GenDirPTE set_table(void *addr)
42 return GenDirPTE(addr);
50 void set_pte(GenDirPTE *table, uint offset)
56 shift_per_level = Arch::page_shift - _LL_LONG_LOGBYTES,
61 typedef u64 VirtAddr, PhysAddr;
62 typedef GenDirPTE DirPTE;
69 PhysAddr Executable:1;
74 PhysAddr FaultOnWrite:1;
75 PhysAddr AddressOnly:1;
77 #elif defined(BITFIELD_BE)
79 PhysAddr AddressOnly:1;
80 PhysAddr FaultOnWrite:1;
85 PhysAddr Executable:1;
90 #error Unspecified/unrecognized bitfield endianness
96 GenPTE(PhysAddr init) : raw(init)
109 static uint addr_to_offset(VirtAddr addr, int shift)
111 int pages_per_table = page_size / sizeof(PhysAddr);
112 return (addr >> shift) & (pages_per_table - 1);
115 PhysAddr pte_to_addr()
117 return raw & ~((u64)page_size - 1);
120 static GenPTE addr_to_pte(PhysAddr phys)
122 return phys & ~((u64)page_size - 1);
125 static void flags_to_pte(Mem::PTEFlags flagsin,
126 Mem::PTEFlags maskin,
130 flagsout = (PhysAddr)flagsin;
131 maskout = (PhysAddr)maskin;
134 GenPTE set_flags(GenPTE mask, GenPTE flags)
136 return (raw & ~mask) | flags;
139 Mem::PTEFlags pte_to_flags()
141 return raw & (page_size - 1);
144 void set_pte(GenPTE *table, uint offset)
149 GenPTE xchg_pte(GenPTE *table, uint offset)
151 GenPTE old = table[offset];
163 // FIXME: decide how to handle stacked dirty pages
173 page_size = Arch::page_size,
174 page_shift = Arch::page_shift,
176 pages_per_table = page_size / sizeof(PhysAddr),
177 shift_per_level = page_shift - 3,
178 num_levels = 2 + (64 - page_shift - shift_per_level - 1) /
179 DirPTE::shift_per_level,
181 // kmap is ignored for stacked aspaces
182 kmap_start = 0, kmap_end = 0