diff options
author | Dan Crowell <dcrowell@us.ibm.com> | 2011-07-06 10:16:21 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2011-07-14 14:53:35 -0500 |
commit | 2583b46750d1e1c062763eff204baa1460e7ae90 (patch) | |
tree | 3fc331001e03e014bba295eda594fe86d248d477 /src/include | |
parent | accc0f438eca45dcd1058a195d192d51a6f1c4aa (diff) | |
download | talos-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.H | 406 | ||||
-rw-r--r-- | src/include/kernel/vmmmgr.H | 96 |
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 |