|  | /* Copyright (c) 2015 Google Inc. | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Arch-specific operations for page tables and PTEs. | 
|  | * | 
|  | * Unfortunately, many of these ops are called from within a memwalk callback, | 
|  | * which expects a full pte.  But doing walks for a KPT and an EPT at the same | 
|  | * time is a pain, and for now we'll do the walks serially.  Because of that, a | 
|  | * given pte_t may have a KPTE and/or an EPTE.  Ideally, it'd be *and*. */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <arch/vmm/ept.h> | 
|  | #include <arch/kpt.h> | 
|  |  | 
|  | /* TODO: (EPT)  build a CONFIG mode where we assert the EPT agrees with the KPT | 
|  | * for all of the read ops */ | 
|  |  | 
|  | 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, can be used for | 
|  | *   some form of hardware access (read, write, user, etc), and 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. | 
|  | *   Currently, all mapped pages should point to an actual physical page.  All | 
|  | *   present are mapped, but not vice versa.  Mapped pages can point to a real | 
|  | *   page, but with no access permissions, which is the main distinction between | 
|  | *   present and mapped. | 
|  | * | 
|  | * - paged_out: we don't actually use this yet.  Since mapped vs present is | 
|  | *   based on the PTE present bits, we'd need to use reserved bits in the PTE to | 
|  | *   differentiate between other states.  Right now, paged_out == mapped, as far | 
|  | *   as the code is concerned. | 
|  | * | 
|  | * - unmapped: completely unused. (0 value) */ | 
|  | static inline bool pte_is_present(pte_t pte) | 
|  | { | 
|  | return kpte_is_present(pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_unmapped(pte_t pte) | 
|  | { | 
|  | return kpte_is_unmapped(pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_mapped(pte_t pte) | 
|  | { | 
|  | return kpte_is_mapped(pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_paged_out(pte_t pte) | 
|  | { | 
|  | return kpte_is_paged_out(pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_dirty(pte_t pte) | 
|  | { | 
|  | return kpte_is_dirty(pte) || | 
|  | epte_is_dirty(kpte_to_epte(pte)); | 
|  | } | 
|  |  | 
|  | static inline bool pte_is_accessed(pte_t pte) | 
|  | { | 
|  | return kpte_is_accessed(pte) || | 
|  | epte_is_accessed(kpte_to_epte(pte)); | 
|  | } | 
|  |  | 
|  | /* Used in debugging code - want something better involving the walk */ | 
|  | static inline bool pte_is_jumbo(pte_t pte) | 
|  | { | 
|  | return kpte_is_jumbo(pte); | 
|  | } | 
|  |  | 
|  | static inline physaddr_t pte_get_paddr(pte_t pte) | 
|  | { | 
|  | return kpte_get_paddr(pte); | 
|  | } | 
|  |  | 
|  | /* Returns the PTE in an unsigned long, for debugging mostly. */ | 
|  | static inline unsigned long pte_print(pte_t pte) | 
|  | { | 
|  | return kpte_print(pte); | 
|  | } | 
|  |  | 
|  | static inline void pte_write(pte_t pte, physaddr_t pa, int settings) | 
|  | { | 
|  | kpte_write(pte, pa, settings); | 
|  | epte_write(kpte_to_epte(pte), pa, settings); | 
|  | } | 
|  |  | 
|  | static inline void pte_clear_present(pte_t pte) | 
|  | { | 
|  | kpte_clear_present(pte); | 
|  | epte_clear_present(kpte_to_epte(pte)); | 
|  | } | 
|  |  | 
|  | static inline void pte_clear_dirty(pte_t pte) | 
|  | { | 
|  | kpte_clear_dirty(pte); | 
|  | epte_clear_dirty(kpte_to_epte(pte)); | 
|  | } | 
|  |  | 
|  | static inline void pte_clear(pte_t pte) | 
|  | { | 
|  | kpte_clear(pte); | 
|  | epte_clear(kpte_to_epte(pte)); | 
|  | } | 
|  |  | 
|  | /* 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_has_perm_ur(pte); | 
|  | } | 
|  |  | 
|  | static inline bool pte_has_perm_urw(pte_t pte) | 
|  | { | 
|  | return kpte_has_perm_urw(pte); | 
|  | } | 
|  |  | 
|  | /* Settings includes protection (maskable via PTE_PROT) and other bits, such as | 
|  | * jumbo, dirty, accessed, etc.  Whatever this returns can get fed back to | 
|  | * 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_get_settings(pte); | 
|  | } | 
|  |  | 
|  | static inline void pte_replace_perm(pte_t pte, int perm) | 
|  | { | 
|  | kpte_replace_perm(pte, perm); | 
|  | epte_replace_perm(kpte_to_epte(pte), perm); | 
|  | } |