x86: changes pte_t to be a KPTE and an EPTE
[akaros.git] / kern / arch / x86 / pmap_ops.h
1 /* Copyright (c) 2015 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Arch-specific operations for page tables and PTEs.
6  *
7  * Unfortunately, many of these ops are called from within a memwalk callback,
8  * which expects a full pte.  But doing walks for a KPT and an EPT at the same
9  * time is a pain, and for now we'll do the walks serially.  Because of that, a
10  * given pte_t may have a KPTE and/or an EPTE.  Ideally, it'd be *and*. */
11
12 #ifndef ROS_ARCH_PMAPS_OPS_H
13 #define ROS_ARCH_PMAPS_OPS_H
14
15 /* TODO: (EPT)  build a CONFIG mode where we assert the EPT agrees with the KPT
16  * for all of the read ops */
17
18 static inline bool pte_walk_okay(pte_t pte)
19 {
20         /* walk_okay should only be called after a walk, when we have both a KPTE
21          * and an EPTE */
22         dassert(pte.kpte ? TRUE : !pte.epte);
23         return pte.kpte ? TRUE : FALSE;
24 }
25
26 /* PTE states:
27  *  - present: the PTE is involved in a valid page table walk, with the physaddr
28  *  part pointing to a physical page.
29  *
30  *      - mapped: the PTE is involved in some sort of mapping, e.g. a VMR.  We're
31  *      storing something in the PTE, but it is isn't necessarily present and
32  *      pointing to an actual physical page.  All present are mapped, but not vice
33  *      versa.  Mapped could also include paged-out, if we support that later.
34  *
35  *      - unmapped: completely unused. (0 value) */
36 static inline bool pte_is_present(pte_t pte)
37 {
38 #if 0   /* could do some debuggin like this.  painful. */
39         bool ret_kpte, ret_epte;
40         assert(pte.kpte || pte.epte);
41         ret_kpte = pte.kpte ? (*pte.kpte & PTE_P ? TRUE : FALSE) : 0;
42         /* TODO: EPT check */
43         ret_epte = pte.epte ? (*pte.epte & PTE_P ? TRUE : FALSE) : 0;
44         if (pte.kpte && pte.epte)
45                 assert(ret_kpte == ret_epte);
46         return pte.kpte ? ret_kpte : ret_epte;
47 #endif
48         return pte.kpte ? (*pte.kpte & PTE_P ? TRUE : FALSE)
49                         : 0; /* TODO: EPT check */
50 }
51
52 static inline bool pte_is_unmapped(pte_t pte)
53 {
54         return pte.kpte ? PAGE_UNMAPPED(*pte.kpte)
55                         : 0; /* TODO: EPT check */
56 }
57
58 static inline bool pte_is_mapped(pte_t pte)
59 {
60         return pte.kpte ? !PAGE_UNMAPPED(*pte.kpte)
61                         : 0; /* TODO: EPT check */
62 }
63
64 static inline bool pte_is_paged_out(pte_t pte)
65 {
66         return pte.kpte ? PAGE_PAGED_OUT(*pte.kpte)
67                         : 0; /* TODO: EPT check */
68 }
69
70 static inline bool pte_is_dirty(pte_t pte)
71 {
72         return pte.kpte ? (*pte.kpte & PTE_D ? TRUE : FALSE)
73                         : 0; /* TODO: EPT check */
74 }
75
76 static inline bool pte_is_accessed(pte_t pte)
77 {
78         return pte.kpte ? (*pte.kpte & PTE_A ? TRUE : FALSE)
79                         : 0; /* TODO: EPT check */
80 }
81
82 /* Used in debugging code - want something better involving the walk */
83 static inline bool pte_is_jumbo(pte_t pte)
84 {
85         return pte.kpte ? (*pte.kpte & PTE_PS ? TRUE : FALSE)
86                         : 0; /* TODO: EPT check */
87 }
88
89 static inline physaddr_t pte_get_paddr(pte_t pte)
90 {
91         return pte.kpte ? PTE_ADDR(*pte.kpte)
92                         : 0; /* TODO: EPT check */
93 }
94
95 /* Returns the PTE in an unsigned long, for debugging mostly. */
96 static inline unsigned long pte_print(pte_t pte)
97 {
98         return pte.kpte ? *pte.kpte
99                         : 0; /* TODO: EPT check */
100 }
101
102 static inline void pte_write(pte_t pte, physaddr_t pa, int perm)
103 {
104         if (pte.kpte)
105                 *pte.kpte = PTE(pa2ppn(pa), perm);
106         if (pte.epte)
107                 /* TODO: EPT write (if EPT) */;
108 }
109
110 static inline void pte_clear_present(pte_t pte)
111 {
112         if (pte.kpte)
113                 *pte.kpte &= ~PTE_P;
114         if (pte.epte)
115                 /* TODO: EPT write (if EPT) */;
116 }
117
118 static inline void pte_clear(pte_t pte)
119 {
120         if (pte.kpte)
121                 *pte.kpte = 0;
122         if (pte.epte)
123                 /* TODO: EPT write (if EPT) */;
124 }
125
126 /* These are used by memcpy_*_user, but are very dangerous (and possibly used
127  * incorrectly there).  These aren't the overall perms for a VA.  For U and W,
128  * we need the intersection of the PTEs along the walk and not just the last
129  * one.  It just so happens that the W is only cleared on the last PTE, so the
130  * check works for that.  But if there was a page under ULIM that wasn't U due
131  * to an intermediate PTE, we'd miss that. */
132 static inline bool pte_has_perm_ur(pte_t pte)
133 {
134         return pte.kpte ? (*pte.kpte & PTE_USER_RO ? TRUE : FALSE)
135                         : 0; /* TODO: EPT check */
136 }
137
138 static inline bool pte_has_perm_urw(pte_t pte)
139 {
140         return pte.kpte ? (*pte.kpte & PTE_USER_RW ? TRUE : FALSE)
141                         : 0; /* TODO: EPT check */
142 }
143
144 /* return the arch-independent format for prots - whatever you'd expect to
145  * receive for pte_write.  Careful with the ret, since a valid type is 0. */
146 static inline int pte_get_perm(pte_t pte)
147 {
148         return pte.kpte ? *pte.kpte & PTE_PERM
149                         : 0; /* TODO: EPT check */
150 }
151
152 static inline void pte_replace_perm(pte_t pte, int perm)
153 {
154         if (pte.kpte)
155                 *pte.kpte = (*pte.kpte & ~PTE_PERM) | perm;
156         if (pte.epte)
157                 /* TODO: EPT write (if EPT) */;
158 }
159
160 #endif /* ROS_ARCH_PMAPS_OPS_H */