]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/include/kern/generic-pte.h
update
[polintos/scott/priv.git] / kernel / include / kern / generic-pte.h
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.
7
8 #ifndef _KERN_GENERIC_PTE_H
9 #define _KERN_GENERIC_PTE_H
10
11 #include <lowlevel/misc.h>
12 #include <lowlevel/atomic.h>
13
14 namespace Mem {
15         struct GenDirPTE {
16                 typedef u64 VirtAddr;
17                 typedef ulong PhysAddr;
18         
19                 void *raw;
20                 
21                 GenDirPTE() : raw(NULL)
22                 {
23                 }
24                 
25                 GenDirPTE(void *RAW) : raw(RAW)
26                 {
27                 }
28
29                 static uint addr_to_offset(VirtAddr addr, int shift)
30                 {
31                         int pages_per_table = Arch::page_size / sizeof(void *);
32                         return (addr >> shift) & (pages_per_table - 1);
33                 }
34         
35                 void *get_table()
36                 {
37                         return raw;
38                 }
39
40                 static GenDirPTE set_table(void *addr)
41                 {
42                         return GenDirPTE(addr);
43                 }
44
45                 bool valid_pte()
46                 {
47                         return raw;
48                 }
49                 
50                 void set_pte(GenDirPTE *table, uint offset)
51                 {
52                         table[offset] = raw;
53                 }
54                 
55                 enum {
56                         shift_per_level = Arch::page_shift - _LL_LONG_LOGBYTES,
57                 };
58         };
59
60         union GenPTE {
61                 typedef u64 VirtAddr, PhysAddr;
62                 typedef GenDirPTE DirPTE;
63
64                 struct {
65 #ifdef BITFIELD_LE
66                         PhysAddr Valid:1;
67                         PhysAddr Writeable:1;
68                         PhysAddr Readable:1;
69                         PhysAddr Executable:1;
70                         PhysAddr User:1;
71                         PhysAddr Accessed:1;
72                         PhysAddr Dirty:1;
73                         PhysAddr Uncached:1;
74                         PhysAddr FaultOnWrite:1;
75                         PhysAddr AddressOnly:1;
76                         PhysAddr Addr:54;
77 #elif defined(BITFIELD_BE)
78                         PhysAddr Addr:54;
79                         PhysAddr AddressOnly:1;
80                         PhysAddr FaultOnWrite:1;
81                         PhysAddr Dirty:1;
82                         PhysAddr Uncached:1;
83                         PhysAddr Accessed:1;
84                         PhysAddr User:1;
85                         PhysAddr Executable:1;
86                         PhysAddr Readable:1;
87                         PhysAddr Writeable:1;
88                         PhysAddr Valid:1;
89 #else
90 #error Unspecified/unrecognized bitfield endianness
91 #endif
92                 };
93
94                 PhysAddr raw;
95
96                 GenPTE(PhysAddr init) : raw(init)
97                 {
98                 }
99                 
100                 GenPTE() : raw(0)
101                 {
102                 }
103
104                 operator PhysAddr()
105                 {
106                         return raw;
107                 }
108
109                 static uint addr_to_offset(VirtAddr addr, int shift)
110                 {
111                         int pages_per_table = page_size / sizeof(PhysAddr);
112                         return (addr >> shift) & (pages_per_table - 1);
113                 }
114         
115                 PhysAddr pte_to_addr()
116                 {
117                         return raw & ~((u64)page_size - 1);
118                 }
119         
120                 static GenPTE addr_to_pte(PhysAddr phys)
121                 {
122                         return phys & ~((u64)page_size - 1);
123                 }
124                 
125                 static void flags_to_pte(Mem::PTEFlags flagsin,
126                                          Mem::PTEFlags maskin,
127                                          GenPTE &flagsout,
128                                          GenPTE &maskout)
129                 {
130                         flagsout = (PhysAddr)flagsin;
131                         maskout = (PhysAddr)maskin;
132                 }
133                 
134                 GenPTE set_flags(GenPTE mask, GenPTE flags)
135                 {
136                         return (raw & ~mask) | flags;
137                 }
138         
139                 Mem::PTEFlags pte_to_flags()
140                 {
141                         return raw & (page_size - 1);
142                 }
143         
144                 void set_pte(GenPTE *table, uint offset)
145                 {
146                         table[offset] = raw;
147                 }
148                 
149                 GenPTE xchg_pte(GenPTE *table, uint offset)
150                 {
151                         GenPTE old = table[offset];
152                         table[offset] = raw;
153                         return old;
154                 }
155                 
156                 bool valid_pte()
157                 {
158                         return Valid;
159                 }
160                 
161                 bool dirty_pte()
162                 {
163                         // FIXME: decide how to handle stacked dirty pages
164                         return false;
165                 }
166                 
167                 bool addronly_pte()
168                 {
169                         return AddressOnly;
170                 }
171                 
172                 enum {
173                         page_size = Arch::page_size,
174                         page_shift = Arch::page_shift,
175         
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,
180                         
181                         // kmap is ignored for stacked aspaces
182                         kmap_start = 0, kmap_end = 0
183                 };
184         };
185 }
186
187 #endif