]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/include/arch-x86/pagetable.h
update
[polintos/scott/priv.git] / kernel / include / arch-x86 / pagetable.h
1 // FIXME: PAE support
2
3 #ifndef _ARCH_PAGETABLE_H
4 #define _ARCH_PAGETABLE_H
5
6 #include <lowlevel/misc.h>
7 #include <lowlevel/atomic.h>
8
9 namespace Arch {
10         union PTE {
11                 typedef ulong PhysAddr, VirtAddr;
12                 typedef PTE DirPTE;
13         
14                 struct {
15                         PhysAddr Valid:1;
16                         PhysAddr Writeable:1;  // Low-level write access:
17                                                // equivalent to PermWrite && !FaultOnWrite
18                         PhysAddr User:1;
19                         PhysAddr WriteThrough:1;
20                         PhysAddr CacheDisable:1;
21                         PhysAddr Accessed:1;
22                         PhysAddr Dirty:1;
23                         PhysAddr PageAttrTable:1;
24                         PhysAddr Global:1;
25                         PhysAddr FaultOnWrite:1;
26                         PhysAddr PermWrite:1;  // High-level permission-based write access
27                         PhysAddr AddressOnly:1;
28                         PhysAddr Addr:20;
29                 };
30                 
31                 PhysAddr raw;
32
33                 PTE(PhysAddr init) : raw(init)
34                 {
35                 }
36                 
37                 PTE() : raw(0)
38                 {
39                 }
40
41                 operator PhysAddr()
42                 {
43                         return raw;
44                 }
45
46                 static uint addr_to_offset(VirtAddr addr, int shift)
47                 {
48                         int pages_per_table = page_size / sizeof(PhysAddr);
49                         return (addr >> shift) & (pages_per_table - 1);
50                 }
51         
52                 PhysAddr pte_to_addr()
53                 {
54                         return raw & 0xfffff000;
55                 }
56         
57                 static PTE addr_to_pte(PhysAddr phys)
58                 {
59                         return phys & 0xfffff000;
60                 }
61                 
62                 // DirPTE only
63                 void *get_table()
64                 {
65                         return static_cast<PTE *>(phys_to_kvirt(pte_to_addr()));
66                 }
67                 
68                 // DirPTE only
69                 static DirPTE set_table(void *addr)
70                 {
71                         return addr_to_pte(kvirt_to_phys(addr)) | 7;
72                 }
73                 
74                 static void flags_to_pte(Mem::PTEFlags flagsin,
75                                          Mem::PTEFlags maskin,
76                                          PTE &flagsout,
77                                          PTE &maskout)
78                 {
79                         maskout = 0;
80                         flagsout = 0;
81                         
82                         maskout.Valid = maskin.Valid;
83                         maskout.FaultOnWrite = maskin.FaultOnWrite;
84                         maskout.AddressOnly = maskin.AddressOnly;
85                         maskout.CacheDisable = maskin.Uncached;
86
87                         flagsout.Valid = flagsin.Valid;
88                         flagsout.FaultOnWrite = flagsin.FaultOnWrite;
89                         flagsout.AddressOnly = flagsin.AddressOnly;
90                         flagsout.CacheDisable = flagsin.Uncached;
91                         
92                         if (maskin.Writeable) {
93                                 maskout.Writeable = 1;
94                                 maskout.PermWrite = 1;
95                                 flagsout.Writeable = flagsin.Writeable;
96                                 flagsout.PermWrite = flagsin.Writeable;
97                                 
98                                 // This must be done here if both mask bits are set,
99                                 // as we may not be going through set_flags in that case.
100
101                                 if (maskin.FaultOnWrite)
102                                         flagsout.Writeable &= !flagsout.FaultOnWrite;
103                         }
104                         
105                         if (maskin.User) {
106                                 maskout.User = 1;
107                                 flagsout.User = flagsin.User;
108                         }
109                 }
110                 
111                 PTE set_flags(PTE mask, PTE flags)
112                 {
113                         PTE ret, new_pte;
114                 
115                         do {
116                                 ret = raw;
117                                 new_pte = (raw & ~mask) | flags;
118                                 new_pte.Writeable &= !new_pte.FaultOnWrite;
119                         } while (!ll_cmpxchg_long(reinterpret_cast<PhysAddr *>
120                                                   (this), ret, new_pte));
121
122                         return ret;
123                 }
124         
125                 Mem::PTEFlags pte_to_flags()
126                 {
127                         Mem::PTEFlags ret = 0;
128                         
129                         ret.Valid = Valid;
130                         
131                         if (Valid) {
132                                 ret.User = User;
133                                 ret.Readable = 1;
134                                 ret.Writeable = PermWrite;
135                                 ret.Executable = 1;
136                                 ret.Uncached = CacheDisable;
137                                 ret.FaultOnWrite = FaultOnWrite;
138                                 ret.AddressOnly = AddressOnly;
139                         }
140                         
141                         return ret;
142                 }
143         
144                 void set_pte(PTE *table, uint offset)
145                 {
146                         table[offset] = raw;
147                 }
148                 
149                 PTE xchg_pte(PTE *table, uint offset)
150                 {
151                         return ll_xchg_long(reinterpret_cast<PhysAddr *>(&table[offset]), raw);
152                 }
153                 
154                 bool valid_pte()
155                 {
156                         return Valid;
157                 }
158                 
159                 bool dirty_pte()
160                 {
161                         return Dirty;
162                 }
163                 
164                 bool addronly_pte()
165                 {
166                         return AddressOnly;
167                 }
168                 
169                 enum {
170                         page_size = Arch::page_size,
171                         page_shift = Arch::page_shift,
172         
173                         pages_per_table = page_size / sizeof(PhysAddr),
174                         num_levels = 2,
175                         shift_per_level = 10,
176         
177                         // All "upper" addresses belong to the kernel.
178                         
179                         kmap_start = 512,
180                         kmap_end = 1023
181                 };
182         };
183
184         static inline void invalidate_tlb_entry(ulong addr)
185         {
186                 ll_invalidate_tlb_entry(addr);
187         }
188 }
189
190 #endif