1/* $NetBSD: pte.h,v 1.14.2.3 2026/06/03 18:17:02 martin Exp $ */
2
3/*
4 * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas (of 3am Software Foundry), Maxime Villard, and
9 * Nick Hudson.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#ifndef _RISCV_PTE_H_
34#define _RISCV_PTE_H_
35
36#ifdef _LP64 /* Sv39 */
37#define PTE_PPN __BITS(53, 10)
38#define PTE_PPN0 __BITS(18, 10)
39#define PTE_PPN1 __BITS(27, 19)
40#define PTE_PPN2 __BITS(53, 28)
41typedef uint64_t pt_entry_t;
42typedef uint64_t pd_entry_t;
43#define atomic_cas_pte atomic_cas_64
44#else /* Sv32 */
45#define PTE_PPN __BITS(31, 10)
46#define PTE_PPN0 __BITS(19, 10)
47#define PTE_PPN1 __BITS(31, 20)
48typedef uint32_t pt_entry_t;
49typedef uint32_t pd_entry_t;
50#define atomic_cas_pte atomic_cas_32
51#endif
52
53#define PTE_PPN_SHIFT 10
54
55#define NPTEPG (NBPG / sizeof(pt_entry_t))
56#define NSEGPG NPTEPG
57#define NPDEPG NPTEPG
58
59
60/* HardWare PTE bits SV39 */
61#define PTE_N __BIT(63) // Svnapot
62#define PTE_PBMT __BITS(62, 61) // Svpbmt
63#define PTE_reserved0 __BITS(60, 54) //
64
65/*
66 * Svpbmt (Page Based Memory Types) extension:
67 *
68 * PMA --> adhere to physical memory attributes
69 * NC --> non-cacheable, idempotent, weakly-ordered
70 * IO --> non-cacheable, non-idempotent, strongly-ordered
71 */
72#define PTE_PBMT_PMA __SHIFTIN(0, PTE_PBMT)
73#define PTE_PBMT_NC __SHIFTIN(1, PTE_PBMT)
74#define PTE_PBMT_IO __SHIFTIN(2, PTE_PBMT)
75
76/* XTheadMae (Memory Attribute Extensions) */
77#define PTE_XMAE __BITS(63,59)
78#define PTE_XMAE_SO __BIT(63) // Strong Order
79#define PTE_XMAE_C __BIT(62) // Cacheable
80#define PTE_XMAE_B __BIT(61) // Bufferable
81#define PTE_XMAE_SH __BIT(60) // Shareable
82#define PTE_XMAE_T __BIT(59) // Trustable
83
84/*
85 * Map to the rough PBMT equivalent:
86 *
87 * PMA (i.e. no specific attribute) --> C B SH
88 * NC --> B SH
89 * IO --> SO SH
90 */
91#define PTE_XMAE_PMA ( PTE_XMAE_C | PTE_XMAE_B | PTE_XMAE_SH)
92#define PTE_XMAE_NC ( PTE_XMAE_B | PTE_XMAE_SH)
93#define PTE_XMAE_IO (PTE_XMAE_SO | PTE_XMAE_SH)
94
95/* Software PTE bits. */
96#define PTE_RSW __BITS(9, 8)
97#define PTE_WIRED __BIT(9)
98
99/* Hardware PTE bits. */
100// These are hardware defined bits
101#define PTE_D __BIT(7) // Dirty
102#define PTE_A __BIT(6) // Accessed
103#define PTE_G __BIT(5) // Global
104#define PTE_U __BIT(4) // User
105#define PTE_X __BIT(3) // eXecute
106#define PTE_W __BIT(2) // Write
107#define PTE_R __BIT(1) // Read
108#define PTE_V __BIT(0) // Valid
109
110#define PTE_HARDWIRED (PTE_A | PTE_D)
111#define PTE_USER (PTE_V | PTE_U)
112#define PTE_KERN (PTE_V | PTE_G)
113#define PTE_RW (PTE_R | PTE_W)
114#define PTE_RX (PTE_R | PTE_X)
115#define PTE_RWX (PTE_R | PTE_W | PTE_X)
116
117#define PTE_ISLEAF_P(pte) (((pte) & PTE_RWX) != 0)
118
119#define PA_TO_PTE(pa) (((pa) >> PGSHIFT) << PTE_PPN_SHIFT)
120#define PTE_TO_PA(pte) (__SHIFTOUT((pte), PTE_PPN) << PGSHIFT)
121
122#if defined(_KERNEL)
123
124static inline bool
125pte_valid_p(pt_entry_t pte)
126{
127 return (pte & PTE_V) != 0;
128}
129
130static inline bool
131pte_wired_p(pt_entry_t pte)
132{
133 return (pte & PTE_WIRED) != 0;
134}
135
136static inline bool
137pte_modified_p(pt_entry_t pte)
138{
139 return (pte & PTE_D) != 0;
140}
141
142static inline bool
143pte_referenced_p(pt_entry_t pte)
144{
145 return (pte & PTE_A) != 0;
146}
147
148static inline bool
149pte_cached_p(pt_entry_t pte)
150{
151 /* TODO: This seems wrong... */
152 return true;
153}
154
155static inline bool
156pte_deferred_exec_p(pt_entry_t pte)
157{
158 return false;
159}
160
161static inline pt_entry_t
162pte_wire_entry(pt_entry_t pte)
163{
164 return pte | PTE_HARDWIRED | PTE_WIRED;
165}
166
167static inline pt_entry_t
168pte_unwire_entry(pt_entry_t pte)
169{
170 return pte & ~(PTE_HARDWIRED | PTE_WIRED);
171}
172
173static inline paddr_t
174pte_to_paddr(pt_entry_t pte)
175{
176 return PTE_TO_PA(pte);
177}
178
179static inline pt_entry_t
180pte_nv_entry(bool kernel_p)
181{
182 return 0;
183}
184
185static inline pt_entry_t
186pte_clear_modify(pt_entry_t pte)
187{
188 return pte & ~PTE_D;
189}
190
191static inline pt_entry_t
192pte_clear_reference(pt_entry_t pte)
193{
194 return pte & ~PTE_A;
195}
196
197static inline pt_entry_t
198pte_prot_downgrade(pt_entry_t pte, vm_prot_t newprot)
199{
200 if ((newprot & VM_PROT_READ) == 0)
201 pte &= ~PTE_R;
202 if ((newprot & VM_PROT_WRITE) == 0)
203 pte &= ~PTE_W;
204 if ((newprot & VM_PROT_EXECUTE) == 0)
205 pte &= ~PTE_X;
206 return pte;
207}
208
209static inline pt_entry_t
210pte_prot_bits(struct vm_page_md *mdpg, vm_prot_t prot, bool kernel_p)
211{
212 KASSERT(prot & VM_PROT_READ);
213 pt_entry_t pte = PTE_R;
214
215 if (prot & VM_PROT_EXECUTE) {
216 pte |= PTE_X;
217 }
218 if (prot & VM_PROT_WRITE) {
219 pte |= PTE_W;
220 }
221
222 return pte;
223}
224
225static inline pt_entry_t
226pte_flag_bits(struct vm_page_md *mdpg, int flags, bool kernel_p)
227{
228 return 0;
229}
230
231#ifdef _LP64
232pt_entry_t pte_enter_flags_to_pbmt(int);
233#else
234static inline pt_entry_t
235pte_enter_flags_to_pbmt(int flags)
236{
237 return 0;
238};
239#endif
240
241static inline pt_entry_t
242pte_make_enter(paddr_t pa, struct vm_page_md *mdpg, vm_prot_t prot,
243 int flags, bool kernel_p)
244{
245 pt_entry_t pte = (pt_entry_t)PA_TO_PTE(pa);
246
247 pte |= kernel_p ? PTE_KERN : PTE_USER;
248 pte |= pte_flag_bits(mdpg, flags, kernel_p);
249 pte |= pte_prot_bits(mdpg, prot, kernel_p);
250 pte |= pte_enter_flags_to_pbmt(flags);
251
252 /*
253 * pmap_enter should have checked flags and updated
254 * VM_PAGEMD_{REFERENCED,MODIFIED}_P, so there is no
255 * need here.
256 */
257 KASSERT(((flags & VM_PROT_ALL) == 0) || VM_PAGEMD_REFERENCED_P(mdpg));
258 KASSERT(((flags & VM_PROT_WRITE) == 0) || VM_PAGEMD_MODIFIED_P(mdpg));
259
260 if (mdpg != NULL) {
261 if ((prot & VM_PROT_WRITE) != 0 && VM_PAGEMD_MODIFIED_P(mdpg)) {
262 /*
263 * This is a writable mapping, and the page's mod state
264 * indicates it has already been modified. No need for
265 * reference or modified emulation.
266 */
267 pte |= PTE_A | PTE_D;
268 } else if (VM_PAGEMD_REFERENCED_P(mdpg)) {
269 /*
270 * The physical page has already been referenced so no need
271 * to re-do referenced emulation here.
272 */
273 pte |= PTE_A;
274 }
275 }
276
277 return pte;
278}
279
280static inline pt_entry_t
281pte_make_kenter_pa(paddr_t pa, struct vm_page_md *mdpg, vm_prot_t prot,
282 int flags)
283{
284 pt_entry_t pte = (pt_entry_t)PA_TO_PTE(pa);
285
286 pte |= PTE_KERN | PTE_HARDWIRED | PTE_WIRED;
287 pte |= pte_flag_bits(NULL, flags, true);
288 pte |= pte_prot_bits(NULL, prot, true);
289 pte |= pte_enter_flags_to_pbmt(flags);
290
291 return pte;
292}
293
294static inline void
295pte_set(pt_entry_t *ptep, pt_entry_t pte)
296{
297 *ptep = pte;
298}
299
300static inline pd_entry_t
301pte_invalid_pde(void)
302{
303 return 0;
304}
305
306static inline pd_entry_t
307pte_pde_pdetab(paddr_t pa, bool kernel_p)
308{
309 return PTE_V | PA_TO_PTE(pa);
310}
311
312static inline pd_entry_t
313pte_pde_ptpage(paddr_t pa, bool kernel_p)
314{
315 return PTE_V | PA_TO_PTE(pa);
316}
317
318static inline bool
319pte_pde_valid_p(pd_entry_t pde)
320{
321 return (pde & (PTE_X | PTE_W | PTE_R | PTE_V)) == PTE_V;
322}
323
324static inline paddr_t
325pte_pde_to_paddr(pd_entry_t pde)
326{
327 return pte_to_paddr((pt_entry_t)pde);
328}
329
330static inline pd_entry_t
331pte_pde_cas(pd_entry_t *pdep, pd_entry_t opde, pt_entry_t npde)
332{
333#ifdef MULTIPROCESSOR
334#ifdef _LP64
335 return atomic_cas_64(pdep, opde, npde);
336#else
337 return atomic_cas_32(pdep, opde, npde);
338#endif
339#else
340 *pdep = npde;
341 return 0;
342#endif
343}
344
345static inline void
346pte_pde_set(pd_entry_t *pdep, pd_entry_t npde)
347{
348
349 *pdep = npde;
350}
351
352static inline pt_entry_t
353pte_value(pt_entry_t pte)
354{
355 return pte;
356}
357
358#endif /* _KERNEL */
359
360#endif /* _RISCV_PTE_H_ */