From 7fbc085167a67603449871376d09b53bcba629a7 Mon Sep 17 00:00:00 2001 From: colby-nyce Date: Fri, 13 Dec 2024 12:27:33 -0600 Subject: [PATCH 1/2] Address PR feedback (#28) Co-authored-by: Colby Nyce --- arch/RegisterDefnsJSON.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/RegisterDefnsJSON.hpp b/arch/RegisterDefnsJSON.hpp index b6ac41a..aba0318 100644 --- a/arch/RegisterDefnsJSON.hpp +++ b/arch/RegisterDefnsJSON.hpp @@ -127,10 +127,13 @@ namespace atlas constexpr sparta::RegisterBase::Definition::HintsT hints = 0; constexpr sparta::RegisterBase::Definition::RegDomainT regdomain = 0; + const bool writable = id != 0 || group_num != 0; + sparta::RegisterBase::Definition defn = { id, name, group_num, group, group_idx, desc, bytes, field_defns, bank_membership, aliases, - subset_of, subset_offset, initial_value, hints, regdomain}; + subset_of, subset_offset, initial_value, hints, regdomain, + writable}; register_defns_.push_back(defn); } From 98ca826f26a508c358fcf32ee2951e9f04b2dd16 Mon Sep 17 00:00:00 2001 From: Shiraz Anwar Khan <40426879+skhanx86@users.noreply.github.com> Date: Fri, 13 Dec 2024 13:43:57 -0500 Subject: [PATCH 2/2] SV32 translation test with basic PageTableWalk (#20) This PR introduces a basic implementation of the SV32 page table walk, following a test-driven approach. A test was written to validate the functionality, which led to defining the `sv32PageTableWalk` method for address translation. The current implementation of `sv32PageTableWalk` checks the validity of PTEs but does not include comprehensive checks for other conditions. This sets up a foundation for further enhancement in the page table walk process, with future iterations expected to include more advanced validations. --------- Co-authored-by: Kathlene Magnus --- core/CMakeLists.txt | 1 + core/PageTable.hpp | 119 ++++++++++++++--- core/PageTable.tpp | 109 ---------------- core/PageTableEntry.hpp | 174 +++++++++++++++---------- core/PageTableEntry.tpp | 60 --------- core/PageTableWalker.cpp | 52 ++++++++ core/PageTableWalker.hpp | 69 ++++++++++ core/Translate.cpp | 1 + test/core/translate/Translate_test.cpp | 102 ++++++++------- 9 files changed, 386 insertions(+), 301 deletions(-) delete mode 100644 core/PageTable.tpp delete mode 100644 core/PageTableEntry.tpp create mode 100644 core/PageTableWalker.cpp create mode 100644 core/PageTableWalker.hpp diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 86bacf8..79c997c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(atlascore Execute.cpp AtlasExtractor.cpp AtlasInst.cpp + PageTableWalker.cpp observers/Observer.cpp observers/CoSimObserver.cpp observers/InstructionLogger.cpp diff --git a/core/PageTable.hpp b/core/PageTable.hpp index c96655d..ae68c6f 100644 --- a/core/PageTable.hpp +++ b/core/PageTable.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include #include "../include/AtlasTypes.hpp" @@ -10,25 +12,110 @@ namespace atlas private: const uint16_t max_entries; const uint32_t baseAddressOfpageTable; - bool isValidIndex(uint32_t idx); - size_t size(); - uint16_t getMaxNumEntries(MMUMode mode) const; + + bool isValidIndex(uint32_t idx) + { + uint32_t pte_size = (Mode == MMUMode::SV32) ? sizeof(RV32) : sizeof(RV64); + return ((idx >= baseAddressOfpageTable) + && (idx < ((max_entries * pte_size) + baseAddressOfpageTable))); + } + + size_t size() const { return pageTable.size(); } + + uint16_t getMaxNumEntries() const + { + if (Mode == MMUMode::SV32) + return PT_ENTRIES_SV32; + else if (Mode == MMUMode::SV39) + return PT_ENTRIES_SV39; + return 0; + } public: std::map> - pageTable; // uint32_t will be able to accomodate all the types of indexes(VPNs) for - // addressing the PTE - - PageTable(uint32_t baseAddr); - void addEntry(uint32_t index, PageTableEntry entry); - PageTableEntry getEntry(uint32_t index); - void removeEntry(uint32_t index); - void print(std::ostream & os); - bool contains(uint32_t index); + pageTable; // uint32_t accommodates all types of VPNs for addressing the PTE + + PageTable(uint32_t baseAddr) : + max_entries(getMaxNumEntries()), + baseAddressOfpageTable(baseAddr) + { + } + + void addEntry(uint32_t index, PageTableEntry entry) + { + if (size() <= max_entries && isValidIndex(index)) + { + auto it = pageTable.find(index); + if (it != pageTable.end()) + { + it->second = entry; // Update the existing entry + } + else + { + pageTable.insert({index, entry}); // Insert the new entry + } + } + else + { + throw std::runtime_error( + "Page table has reached its maximum capacity or index is out of bounds!"); + } + } + + PageTableEntry getEntry(uint32_t index) + { + if (isValidIndex(index)) + { + auto it = pageTable.find(index); + if (it != pageTable.end()) + { + return it->second; + } + else + { + throw std::out_of_range("Index not found in the page table"); + } + } + else + { + throw std::out_of_range("Invalid index"); + } + } + + void removeEntry(uint32_t index) + { + if (isValidIndex(index)) + { + auto it = pageTable.find(index); + if (it != pageTable.end()) + { + pageTable.erase(it); + } + else + { + throw std::out_of_range("Index not found in the page table"); + } + } + else + { + throw std::out_of_range("Invalid index"); + } + } + + bool contains(uint32_t index) const { return pageTable.find(index) != pageTable.end(); } + + void print(std::ostream & os) const + { + for (const auto & [index, entry] : pageTable) + { + os << "Index: " << index << " | PTE: " << entry.getPTE() << std::endl; + } + } }; - template - std::ostream & operator<<(std::ostream & os, const PageTable & pt); + template std::ostream & operator<<(std::ostream & os, const PageTable & pt) + { + pt.print(os); + return os; + } } // namespace atlas - -#include "PageTable.tpp" \ No newline at end of file diff --git a/core/PageTable.tpp b/core/PageTable.tpp deleted file mode 100644 index 0c93977..0000000 --- a/core/PageTable.tpp +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include - -namespace atlas{ - // constructor that sets the maximum number of entries in the page table - - template - uint16_t PageTable::getMaxNumEntries(MMUMode mode) const - { - if(mode == MMUMode::SV32) - return PT_ENTRIES_SV32; - else if (mode == MMUMode::SV39) - return PT_ENTRIES_SV39; - return 0; - } - - template - PageTable::PageTable(uint32_t baseAddr) : - max_entries(getMaxNumEntries(Mode)) , baseAddressOfpageTable(baseAddr) - {} - - template <> void PageTable::addEntry(uint32_t index, PageTableEntry entry) { - if (size() <= max_entries && isValidIndex(index)) { - auto it = pageTable.find(index); - if (it != pageTable.end()) { - // Update the existing entry - it->second = entry; - } else { - // Insert the new entry - pageTable.insert({index, entry}); - } - } else { - throw std::runtime_error("Page table has reached its maximum capacity/PageTable index out of bound!"); - } - } - - // template <> void PageTable::addEntry(uint32_t index, PageTableEntry entry) { - // if (size() < max_entries && isValidIndex(index)) { - // if(pageTable.contains(index)) - // pageTable[index] = entry; - // } else { - // throw std::runtime_error("Page table has reached its maximum capacity/PageTable index out of bound!"); - // } - // } - - template bool PageTable::isValidIndex(uint32_t idx){ - return ((idx > baseAddressOfpageTable) && (idx <= (max_entries + baseAddressOfpageTable))); - } - - - // Method to get an entry from the page table at a given index - template PageTableEntry PageTable::getEntry(uint32_t index) { - if(isValidIndex(index)){ - auto it = pageTable.find(index); - if (it != pageTable.end()) { - return it->second; - } else { - throw std::out_of_range("Index not found in the page table"); - } - } - else - throw std::out_of_range("Index Invalid"); - } - - // Method to remove an entry from the page table at a given index - template void PageTable::removeEntry(uint32_t index) { - if(isValidIndex(index)){ - auto it = pageTable.find(index); - if (it != pageTable.end()) { - pageTable.erase(it); - } else { - throw std::out_of_range("Index not found in the page table"); - } - } else{ - throw std::out_of_range("Index Invalid"); - } - } - - // Method to check if an entry exists at a given index - template bool PageTable::contains(uint32_t index) { - return pageTable.find(index) != pageTable.end(); - } - - // Method to get the current number of entries in the page table - template size_t PageTable::size() { - return pageTable.size(); - } - - // // Method to print all entries in the page table - // template void PageTable::print() { - // for ( auto& [index, entry] : pageTable) { - // std::cout << "Index: " << index << " | PTE: " << entry.getPTE() << std::endl; - // } - // } - - template - void PageTable::print(std::ostream& os) { - for (const auto& [index, entry] : pageTable) { - os << "Index: " << index << " | PTE: " << entry.getPTE() << std::endl; - } - } - - template - std::ostream & operator<<(std::ostream & os, const PageTable& pt) - { - pt.print(os); - return os; - } -} diff --git a/core/PageTableEntry.hpp b/core/PageTableEntry.hpp index aed084c..b01ed5c 100644 --- a/core/PageTableEntry.hpp +++ b/core/PageTableEntry.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include "../include/AtlasTypes.hpp" @@ -33,92 +35,120 @@ namespace atlas bool V_; // Valid bit public: - PageTableEntry(xLen pte); + PageTableEntry(xLen pte) + { + if constexpr (Mode == MMUMode::SV32) + { + pageTableEntryValue_ = pte; + unUsedBits_ = 0; // no such field exist here hence 0 + uint32_t PPN1 = (pte >> 20) & TWELVE_BIT_MASK; // 12 bits + uint32_t PPN0 = + (pte >> 10) & TEN_BIT_MASK; // Extract PPN[0] (bits 19-10) // 10 bits + this->PPN_ = (PPN1 << 10) + | PPN0; // Combine PPN1 and PPN0 to form the full PPN // 22 bits total + decodePTEFields_(pte); + } + } // Getter methods for each field - xLen getPTE() const; - uint32_t getUnusedBits() const; - uint32_t getPPN() const; - uint32_t getPPN1() const; - uint32_t getPPN0() const; - uint8_t getRSW() const; - bool isDirty() const; - bool isAccessed() const; - bool isGlobal() const; - bool isUserMode() const; - bool canExecute() const; - bool canWrite() const; - bool canRead() const; - bool isValid() const; - - private: - // Setter methods for each field - void setPTE_(xLen pte); - void setUnusedBits_(uint32_t unusedBits); - void setPPN_(uint32_t ppn); - void setPPN0_(uint32_t ppn0); - void setPPN1_(uint32_t ppn1); - void setRSW_(uint8_t rsw); - void setDirty_(bool d); - void setAccessed_(bool a); - void setGlobal_(bool g); - void setUserMode_(bool u); - void setExecute_(bool x); - void setWrite_(bool w); - void setRead_(bool r); - void setValid_(bool v); - - void decodePTEFields_(xLen pte); - }; - - template void PageTableEntry::setPTE_(xLen pte) - { - pageTableEntryValue_ = pte; - } - - template void PageTableEntry::setRSW_(uint8_t rsw) - { - RSW_ = rsw & 0x3; - } // Mask to ensure it's a 2-bit value + xLen getPTE() const { return pageTableEntryValue_; } - template void PageTableEntry::setDirty_(bool d) { D_ = d; } + uint32_t getUnusedBits() const { return (Mode == MMUMode::SV32) ? 0 : unUsedBits_; } - template void PageTableEntry::setAccessed_(bool a) { A_ = a; } + uint32_t getPPN() const { return PPN_; } - template void PageTableEntry::setGlobal_(bool g) { G_ = g; } + uint32_t getPPN1() const + { + return (Mode == MMUMode::SV32) ? ((PPN_ >> 10) & 0xFFF) : 0; + } // 12 bits for PPN1 - template void PageTableEntry::setUserMode_(bool u) { U_ = u; } + uint32_t getPPN0() const + { + return (Mode == MMUMode::SV32) ? (PPN_ & 0x3FF) : 0; + } // 10 bits for PPN0 - template void PageTableEntry::setExecute_(bool x) { X_ = x; } + uint8_t getRSW() const { return RSW_; } - template void PageTableEntry::setWrite_(bool w) { W_ = w; } + bool isDirty() const { return D_; } - template void PageTableEntry::setRead_(bool r) { R_ = r; } + bool isAccessed() const { return A_; } - template void PageTableEntry::setValid_(bool v) { V_ = v; } + bool isGlobal() const { return G_; } - template typename PageTableEntry::xLen PageTableEntry::getPTE() const - { - return pageTableEntryValue_; - } - - template uint8_t PageTableEntry::getRSW() const { return RSW_; } - - template bool PageTableEntry::isDirty() const { return D_; } - - template bool PageTableEntry::isAccessed() const { return A_; } - - template bool PageTableEntry::isGlobal() const { return G_; } + bool isUserMode() const { return U_; } - template bool PageTableEntry::isUserMode() const { return U_; } + bool canExecute() const { return X_; } - template bool PageTableEntry::canExecute() const { return X_; } + bool canWrite() const { return W_; } - template bool PageTableEntry::canWrite() const { return W_; } + bool canRead() const { return R_; } - template bool PageTableEntry::canRead() const { return R_; } + bool isValid() const { return V_; } - template bool PageTableEntry::isValid() const { return V_; } + private: + // Setter methods for each field + void setPTE_(xLen pte) { pageTableEntryValue_ = pte; } + + void setUnusedBits_(uint32_t unusedBits) + { + if constexpr (Mode != MMUMode::SV32) + { + unUsedBits_ = unusedBits; + } + } + + void setPPN_(uint32_t ppn) { PPN_ = ppn; } // Setter for full PPN + + void setPPN0_(uint32_t ppn0) + { + if constexpr (Mode == MMUMode::SV32) + { + PPN_ &= ~0x3FF; // Clear the lower 10 bits (PPN0) + PPN_ |= (ppn0 & 0x3FF); // Set the lower 10 bits (PPN0) + } + } + + void setPPN1_(uint32_t ppn1) + { + if constexpr (Mode == MMUMode::SV32) + { + PPN_ &= ~(0xFFF << 10); // Clear bits 21-10 (PPN1) + PPN_ |= (ppn1 & 0xFFF) << 10; // Set bits 21-10 (PPN1) + } + } + + void setRSW_(uint8_t rsw) { RSW_ = rsw & 0x3; } // Mask to ensure it's a 2-bit value + + void setDirty_(bool d) { D_ = d; } + + void setAccessed_(bool a) { A_ = a; } + + void setGlobal_(bool g) { G_ = g; } + + void setUserMode_(bool u) { U_ = u; } + + void setExecute_(bool x) { X_ = x; } + + void setWrite_(bool w) { W_ = w; } + + void setRead_(bool r) { R_ = r; } + + void setValid_(bool v) { V_ = v; } + + void decodePTEFields_(xLen pte) + { + if constexpr (Mode == MMUMode::SV32) + { + RSW_ = (pte >> 8) & TWO_BIT_MASK; // Extract RSW_ (bits 9-8) // 2 bits + D_ = pte & PTE_D_MASK; // Extract D_ (Dirty bit, bit 7) // 1 bit + A_ = pte & PTE_A_MASK; // Extract A_ (Accessed bit, bit 6) // 1 bit + G_ = pte & PTE_G_MASK; // Extract G_ (Global bit, bit 5) // 1 bit + U_ = pte & PTE_U_MASK; // Extract U_ (User-mode bit, bit 4) // 1 bit + X_ = pte & PTE_X_MASK; // Extract X_ (Execute bit, bit 3) // 1 bit + W_ = pte & PTE_W_MASK; // Extract W_ (Write bit, bit 2) // 1 bit + R_ = pte & PTE_R_MASK; // Extract R_ (Read bit, bit 1) // 1 bit + V_ = pte & PTE_V_MASK; // Extract V_ (Valid bit, bit 0) // 1 bit + } + } + }; } // namespace atlas - -#include "PageTableEntry.tpp" \ No newline at end of file diff --git a/core/PageTableEntry.tpp b/core/PageTableEntry.tpp deleted file mode 100644 index 02f9126..0000000 --- a/core/PageTableEntry.tpp +++ /dev/null @@ -1,60 +0,0 @@ -namespace atlas -{ - // Constructor to initialize from a 32-bit PTE value - template <> - PageTableEntry::PageTableEntry(uint32_t pte){ - // using xlen = RV32; - pageTableEntryValue_ = pte; - unUsedBits_ = 0; //no such field exist here hence 0 - uint32_t PPN1 = (pte >> 20) & TWELVE_BIT_MASK; // 12 bits - uint32_t PPN0 = (pte >> 10) & TEN_BIT_MASK; // Extract PPN[0] (bits 19-10) // 10 bits - this->PPN_ = (PPN1 << 10) | PPN0; // Combine PPN1 and PPN0 to form the full PPN // 22 bits total - decodePTEFields_(pte); - } - - template <> - void PageTableEntry::setUnusedBits_(uint32_t unusedBits){ - (void)unusedBits; - unUsedBits_ = 0; //unUsedBits not present in PTE - } - - template <> - void PageTableEntry::setPPN_(uint32_t ppn) {PPN_ = ppn;} // Setter for full PPN - - template <> // Setter for lower 10 bits (PPN0) - void PageTableEntry::setPPN0_(uint32_t ppn0) { - PPN_ &= ~0x3FF; // Clear the lower 10 bits (PPN0) - PPN_ |= (ppn0 & 0x3FF); // Set the lower 10 bits (PPN0) - } - - template <> // Setter for upper 12 bits (PPN1) - void PageTableEntry::setPPN1_(uint32_t ppn1) { - PPN_ &= ~(0xFFF << 10); // Clear bits 21-10 (PPN1) - PPN_ |= (ppn1 & 0xFFF) << 10; // Set bits 21-10 (PPN1) - } - - template <> - uint32_t PageTableEntry::getPPN() const {return PPN_;} - - template <> - uint32_t PageTableEntry::getPPN1() const {return (PPN_ >> 10) & 0xFFF;} // 12 bits for PPN1 - - template <> - uint32_t PageTableEntry::getPPN0() const {return PPN_ & 0x3FF;} // 10 bits for PPN0 - - template <> - uint32_t PageTableEntry::getUnusedBits() const {return 0;} - - template - void PageTableEntry::decodePTEFields_(xLen pte) { - RSW_ = (pte >> 8) & TWO_BIT_MASK; // Extract RSW_ (bits 9-8) // 2 bits - D_ = pte & PTE_D_MASK; // Extract D_ (Dirty bit, bit 7) // 1 bit - A_ = pte & PTE_A_MASK; // Extract A_ (Accessed bit, bit 6) // 1 bit - G_ = pte & PTE_G_MASK; // Extract G_ (Global bit, bit 5) // 1 bit - U_ = pte & PTE_U_MASK; // Extract U_ (User-mode bit, bit 4) // 1 bit - X_ = pte & PTE_X_MASK; // Extract X_ (Execute bit, bit 3) // 1 bit - W_ = pte & PTE_W_MASK; // Extract W_ (Write bit, bit 2) // 1 bit - R_ = pte & PTE_R_MASK; // Extract R_ (Read bit, bit 1) // 1 bit - V_ = pte & PTE_V_MASK; // Extract V_ (Valid bit, bit 0) // 1 bit - } -} \ No newline at end of file diff --git a/core/PageTableWalker.cpp b/core/PageTableWalker.cpp new file mode 100644 index 0000000..d76c453 --- /dev/null +++ b/core/PageTableWalker.cpp @@ -0,0 +1,52 @@ +// +// Created by skhan on 11/20/24. +// + +#include "../include/AtlasTypes.hpp" +#include "PageTableWalker.hpp" +#include "PageTableEntry.hpp" + +namespace atlas +{ + + uint32_t PageTableWalker::sv32PageTableWalk(uint32_t virtAddr, uint32_t satpRegVal, + AtlasState* state) + { + uint32_t PTEaddresss, ptbaseAddress; + const uint32_t PTE_SIZE = sizeof(RV32); + const uint32_t offset = extractOffset(virtAddr, MMUMode::SV32); + const std::vector vpnValues = extractVPN(virtAddr, MMUMode::SV32); + // TODO: getBaseAddrFromSatpReg(); + int vpnVectorIndex = vpnValues.size() - 1; + ptbaseAddress = satpRegVal; + while (vpnVectorIndex > (-1)) + { + PTEaddresss = ptbaseAddress + vpnValues[vpnVectorIndex] * PTE_SIZE; + ptbaseAddress = getPFN(PTEaddresss, state); + vpnVectorIndex--; + } + const uint32_t PhyMemFrameAddress = + ptbaseAddress + + offset * PTE_SIZE; // ptbaseAddress points to the Physical Memory base Address + return PhyMemFrameAddress; + } + + // convert this to template method, make uint32_t as template + uint32_t PageTableWalker::getPFN(const uint32_t entryValues, AtlasState* state) + { + const uint64_t pteValueFromMem = state->readMemory(entryValues); + PageTableEntry entry(pteValueFromMem); + // TODO: + // If accessing pte violates a PMA or PMP check, raise an access-fault exception + // corresponding to the original access type + if (!entry.isValid() || ((!entry.canRead()) && entry.canWrite())) + { + throw std::runtime_error("page-fault exception"); + } + // TODO: maybe this should be in PageTableWalk method itself, as this should be controlling + // if next level is phyMem or next level of PT + // If ((!(pte.r==1)) || (!(pte.x==1))) + // PTE points to next level pageTable + return (pteValueFromMem >> 10) << 10; + } +} // namespace atlas \ No newline at end of file diff --git a/core/PageTableWalker.hpp b/core/PageTableWalker.hpp new file mode 100644 index 0000000..a5013d6 --- /dev/null +++ b/core/PageTableWalker.hpp @@ -0,0 +1,69 @@ +// +// Created by skhan on 11/20/24. +// +#pragma once + +#include "AtlasState.hpp" + +namespace atlas +{ + // TODO: A template class based on Mode, all methods will work according to the mode, hence + // methods will also be template + class PageTableWalker + { + + const std::vector offsets_{12, 12, 12}; + const std::vector> vpn_ = { + {10, 10}, // Sv32 + {9, 9, 9}, // Sv39 + {9, 9, 9, 9} // Sv48 + }; + + inline uint32_t getMMUModeOffset(MMUMode mmu_mode) + { + return offsets_.at(static_cast(mmu_mode)); + } + + inline uint32_t getMMUModeVPNBits(MMUMode mmu_mode, int index) + { + const auto & vpn_bits = vpn_.at(static_cast(mmu_mode)); + if (index >= ((int)vpn_bits.size())) + { + throw std::out_of_range("VPN index out of range for MMU mode"); + } + return vpn_bits[index]; + } + + std::vector getMMUModeVPNs(MMUMode mmu_mode) + { + return vpn_.at(static_cast(mmu_mode)); + } + + uint32_t extractOffset(uint32_t virtualAddress, MMUMode mode) + { + uint32_t offsetBitsSize = getMMUModeOffset(mode); + return virtualAddress + & ((1 << offsetBitsSize) - 1); // Mask to extract the lower 'offsetBitsSize' bits + } + + std::vector extractVPN(uint32_t virtualAddress, MMUMode mode) + { + std::vector vpnValues; + std::vector vpn_bits = getMMUModeVPNs(mode); + uint32_t shift = getMMUModeOffset(mode); + for (uint32_t bits : vpn_bits) + { + vpnValues.push_back((virtualAddress >> shift) & ((1 << bits) - 1)); + shift += bits; + } + return vpnValues; + } + + public: + PageTableWalker() {} + + uint32_t getPFN(uint32_t, AtlasState*); + uint32_t sv32PageTableWalk(uint32_t, uint32_t, AtlasState*); + }; + +} // namespace atlas \ No newline at end of file diff --git a/core/Translate.cpp b/core/Translate.cpp index 73e630f..8dce9fb 100644 --- a/core/Translate.cpp +++ b/core/Translate.cpp @@ -32,6 +32,7 @@ namespace atlas ILOG("Translating 0x" << std::hex << request.virtual_addr); // Translation currently not supported, assume VA = PA + // TODO: PageTableWalker.pageTableWalk(request.virtual_addr, state); translation_state->setTranslationResult(request.virtual_addr, request.size); // Keep going diff --git a/test/core/translate/Translate_test.cpp b/test/core/translate/Translate_test.cpp index f8e8d38..88abfed 100644 --- a/test/core/translate/Translate_test.cpp +++ b/test/core/translate/Translate_test.cpp @@ -3,11 +3,13 @@ #include "include/AtlasTypes.hpp" #include "core/PageTableEntry.hpp" #include "core/PageTable.hpp" +#include "core/PageTableWalker.hpp" #include #include "sparta/utils/SpartaTester.hpp" class AtlasTranslateTester { + public: AtlasTranslateTester() { @@ -118,6 +120,7 @@ class AtlasTranslateTester void testPageTable() // unit test for PageTable.cpp { uint32_t pa = 0x7B1EEFF; + uint32_t PTE_SIZE = sizeof(atlas::RV32); // since test is for SV32 uint32_t baseAddrOfPT = 0xFFFF0000; atlas::PageTable pt(baseAddrOfPT); atlas::PageTableEntry sv32PTE1( @@ -128,65 +131,75 @@ class AtlasTranslateTester // 1111 0000 1111) atlas::PageTableEntry sv32PTE3( 0x7F03D4C3); // Valid, Read-only (0111 1111 0000 0011 1101 0100 1100 0011) - atlas::PageTableEntry sv32PTE4( - 0xABC12FF); // Invalid PTE (0000 0000 0000 0000 0000 0000 0000 0000) + atlas::PageTableEntry sv32PTE4(0xABC12FF); - pt.addEntry(baseAddrOfPT + 1, sv32PTE1); - pt.addEntry(baseAddrOfPT + 10, sv32PTE2); - pt.addEntry(baseAddrOfPT + 100, sv32PTE3); - pt.addEntry(baseAddrOfPT + 1024, sv32PTE4); + pt.addEntry(baseAddrOfPT + 1 * PTE_SIZE, sv32PTE1); + pt.addEntry(baseAddrOfPT + 10 * PTE_SIZE, sv32PTE2); + pt.addEntry(baseAddrOfPT + 100 * PTE_SIZE, sv32PTE3); + pt.addEntry(baseAddrOfPT + 1023 * PTE_SIZE, sv32PTE4); - EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 1).getPPN(), sv32PTE1.getPPN()); - EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 10).getPPN(), sv32PTE2.getPPN()); - EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 100).getPPN(), sv32PTE3.getPPN()); - EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 1024).getPPN(), sv32PTE4.getPPN()); + EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 1 * PTE_SIZE).getPPN(), sv32PTE1.getPPN()); + EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 10 * PTE_SIZE).getPPN(), sv32PTE2.getPPN()); + EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 100 * PTE_SIZE).getPPN(), sv32PTE3.getPPN()); + EXPECT_EQUAL(pt.getEntry(baseAddrOfPT + 1023 * PTE_SIZE).getPPN(), sv32PTE4.getPPN()); EXPECT_THROW(pt.addEntry( - baseAddrOfPT + 1025, - sv32PTE4)); // Page table has reached its maximum capacity/PageTable index out of bound! - EXPECT_THROW(pt.addEntry( - baseAddrOfPT, + baseAddrOfPT + 1024 * PTE_SIZE, sv32PTE4)); // Page table has reached its maximum capacity/PageTable index out of bound! - EXPECT_THROW( - pt.getEntry(baseAddrOfPT + 1023).getPPN()); // entry not present at the provided index + EXPECT_THROW(pt.getEntry(baseAddrOfPT + 1022 * PTE_SIZE) + .getPPN()); // entry not present at the provided index - EXPECT_THROW(pt.removeEntry(baseAddrOfPT + 1044)); // Index Invalid + EXPECT_THROW(pt.removeEntry(baseAddrOfPT + 1044 * PTE_SIZE)); // Index Invalid - EXPECT_TRUE(pt.contains(baseAddrOfPT + 1024)); - pt.removeEntry(baseAddrOfPT + 1024); - EXPECT_FALSE(pt.contains(baseAddrOfPT + 1024)); + EXPECT_TRUE(pt.contains(baseAddrOfPT + 1023 * PTE_SIZE)); + pt.removeEntry(baseAddrOfPT + 1023 * PTE_SIZE); + EXPECT_FALSE(pt.contains(baseAddrOfPT + 1023 * PTE_SIZE)); - EXPECT_TRUE(pt.contains(baseAddrOfPT + 100)); - pt.removeEntry(baseAddrOfPT + 100); - EXPECT_FALSE(pt.contains(baseAddrOfPT + 100)); + EXPECT_TRUE(pt.contains(baseAddrOfPT + 100 * PTE_SIZE)); + pt.removeEntry(baseAddrOfPT + 100 * PTE_SIZE); + EXPECT_FALSE(pt.contains(baseAddrOfPT + 100 * PTE_SIZE)); - EXPECT_TRUE(pt.contains(baseAddrOfPT + 10)); - pt.removeEntry(baseAddrOfPT + 10); - EXPECT_FALSE(pt.contains(baseAddrOfPT + 10)); + EXPECT_TRUE(pt.contains(baseAddrOfPT + 10 * PTE_SIZE)); + pt.removeEntry(baseAddrOfPT + 10 * PTE_SIZE); + EXPECT_FALSE(pt.contains(baseAddrOfPT + 10 * PTE_SIZE)); - EXPECT_TRUE(pt.contains(baseAddrOfPT + 1)); - pt.removeEntry(baseAddrOfPT + 1); - EXPECT_FALSE(pt.contains(baseAddrOfPT + 1)); + EXPECT_TRUE(pt.contains(baseAddrOfPT + 1 * PTE_SIZE)); + pt.removeEntry(baseAddrOfPT + 1 * PTE_SIZE); + EXPECT_FALSE(pt.contains(baseAddrOfPT + 1 * PTE_SIZE)); } void testSv32Translation() { - // const atlas::Addr pa = 0x1000; - // const uint64_t value = 0xdeadbeef; - // state_->writeMemory(pa, value); - - // presetup fopr the test, install all the addresses in pageTable Setups - - // uint32_t va = 0xABCD; - // uint64_t satpBaseAddress = 0x0000; - - // call ptw with the above fields - - // indexFromVa = extract index from VA - // pte = use that index to get PTE from the PageTable Map - // PA = use the pte to get PA from it, pass the PA to next level page for the - // further walk + atlas::PageTableWalker walker; + uint32_t PTE_SIZE = sizeof(atlas::RV32); + uint32_t va = 0x143FFABC; //{vpn[1]-->0x50-->d(80) , vpn[1]-->0xFF-->d(1023) , + // offset-->0xABC-->d(2748)} + uint32_t satpBaseAddress = 0xFFFF0000; // base address of PD + uint32_t pdeAddress = satpBaseAddress + (80 * PTE_SIZE); + uint32_t pdeVal = 0x7B1EEFF; + uint32_t pageTableBaseAddr = (pdeVal >> 10) << 10; // 7B1EC00 + uint32_t pteAddress = pageTableBaseAddr + (1023 * PTE_SIZE); + uint32_t pteVal = 0x7F03D4C3; + const atlas::Addr phyMemoryBaseAddr = (pteVal >> 10) << 10; // 0x7F03D400 + const atlas::Addr pa = (phyMemoryBaseAddr + (2748 * PTE_SIZE)); + const uint64_t val = 0xABCD1234; + + atlas::PageTable pageDirectory(satpBaseAddress); + atlas::PageTableEntry pageDirectoryEntry(pdeVal); + pageDirectory.addEntry(pdeAddress, pageDirectoryEntry); + atlas::PageTable pageTable(pageTableBaseAddr); + atlas::PageTableEntry PageTableEntry(pteVal); + pageTable.addEntry(pteAddress, PageTableEntry); + + state_->writeMemory(pa, val); + state_->writeMemory(pdeAddress, pdeVal); + state_->writeMemory(pteAddress, pteVal); + + uint32_t transaltedPA = walker.sv32PageTableWalk(va, satpBaseAddress, state_); + + EXPECT_EQUAL(pa, transaltedPA); + EXPECT_EQUAL(val, state_->readMemory(transaltedPA)); } private: @@ -206,6 +219,7 @@ int main(int argc, char** argv) translate_tester.testBaremetalTranslation(); translate_tester.testPageTableEntryCreation(); translate_tester.testAtlasTranslationState(); + translate_tester.testSv32Translation(); translate_tester.testPageTable(); REPORT_ERROR;