DragonV2/src/hardware/MMU.hpp
2026-05-22 06:38:32 +02:00

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; }
};
}
}