111 lines
4.8 KiB
C++
111 lines
4.8 KiB
C++
/*
|
|
DragonV2 - A collection of useful functionality
|
|
Copyright (C) 2026 OmniaX-Dev
|
|
|
|
This file is part of DragonV2.
|
|
|
|
DragonV2 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
DragonV2 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with DragonV2. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BUS.hpp"
|
|
|
|
namespace dragon
|
|
{
|
|
namespace hw
|
|
{
|
|
class MMU : public MemoryDevice
|
|
{
|
|
public:
|
|
MMU(BUS& bus, const MMUAccessMode* mode_ptr);
|
|
PhysicalAddress translate(VirtualAddress va, MMUAccessType type, MMUAccessMode mode) const;
|
|
void enable(bool value = true);
|
|
void setPtb(PhysicalAddress ptb);
|
|
void invalidateAll(void);
|
|
void invalidatePage(VirtualAddress va);
|
|
|
|
bool guest_cas_u32(PhysicalAddress addr, u32 expected, u32& actual, u32 desired) override;
|
|
|
|
// ---- Aligned loads ----
|
|
u64 load_u64(PhysicalAddress addr) const override;
|
|
u32 load_u32(PhysicalAddress addr) const override;
|
|
u16 load_u16(PhysicalAddress addr) const override;
|
|
u8 load_u8 (PhysicalAddress addr) const override;
|
|
|
|
// ---- Aligned stores ----
|
|
bool store_u64(PhysicalAddress addr, u64 value) override;
|
|
bool store_u32(PhysicalAddress addr, u32 value) override;
|
|
bool store_u16(PhysicalAddress addr, u16 value) override;
|
|
bool store_u8 (PhysicalAddress addr, u8 value) override;
|
|
|
|
inline void setCurrentAsid(u8 asid) { m_currentAsid = asid; }
|
|
inline u8 getCurrentAsid(void) const { return m_currentAsid; }
|
|
inline void disable(void) { enable(false); }
|
|
inline bool isEnabled(void) const { return m_enabled; }
|
|
inline PhysicalAddress getPtb(void) const { return m_ptb; }
|
|
|
|
// Convenience: translate using current mode
|
|
inline PhysicalAddress translate(VirtualAddress va, MMUAccessType type) const { return translate(va, type, *m_modePtr); }
|
|
u32 fetch_u32(VirtualAddress va) const;
|
|
|
|
private:
|
|
ExceptionCause get_exception_cause(MMUFaultKind kind, MMUAccessType type) const;
|
|
|
|
private:
|
|
bool m_enabled { false };
|
|
PhysicalAddress m_ptb { 0 };
|
|
u8 m_currentAsid { 0 }; //TODO:
|
|
BUS& m_bus;
|
|
const MMUAccessMode* m_modePtr;
|
|
|
|
private:
|
|
// Page Table Entry bit layout (32 bits):
|
|
//
|
|
// 31 12 11 .. 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
|
// ┌─────────────────────────────┬─────────┬───┬───┬───┬───┬───┬───┬───┐
|
|
// │ physical page number (20) │ reserved│ G │ U │ X │ W │ R │ A │ P │
|
|
// └─────────────────────────────┴─────────┴───┴───┴───┴───┴───┴───┴───┘
|
|
//
|
|
// P = Present : entry is valid; if 0, access faults
|
|
// A = Accessed : set by hardware on any access to this page
|
|
// R = Readable : load access permitted
|
|
// W = Writable : store access permitted
|
|
// X = Executable : instruction fetch permitted
|
|
// U = User-accessible: accessible from user mode (else supervisor-only)
|
|
// G = Global : translation valid in all address spaces (kernel mappings)
|
|
|
|
inline static constexpr u32 PTE_PRESENT = 1u << 0; // 0x001
|
|
inline static constexpr u32 PTE_ACCESSED = 1u << 1; // 0x002
|
|
inline static constexpr u32 PTE_READ = 1u << 2; // 0x004
|
|
inline static constexpr u32 PTE_WRITE = 1u << 3; // 0x008
|
|
inline static constexpr u32 PTE_EXEC = 1u << 4; // 0x010
|
|
inline static constexpr u32 PTE_USER = 1u << 5; // 0x020
|
|
inline static constexpr u32 PTE_GLOBAL = 1u << 6; // 0x040
|
|
inline static constexpr u32 PTE_DIRTY = 1u << 7; // 0x080
|
|
|
|
// Bits 7..11 reserved for future use (Dirty bit, cache attributes, etc.)
|
|
|
|
inline static constexpr u32 PTE_PERM_MASK = PTE_READ | PTE_WRITE | PTE_EXEC | PTE_USER | PTE_GLOBAL;
|
|
inline static constexpr u32 PTE_FLAGS_MASK = 0xFFFu; // bottom 12 bits = flags
|
|
inline static constexpr u32 PTE_PHYS_MASK = 0xFFFFF000u; // top 20 bits = phys page number
|
|
|
|
// Helper: extract the physical page-aligned address from a PTE
|
|
inline static constexpr u32 pte_phys_addr(u32 pte) { return pte & PTE_PHYS_MASK; }
|
|
|
|
// Helper: check a single bit
|
|
inline static constexpr bool pte_has(u32 pte, u32 flag) { return (pte & flag) != 0; }
|
|
};
|
|
}
|
|
}
|