summaryrefslogtreecommitdiffstats
path: root/src/include
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2011-07-06 10:16:21 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2011-07-14 14:53:35 -0500
commit2583b46750d1e1c062763eff204baa1460e7ae90 (patch)
tree3fc331001e03e014bba295eda594fe86d248d477 /src/include
parentaccc0f438eca45dcd1058a195d192d51a6f1c4aa (diff)
downloadtalos-hostboot-2583b46750d1e1c062763eff204baa1460e7ae90.tar.gz
talos-hostboot-2583b46750d1e1c062763eff204baa1460e7ae90.zip
Initial checkin of PageTableManager - RTC:3195
Add new delRange method to delete based on page numbers, part of RTC:3195 Plus code review comments from previous commit - http://gfw160.austin.ibm.com:8080/gerrit/188 Change-Id: Ie45365162cf1367c5c0dcc3afc2907a6ddfa53d3 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/188 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com> Reviewed-by: MATTHEW S. BARTH <msbarth@us.ibm.com>
Diffstat (limited to 'src/include')
-rw-r--r--src/include/kernel/ptmgr.H406
-rw-r--r--src/include/kernel/vmmmgr.H96
2 files changed, 409 insertions, 93 deletions
diff --git a/src/include/kernel/ptmgr.H b/src/include/kernel/ptmgr.H
new file mode 100644
index 000000000..db552ada4
--- /dev/null
+++ b/src/include/kernel/ptmgr.H
@@ -0,0 +1,406 @@
+#ifndef __KERNEL_PTMGR_H
+#define __KERNEL_PTMGR_H
+
+#include <stdint.h>
+#include <util/lockfree/stack.H>
+#include <kernel/vmmmgr.H>
+
+/**
+ * @class PageTableManager
+ * @brief Manages the Page Table in the hardware
+ */
+class PageTableManager
+{
+ public:
+ // Public Constants
+
+ /**
+ * Status Values
+ */
+ enum
+ {
+ PTE_UNKNOWN = 0x0000000000000000, /**< Entry wasn't found */
+ PTE_PRESENT = 0x0000000000000001, /**< Entry is present in table */
+ PTE_VALID = 0x0000000000000002, /**< Entry is valid */
+ PTE_READ_ONLY = 0x0000000000000004, /**< Read-Only */
+ PTE_EXECUTE = 0x0000000000000008, /**< Execute permission */
+ PTE_CACHE_INHIBITED = 0x0000000000000010, /**< Cache-Inhibited Access */
+ PTE_MODIFIED = 0x0000000000000020, /**< Page has been modified */
+ PTE_ACCESSED = 0x0000000000000040, /**< Page has been accessed */
+ };
+
+ /**
+ * Page Table Constants
+ */
+ enum
+ {
+ PT_SIZE = (1 << 18), /**< Size of Page Table in bytes */
+ PTE_SIZE = 2*sizeof(uint64_t), /**< Size of a single Page Table Entry in bytes */
+ PTEG_SIZE = 8, /**< Number of PTEs in a single PTE Group */
+ PTEG_COUNT = (PT_SIZE / PTE_SIZE) / PTEG_SIZE, /**< Number of PTEGs in the Page Table */
+ INVALID_PN = 0xFFFFFFFFFFFFFFFF, /**< Invalid value for a Page Number return */
+ };
+
+ /**
+ * @brief Static Initializer
+ */
+ static void init();
+
+ /**
+ * @brief Add an entry to the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be mapped (full address)
+ * @param[in] i_page Real physical page number to map to (page number)
+ * @param[in] i_accessType Type of access page will be given
+ */
+ static void addEntry( uint64_t i_vAddr,
+ uint64_t i_page,
+ VmmManager::ACCESS_TYPES i_accessType );
+
+ /**
+ * @brief Remove an entry from the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be removed (full address)
+ */
+ static void delEntry( uint64_t i_vAddr );
+
+ /**
+ * @brief Remove a range of entries from the hardware page table
+ *
+ * @param[in] i_vAddrStart Beginning of VA range to remove (full address)
+ * @param[in] i_vAddrFinish End of VA range to remove (full address)
+ */
+ static void delRangeVA( uint64_t i_vAddrStart,
+ uint64_t i_vAddrFinish );
+
+
+ /**
+ * @brief Remove a range of entries from the hardware page table
+ *
+ * @param[in] i_pnStart First Physical Page to remove (page number)
+ * @param[in] i_pnFinish Last Physical Page to remove (page number)
+ */
+ static void delRangePN( uint64_t i_pnStart,
+ uint64_t i_pnFinish );
+
+ /**
+ * @brief Return status information about an entry in the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be queried (full address)
+ * @param[out] o_pn Real physical page number to map to, INVALID_PN if PTE is invalid
+ *
+ * @return uint64_t ORed combination of status flags
+ */
+ static uint64_t getStatus( uint64_t i_vAddr,
+ uint64_t& o_pn );
+
+ /**
+ * @brief Print out the contents of a PTE to the printk buffer
+ *
+ * @param[in] i_label string to display along with the PTE data
+ * @param[in] i_pteAddr address/pointer to the PTE to display
+ * @param[in] i_verbose true=break out all attributes, false=abbreviated output
+ */
+ static void printPTE( const char* i_label,
+ uint64_t i_pteAddr,
+ bool i_verbose = false );
+
+ /**
+ * @brief Print out the contents of a PTE based on a VA
+ *
+ * @param[in] i_va Virtual address that is part of the page the PTE points to
+ * @param[in] i_verbose true=break out all attributes, false=abbreviated output
+ */
+ static void printPTE( uint64_t i_va,
+ bool i_verbose = false );
+
+ /**
+ * @brief Print out the entire Page Table
+ */
+ static void printPT( void );
+
+
+ protected:
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_userSpace true=declare a local page table for user-space testing
+ */
+ PageTableManager( bool i_userSpace = false );
+
+ /**
+ * @brief Destructor
+ */
+ ~PageTableManager();
+
+ private:
+ /**
+ * Local copy of Page Table for user-space testing
+ * (set to NULL for kernel instance)
+ */
+ char* ivTABLE;
+
+
+ /**
+ * Represents a single entry in the page table
+ */
+ struct PageTableEntry
+ {
+ /**
+ * Dword0
+ */
+ union {
+ struct { /**< Dword0 Attributes */
+ uint64_t B:2; /**< 0:1 Segment Size */
+ uint64_t AVA:55; /**< 2:56 Abbreviated Virtual Address = VA w/o bottom 23 bits */
+ uint64_t SW:2; /**< 57:58 =SW[0:1] - Reserved */
+ uint64_t LRU:2; /**< 59:60 =SW[2:3] - Used for LRU algorithm */
+ uint64_t L:1; /**< 61 Virtual page size */
+ uint64_t H:1; /**< 62 Hash function identifier */
+ uint64_t V:1; /**< 63 Entry valid */
+ };
+ uint64_t dword0; /**< Full Dword0 */
+ };
+
+ /**
+ * Dword1
+ */
+ union {
+ struct { /**< Dword0 Attributes */
+ uint64_t pp0:1; /**< 0 Page Protection bit 0 */
+ uint64_t rsv:1; /**< 1 Reserved */
+ uint64_t key0_1:2; /**< 2:3 KEY bits 0:1 <unused> */
+ uint64_t PN:48; /**< 4:52 Abbreviated Real Page Number + Large page size selector */
+ uint64_t key2_4:3; /**< 53:54 KEY bits 2:4 <unused> */
+ uint64_t R:1; /**< 55 Reference bit */
+ uint64_t C:1; /**< 56 Change bit */
+ uint64_t WIMG:4; /**< 57:60 Storage control bits */
+ uint64_t N:1; /**< 61 No-execute page (N==1) */
+ uint64_t pp1_2:2; /**< 62:63 Page Protection bits 1:2 */
+ };
+ uint64_t dword1; /**< Full Dword1 */
+ };
+ } PACKED;
+
+ /**
+ * Internal Constants
+ */
+ enum {
+ PTE_ACCESS_BITS = 0x800000000000007B, /**< pp0 + WIMG + pp1_2 */
+ PTEG_SIZE_BYTES = (sizeof(PageTableEntry)*8), /**< Size of PTE Group in bytes */
+
+ SLBE_b = 12, /**< Page Size in bits per SLBE */
+ SLBE_s = 40, /**< Segment Size in bits per SLBE */
+
+ };
+
+ /**
+ * @brief Return the hash value of the VA
+ *
+ * @param[in] i_vAddr Virtual Address to hash
+ *
+ * @return uint64_t hash value used by Page Table hardware
+ */
+ uint64_t computeHash( uint64_t i_vAddr );
+
+ /**
+ * @brief Find the real address of the PTEG that matches the given VA
+ *
+ * @param[in] i_vAddr Virtual Address to look up
+ *
+ * @return uint64_t PTEG address
+ */
+ uint64_t findPTEG( uint64_t i_vAddr );
+
+ /**
+ * @brief Find the PTE that matches the given VA
+ *
+ * @param[in] i_vAddr Virtual Address to search for
+ *
+ * @return PageTableEntry* Pointer to PTE, this is a real address
+ */
+ PageTableEntry* findPTE( uint64_t i_vAddr );
+
+ /**
+ * @brief Find the real address of the PTE that matches the given address
+ *
+ * @param[in] i_vAddr Virtual Address to search for
+ * @param[in] i_ptegAddr Real Address of PTEG that would own this PTE
+ *
+ * @return PageTableEntry* Pointer to PTE, this is a real address
+ */
+ PageTableEntry* findPTE( uint64_t i_vAddr,
+ uint64_t i_ptegAddr );
+
+ /**
+ * @brief Find the real address of a PTE that that is empty or invalid
+ *
+ * @param[in] i_ptegAddr Real Address of PTEG that would own this PTE
+ *
+ * @return PageTableEntry* Pointer to PTE slot, this is a real address
+ */
+ PageTableEntry* findEmptyPTE( uint64_t i_ptegAddr );
+
+ /**
+ * @brief Find the real address of a PTE that can be invalidated
+ * and replaced
+ *
+ * @param[in] i_ptegAddr Real Address of PTEG that would own this PTE
+ *
+ * @return PageTableEntry* Pointer to PTE, this is a real address
+ */
+ PageTableEntry* findOldPTE( uint64_t i_ptegAddr );
+
+ /**
+ * @brief Write a PTE to memory and update caches appropriately
+ *
+ * @param[in] i_pte Local pointer to PTE data
+ * @param[in] i_dest Real Address inside page table to write i_pte data into
+ * @param[in] i_valid true=set Valid bit, false=clear Valid bit
+ */
+ void writePTE( PageTableEntry* i_pte,
+ PageTableEntry* i_dest,
+ bool i_valid );
+
+ /**
+ * @brief Add an entry to the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be mapped
+ * @param[in] i_page Real physical page number to map to
+ * @param[in] i_accessType Type of access page will be given
+ */
+ void _addEntry( uint64_t i_vAddr,
+ uint64_t i_page,
+ VmmManager::ACCESS_TYPES i_accessType );
+
+ /**
+ * @brief Remove an entry from the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be removed
+ */
+ void _delEntry( uint64_t i_vAddr );
+
+ /**
+ * @brief Remove an entry from the hardware page table
+ *
+ * @param[in] i_pte Pointer to real PTE in the page table
+ */
+ void delEntry( PageTableEntry* i_pte );
+
+ /**
+ * @brief Remove a range of entries from the hardware page table
+ *
+ * @param[in] i_vAddrStart Beginning of VA range to remove
+ * @param[in] i_vAddrFinish End of VA range to remove
+ */
+ void _delRangeVA( uint64_t i_vAddrStart,
+ uint64_t i_vAddrFinish );
+
+ /**
+ * @brief Remove a range of entries from the hardware page table
+ *
+ * @param[in] i_pnStart First Physical Page to remove
+ * @param[in] i_pnFinish Last Physical Page to remove
+ */
+ void _delRangePN( uint64_t i_pnStart,
+ uint64_t i_pnFinish );
+
+ /**
+ * @brief Return status information about an entry in the hardware page table
+ *
+ * @param[in] i_vAddr Virtual Address within the page to be queried
+ * @param[out] o_pn Real physical page number to map to, INVALID_PN if PTE is invalid
+ *
+ * @return uint64_t ORed combination of status flags
+ */
+ uint64_t _getStatus( uint64_t i_vAddr,
+ uint64_t& o_pn );
+
+ /**
+ * @brief Translate a PTE into the status bits
+ *
+ * @param[in] i_pte Pointer to PTE, could be local memory or part of page table
+ *
+ * @return uint64_t ORed combination of status flags
+ */
+ uint64_t getStatus( PageTableEntry* i_pte );
+
+ /**
+ * @brief Update the LRU statistics for other PTEs in the same PTEG as the target
+ *
+ * @param[in] i_newPTE Real address of PTE that is being added to the Page Table
+ */
+ void updateLRU( const PageTableEntry* i_newPTE );
+
+ /**
+ * @brief Invalidate TLB for a PTE
+ *
+ * @param[in] i_newPTE Real address of PTE that is being modified
+ */
+ void invalidateTLB( PageTableEntry* i_pte );
+
+ /**
+ * @brief Invalidate all PTEs in the table
+ */
+ void invalidatePT( void );
+
+ /**
+ * @brief Print out the contents of a PTE to the printk buffer
+ *
+ * @param[in] i_label string to display along with the PTE data
+ * @param[in] i_pteAddr pointer to the PTE to display
+ * @param[in] i_verbose true=break out all attributes, false=abbreviated output
+ */
+ void printPTE( const char* i_label,
+ const PageTableEntry* i_pte,
+ bool i_verbose = false );
+
+ /**
+ * @brief Print out the entire Page Table to the printk buffer
+ */
+ void _printPT( void );
+
+ /**
+ * @brief Return the real address of the page table in memory
+ * @return uint64_t Page Table Address
+ */
+ uint64_t getAddress( void );
+
+ /**
+ * @brief Return the size of the page table in memory in bytes
+ * @return uint64_t Size of Page Table in bytes
+ */
+ uint64_t getSize( void );
+
+ /**
+ * @brief Set bits in PTE for the given ACCESS_TYPES
+ *
+ * @param[out] o_pte PTE to modify
+ * @param[in] i_accessType Access parameter to apply to PTE
+ */
+ void setAccessBits( PageTableEntry* o_pte,
+ VmmManager::ACCESS_TYPES i_accessType );
+
+ /**
+ * @brief Convert the bits from a PTE into a ACCESS_TYPES
+ *
+ * @param[in] i_pte PTE to examine
+ *
+ * @return ACCESS_TYPES Access parameters of given PTE
+ */
+ VmmManager::ACCESS_TYPES getAccessType( const PageTableEntry* i_pte );
+
+ /**
+ * @brief Fill in default values for the PTE
+ *
+ * @param[out] o_pte PTE to modify
+ */
+ static void setupDefaultPTE( PageTableEntry* o_pte );
+
+
+
+ // Allow testcase to see inside
+ friend class ptmgrtest;
+};
+
+#endif
diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H
index 4fc378578..c194b0456 100644
--- a/src/include/kernel/vmmmgr.H
+++ b/src/include/kernel/vmmmgr.H
@@ -7,11 +7,6 @@
class VmmManager
{
public:
- struct pte_t
- {
- uint64_t a,b;
- };
-
enum VMM_CONSTS
{
EIGHT_MEG = 8 * 1024 * 1024,
@@ -19,10 +14,8 @@ class VmmManager
FULL_MEM_SIZE = 1 * EIGHT_MEG,
PAGESIZE = 4096,
- PTSIZE = (1 << 18),
- PTEG_SIZE = 8,
- PTEG_COUNT = (PTSIZE / sizeof(pte_t)) / PTEG_SIZE,
-
+ // put the Page Table at the end of our memory space
+ PTSIZE = (1 << 18),
HTABORG = (FULL_MEM_SIZE - PTSIZE),
};
@@ -32,6 +25,7 @@ class VmmManager
READ_O_ACCESS,
NORMAL_ACCESS,
CI_ACCESS,
+ RO_EXE_ACCESS,
};
enum PID_ALLOCATIONS
@@ -70,90 +64,6 @@ class VmmManager
void* _mmioMap(void*, size_t);
int _mmioUnmap(void*, size_t);
- static pte_t* page_table;
-
- inline volatile pte_t& getPte(uint64_t pteg, uint64_t idx)
- {
- return page_table[pteg * PTEG_SIZE + idx];
- }
-
- inline void defaultPte(volatile pte_t& pte)
- {
- pte.a = 0x4000000000000000; // B = 01 (1TB).
- pte.b = 0x0;
- }
-
- inline void setValid(bool valid, volatile pte_t& pte)
- {
- // Adding a page requires EIEIO to ensure update of PTE prior
- // to making valid and PTESYNC afterwards.
- // Removing a page just requires PTESYNC afterwards.
- if (valid)
- {
- asm volatile("eieio" ::: "memory");
- }
-
- pte.a &= ~0x01;
- pte.a |= (valid ? 0x1 : 0x0);
-
- if (!valid)
- {
- asm volatile("ptesync" ::: "memory");
-
- register uint64_t rS = 0, rB = 0;
- rB = (getTid(pte) << 11) // VA[0:54).
- | (((uint64_t)&pte) & 0x3FF8) >> 7; // VA[55:65].
- rB <<= 12; // Put in rB[0:51].
- rB |= 0x0100; // B = 01 (1TB).
-
- // TLBIE isn't correct in gcc, hand code asm.
- asm volatile(".long 0x7c000264 | (%0 << 11) | (%1 << 21)" ::
- "r"(rB), "r"(rS) : "memory");
-
- asm volatile("eieio" ::: "memory");
- asm volatile("tlbsync" ::: "memory");
- }
-
- asm volatile("ptesync" ::: "memory");
- }
-
- inline bool isValid(volatile pte_t& pte)
- {
- return ((pte.a & 0x01) == 0x01);
- }
-
- inline void setTid(tid_t tid, volatile pte_t& pte)
- {
- pte.a &= 0xC00000000000007F;
- pte.a |= ((uint64_t) tid) << 7;
- }
-
- inline tid_t getTid(volatile pte_t& pte)
- {
- return (tid_t) ((pte.a & 0xC00000000000007F) >> 7);
- }
-
- inline void setAccess(ACCESS_TYPES t, volatile pte_t& pte)
- {
- uint64_t pteMask = ~0x800000000000007B;
- pte.b &= pteMask;
- pte.b |= (NO_USER_ACCESS == t ? 0x0000000000000010 :
- (READ_O_ACCESS == t ? 0x0000000000000011 :
- (NORMAL_ACCESS == t ? 0x0000000000000012 :
- (CI_ACCESS == t ? 0x000000000000002A :
- 0x0))));
- }
-
- inline void setPage(uint64_t page, volatile pte_t& pte)
- {
- pte.b &= ~0x0FFFFFFFFFFFF000;
- pte.b |= page << 12;
- }
-
- inline uint64_t getPage(volatile pte_t& pte)
- {
- return (pte.b & 0x0FFFFFFFFFFFF000) >> 12;
- }
};
#endif
OpenPOWER on IntegriCloud