diff --git a/CMakeLists.txt b/CMakeLists.txt index 68e338c..eb89f72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,12 +33,14 @@ list(APPEND RUNTIME_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/hardware/CPU.cpp ${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp ) list(APPEND DEBUGGER_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/debugger/debugger_main.cpp ${CMAKE_CURRENT_LIST_DIR}/src/hardware/CPU.cpp ${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp ) list(APPEND ASSEMBLER_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/assembler/assembler_main.cpp @@ -49,6 +51,7 @@ list(APPEND TOOLS_SOURCE_FILES list(APPEND TEST_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/RAM_test.cpp ${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp ) #----------------------------------------------------------------------------------------- diff --git a/other/build.nr b/other/build.nr index ec63514..f599e28 100644 --- a/other/build.nr +++ b/other/build.nr @@ -1 +1 @@ -9 +10 diff --git a/src/common/Data.hpp b/src/common/Data.hpp new file mode 100644 index 0000000..adf90ae --- /dev/null +++ b/src/common/Data.hpp @@ -0,0 +1,35 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include + +namespace dragon +{ + // ------ Contextual Aliases ------ + using AddressType = u32; + using VirtualAddress = AddressType; + using PhysycalAddress = AddressType; + // -------------------------------- + + enum class MMUAccessType { Read, Write, Execute }; +} diff --git a/src/hardware/BUS.cpp b/src/hardware/BUS.cpp new file mode 100644 index 0000000..39c9eba --- /dev/null +++ b/src/hardware/BUS.cpp @@ -0,0 +1,148 @@ +/* + 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 . +*/ + +#include "BUS.hpp" + +namespace dragon +{ + AtomicStorageMemoryDevice::AtomicStorageMemoryDevice(u64 size) + { + if (size == 0) // Special case, for classes like BUS, that are MemoryDevices but don't own any data + { + m_wordCount = 0; + m_size = 0; + m_words = nullptr; + return; + } + m_wordCount = (size + 7) / 8; // Round up to multiple of 8 bytes for the word-granular backing + m_size = size; + m_words = new std::atomic[m_wordCount]; + for (u64 i = 0; i < m_wordCount; ++i) + m_words[i].store(0, std::memory_order_relaxed); + } + + AtomicStorageMemoryDevice::~AtomicStorageMemoryDevice(void) + { + delete[] m_words; + } + + bool MemoryDevice::guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired) + { + fault(addr, 4, "CAS not supported on this device"); + return false; + } + + + + + + namespace hw + { + bool BUS::guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) + { + auto region = findRegion(addr); + if (!region) { /* fault */ return false; } + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->guest_cas_u32(finalAddr, expected, actual, desired); + } + + u8 BUS::load_u8(PhysycalAddress addr) const + { + auto region = findRegion(addr); + if (region == nullptr) return 0x00; //TODO: Error + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->load_u8(finalAddr); + } + + u16 BUS::load_u16(PhysycalAddress addr) const + { + auto region = findRegion(addr); + if (region == nullptr) return 0x0000; //TODO: Error + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->load_u16(finalAddr); + } + + u32 BUS::load_u32(PhysycalAddress addr) const + { + auto region = findRegion(addr); + if (region == nullptr) return 0x0000'0000; //TODO: Error + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->load_u32(finalAddr); + } + + u64 BUS::load_u64(PhysycalAddress addr) const + { + auto region = findRegion(addr); + if (region == nullptr) return 0x0000'0000'0000'0000; //TODO: Error + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->load_u64(finalAddr); + } + + bool BUS::store_u8(PhysycalAddress addr, u8 value) + { + auto region = findRegion(addr); + if (region == nullptr) return false; + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->store_u8(finalAddr, value); + } + + bool BUS::store_u16(PhysycalAddress addr, u16 value) + { + auto region = findRegion(addr); + if (region == nullptr) return false; + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->store_u16(finalAddr, value); + } + + bool BUS::store_u32(PhysycalAddress addr, u32 value) + { + auto region = findRegion(addr); + if (region == nullptr) return false; + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->store_u32(finalAddr, value); + } + + bool BUS::store_u64(PhysycalAddress addr, u64 value) + { + auto region = findRegion(addr); + if (region == nullptr) return false; + AddressType finalAddr = (region->remap ? addr - region->startAddress : addr); + return region->device->store_u64(finalAddr, value); + } + + void BUS::mapDevice(MemoryDevice& device, PhysycalAddress startAddr, PhysycalAddress endAddr, bool remap, ostd::String name) + { + m_regions.push_back({ &device, startAddr, endAddr, remap, name }); + } + + ostd::String BUS::getMemoryRegionName(PhysycalAddress address) + { + tMemoryRegion* region = findRegion(address); + if (region == nullptr) return "Invalid"; + return region->name; + } + + void BUS::fault(PhysycalAddress addr, u32 size, const String& msg) const + { + std::cout << msg << ostd::String::getHexStr(addr, true, 4) << "\n"; + /* TODO: This function basically only has to deal with the "region not mapped" problem. */ + } + } +} diff --git a/src/hardware/BUS.hpp b/src/hardware/BUS.hpp new file mode 100644 index 0000000..c01b8ad --- /dev/null +++ b/src/hardware/BUS.hpp @@ -0,0 +1,144 @@ +/* + 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 . +*/ + +#include +#include +#include "../common/Data.hpp" + +#pragma once + +namespace dragon +{ + class MemoryDevice : public ostd::BaseObject + { + public: + MemoryDevice(void) = default; + MemoryDevice(const MemoryDevice&) = delete; + MemoryDevice& operator=(const MemoryDevice&) = delete; + MemoryDevice(MemoryDevice&&) = delete; + MemoryDevice& operator=(MemoryDevice&&) = delete; + virtual ~MemoryDevice() = default; + + virtual bool guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired); + + // ---- Aligned loads ---- + virtual u64 load_u64(AddressType addr) const = 0; + virtual u32 load_u32(AddressType addr) const = 0; + virtual u16 load_u16(u32 addr) const = 0; + virtual u8 load_u8 (u32 addr) const = 0; + + inline i64 load_i64(AddressType addr) const { return cast(load_u64(addr)); } + inline i32 load_i32(AddressType addr) const { return cast(load_u32(addr)); } + inline i16 load_i16(AddressType addr) const { return cast(load_u16(addr)); } + inline i8 load_i8 (AddressType addr) const { return cast(load_u8 (addr)); } + + // ---- Aligned stores ---- + virtual bool store_u64(AddressType addr, u64 value) = 0; + virtual bool store_u32(AddressType addr, u32 value) = 0; + virtual bool store_u16(AddressType addr, u16 value) = 0; + virtual bool store_u8 (AddressType addr, u8 value) = 0; + + inline bool store_i64(AddressType addr, u64 value) { return store_u64(addr, cast(value)); } + inline bool store_i32(AddressType addr, u32 value) { return store_u32(addr, cast(value)); } + inline bool store_i16(AddressType addr, u16 value) { return store_u16(addr, cast(value)); } + inline bool store_i8 (AddressType addr, u8 value) { return store_u8 (addr, cast(value)); } + + [[noreturn]] virtual void fault(AddressType addr, u32 size, const String& msg = "") const = 0; // Message can be useful for debugging + + }; + + class AtomicStorageMemoryDevice : public MemoryDevice + { + public: + explicit AtomicStorageMemoryDevice(u64 size); + virtual ~AtomicStorageMemoryDevice(void); + AtomicStorageMemoryDevice(const AtomicStorageMemoryDevice&) = delete; + AtomicStorageMemoryDevice& operator=(const AtomicStorageMemoryDevice&) = delete; + AtomicStorageMemoryDevice(AtomicStorageMemoryDevice&&) = delete; + AtomicStorageMemoryDevice& operator=(AtomicStorageMemoryDevice&&) = delete; + + // ---- Helpers ---- + inline u64 getWordCount(void) const { return m_wordCount; } + inline u64 getSize(void) const { return m_size; } + inline virtual std::span> getRawData(void) { return { m_words, m_size }; } + inline virtual std::span> getRawData(void) const { return { m_words, m_size }; } + // Both getRawData() can be overridden to return empty spans for devices where internal memory shouldn't be exposed + + protected: + std::atomic* m_words; + u64 m_wordCount; + u64 m_size; + }; + namespace hw + { + class BUS : public MemoryDevice + { + public: + private: struct tMemoryRegion + { + MemoryDevice* device { nullptr }; + PhysycalAddress startAddress { 0x0000'0000 }; + PhysycalAddress endAddress { 0x0000'0000 }; + bool remap { false }; + ostd::String name { "" }; + }; + + public: + BUS(void) = default; + + bool guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) override; + + // ---- Aligned loads ---- + u64 load_u64(PhysycalAddress addr) const override; + u32 load_u32(PhysycalAddress addr) const override; + u16 load_u16(PhysycalAddress addr) const override; + u8 load_u8 (PhysycalAddress addr) const override; + + // ---- Aligned stores ---- + bool store_u64(PhysycalAddress addr, u64 value) override; + bool store_u32(PhysycalAddress addr, u32 value) override; + bool store_u16(PhysycalAddress addr, u16 value) override; + bool store_u8 (PhysycalAddress addr, u8 value) override; + + void mapDevice(MemoryDevice& device, PhysycalAddress startAddr, PhysycalAddress endAddr, bool remap = false, ostd::String name = ""); + ostd::String getMemoryRegionName(PhysycalAddress address); + + [[noreturn]] void fault(PhysycalAddress addr, u32 size, const String& msg) const override; + + private: + template + auto findRegion(this Self&& self, PhysycalAddress address) + { + for (auto& region : self.m_regions) + { // works whether self is const or not + if (address >= region.startAddress && address <= region.endAddress) + return ®ion; + } + self.fault(address, 0, "Memory device not found: "); + return decltype(&self.m_regions[0]){nullptr}; + } + + private: + std::vector m_regions; + + private: + }; + } +} diff --git a/src/hardware/CPU.hpp b/src/hardware/CPU.hpp index a0a9fa5..4ddf05b 100644 --- a/src/hardware/CPU.hpp +++ b/src/hardware/CPU.hpp @@ -20,10 +20,16 @@ #pragma once -#include +#include "../common/Data.hpp" namespace dragon { + struct GuestException + { + // ExceptionCause cause; + VirtualAddress fault_addr; // VA for translation faults, PA for bus faults, 0 otherwise + u32 faulting_pc; // set by the CPU before fault propagation, not by the throwsite + }; namespace hw { class CPU diff --git a/src/hardware/MMU.cpp b/src/hardware/MMU.cpp new file mode 100644 index 0000000..a4a810a --- /dev/null +++ b/src/hardware/MMU.cpp @@ -0,0 +1,68 @@ +/* + 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 . +*/ + +#include "MMU.hpp" + +namespace dragon +{ + namespace hw + { + } +} + + + +// PhysycalAddress MMU::translate(VirtualAddress va, AccessType type, Mode mode) +// { +// if (!m_enabled) return va; // identity map when disabled + +// u32 l1_idx = (va >> 22) & 0x3FF; +// u32 l2_idx = (va >> 12) & 0x3FF; +// u32 offset = va & 0xFFF; + +// // Walk level 1 +// u32 l1_pte_addr = m_ptb + l1_idx * 4; +// u32 l1_pte = ram.load_u32(l1_pte_addr); +// if (!(l1_pte & PTE_PRESENT)) +// throw GuestException{cause_for(type, PageFault), va}; + +// // Walk level 2 +// u32 l2_table_phys = (l1_pte >> 12) << 12; // physical address of L2 table +// u32 l2_pte_addr = l2_table_phys + l2_idx * 4; +// u32 l2_pte = ram.load_u32(l2_pte_addr); +// if (!(l2_pte & PTE_PRESENT)) +// throw GuestException{cause_for(type, PageFault), va}; + +// // Permission check +// if (mode == Mode::User && !(l2_pte & PTE_USER)) +// throw GuestException{cause_for(type, PrivPageFault), va}; +// if (type == AccessType::Read && !(l2_pte & PTE_READ)) throw GuestException{...}; +// if (type == AccessType::Write && !(l2_pte & PTE_WRITE)) throw GuestException{...}; +// if (type == AccessType::Execute && !(l2_pte & PTE_EXEC)) throw GuestException{...}; + +// // Set accessed bit (atomic so we don't race with other cores walking the same PTE) +// if (!(l2_pte & PTE_ACCESSED)) { +// // CAS to set the bit; ignore failure (means someone else set it) +// ram.guest_cas_u32(l2_pte_addr, l2_pte, l2_pte | PTE_ACCESSED); +// } + +// u32 phys_page = (l2_pte >> 12) << 12; +// return phys_page | offset; +// } diff --git a/src/hardware/MMU.hpp b/src/hardware/MMU.hpp new file mode 100644 index 0000000..3c78471 --- /dev/null +++ b/src/hardware/MMU.hpp @@ -0,0 +1,37 @@ +/* + 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 . +*/ + +#pragma once + +#include "BUS.hpp" + +namespace dragon +{ + namespace hw + { + class MMU : public MemoryDevice + { + public: + explicit MMU(void); + + + }; + } +} diff --git a/src/hardware/RAM.cpp b/src/hardware/RAM.cpp index e35bda1..1be41bf 100644 --- a/src/hardware/RAM.cpp +++ b/src/hardware/RAM.cpp @@ -26,35 +26,55 @@ namespace dragon { namespace hw { - RAM::RAM(u64 size) + bool RAM::guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) { - m_wordCount = (size + 7) / 8; // Round up to multiple of 8 bytes for the word-granular backing - m_size = size; - m_words = new std::atomic[m_wordCount]; - for (u64 i = 0; i < m_wordCount; ++i) - m_words[i].store(0, std::memory_order_relaxed); + if (addr + 4 > m_size || (addr & 3)) + { + fault(addr, 4, "Misaligned/OOB CAS"); + return false; + } + + u32 shift = (addr & 4) * 8; + u64 mask = u64(0xFFFFFFFFu) << shift; + std::atomic& word = m_words[addr >> 3]; + + u64 word_expected = word.load(std::memory_order_seq_cst); + while (true) + { + u32 current_in_slot = static_cast(word_expected >> shift); + if (current_in_slot != expected) + { + // CAS fails: report what we saw, don't modify + actual = current_in_slot; + return false; + } + // CAS could succeed: try to update + u64 word_desired = (word_expected & ~mask) | (u64(desired) << shift); + if (word.compare_exchange_weak(word_expected, word_desired, std::memory_order_seq_cst, std::memory_order_seq_cst)) + { + actual = expected; // tell caller we succeeded + return true; + } + // CAS spuriously failed or someone else changed the word; word_expected + // is updated. Loop and re-check. + } } - RAM::~RAM(void) - { - delete[] m_words; - } - - u64 RAM::load_u64(u32 addr) const + u64 RAM::load_u64(PhysycalAddress addr) const { if (addr + 8 > m_size || (addr & 7)) { - fault(addr, 8); + fault(addr, 8, "Memory Fault: "); return 0; } return m_words[addr >> 3].load(std::memory_order_seq_cst); } - u32 RAM::load_u32(u32 addr) const + u32 RAM::load_u32(PhysycalAddress addr) const { if (addr + 4 > m_size || (addr & 3)) { - fault(addr, 4); + fault(addr, 4, "Memory Fault: "); return 0; } u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst); @@ -62,11 +82,11 @@ namespace dragon return static_cast(word >> shift); } - u16 RAM::load_u16(u32 addr) const + u16 RAM::load_u16(PhysycalAddress addr) const { if (addr + 2 > m_size || (addr & 1)) { - fault(addr, 2); + fault(addr, 2, "Memory Fault: "); return 0; } u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst); @@ -74,11 +94,11 @@ namespace dragon return static_cast(word >> shift); } - u8 RAM::load_u8(u32 addr) const + u8 RAM::load_u8(PhysycalAddress addr) const { if (addr >= m_size) { - fault(addr, 1); + fault(addr, 1, "Memory Fault: "); return 0; } u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst); @@ -86,22 +106,23 @@ namespace dragon return static_cast(word >> shift); } - void RAM::store_u64(u32 addr, u64 value) + bool RAM::store_u64(PhysycalAddress addr, u64 value) { if (addr + 8 > m_size || (addr & 7)) { - fault(addr, 8); - return; + fault(addr, 8, "Memory Fault: "); + return false; } m_words[addr >> 3].store(value, std::memory_order_seq_cst); + return true; } - void RAM::store_u32(u32 addr, u32 value) + bool RAM::store_u32(PhysycalAddress addr, u32 value) { if (addr + 4 > m_size || (addr & 3)) { - fault(addr, 4); - return; + fault(addr, 4, "Memory Fault: "); + return false; } u32 shift = (addr & 4) * 8; u64 mask = u64(0xFFFFFFFFu) << shift; @@ -112,14 +133,15 @@ namespace dragon { desired = (expected & ~mask) | (u64(value) << shift); } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed)); + return true; } - void RAM::store_u16(u32 addr, u16 value) + bool RAM::store_u16(PhysycalAddress addr, u16 value) { if (addr + 2 > m_size || (addr & 1)) { - fault(addr, 2); - return; + fault(addr, 2, "Memory Fault: "); + return false; } u32 shift = (addr & 6) * 8; u64 mask = u64(0xFFFFu) << shift; @@ -130,14 +152,15 @@ namespace dragon { desired = (expected & ~mask) | (u64(value) << shift); } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed)); + return true; } - void RAM::store_u8(u32 addr, u8 value) + bool RAM::store_u8(PhysycalAddress addr, u8 value) { if (addr >= m_size) { - fault(addr, 1); - return; + fault(addr, 1, "Memory Fault: "); + return false; } u32 shift = (addr & 7) * 8; u64 mask = u64(0xFFu) << shift; @@ -148,11 +171,12 @@ namespace dragon { desired = (expected & ~mask) | (u64(value) << shift); } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed)); + return true; } - void RAM::fault(u32 addr, u32 size) const + void RAM::fault(PhysycalAddress addr, u32 size, const String& msg) const { - std::cout << "Memory Fault: " << ostd::String::getHexStr(addr, true, 4) << "\n"; + std::cout << msg << ostd::String::getHexStr(addr, true, 4) << "\n"; /* TODO: raise guest trap */ } } diff --git a/src/hardware/RAM.hpp b/src/hardware/RAM.hpp index d31a27e..54c24f4 100644 --- a/src/hardware/RAM.hpp +++ b/src/hardware/RAM.hpp @@ -21,46 +21,33 @@ #pragma once #include -#include + +#include "BUS.hpp" namespace dragon { namespace hw { - class RAM + class RAM : public AtomicStorageMemoryDevice { public: - explicit RAM(u64 size); - ~RAM(void); - RAM(const RAM&) = delete; - RAM& operator=(const RAM&) = delete; + explicit RAM(u64 size) : AtomicStorageMemoryDevice(size) { } + + bool guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) override; // ---- Aligned loads ---- - u64 load_u64(u32 addr) const; - u32 load_u32(u32 addr) const; - u16 load_u16(u32 addr) const; - u8 load_u8 (u32 addr) const; - inline i64 load_i64(u32 addr) const { return cast(load_u64(addr)); } - inline i32 load_i32(u32 addr) const { return cast(load_u32(addr)); } - inline i16 load_i16(u32 addr) const { return cast(load_u16(addr)); } - inline i8 load_i8 (u32 addr) const { return cast(load_u8 (addr)); } + u64 load_u64(PhysycalAddress addr) const override; + u32 load_u32(PhysycalAddress addr) const override; + u16 load_u16(PhysycalAddress addr) const override; + u8 load_u8 (PhysycalAddress addr) const override; // ---- Aligned stores ---- - void store_u64(u32 addr, u64 value); - void store_u32(u32 addr, u32 value); - void store_u16(u32 addr, u16 value); - void store_u8 (u32 addr, u8 value); - inline void store_i64(u32 addr, u64 value) { store_u64(addr, cast(value)); } - inline void store_i32(u32 addr, u32 value) { store_u32(addr, cast(value)); } - inline void store_i16(u32 addr, u16 value) { store_u16(addr, cast(value)); } - inline void store_i8 (u32 addr, u8 value) { store_u8 (addr, cast(value)); } + bool store_u64(PhysycalAddress addr, u64 value) override; + bool store_u32(PhysycalAddress addr, u32 value) override; + bool store_u16(PhysycalAddress addr, u16 value) override; + bool store_u8 (PhysycalAddress addr, u8 value) override; - void fault(u32 addr, u32 size) const; - - private: - std::atomic* m_words; - u64 m_wordCount; - u64 m_size; + [[noreturn]] void fault(PhysycalAddress addr, u32 size, const String& msg = "") const override; }; } } diff --git a/src/tools/tools_main.cpp b/src/tools/tools_main.cpp index 1369646..891c37d 100644 --- a/src/tools/tools_main.cpp +++ b/src/tools/tools_main.cpp @@ -1,3 +1,23 @@ +/* + 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 . +*/ + #include int main(int argc, char** argv)