|  | /* Copyright (c) 2015 Google Inc. | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Arch-specific operations for page tables and PTEs */ | 
|  |  | 
|  | #warning "These are the x86 ops.  Adopt them for RISC-V" | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | static inline bool pte_walk_okay(pte_t pte) | 
|  | { | 
|  | return pte ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | /* PTE states: | 
|  | *  - present: the PTE is involved in a valid page table walk, with the physaddr | 
|  | *  part pointing to a physical page. | 
|  | * | 
|  | * 	- mapped: the PTE is involved in some sort of mapping, e.g. a VMR.  We're | 
|  | * 	storing something in the PTE, but it is isn't necessarily present and | 
|  | * 	pointing to an actual physical page.  All present are mapped, but not vice | 
|  | * 	versa.  Mapped could also include paged-out, if we support that later. | 
|  | * | 
|  | * 	- unmapped: completely unused. (0 value) */ | 
|  | static inline bool pte_is_present(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_P ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_unmapped(pte_t pte) | 
|  | { | 
|  | return PAGE_UNMAPPED(*(kpte_t*)pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_mapped(pte_t pte) | 
|  | { | 
|  | return !PAGE_UNMAPPED(*(kpte_t*)pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_paged_out(pte_t pte) | 
|  | { | 
|  | return PAGE_PAGED_OUT(*(kpte_t*)pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_dirty(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_D ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_accessed(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_A ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | /* Used in debugging code - want something better involving the walk */ | 
|  | static inline bool pte_is_jumbo(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_PS ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline physaddr_t pte_get_paddr(pte_t pte) | 
|  | { | 
|  | return PTE_ADDR(*(kpte_t*)pte); | 
|  | } | 
|  |  | 
|  | /* Returns the PTE in an unsigned long, for debugging mostly. */ | 
|  | static inline unsigned long pte_print(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte; | 
|  | } | 
|  |  | 
|  | static inline void pte_write(pte_t pte, physaddr_t pa, int settings) | 
|  | { | 
|  | *(kpte_t*)pte = build_pte(pa, settings); | 
|  | } | 
|  |  | 
|  | static inline void pte_clear_present(pte_t pte) | 
|  | { | 
|  | *(kpte_t*)pte &= ~PTE_P; | 
|  | } | 
|  |  | 
|  | static inline void pte_clear(pte_t pte) | 
|  | { | 
|  | *(kpte_t*)pte = 0; | 
|  | } | 
|  |  | 
|  | /* These are used by memcpy_*_user, but are very dangerous (and possibly used | 
|  | * incorrectly there).  These aren't the overall perms for a VA.  For U and W, | 
|  | * we need the intersection of the PTEs along the walk and not just the last | 
|  | * one.  It just so happens that the W is only cleared on the last PTE, so the | 
|  | * check works for that.  But if there was a page under ULIM that wasn't U due | 
|  | * to an intermediate PTE, we'd miss that. */ | 
|  | static inline bool pte_has_perm_ur(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_USER_RO ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool pte_has_perm_urw(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_USER_RW ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | /* Settings includes protection (maskable via PTE_PROT) and other bits, such as | 
|  | * jumbo, dirty, accessed, etc.  Whatever this returns can get fed back to | 
|  | * replace_settings or pte_write. | 
|  | * | 
|  | * Arch-indep settings include: PTE_PERM (U, W, P, etc), PTE_D, PTE_A, PTE_PS. | 
|  | * Other OSs (x86) may include others. */ | 
|  | static inline int pte_get_settings(pte_t pte) | 
|  | { | 
|  | return *(kpte_t*)pte & PTE_PERM; | 
|  | } | 
|  |  | 
|  | static inline void pte_replace_perm(pte_t pte, int perm) | 
|  | { | 
|  | *(kpte_t*)pte = (*(kpte_t*)pte & ~PTE_PERM) | perm; | 
|  | } |