]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/include/kern/generic-pte.h
Initial checkin from Perforce.
[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 FaultOnWrite:1;
74                         PhysAddr Addr:56;
75 #elif defined(BITFIELD_BE)
76                         PhysAddr Addr:56;
77                         PhysAddr FaultOnWrite:1;
78                         PhysAddr Dirty:1;
79                         PhysAddr Accessed:1;
80                         PhysAddr User:1;
81                         PhysAddr Executable:1;
82                         PhysAddr Readable:1;
83                         PhysAddr Writeable:1;
84                         PhysAddr Valid:1;
85 #else
86 #error Unspecified/unrecognized bitfield endianness
87 #endif
88                 };
89
90                 PhysAddr raw;
91
92                 GenPTE(PhysAddr init) : raw(init)
93                 {
94                 }
95                 
96                 GenPTE() : raw(0)
97                 {
98                 }
99
100                 operator PhysAddr()
101                 {
102                         return raw;
103                 }
104
105                 static uint addr_to_offset(VirtAddr addr, int shift)
106                 {
107                         int pages_per_table = page_size / sizeof(PhysAddr);
108                         return (addr >> shift) & (pages_per_table - 1);
109                 }
110         
111                 PhysAddr pte_to_addr()
112                 {
113                         return raw & ~((u64)page_size - 1);
114                 }
115         
116                 static GenPTE addr_to_pte(PhysAddr phys)
117                 {
118                         return phys & ~((u64)page_size - 1);
119                 }
120                 
121                 static void flags_to_pte(Mem::PTEFlags flagsin,
122                                          Mem::PTEFlags maskin,
123                                          GenPTE &flagsout,
124                                          GenPTE &maskout)
125                 {
126                         flagsout = (PhysAddr)flagsin;
127                         maskout = (PhysAddr)maskin;
128                 }
129                 
130                 GenPTE set_flags(GenPTE mask, GenPTE flags)
131                 {
132                         return (raw & ~mask) | flags;
133                 }
134         
135                 Mem::PTEFlags pte_to_flags()
136                 {
137                         return raw & (page_size - 1);
138                 }
139         
140                 void set_pte(GenPTE *table, uint offset)
141                 {
142                         table[offset] = raw;
143                 }
144                 
145                 GenPTE xchg_pte(GenPTE *table, uint offset)
146                 {
147                         GenPTE old = table[offset];
148                         table[offset] = raw;
149                         return old;
150                 }
151                 
152                 bool valid_pte()
153                 {
154                         return Valid;
155                 }
156                 
157                 bool dirty_pte()
158                 {
159                         // FIXME: decide how to handle stacked dirty pages
160                         return false;
161                 }
162                 
163                 enum {
164                         page_size = Arch::page_size,
165                         page_shift = Arch::page_shift,
166         
167                         pages_per_table = page_size / sizeof(PhysAddr),
168                         shift_per_level = page_shift - 3,
169                         num_levels = 2 + (64 - page_shift - shift_per_level - 1) /
170                                      DirPTE::shift_per_level,
171                         
172                         // kmap is ignored for stacked aspaces
173                         kmap_start = 0, kmap_end = 0
174                 };
175         };
176 }
177
178 #endif